/* * Copyright 2014 Martin Gräßlin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "decorationmodel.h" // KDecoration2 #include #include // KDE #include #include #include #include // Qt #include namespace KDecoration2 { namespace Configuration { static const QString s_pluginName = QStringLiteral("org.kde.kdecoration2"); DecorationsModel::DecorationsModel(QObject *parent) : QAbstractListModel(parent) { } DecorationsModel::~DecorationsModel() = default; int DecorationsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_plugins.size(); } QVariant DecorationsModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.column() != 0 || index.row() < 0 || index.row() >= int(m_plugins.size())) { return QVariant(); } const Data &d = m_plugins.at(index.row()); switch (role) { case Qt::DisplayRole: return d.visibleName; case PluginNameRole: return d.pluginName; case ThemeNameRole: return d.themeName; case ConfigurationRole: return d.configuration; case RecommendedBorderSizeRole: return Utils::borderSizeToString(d.recommendedBorderSize); } return QVariant(); } QHash< int, QByteArray > DecorationsModel::roleNames() const { QHash roles({ {Qt::DisplayRole, QByteArrayLiteral("display")}, {PluginNameRole, QByteArrayLiteral("plugin")}, {ThemeNameRole, QByteArrayLiteral("theme")}, {ConfigurationRole, QByteArrayLiteral("configureable")}, {RecommendedBorderSizeRole, QByteArrayLiteral("recommendedbordersize")} }); return roles; } static bool isThemeEngine(const QVariantMap &decoSettingsMap) { auto it = decoSettingsMap.find(QStringLiteral("themes")); if (it == decoSettingsMap.end()) { return false; } return it.value().toBool(); } static bool isConfigureable(const QVariantMap &decoSettingsMap) { auto it = decoSettingsMap.find(QStringLiteral("kcmodule")); if (it == decoSettingsMap.end()) { return false; } return it.value().toBool(); } static KDecoration2::BorderSize recommendedBorderSize(const QVariantMap &decoSettingsMap) { auto it = decoSettingsMap.find(QStringLiteral("recommendedBorderSize")); if (it == decoSettingsMap.end()) { return KDecoration2::BorderSize::Normal; } return Utils::stringToBorderSize(it.value().toString()); } static QString themeListKeyword(const QVariantMap &decoSettingsMap) { auto it = decoSettingsMap.find(QStringLiteral("themeListKeyword")); if (it == decoSettingsMap.end()) { return QString(); } return it.value().toString(); } static QString findKNewStuff(const QVariantMap &decoSettingsMap) { auto it = decoSettingsMap.find(QStringLiteral("KNewStuff")); if (it == decoSettingsMap.end()) { return QString(); } return it.value().toString(); } void DecorationsModel::init() { beginResetModel(); m_plugins.clear(); const auto plugins = KPluginTrader::self()->query(s_pluginName, s_pluginName); for (const auto &info : plugins) { KPluginLoader loader(info.libraryPath()); KPluginFactory *factory = loader.factory(); if (!factory) { continue; } auto metadata = loader.metaData().value(QStringLiteral("MetaData")).toObject().value(s_pluginName); Data data; if (!metadata.isUndefined()) { const auto decoSettingsMap = metadata.toObject().toVariantMap(); const QString &kns = findKNewStuff(decoSettingsMap); if (!kns.isEmpty() && !m_knsProviders.contains(kns)) { m_knsProviders.append(kns); } if (isThemeEngine(decoSettingsMap)) { const QString keyword = themeListKeyword(decoSettingsMap); if (keyword.isNull()) { // We cannot list the themes continue; } QScopedPointer themeFinder(factory->create(keyword)); if (themeFinder.isNull()) { continue; } QVariant themes = themeFinder->property("themes"); if (!themes.isValid()) { continue; } const auto themesMap = themes.toMap(); for (auto it = themesMap.begin(); it != themesMap.end(); ++it) { Data d; d.pluginName = info.pluginName(); d.themeName = it.value().toString(); d.visibleName = it.key(); QMetaObject::invokeMethod(themeFinder.data(), "hasConfiguration", Q_RETURN_ARG(bool, d.configuration), Q_ARG(QString, d.themeName)); m_plugins.emplace_back(std::move(d)); } // it's a theme engine, we don't want to show this entry continue; } data.configuration = isConfigureable(decoSettingsMap); data.recommendedBorderSize = recommendedBorderSize(decoSettingsMap); } data.pluginName = info.pluginName(); data.visibleName = info.name().isEmpty() ? info.pluginName() : info.name(); data.themeName = data.visibleName; m_plugins.emplace_back(std::move(data)); } endResetModel(); } QModelIndex DecorationsModel::findDecoration(const QString &pluginName, const QString &themeName) const { auto it = std::find_if(m_plugins.cbegin(), m_plugins.cend(), [pluginName, themeName](const Data &d) { return d.pluginName == pluginName && d.themeName == themeName; } ); if (it == m_plugins.cend()) { return QModelIndex(); } const auto distance = std::distance(m_plugins.cbegin(), it); return createIndex(distance, 0); } } }