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"