File indexing completed on 2024-05-12 17:08:23

0001 /*
0002     SPDX-FileCopyrightText: 2014-2015 Sebastian Kügler <sebas@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "iconmodel.h"
0008 
0009 #include <QByteArray>
0010 #include <QDateTime>
0011 #include <QDebug>
0012 #include <QDir>
0013 #include <QDirIterator>
0014 #include <QElapsedTimer>
0015 #include <QFile>
0016 #include <QIcon>
0017 #include <QJsonDocument>
0018 #include <QStandardPaths>
0019 
0020 #include <KConfigGroup>
0021 #include <KIO/OpenFileManagerWindowJob>
0022 #include <KIconLoader>
0023 #include <KIconTheme>
0024 #include <KSharedConfig>
0025 
0026 #include <algorithm>
0027 #include <cstring>
0028 #include <iostream>
0029 
0030 using namespace CuttleFish;
0031 
0032 static QTextStream cout(stdout);
0033 
0034 IconModel::IconModel(QObject *parent)
0035     : QAbstractListModel(parent)
0036     , m_loading(false)
0037 {
0038     m_roleNames.insert(FileName, "fileName");
0039     m_roleNames.insert(IconName, "iconName");
0040     m_roleNames.insert(Icon, "icon");
0041     m_roleNames.insert(FullPath, "fullPath");
0042     m_roleNames.insert(Category, "category");
0043     m_roleNames.insert(Scalable, "scalable");
0044     m_roleNames.insert(Sizes, "sizes");
0045     m_roleNames.insert(Theme, "iconTheme");
0046     m_roleNames.insert(Type, "type");
0047 
0048     m_categories = QStringList() << "all"
0049                                  << "actions"
0050                                  << "animations"
0051                                  << "apps"
0052                                  << "categories"
0053                                  << "devices"
0054                                  << "emblems"
0055                                  << "emotes"
0056                                  << "filesystems"
0057                                  << "international"
0058                                  << "mimetypes"
0059                                  << "places"
0060                                  << "status";
0061 
0062     load();
0063 }
0064 
0065 QHash<int, QByteArray> IconModel::roleNames() const
0066 {
0067     return m_roleNames;
0068 }
0069 
0070 int IconModel::rowCount(const QModelIndex &parent) const
0071 {
0072     Q_UNUSED(parent)
0073     if (m_data.size() <= 0) {
0074         return 0;
0075     } else {
0076         return m_data.size();
0077     }
0078 }
0079 
0080 QVariant IconModel::data(const QModelIndex &index, int role) const
0081 {
0082     if (index.isValid()) {
0083         QString icon = m_icons.at(index.row());
0084         switch (role) {
0085         case IconName:
0086             return icon;
0087         }
0088         return m_data[icon][key(role)];
0089     }
0090     return QVariant();
0091 }
0092 
0093 QString IconModel::key(int role) const
0094 {
0095     return QString::fromLocal8Bit(m_roleNames[role]);
0096 }
0097 
0098 void IconModel::add(const QFileInfo &info, const QString &cat)
0099 {
0100     QStringList cats;
0101     Q_FOREACH (auto c, m_categories) {
0102         cats << c.toLower();
0103     }
0104 
0105     if (!cats.contains(cat)) {
0106         m_categories << cat;
0107         emit categoriesChanged();
0108     }
0109 
0110     const QString fname = info.fileName();
0111     bool scalable = false;
0112     QString icon = fname;
0113     if (fname.endsWith(QLatin1String(".png"))) {
0114         icon.remove(".png");
0115     } else if (fname.endsWith(QLatin1String(".svgz"))) {
0116         icon.remove(".svgz");
0117         scalable = true;
0118     } else if (fname.endsWith(QLatin1String(".svg"))) {
0119         icon.remove(".svg");
0120         scalable = true;
0121     }
0122     QVariantMap &data = m_data[icon];
0123     if (!m_icons.contains(icon)) {
0124         data["fullPath"] = info.absoluteFilePath();
0125         data["iconName"] = icon;
0126         data["fileName"] = info.fileName();
0127         data["category"] = cat;
0128         data["type"] = QStringLiteral("icon");
0129         data["scalable"] = scalable;
0130         data["iconTheme"] = QStringLiteral("breeze");
0131 
0132         m_icons << icon;
0133     }
0134     if (scalable && !data["scalable"].toBool()) {
0135         data["scalable"] = true;
0136     }
0137 
0138     QStringList _s = info.path().split('/');
0139     if (_s.count() > 2) {
0140         QString size = _s[_s.count() - 2]; // last but one is size, last is category
0141         if (size.indexOf("x") > 1) {
0142             size = size.split("x")[0];
0143             QStringList sizes = data["sizes"].toStringList();
0144             if (!sizes.contains(size)) {
0145                 // qDebug() << "Size added" <<  sizes << size << data["iconName"];
0146                 sizes << size;
0147                 data["sizes"] = sizes;
0148             }
0149         }
0150     }
0151 }
0152 
0153 QStringList IconModel::categories() const
0154 {
0155     return m_categories;
0156 }
0157 
0158 void IconModel::load()
0159 {
0160     // qDebug() << "\n -- Loading (category / filter) : " << m_category << m_filter;
0161     m_loading = true;
0162     emit loadingChanged();
0163 
0164     QElapsedTimer tt;
0165     tt.start();
0166     const QDirIterator::IteratorFlags flags = QDirIterator::Subdirectories;
0167     const QStringList nameFilters = QStringList();
0168 
0169     beginResetModel();
0170     m_data.clear();
0171     m_icons.clear();
0172     // sm_categories.clear();
0173     QString iconTheme;
0174     if (KIconLoader::global()) {
0175         iconTheme = KIconLoader::global()->theme()->internalName();
0176     } else {
0177         return;
0178     }
0179     QStringList searchPaths;
0180 
0181     QStringList iconThemePaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, //
0182                                                            QStringLiteral("icons/") + iconTheme,
0183                                                            QStandardPaths::LocateDirectory);
0184 
0185     if (iconThemePaths.count() > 0) {
0186         searchPaths << iconThemePaths;
0187     }
0188 
0189     QStringList hicolorThemePaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, //
0190                                                               QStringLiteral("icons/hicolor"),
0191                                                               QStandardPaths::LocateDirectory);
0192     if (hicolorThemePaths.count() > 0) {
0193         searchPaths << hicolorThemePaths;
0194     }
0195 
0196     foreach (const QString &iconPath, searchPaths) {
0197         QDirIterator cats(iconPath, nameFilters, QDir::Dirs, QDirIterator::NoIteratorFlags);
0198         while (cats.hasNext()) {
0199             cats.next();
0200             const QString fpath = cats.filePath();
0201             const QString category = cats.fileName();
0202             if (category != "." && category != "..") {
0203                 QDirIterator it(fpath, nameFilters, QDir::Files, flags);
0204                 while (it.hasNext()) {
0205                     it.next();
0206                     const QFileInfo &info = it.fileInfo();
0207                     add(info, categoryFromPath(info.absoluteFilePath()));
0208                 }
0209             }
0210         }
0211     }
0212 
0213     endResetModel();
0214 
0215     m_loading = false;
0216     emit loadingChanged();
0217 }
0218 
0219 QString IconModel::categoryFromPath(const QString &path)
0220 {
0221     QStringList cats;
0222     Q_FOREACH (auto c, m_categories) {
0223         cats << c.toLower();
0224     }
0225     // cats << "actions" << "apps" << "places" << "status";
0226     const QStringList _p1 = path.split("/icons/");
0227     if (_p1.count() > 1) {
0228         foreach (const QString &cat, cats) {
0229             if (_p1[1].indexOf(cat) != -1) {
0230                 return cat;
0231             }
0232         }
0233     }
0234     return QString();
0235 }
0236 
0237 bool IconModel::loading()
0238 {
0239     return m_loading;
0240 }
0241 
0242 void IconModel::output(const QString &text)
0243 {
0244     cout << text.toLocal8Bit();
0245     cout.flush();
0246 }
0247 
0248 void IconModel::openContainingFolder(const QString &filename)
0249 {
0250     KIO::highlightInFileManager({QUrl(filename)});
0251 }
0252 
0253 QVariantList IconModel::inOtherThemes(const QString &name, int iconSize)
0254 {
0255     QVariantList list;
0256     const QStringList themes = KIconTheme::list();
0257     for (const auto &themeName : themes) {
0258         const KIconTheme theme(themeName);
0259         const QString iconPath = theme.iconPathByName(name, iconSize, KIconLoader::MatchBest);
0260         list.append(QVariantMap({{"themeName", themeName}, {"iconPath", iconPath}}));
0261     }
0262     return list;
0263 }