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

0001 /*
0002     SPDX-FileCopyrightText: 2017 Nicolas Carion
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #include "profiletreemodel.hpp"
0007 #include "../profilemodel.hpp"
0008 #include "../profilerepository.hpp"
0009 #include "abstractmodel/treeitem.hpp"
0010 
0011 #include <KLocalizedString>
0012 #include <QIcon>
0013 #include <array>
0014 #include <functional>
0015 #include <vector>
0016 
0017 ProfileTreeModel::ProfileTreeModel(QObject *parent)
0018     : AbstractTreeModel(parent)
0019 {
0020 }
0021 
0022 std::shared_ptr<ProfileTreeModel> ProfileTreeModel::construct(QObject *parent)
0023 {
0024     std::shared_ptr<ProfileTreeModel> self(new ProfileTreeModel(parent));
0025     QList<QVariant> rootData;
0026     rootData << "Description"
0027              << "Path"
0028              << "Height"
0029              << "Width"
0030              << "display_aspect_num"
0031              << "display_aspect_den"
0032              << "sample_aspect_ratio"
0033              << "fps"
0034              << "colorspace";
0035     self->rootItem = TreeItem::construct(rootData, self, true);
0036     ProfileRepository::get()->refresh();
0037     QVector<QPair<QString, QString>> profiles = ProfileRepository::get()->getAllProfiles();
0038 
0039     constexpr size_t nbCrit = 3; // number of criterion we check for profile classification
0040 
0041     // helper lambda that creates a profile category with the given name
0042     auto createCat = [&](const QString &name) { return self->rootItem->appendChild(QList<QVariant>{name}); };
0043     // We define the filters as a vector of pairs. The first element correspond to the tree item holding matching profiles, and the array correspond to the
0044     // filter itself
0045     std::vector<std::pair<std::shared_ptr<TreeItem>, std::array<QVariant, nbCrit>>> filters{
0046         {createCat(i18n("5K (Wide 2160)")), {{5120, 2160, -1}}},
0047         {createCat(i18n("4K UHD 2160")), {{3840, 2160, -1}}},
0048         {createCat(i18n("4K DCI 2160")), {{4096, 2160, -1}}},
0049         {createCat(i18n("2.5K QHD 1440")), {{-1, 1440, -1}}},
0050         {createCat(i18n("Full HD 1080")), {{1920, 1080, -1}}},
0051         {createCat(i18n("HD 720")), {{-1, 720, -1}}},
0052         {createCat(i18n("SD/DVD")), {{720, QVariant::fromValue(QPair<int, int>{480, 576}), 4}}},
0053         {createCat(i18n("SD/DVD Widescreen")), {{720, QVariant::fromValue(QPair<int, int>{480, 576}), 16}}},
0054     };
0055 
0056     auto customCat = createCat(i18n("Custom"));
0057     // We define lambdas that controls how a given field should be filtered
0058     std::array<std::function<bool(QVariant, std::unique_ptr<ProfileModel> &)>, nbCrit> filtLambdas;
0059     filtLambdas[0] = [](const QVariant &width, std::unique_ptr<ProfileModel> &ptr) { return width == -1 || ptr->width() == width; };
0060     filtLambdas[1] = [](const QVariant &height, std::unique_ptr<ProfileModel> &ptr) {
0061         if (height.canConvert<int>()) {
0062             return height.toInt() == -1 || ptr->height() == height.toInt();
0063         }
0064         QPair<int, int> valid_values = height.value<QPair<int, int>>();
0065         return ptr->height() == valid_values.first || ptr->height() == valid_values.second;
0066     };
0067     filtLambdas[2] = [](const QVariant &display_aspect_num, std::unique_ptr<ProfileModel> &ptr) {
0068         return display_aspect_num == -1 || ptr->display_aspect_num() == display_aspect_num;
0069     };
0070     for (const auto &profile : qAsConst(profiles)) {
0071         bool foundMatch = false;
0072         // we get a pointer to the profilemodel
0073         std::unique_ptr<ProfileModel> &ptr = ProfileRepository::get()->getProfile(profile.second);
0074         // we create the data list corresponding to this profile
0075         QList<QVariant> data;
0076         data << profile.first << profile.second << ptr->height() << ptr->width() << ptr->display_aspect_num() << ptr->display_aspect_den() << ptr->sar()
0077              << ptr->fps() << ProfileRepository::getColorspaceDescription(ptr->colorspace());
0078         for (const auto &filter : filters) {
0079             bool matching = true;
0080             for (size_t i = 0; i < nbCrit && matching; ++i) {
0081                 matching = filtLambdas[i](filter.second[i], ptr);
0082             }
0083             if (matching) {
0084                 foundMatch = true;
0085                 filter.first->appendChild(data);
0086                 break;
0087             }
0088         }
0089         if (!foundMatch) {
0090             // no filter matched, we default to custom
0091             customCat->appendChild(data);
0092         }
0093     }
0094     return self;
0095 }
0096 
0097 QVariant ProfileTreeModel::data(const QModelIndex &index, int role) const
0098 {
0099     if (!index.isValid()) {
0100         return QVariant();
0101     }
0102 
0103     auto item = getItemById(int(index.internalId()));
0104     if (role == Qt::DecorationRole) {
0105         if (item->depth() == 1) {
0106             return QIcon::fromTheme(QStringLiteral("folder"));
0107         }
0108         return QIcon::fromTheme(QStringLiteral("file"));
0109     }
0110 
0111     if (role != Qt::DisplayRole) {
0112         return QVariant();
0113     }
0114     return item->dataColumn(index.column());
0115 }
0116 
0117 QString ProfileTreeModel::getProfile(const QModelIndex &index)
0118 {
0119     if (index.isValid()) {
0120         auto item = getItemById(int(index.internalId()));
0121         if (item->depth() == 2) {
0122             return item->dataColumn(1).toString();
0123         }
0124     }
0125     return QString();
0126 }
0127 
0128 QModelIndex ProfileTreeModel::findProfile(const QString &profile)
0129 {
0130     // we iterate over categories
0131     for (int i = 0; i < rootItem->childCount(); ++i) {
0132         // we iterate over profiles of the category
0133         std::shared_ptr<TreeItem> category = rootItem->child(i);
0134         for (int j = 0; j < category->childCount(); ++j) {
0135             // we retrieve profile path
0136             std::shared_ptr<TreeItem> child = category->child(j);
0137             QString path = child->dataColumn(1).toString();
0138             if (path == profile) {
0139                 return createIndex(j, 0, quintptr(child->getId()));
0140             }
0141         }
0142     }
0143     return {};
0144 }