From 94aa71163497ea36a694d2a332cb2d90762842c5 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sat, 2 Sep 2023 09:47:58 -0400 Subject: [PATCH] Add support for configuring featured art --- CMakeLists.txt | 2 ++ src/artconfigwindow.cpp | 33 ++++++++++++++++--- src/artconfigwindow.h | 8 ++++- src/artmodel.cpp | 4 ++- src/artmodel.h | 8 +++-- src/featuredartmodel.cpp | 71 ++++++++++++++++++++++++++++++++++++++++ src/featuredartmodel.h | 24 ++++++++++++++ src/mainwindow.cpp | 5 +-- 8 files changed, 145 insertions(+), 10 deletions(-) create mode 100644 src/featuredartmodel.cpp create mode 100644 src/featuredartmodel.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9043215..f63dc78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,8 @@ target_sources(Redai PRIVATE src/artdetailwindow.h src/artmodel.cpp src/artmodel.h + src/featuredartmodel.cpp + src/featuredartmodel.h src/imagelabel.cpp src/imagelabel.h src/main.cpp diff --git a/src/artconfigwindow.cpp b/src/artconfigwindow.cpp index 6e8263b..5d98362 100644 --- a/src/artconfigwindow.cpp +++ b/src/artconfigwindow.cpp @@ -15,7 +15,7 @@ #include #include -ArtConfigWindow::ArtConfigWindow(const QString &filename, QWidget *parent) +ArtConfigWindow::ArtConfigWindow(const QString &filename, const QString &definitionDirectory, const QString &assetDirectory, QWidget *parent) : QDialog(parent) { setWindowModality(Qt::WindowModality::WindowModal); @@ -30,8 +30,11 @@ ArtConfigWindow::ArtConfigWindow(const QString &filename, QWidget *parent) formLayoutWidget->setLayout(formLayout); mainLayout->addWidget(formLayoutWidget); - auto galleryScrollArea = new QScrollArea(); - formLayout->addWidget(galleryScrollArea); + model = new FeaturedArtModel(definitionDirectory, assetDirectory); + + auto galleryListView = new QListView(); + galleryListView->setModel(model); + formLayout->addWidget(galleryListView); m_newBannerEdit = new QLineEdit(); formLayout->addRow(i18nc("@label:textbox", "New Banner"), m_newBannerEdit); @@ -47,10 +50,11 @@ ArtConfigWindow::ArtConfigWindow(const QString &filename, QWidget *parent) bottomButtonLayout->addWidget(cancelButton); bottomButtonLayout->addStretch(1); - auto saveButton = new QPushButton(QIcon::fromTheme(QStringLiteral("dialog-ok")), i18nc("@action:button", "Save")); + saveButton = new QPushButton(QIcon::fromTheme(QStringLiteral("dialog-ok")), i18nc("@action:button", "Save")); connect(saveButton, &QPushButton::clicked, this, [this, filename] { saveData(filename); }); + saveButton->setEnabled(false); bottomButtonLayout->addWidget(saveButton); if (QFile::exists(filename)) { @@ -69,6 +73,16 @@ void ArtConfigWindow::loadData(const QString &filename) m_newBannerEdit->setText(artJson[QStringLiteral("new-banner")].toString()); m_commissionsOpen->setChecked(artJson[QStringLiteral("commissions")].toBool()); + + connect(model, &ArtModel::loadingFinished, this, [=] { + saveButton->setEnabled(true); + + QStringList featuredList; + for (auto featuredId : artJson["featured"].toArray()) { + featuredList.push_back(featuredId.toString()); + } + model->setFeaturedItems(featuredList); + }); } void ArtConfigWindow::saveData(const QString &filename) @@ -79,6 +93,17 @@ void ArtConfigWindow::saveData(const QString &filename) object[QStringLiteral("new-banner")] = m_newBannerEdit->text(); object[QStringLiteral("commissions")] = m_commissionsOpen->isChecked(); + QJsonArray featuredArray; + for (int i = 0; i < model->rowCount({}); i++) { + const auto checkState = model->data(model->index(i, 0), Qt::CheckStateRole).value(); + if (checkState == Qt::Checked) { + QFileInfo fileInfo(model->data(model->index(i, 1), Qt::DisplayRole).toString()); + featuredArray.push_back(fileInfo.baseName()); + } + } + + object["featured"] = featuredArray; + const QJsonDocument jsonDoc(object); QFile file(filename); diff --git a/src/artconfigwindow.h b/src/artconfigwindow.h index 5ad6218..3c9d2d9 100644 --- a/src/artconfigwindow.h +++ b/src/artconfigwindow.h @@ -13,11 +13,13 @@ #include #include +#include "featuredartmodel.h" + class ArtConfigWindow : public QDialog { Q_OBJECT public: - explicit ArtConfigWindow(const QString &filename, QWidget *parent = nullptr); + explicit ArtConfigWindow(const QString &filename, const QString &definitionDirectory, const QString &assetDirectory, QWidget *parent = nullptr); private: void loadData(const QString &filename); @@ -25,4 +27,8 @@ private: QLineEdit *m_newBannerEdit = nullptr; QCheckBox *m_commissionsOpen = nullptr; + + FeaturedArtModel *model = nullptr; + + QPushButton *saveButton = nullptr; }; \ No newline at end of file diff --git a/src/artmodel.cpp b/src/artmodel.cpp index 76cd96e..838c247 100644 --- a/src/artmodel.cpp +++ b/src/artmodel.cpp @@ -43,7 +43,7 @@ ArtModel::ArtModel(const QDir &definitionDirectory, const QDir &assetDirectory, endInsertRows(); } - const std::function loadPiece = [this](const PieceInformation &info) -> ArtPiece { + const std::function loadPiece = [](const PieceInformation &info) -> ArtPiece { ArtPiece p(info.definition, info.asset); p.image.load(p.filename); @@ -134,6 +134,8 @@ void ArtModel::finished() }); Q_EMIT dataChanged(index(0, 0), index(m_artPieces.size(), 0)); + + Q_EMIT loadingFinished(); } ArtPiece::ArtPiece(const QString &filename, const QString &assetFilename) diff --git a/src/artmodel.h b/src/artmodel.h index d75f819..b3b69ca 100644 --- a/src/artmodel.h +++ b/src/artmodel.h @@ -38,11 +38,15 @@ public: [[nodiscard]] QVariant data(const QModelIndex &index, int role) const override; [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override; +Q_SIGNALS: + void loadingFinished(); + +protected: + QVector m_artPieces; + private: void pieceFinished(int index); void finished(); QFutureWatcher *piecesFuture; - - QVector m_artPieces; }; diff --git a/src/featuredartmodel.cpp b/src/featuredartmodel.cpp new file mode 100644 index 0000000..e789ea4 --- /dev/null +++ b/src/featuredartmodel.cpp @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "featuredartmodel.h" + +#include + +FeaturedArtModel::FeaturedArtModel(const QString &definitionDirectory, const QString &assetDirectory) + : ArtModel(definitionDirectory, assetDirectory) +{ +} + +QVariant FeaturedArtModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == Qt::DisplayRole) { + if (index.column() == 0) { + return ArtModel::data(FeaturedArtModel::index(index.row(), 2), role); + } else { + return ArtModel::data(FeaturedArtModel::index(index.row(), 0), role); + } + } else if (role == Qt::DecorationRole && index.column() == 0) { + return ArtModel::data(FeaturedArtModel::index(index.row(), 1), role); + } else if (role == Qt::CheckStateRole) { + return checkedItems.contains(index) ? Qt::Checked : Qt::Unchecked; + } + + return ArtModel::data(index, role); +} + +Qt::ItemFlags FeaturedArtModel::flags(const QModelIndex &index) const +{ + const Qt::ItemFlags defaultFlags = ArtModel::flags(index); + if (index.isValid()) { + return defaultFlags | Qt::ItemIsUserCheckable; + } + + return defaultFlags; +} + +bool FeaturedArtModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid() || role != Qt::CheckStateRole) { + return false; + } + + if (value == Qt::Checked) { + checkedItems.insert(index); + } else { + checkedItems.remove(index); + } + + emit dataChanged(index, index); + return true; +} + +void FeaturedArtModel::setFeaturedItems(QStringList featured) +{ + for (const auto &id : featured) { + for (int i = 0; i < m_artPieces.size(); i++) { + ArtPiece &piece = m_artPieces[i]; + QFileInfo fileInfo(piece.jsonFilename); + if (fileInfo.baseName() == id) { + setData(index(i, 0), Qt::Checked, Qt::CheckStateRole); + } + } + } +} diff --git a/src/featuredartmodel.h b/src/featuredartmodel.h new file mode 100644 index 0000000..5bb0115 --- /dev/null +++ b/src/featuredartmodel.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "artmodel.h" + +class FeaturedArtModel : public ArtModel +{ +public: + FeaturedArtModel(const QString &definitionDirectory, const QString &assetDirectory); + + [[nodiscard]] QVariant data(const QModelIndex &index, int role) const override; + + [[nodiscard]] Qt::ItemFlags flags(const QModelIndex &index) const override; + + bool setData(const QModelIndex &index, const QVariant &value, int role) override; + + void setFeaturedItems(QStringList featured); + +private: + QSet checkedItems; +}; \ No newline at end of file diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 55f2c50..c355b3c 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -25,8 +25,9 @@ MainWindow::MainWindow(const QDir &definitionDirectory, const QDir &assetDirecto auto manageMenu = menuBar->addMenu(i18nc("@title:menu Manage site", "Manage")); auto editConfigAction = manageMenu->addAction(i18nc("@action:inmenu", "Edit Config...")); - connect(editConfigAction, &QAction::triggered, this, [this, dataDirectory] { - auto window = new ArtConfigWindow(dataDirectory.absoluteFilePath("art-config.json"), this); + connect(editConfigAction, &QAction::triggered, this, [this, dataDirectory, definitionDirectory, assetDirectory] { + auto window = + new ArtConfigWindow(dataDirectory.absoluteFilePath("art-config.json"), definitionDirectory.absolutePath(), assetDirectory.absolutePath(), this); window->show(); });