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 }