File indexing completed on 2024-04-21 05:36:33
0001 /* 0002 SPDX-FileCopyrightText: 2013 Reza Fatahilah Shah <rshah0385@kireihana.com> 0003 SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.de> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 #include "themesmodel.h" 0008 #include "config.h" 0009 #include "thememetadata.h" 0010 0011 #include <QDir> 0012 #include <QStandardPaths> 0013 #include <QString> 0014 #include <QUrl> 0015 0016 #include <KConfig> 0017 #include <KConfigGroup> 0018 #include <KSharedConfig> 0019 #include <QDebug> 0020 0021 ThemesModel::ThemesModel(QObject *parent) 0022 : QAbstractListModel(parent) 0023 { 0024 populate(); 0025 m_customInstalledThemes = KSharedConfig::openConfig(QStringLiteral("sddmthemeinstallerrc"))->group("DownloadedThemes").entryMap().values(); 0026 } 0027 0028 ThemesModel::~ThemesModel() 0029 { 0030 } 0031 0032 int ThemesModel::rowCount(const QModelIndex &parent) const 0033 { 0034 Q_UNUSED(parent); 0035 0036 return mThemeList.size(); 0037 } 0038 0039 QHash<int, QByteArray> ThemesModel::roleNames() const 0040 { 0041 return { 0042 {Qt::DisplayRole, QByteArrayLiteral("display")}, 0043 {IdRole, QByteArrayLiteral("id")}, 0044 {AuthorRole, QByteArrayLiteral("author")}, 0045 {DescriptionRole, QByteArrayLiteral("description")}, 0046 {LicenseRole, QByteArrayLiteral("license")}, 0047 {EmailRole, QByteArrayLiteral("email")}, 0048 {WebsiteRole, QByteArrayLiteral("website")}, 0049 {CopyrightRole, QByteArrayLiteral("copyright")}, 0050 {VersionRole, QByteArrayLiteral("version")}, 0051 {ThemeApiRole, QByteArrayLiteral("themeApi")}, 0052 {PreviewRole, QByteArrayLiteral("preview")}, 0053 {PathRole, QByteArrayLiteral("path")}, 0054 {ConfigFileRole, QByteArrayLiteral("configFile")}, 0055 {CurrentBackgroundRole, QByteArrayLiteral("currentBackground")}, 0056 {DeletableRole, QByteArrayLiteral("deletable")}, 0057 }; 0058 } 0059 0060 QVariant ThemesModel::data(const QModelIndex &index, int role) const 0061 { 0062 if (!checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid)) { 0063 return QVariant(); 0064 } 0065 0066 const ThemeMetadata metadata = mThemeList[index.row()]; 0067 0068 switch (role) { 0069 case Qt::DisplayRole: 0070 return metadata.name(); 0071 case ThemesModel::IdRole: 0072 return metadata.themeid(); 0073 case ThemesModel::AuthorRole: 0074 return metadata.author(); 0075 case ThemesModel::DescriptionRole: 0076 return metadata.description(); 0077 case ThemesModel::LicenseRole: 0078 return metadata.license(); 0079 case ThemesModel::EmailRole: 0080 return metadata.email(); 0081 case ThemesModel::WebsiteRole: 0082 return metadata.website(); 0083 case ThemesModel::CopyrightRole: 0084 return metadata.copyright(); 0085 case ThemesModel::VersionRole: 0086 return metadata.version(); 0087 case ThemesModel::ThemeApiRole: 0088 return metadata.themeapi(); 0089 case ThemesModel::PreviewRole: 0090 return QUrl::fromLocalFile(metadata.path() + metadata.screenshot()); 0091 case ThemesModel::PathRole: 0092 return metadata.path(); 0093 case ThemesModel::ConfigFileRole: 0094 return metadata.configfile(); 0095 case ThemesModel::CurrentBackgroundRole: 0096 if (metadata.supportsBackground()) { 0097 return m_currentWallpapers[metadata.themeid()]; 0098 } 0099 break; 0100 case DeletableRole: 0101 return m_customInstalledThemes.contains(metadata.path().chopped(1)); // Chop the trailing / 0102 } 0103 0104 return QVariant(); 0105 } 0106 0107 bool ThemesModel::setData(const QModelIndex &index, const QVariant &value, int role) 0108 { 0109 if (!checkIndex(index, CheckIndexOption::IndexIsValid | CheckIndexOption::ParentIsInvalid)) { 0110 return false; 0111 } 0112 if (role != ThemesModel::CurrentBackgroundRole) { 0113 return false; 0114 } 0115 m_currentWallpapers[mThemeList[index.row()].themeid()] = value.toString(); 0116 Q_EMIT dataChanged(index, index, {ThemesModel::CurrentBackgroundRole}); 0117 return true; 0118 } 0119 0120 void ThemesModel::populate() 0121 { 0122 if (!mThemeList.isEmpty()) { 0123 beginResetModel(); 0124 mThemeList.clear(); 0125 endResetModel(); 0126 } 0127 0128 const QString themesBaseDir = KSharedConfig::openConfig(QStringLiteral(SDDM_CONFIG_FILE), KConfig::SimpleConfig)->group("Theme").readEntry("ThemeDir"); 0129 QStringList themesBaseDirs; 0130 if (!themesBaseDir.isEmpty()) { 0131 themesBaseDirs.append(themesBaseDir); 0132 } else { 0133 themesBaseDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("sddm/themes"), QStandardPaths::LocateDirectory); 0134 } 0135 0136 auto alreadyHave = [this](const QString &theme) { 0137 return std::any_of(mThemeList.cbegin(), mThemeList.cend(), [&theme](const ThemeMetadata &data) { 0138 return data.themeid() == theme; 0139 }); 0140 }; 0141 for (const auto &folder : themesBaseDirs) { 0142 QDir dir(folder); 0143 if (!dir.exists()) { 0144 return; 0145 } 0146 for (const QString &theme : dir.entryList(QDir::AllDirs | QDir::Readable | QDir::NoDotAndDotDot)) { 0147 QString path = folder + QLatin1Char('/') + theme; 0148 if (!alreadyHave(theme) && QFile::exists(path + QStringLiteral("/metadata.desktop"))) { 0149 add(theme, path); 0150 } 0151 } 0152 } 0153 } 0154 0155 void ThemesModel::add(const QString &id, const QString &path) 0156 { 0157 beginInsertRows(QModelIndex(), mThemeList.count(), mThemeList.count()); 0158 0159 const auto data = ThemeMetadata(id, path); 0160 mThemeList.append(data); 0161 if (data.supportsBackground()) { 0162 const QString themeConfigPath = data.path() + data.configfile(); 0163 auto themeConfig = KSharedConfig::openConfig(themeConfigPath + QStringLiteral(".user"), KConfig::CascadeConfig); 0164 themeConfig->addConfigSources({themeConfigPath}); 0165 const QString backgroundPath = themeConfig->group("General").readEntry("background"); 0166 if (backgroundPath.startsWith(QStringLiteral("/"))) { 0167 m_currentWallpapers.insert(data.themeid(), backgroundPath); 0168 } else { 0169 m_currentWallpapers.insert(data.themeid(), data.path() + backgroundPath); 0170 } 0171 } 0172 endInsertRows(); 0173 } 0174 0175 void ThemesModel::dump(const QString &id, const QString &path) 0176 { 0177 Q_UNUSED(id) 0178 0179 ThemeMetadata metadata(path); 0180 0181 qDebug() << "Theme Path:" << metadata.path(); 0182 qDebug() << "Name: " << metadata.name(); 0183 qDebug() << "Version: " << metadata.version(); 0184 qDebug() << "Author: " << metadata.author(); 0185 qDebug() << "Description: " << metadata.description(); 0186 qDebug() << "Email: " << metadata.email(); 0187 qDebug() << "License: " << metadata.license(); 0188 qDebug() << "Copyright: " << metadata.copyright(); 0189 qDebug() << "Screenshot: " << metadata.screenshot(); 0190 } 0191 0192 int ThemesModel::currentIndex() const 0193 { 0194 return m_currentIndex; 0195 } 0196 0197 QString ThemesModel::currentTheme() const 0198 { 0199 return mThemeList[m_currentIndex].themeid(); 0200 } 0201 0202 void ThemesModel::setCurrentTheme(const QString &theme) 0203 { 0204 auto it = std::find_if(mThemeList.cbegin(), mThemeList.cend(), [&theme](const ThemeMetadata &themeData) { 0205 return themeData.themeid() == theme; 0206 }); 0207 const int index = it - mThemeList.cbegin(); 0208 if (it == mThemeList.cend() || index == m_currentIndex) { 0209 return; 0210 } 0211 m_currentIndex = index; 0212 Q_EMIT currentIndexChanged(); 0213 }