// SPDX-FileCopyrightText: 2023 Joshua Goins // // SPDX-License-Identifier: GPL-3.0-or-later #include "artmodel.h" #include #include #include #include #include #include #include #include #include ArtModel::ArtModel(const QDir &definitionDirectory, const QDir &assetDirectory, QObject *parent) : QAbstractTableModel(parent) { piecesFuture = new QFutureWatcher(this); connect(piecesFuture, &QFutureWatcher::resultReadyAt, this, &ArtModel::pieceFinished); connect(piecesFuture, &QFutureWatcher::finished, this, &ArtModel::finished); struct PieceInformation { QString definition; QString asset; }; QVector pieceList; QDirIterator it(definitionDirectory); while (it.hasNext()) { QFileInfo info(it.next()); if (!info.isFile()) { continue; } pieceList.push_back(PieceInformation{definitionDirectory.absoluteFilePath(info.baseName()), assetDirectory.absoluteFilePath(info.baseName())}); beginInsertRows(QModelIndex(), m_artPieces.size(), m_artPieces.size() + 1); m_artPieces.push_back({}); endInsertRows(); } const std::function loadPiece = [](const PieceInformation &info) -> ArtPiece { ArtPiece p(info.definition, info.asset); p.image.load(p.filename); p.thumbnail = QPixmap::fromImage(p.image).scaled(100, 100, Qt::AspectRatioMode::KeepAspectRatio).toImage(); return p; }; piecesFuture->setFuture(QtConcurrent::mapped(pieceList, loadPiece)); } int ArtModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return m_artPieces.size(); } int ArtModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 4; } QVariant ArtModel::data(const QModelIndex &index, const int role) const { if (!index.isValid()) { return {}; } if (role == Qt::DisplayRole) { switch (index.column()) { case 0: return m_artPieces[index.row()].filename; case 1: return {}; case 2: return m_artPieces[index.row()].title; case 3: return m_artPieces[index.row()].hasAltText; } } else if (role == Qt::UserRole) { return m_artPieces[index.row()].object; } else if (role == Qt::DecorationRole) { switch (index.column()) { case 1: return m_artPieces[index.row()].thumbnail; case 3: return m_artPieces[index.row()].hasAltText ? QIcon::fromTheme(QStringLiteral("emblem-checked")) : QIcon::fromTheme(QStringLiteral("emblem-error")); } } else if (role == Qt::UserRole + 1) { return m_artPieces[index.row()].jsonFilename; } return {}; } QVariant ArtModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Orientation::Horizontal && role == Qt::DisplayRole) { switch (section) { case 0: return i18nc("@title:column", "Filename"); case 1: return i18nc("@title:column", "Image"); case 2: return i18nc("@title:column", "Title"); case 3: return i18nc("@title:column", "Has Alt Text"); default: Q_UNREACHABLE(); } } return QAbstractTableModel::headerData(section, orientation, role); } void ArtModel::pieceFinished(const int row) { m_artPieces[row] = piecesFuture->resultAt(row); Q_EMIT dataChanged(index(row, 0), index(row + 1, 0)); } void ArtModel::finished() { std::sort(m_artPieces.begin(), m_artPieces.end(), [](const ArtPiece &a, const ArtPiece &b) { return a.date > b.date; }); Q_EMIT dataChanged(index(0, 0), index(m_artPieces.size(), 0)); Q_EMIT loadingFinished(); } ArtPiece::ArtPiece(const QString &filename, const QString &assetFilename) { jsonFilename = filename + ".json"; this->filename = assetFilename; QFile artFile(jsonFilename); artFile.open(QFile::ReadOnly); const QJsonDocument artJson = QJsonDocument::fromJson(artFile.readAll()); if (artJson[QStringLiteral("date")].toString().contains(QStringLiteral("-"))) { date = QDate::fromString(artJson[QStringLiteral("date")].toString(), QStringLiteral("yyyy-MM-dd")); } else { date = QDate::fromString(artJson[QStringLiteral("date")].toString(), QStringLiteral("yyyy")); } if (artJson.object().contains(QStringLiteral("title"))) { title = artJson.object()[QStringLiteral("title")].toString(); } if (artJson.object().contains(QStringLiteral("alt_text"))) { hasAltText = true; } }