File indexing completed on 2024-05-05 04:53:18

0001 /*
0002     SPDX-FileCopyrightText: 2023 Julius Künzel <jk.kdedev@smartlab.uber.space>
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #include "documentcheckertreemodel.h"
0007 
0008 #include "abstractmodel/treeitem.hpp"
0009 
0010 #include <KColorScheme>
0011 
0012 DocumentCheckerTreeModel::DocumentCheckerTreeModel(QObject *parent)
0013     : AbstractTreeModel{parent}
0014     , m_resourceItems()
0015 {
0016 }
0017 
0018 Qt::ItemFlags DocumentCheckerTreeModel::flags(const QModelIndex &index) const
0019 {
0020     const auto flags = QAbstractItemModel::flags(index);
0021     return flags;
0022 }
0023 
0024 std::shared_ptr<DocumentCheckerTreeModel> DocumentCheckerTreeModel::construct(const std::vector<DocumentChecker::DocumentResource> &items, QObject *parent)
0025 {
0026     std::shared_ptr<DocumentCheckerTreeModel> self(new DocumentCheckerTreeModel(parent));
0027     QList<QVariant> rootData;
0028     rootData << "Type"
0029              << "Status"
0030              << "Original Path"
0031              << "New Path";
0032     self->rootItem = TreeItem::construct(rootData, self, true);
0033 
0034     // auto createCat = [&](const QString &name) { return self->rootItem->appendChild(QList<QVariant>{name}); };
0035     // std::vector<std::shared_ptr<TreeItem>> cats{};
0036 
0037     QList<QVariant> data;
0038     data.reserve(3);
0039     for (const auto &item : items) {
0040         if (item.type == DocumentChecker::MissingType::Proxy) {
0041             // Skip proxy as they are shown in a different widget
0042             continue;
0043         }
0044 
0045         // we create the data list corresponding to this resource
0046         data.clear();
0047         data << DocumentChecker::readableNameForMissingType(item.type);
0048         data << DocumentChecker::readableNameForMissingStatus(item.status);
0049         data << item.originalFilePath;
0050         data << item.newFilePath;
0051 
0052         std::shared_ptr<TreeItem> newItem = self->rootItem->appendChild(data);
0053         self->m_resourceItems.insert(newItem->getId(), item);
0054     }
0055 
0056     return self;
0057 }
0058 
0059 void DocumentCheckerTreeModel::removeItem(const QModelIndex &ix)
0060 {
0061     int itemId = int(ix.internalId());
0062     m_resourceItems[itemId].status = DocumentChecker::MissingStatus::Remove;
0063     Q_EMIT dataChanged(index(ix.row(), 0), index(ix.row(), columnCount() - 1));
0064 }
0065 
0066 void DocumentCheckerTreeModel::slotSearchRecursively(const QString &newpath)
0067 {
0068     QDir searchDir(newpath);
0069     QMap<QModelIndex, QString> fixedMap;
0070     QMapIterator<int, DocumentChecker::DocumentResource> i(m_resourceItems);
0071     int counter = 1;
0072     while (i.hasNext()) {
0073         i.next();
0074         Q_EMIT searchProgress(counter, m_resourceItems.count());
0075         counter++;
0076         if (i.value().status != DocumentChecker::MissingStatus::Missing && i.value().status != DocumentChecker::MissingStatus::MissingButProxy) {
0077             continue;
0078         }
0079         QString newPath;
0080         if (i.value().type == DocumentChecker::MissingType::Clip) {
0081             ClipType::ProducerType type = i.value().clipType;
0082             if (type == ClipType::SlideShow) {
0083                 // Slideshows cannot be found with hash / size
0084                 newPath = DocumentChecker::searchDirRecursively(searchDir, i.value().hash, i.value().originalFilePath);
0085             } else {
0086                 newPath = DocumentChecker::searchFileRecursively(searchDir, i.value().fileSize, i.value().hash, i.value().originalFilePath);
0087             }
0088             if (newPath.isEmpty()) {
0089                 newPath = DocumentChecker::searchPathRecursively(searchDir, QUrl::fromLocalFile(i.value().originalFilePath).fileName(), type);
0090             }
0091         } else if (i.value().type == DocumentChecker::MissingType::Luma) {
0092             newPath = DocumentChecker::searchLuma(searchDir, i.value().originalFilePath);
0093 
0094         } else if (i.value().type == DocumentChecker::MissingType::AssetFile) {
0095             newPath = DocumentChecker::searchPathRecursively(searchDir, QFileInfo(i.value().originalFilePath).fileName());
0096 
0097         } else if (i.value().type == DocumentChecker::MissingType::TitleImage) {
0098             newPath = DocumentChecker::searchPathRecursively(searchDir, QFileInfo(i.value().originalFilePath).fileName());
0099         }
0100         if (!newPath.isEmpty()) {
0101             fixedMap.insert(getIndexFromId(i.key()), newPath);
0102         }
0103     }
0104     QMapIterator<QModelIndex, QString> j(fixedMap);
0105     while (j.hasNext()) {
0106         j.next();
0107         setItemsNewFilePath(j.key(), j.value(), DocumentChecker::MissingStatus::Fixed, false);
0108     }
0109     Q_EMIT dataChanged(QModelIndex(), QModelIndex());
0110     Q_EMIT searchDone();
0111 }
0112 
0113 void DocumentCheckerTreeModel::usePlaceholdersForMissing()
0114 {
0115     QMapIterator<int, DocumentChecker::DocumentResource> i(m_resourceItems);
0116     while (i.hasNext()) {
0117         i.next();
0118         if (i.value().type == DocumentChecker::MissingType::TitleFont) {
0119             continue;
0120         }
0121         if (i.value().status != DocumentChecker::MissingStatus::Missing && i.value().status != DocumentChecker::MissingStatus::MissingButProxy) {
0122             continue;
0123         }
0124         m_resourceItems[i.key()].status = DocumentChecker::MissingStatus::Placeholder;
0125     }
0126     Q_EMIT dataChanged(QModelIndex(), QModelIndex());
0127 }
0128 
0129 void DocumentCheckerTreeModel::setItemsNewFilePath(const QModelIndex &ix, const QString &url, DocumentChecker::MissingStatus status, bool refresh)
0130 {
0131     int itemId = int(ix.internalId());
0132     m_resourceItems[itemId].status = status;
0133     m_resourceItems[itemId].newFilePath = url;
0134     if (refresh) {
0135         Q_EMIT dataChanged(index(ix.row(), 0), index(ix.row(), columnCount() - 1));
0136     }
0137 }
0138 
0139 void DocumentCheckerTreeModel::setItemsFileHash(const QModelIndex &index, const QString &hash)
0140 {
0141     m_resourceItems[int(index.internalId())].hash = hash;
0142 }
0143 
0144 QVariant DocumentCheckerTreeModel::data(const QModelIndex &index, int role) const
0145 {
0146     if (!index.isValid()) {
0147         qDebug() << "Index is not valid" << index;
0148         return QVariant();
0149     }
0150 
0151     if (m_resourceItems.contains(int(index.internalId()))) {
0152         DocumentChecker::DocumentResource resource = m_resourceItems.value(int(index.internalId()));
0153 
0154         if (role == Qt::ForegroundRole) {
0155             if (resource.status == DocumentChecker::MissingStatus::Remove) {
0156                 KColorScheme scheme(qApp->palette().currentColorGroup(), KColorScheme::Window);
0157                 return scheme.foreground(KColorScheme::InactiveText).color();
0158             }
0159         }
0160 
0161         if (role == Qt::BackgroundRole && resource.status == DocumentChecker::MissingStatus::Missing && index.column() == 1) {
0162             KColorScheme scheme(qApp->palette().currentColorGroup(), KColorScheme::Window);
0163             return scheme.background(KColorScheme::NegativeBackground).color();
0164         }
0165 
0166         if (role == Qt::FontRole) {
0167             if (resource.status == DocumentChecker::MissingStatus::Remove && index.column() == 2) {
0168                 QFont f = qApp->font();
0169                 f.setStrikeOut(true);
0170                 return f;
0171             }
0172         }
0173 
0174         if (role == Qt::ToolTipRole) {
0175             if (!resource.originalFilePath.isEmpty()) {
0176                 return resource.originalFilePath;
0177             }
0178         }
0179 
0180         if (role == Qt::DecorationRole && index.column() == 1) {
0181             if (resource.status == DocumentChecker::MissingStatus::Missing) {
0182                 return QIcon::fromTheme(QStringLiteral("dialog-close"));
0183             }
0184 
0185             if (resource.status == DocumentChecker::MissingStatus::Fixed) {
0186                 return QIcon::fromTheme(QStringLiteral("dialog-ok"));
0187             }
0188 
0189             if (resource.status == DocumentChecker::MissingStatus::Placeholder) {
0190                 return QIcon::fromTheme(QStringLiteral("view-preview"));
0191             }
0192 
0193             if (resource.status == DocumentChecker::MissingStatus::Reload) {
0194                 return QIcon::fromTheme(QStringLiteral("dialog-information"));
0195             }
0196 
0197             if (resource.status == DocumentChecker::MissingStatus::Remove) {
0198                 return QIcon::fromTheme(QStringLiteral("entry-delete"));
0199             }
0200 
0201             return QVariant();
0202         }
0203         if (role != Qt::DisplayRole) {
0204             return QVariant();
0205         }
0206         switch (index.column()) {
0207         case 0:
0208             return DocumentChecker::readableNameForMissingType(resource.type);
0209         case 1:
0210             return DocumentChecker::readableNameForMissingStatus(resource.status);
0211         case 2:
0212             return resource.originalFilePath;
0213         case 3:
0214             return resource.newFilePath;
0215         default:
0216             return QVariant();
0217         }
0218     }
0219     return QVariant();
0220 }
0221 
0222 DocumentChecker::DocumentResource DocumentCheckerTreeModel::getDocumentResource(const QModelIndex &index)
0223 {
0224     return m_resourceItems.value(int(index.internalId()));
0225 }