File indexing completed on 2026-07-12 16:17:44

0001 /*
0002     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 #include "decorationmodel.h"
0007 // KDecoration2
0008 #include <KDecoration2/Decoration>
0009 #include <KDecoration2/DecorationSettings>
0010 #include <KDecoration2/DecorationThemeProvider>
0011 // KDE
0012 #include <KPluginFactory>
0013 #include <KPluginMetaData>
0014 // Qt
0015 #include <QDebug>
0016 
0017 namespace KDecoration2
0018 {
0019 
0020 namespace Configuration
0021 {
0022 static const QString s_pluginName = QStringLiteral("org.kde.kdecoration2");
0023 
0024 DecorationsModel::DecorationsModel(QObject *parent)
0025     : QAbstractListModel(parent)
0026 {
0027 }
0028 
0029 DecorationsModel::~DecorationsModel() = default;
0030 
0031 int DecorationsModel::rowCount(const QModelIndex &parent) const
0032 {
0033     if (parent.isValid()) {
0034         return 0;
0035     }
0036     return m_plugins.size();
0037 }
0038 
0039 QVariant DecorationsModel::data(const QModelIndex &index, int role) const
0040 {
0041     if (!index.isValid() || index.column() != 0 || index.row() < 0 || index.row() >= int(m_plugins.size())) {
0042         return QVariant();
0043     }
0044     const KDecoration2::DecorationThemeMetaData &d = m_plugins.at(index.row());
0045     switch (role) {
0046     case Qt::DisplayRole:
0047         return d.visibleName();
0048     case PluginNameRole:
0049         return d.pluginId();
0050     case ThemeNameRole:
0051         return d.themeName();
0052     case ConfigurationRole:
0053         return d.hasConfiguration();
0054     case RecommendedBorderSizeRole:
0055         return Utils::borderSizeToString(d.borderSize());
0056     }
0057     return QVariant();
0058 }
0059 
0060 QHash<int, QByteArray> DecorationsModel::roleNames() const
0061 {
0062     QHash<int, QByteArray> roles({{Qt::DisplayRole, QByteArrayLiteral("display")},
0063                                   {PluginNameRole, QByteArrayLiteral("plugin")},
0064                                   {ThemeNameRole, QByteArrayLiteral("theme")},
0065                                   {ConfigurationRole, QByteArrayLiteral("configureable")},
0066                                   {RecommendedBorderSizeRole, QByteArrayLiteral("recommendedbordersize")}});
0067     return roles;
0068 }
0069 
0070 static bool isThemeEngine(const QVariantMap &decoSettingsMap)
0071 {
0072     auto it = decoSettingsMap.find(QStringLiteral("themes"));
0073     if (it == decoSettingsMap.end()) {
0074         return false;
0075     }
0076     return it.value().toBool();
0077 }
0078 
0079 static bool isConfigureable(const QVariantMap &decoSettingsMap)
0080 {
0081     auto it = decoSettingsMap.find(QStringLiteral("kcmodule"));
0082     if (it == decoSettingsMap.end()) {
0083         return false;
0084     }
0085     return it.value().toBool();
0086 }
0087 
0088 static KDecoration2::BorderSize recommendedBorderSize(const QVariantMap &decoSettingsMap)
0089 {
0090     auto it = decoSettingsMap.find(QStringLiteral("recommendedBorderSize"));
0091     if (it == decoSettingsMap.end()) {
0092         return KDecoration2::BorderSize::Normal;
0093     }
0094     return Utils::stringToBorderSize(it.value().toString());
0095 }
0096 
0097 static QString themeListKeyword(const QVariantMap &decoSettingsMap)
0098 {
0099     auto it = decoSettingsMap.find(QStringLiteral("themeListKeyword"));
0100     if (it == decoSettingsMap.end()) {
0101         return QString();
0102     }
0103     return it.value().toString();
0104 }
0105 
0106 static QString findKNewStuff(const QVariantMap &decoSettingsMap)
0107 {
0108     auto it = decoSettingsMap.find(QStringLiteral("KNewStuff"));
0109     if (it == decoSettingsMap.end()) {
0110         return QString();
0111     }
0112     return it.value().toString();
0113 }
0114 
0115 void DecorationsModel::init()
0116 {
0117     beginResetModel();
0118     m_plugins.clear();
0119     const auto plugins = KPluginMetaData::findPlugins(s_pluginName);
0120     for (const auto &info : plugins) {
0121         std::unique_ptr<KDecoration2::DecorationThemeProvider> themeFinder(
0122             KPluginFactory::instantiatePlugin<KDecoration2::DecorationThemeProvider>(info).plugin);
0123         KDecoration2::DecorationThemeMetaData data;
0124         const auto decoSettingsMap = info.rawData().value("org.kde.kdecoration2").toObject().toVariantMap();
0125         if (themeFinder) {
0126             const QString &kns = findKNewStuff(decoSettingsMap);
0127             if (!kns.isEmpty() && !m_knsProviders.contains(kns)) {
0128                 m_knsProviders.append(kns);
0129             }
0130             if (isThemeEngine(decoSettingsMap)) {
0131                 const QString keyword = themeListKeyword(decoSettingsMap);
0132                 if (keyword.isNull()) {
0133                     // We cannot list the themes
0134                     continue;
0135                 }
0136                 const auto themesList = themeFinder->themes();
0137                 for (const KDecoration2::DecorationThemeMetaData &data : themesList) {
0138                     m_plugins.emplace_back(data);
0139                 }
0140 
0141                 // it's a theme engine, we don't want to show this entry
0142                 continue;
0143             }
0144         }
0145         data.setHasConfiguration(isConfigureable(decoSettingsMap));
0146         data.setBorderSize(recommendedBorderSize(decoSettingsMap));
0147         data.setVisibleName(info.name().isEmpty() ? info.pluginId() : info.name());
0148         data.setPluginId(info.pluginId());
0149         data.setThemeName(data.visibleName());
0150 
0151         m_plugins.emplace_back(std::move(data));
0152     }
0153     endResetModel();
0154 }
0155 
0156 QModelIndex DecorationsModel::findDecoration(const QString &pluginName, const QString &themeName) const
0157 {
0158     auto it = std::find_if(m_plugins.cbegin(), m_plugins.cend(), [pluginName, themeName](const KDecoration2::DecorationThemeMetaData &d) {
0159         return d.pluginId() == pluginName && d.themeName() == themeName;
0160     });
0161     if (it == m_plugins.cend()) {
0162         return QModelIndex();
0163     }
0164     const auto distance = std::distance(m_plugins.cbegin(), it);
0165     return createIndex(distance, 0);
0166 }
0167 
0168 }
0169 }