File indexing completed on 2024-06-02 05:42:56

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 = {
0049         QLatin1String("all"),
0050         QLatin1String("actions"),
0051         QLatin1String("animations"),
0052         QLatin1String("apps"),
0053         QLatin1String("categories"),
0054         QLatin1String("devices"),
0055         QLatin1String("emblems"),
0056         QLatin1String("emotes"),
0057         QLatin1String("filesystems"),
0058         QLatin1String("international"),
0059         QLatin1String("mimetypes"),
0060         QLatin1String("places"),
0061         QLatin1String("status"),
0062     };
0063 
0064     load();
0065 }
0066 
0067 QHash<int, QByteArray> IconModel::roleNames() const
0068 {
0069     return m_roleNames;
0070 }
0071 
0072 int IconModel::rowCount(const QModelIndex &parent) const
0073 {
0074     Q_UNUSED(parent)
0075     if (m_data.size() <= 0) {
0076         return 0;
0077     } else {
0078         return m_data.size();
0079     }
0080 }
0081 
0082 QVariant IconModel::data(const QModelIndex &index, int role) const
0083 {
0084     if (index.isValid()) {
0085         QString icon = m_icons.at(index.row());
0086         switch (role) {
0087         case IconName:
0088             return icon;
0089         }
0090         return m_data[icon][key(role)];
0091     }
0092     return QVariant();
0093 }
0094 
0095 QString IconModel::key(int role) const
0096 {
0097     return QString::fromLocal8Bit(m_roleNames[role]);
0098 }
0099 
0100 void IconModel::add(const QFileInfo &info, const QString &cat)
0101 {
0102     QStringList cats;
0103     for (const auto &c : std::as_const(m_categories)) {
0104         cats << c.toLower();
0105     }
0106     if (!m_categories.contains(cat)) {
0107         m_categories.append(cat);
0108         Q_EMIT categoriesChanged();
0109     }
0110 
0111     const QString fname = info.fileName();
0112     bool scalable = false;
0113     QString icon = fname;
0114     if (fname.endsWith(QLatin1String(".png"))) {
0115         icon.remove(".png");
0116     } else if (fname.endsWith(QLatin1String(".svgz"))) {
0117         icon.remove(".svgz");
0118         scalable = true;
0119     } else if (fname.endsWith(QLatin1String(".svg"))) {
0120         icon.remove(".svg");
0121         scalable = true;
0122     }
0123     QVariantMap &data = m_data[icon];
0124     if (!m_icons.contains(icon)) {
0125         data["fullPath"] = info.absoluteFilePath();
0126         data["iconName"] = icon;
0127         data["fileName"] = info.fileName();
0128         data["category"] = cat;
0129         data["type"] = QStringLiteral("icon");
0130         data["scalable"] = scalable;
0131         data["iconTheme"] = QStringLiteral("breeze");
0132 
0133         m_icons << icon;
0134     }
0135     if (scalable && !data["scalable"].toBool()) {
0136         data["scalable"] = true;
0137     }
0138 
0139     QStringList _s = info.path().split('/');
0140     if (_s.count() > 2) {
0141         QString size = _s[_s.count() - 2]; // last but one is size, last is category
0142         if (size.indexOf("x") > 1) {
0143             size = size.split("x")[0];
0144             QStringList sizes = data["sizes"].toStringList();
0145             if (!sizes.contains(size)) {
0146                 // qDebug() << "Size added" <<  sizes << size << data["iconName"];
0147                 sizes << size;
0148                 data["sizes"] = sizes;
0149             }
0150         }
0151     }
0152 }
0153 
0154 QStringList IconModel::categories() const
0155 {
0156     return m_categories;
0157 }
0158 
0159 void IconModel::load()
0160 {
0161     // qDebug() << "\n -- Loading (category / filter) : " << m_category << m_filter;
0162     m_loading = true;
0163     Q_EMIT loadingChanged();
0164 
0165     QElapsedTimer tt;
0166     tt.start();
0167     const QDirIterator::IteratorFlags flags = QDirIterator::Subdirectories;
0168     const QStringList nameFilters = QStringList();
0169 
0170     beginResetModel();
0171     m_data.clear();
0172     m_icons.clear();
0173     // sm_categories.clear();
0174     QString iconTheme;
0175     if (KIconLoader::global()) {
0176         iconTheme = KIconLoader::global()->theme()->internalName();
0177     } else {
0178         return;
0179     }
0180     QStringList searchPaths;
0181 
0182     QStringList iconThemePaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, //
0183                                                            QStringLiteral("icons/") + iconTheme,
0184                                                            QStandardPaths::LocateDirectory);
0185 
0186     if (iconThemePaths.count() > 0) {
0187         searchPaths << iconThemePaths;
0188     }
0189 
0190     QStringList hicolorThemePaths = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, //
0191                                                               QStringLiteral("icons/hicolor"),
0192                                                               QStandardPaths::LocateDirectory);
0193     if (hicolorThemePaths.count() > 0) {
0194         searchPaths << hicolorThemePaths;
0195     }
0196 
0197     for (const QString &iconPath : searchPaths) {
0198         QDirIterator cats(iconPath, nameFilters, QDir::Dirs, QDirIterator::NoIteratorFlags);
0199         while (cats.hasNext()) {
0200             cats.next();
0201             const QString fpath = cats.filePath();
0202             const QString category = cats.fileName();
0203             if (category != "." && category != "..") {
0204                 QDirIterator it(fpath, nameFilters, QDir::Files, flags);
0205                 while (it.hasNext()) {
0206                     it.next();
0207                     const QFileInfo &info = it.fileInfo();
0208                     add(info, categoryFromPath(info.absoluteFilePath()));
0209                 }
0210             }
0211         }
0212     }
0213 
0214     endResetModel();
0215 
0216     m_loading = false;
0217     Q_EMIT loadingChanged();
0218 }
0219 
0220 QString IconModel::categoryFromPath(const QString &path)
0221 {
0222     QStringList cats;
0223     for (const auto &c : m_categories) {
0224         cats << c.toLower();
0225     }
0226     // cats << "actions" << "apps" << "places" << "status";
0227     const QStringList _p1 = path.split("/icons/");
0228     if (_p1.count() > 1) {
0229         for (const QString &cat : cats) {
0230             if (_p1[1].indexOf(cat) != -1) {
0231                 return cat;
0232             }
0233         }
0234     }
0235     return QString();
0236 }
0237 
0238 bool IconModel::loading()
0239 {
0240     return m_loading;
0241 }
0242 
0243 void IconModel::output(const QString &text)
0244 {
0245     cout << text.toLocal8Bit();
0246     cout.flush();
0247 }
0248 
0249 void IconModel::openContainingFolder(const QString &filename)
0250 {
0251     KIO::highlightInFileManager({QUrl(filename)});
0252 }
0253 
0254 QVariantList IconModel::inOtherThemes(const QString &name, int iconSize)
0255 {
0256     QVariantList list;
0257     const QStringList themes = KIconTheme::list();
0258     for (const auto &themeName : themes) {
0259         const KIconTheme theme(themeName);
0260         const QString iconPath = theme.iconPathByName(name, iconSize, KIconLoader::MatchBest);
0261         list.append(QVariantMap({{"themeName", themeName}, {"iconPath", iconPath}}));
0262     }
0263     return list;
0264 }
0265 
0266 #include "moc_iconmodel.cpp"