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 }