Files
applet-window-buttons6/libappletdecoration/decorationsmodel.cpp
T
2026-02-20 07:36:46 +01:00

284 lines
8.2 KiB
C++

/*
* SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
* SPDX-FileCopyrightText: 2018 Michail Vourlakos <mvourlakos@gmail.org>
*
* This file is part of the libappletdecoration library
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "decorationsmodel.h"
#include "previewbridge.h"
#include <KConfigGroup>
#include <KDecoration3/Decoration>
#include <KDecoration3/DecorationSettings>
#include <KDecoration3/DecorationThemeProvider>
#include <KDirWatch>
#include <KPluginFactory>
#include <KSharedConfig>
#include <Plasma/PluginLoader>
#include <QDebug>
#include <QDir>
#include <qloggingcategory.h>
Q_LOGGING_CATEGORY(decorations_model, "DecorationsModel");
static const QString s_defaultPlugin = QStringLiteral("org.kde.breeze");
static const QString s_defaultTheme;
static const QString s_auroraePlugin = QStringLiteral("org.kde.kwin.aurorae");
static const QString s_auroraePluginV2 = QStringLiteral("org.kde.kwin.aurorae.v2");
static const QString s_auroraeSvgTheme = QStringLiteral("__aurorae__svg__");
static const QString s_kwinrc = QStringLiteral("kwinrc");
static const QString s_pluginName = QStringLiteral("org.kde.kdecoration3");
DecorationsModel::DecorationsModel(QObject *parent) : QAbstractListModel(parent)
{
init();
loadCurrents();
const auto kwinRc = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + s_kwinrc;
KDirWatch::self()->addFile(kwinRc);
connect(KDirWatch::self(), &KDirWatch::dirty, this, &DecorationsModel::kwinChanged);
connect(KDirWatch::self(), &KDirWatch::created, this, &DecorationsModel::kwinChanged);
}
DecorationsModel::~DecorationsModel() = default;
int DecorationsModel::count() const
{
return m_plugins.size();
}
QString DecorationsModel::currentPlugin() const
{
return m_currentPlugin;
}
void DecorationsModel::setCurrentPlugin(QString plugin)
{
if (m_currentPlugin == plugin)
{
return;
}
m_currentPlugin = plugin;
emit currentPluginChanged();
}
QString DecorationsModel::currentTheme() const
{
return m_currentTheme;
}
void DecorationsModel::setCurrentTheme(QString theme)
{
if (m_currentTheme == theme)
{
return;
}
m_currentTheme = theme;
emit currentThemeChanged();
}
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 Qt::UserRole + 4: return d.pluginName;
case Qt::UserRole + 5: return d.themeName;
case Qt::UserRole + 6: return d.isAuroraeTheme;
case Qt::UserRole + 7: return d.configuration;
}
return QVariant();
}
QHash<int, QByteArray> DecorationsModel::roleNames() const
{
QHash<int, QByteArray> roles({ { Qt::DisplayRole, QByteArrayLiteral("display") },
{ Qt::UserRole + 4, QByteArrayLiteral("plugin") },
{ Qt::UserRole + 5, QByteArrayLiteral("theme") },
{ Qt::UserRole + 6, QByteArrayLiteral("isAuroraeTheme") },
{ Qt::UserRole + 7, QByteArrayLiteral("configureable") } });
return roles;
}
static bool isThemeEngine(const QVariantMap &decoSettingsMap)
{
return decoSettingsMap["themes"].toBool();
}
static bool isConfigureable(const QVariantMap &decoSettingsMap)
{
return decoSettingsMap["kcmodule"].toBool();
}
static QString themeListKeyword(const QVariantMap &decoSettingsMap)
{
return decoSettingsMap["themeListKeyword"].toString();
}
static QString findKNewStuff(const QVariantMap &decoSettingsMap)
{
return decoSettingsMap["KNewStuff"].toString();
}
void DecorationsModel::init()
{
beginResetModel();
m_plugins.clear();
const auto plugins = KPluginMetaData::findPlugins(s_pluginName);
for (const auto &info : plugins)
{
const auto decoSettingsMap = info.rawData().value("org.kde.kdecoration3").toObject().toVariantMap();
const QString &kns = findKNewStuff(decoSettingsMap);
if (!kns.isEmpty() && !m_knsProvides.contains(kns))
m_knsProvides.insert(kns, info.name().isEmpty() ? info.pluginId() : info.name());
if (isThemeEngine(decoSettingsMap))
{
const QString keyword = themeListKeyword(decoSettingsMap);
if (keyword.isNull())
{
// We cannot list the themes
qWarning() << "No theme list keyword for" << info.pluginId();
continue;
}
const auto themeProvider = KPluginFactory::instantiatePlugin<KDecoration3::DecorationThemeProvider>(info).plugin;
for (const auto &t : themeProvider->themes())
{
Data data;
data.pluginName = t.pluginId();
data.themeName = t.themeName();
data.visibleName = t.visibleName();
if ((data.pluginName == s_auroraePlugin || data.pluginName == s_auroraePluginV2) && data.themeName.startsWith(s_auroraeSvgTheme))
data.isAuroraeTheme = true;
qCInfo(decorations_model) << "Adding theme" << data.visibleName << "from" << data.pluginName;
m_plugins.emplace_back(std::move(data));
}
}
else
{
const Data data{
.pluginName = info.pluginId(),
.themeName = QString(),
.visibleName = info.name().isEmpty() ? info.pluginId() : info.name(),
.isAuroraeTheme = false,
.configuration = isConfigureable(decoSettingsMap),
};
qCInfo(decorations_model) << "Adding theme" << data.visibleName << "from" << data.pluginName;
m_plugins.emplace_back(std::move(data));
}
}
endResetModel();
}
void DecorationsModel::loadCurrents()
{
const KConfigGroup config = KSharedConfig::openConfig(s_kwinrc)->group(s_pluginName);
const QString plugin = config.readEntry("library", s_defaultPlugin);
const QString theme = config.readEntry("theme", s_defaultTheme);
bool exists{ false };
bool isAur{ isAurorae(plugin, theme) };
if ((!isAur && pluginExists(plugin)) || (isAur && decorationExists(plugin, theme)))
{
exists = true;
}
setCurrentPlugin(exists ? plugin : s_defaultPlugin);
setCurrentTheme(exists ? theme : s_defaultTheme);
}
void DecorationsModel::kwinChanged(const QString &filename)
{
if (!filename.endsWith(s_kwinrc))
{
return;
}
loadCurrents();
}
bool DecorationsModel::isAurorae(const QString &plugin, const QString &theme)
{
auto it = std::find_if(m_plugins.cbegin(), m_plugins.cend(), [plugin, theme](const Data &d) { return d.pluginName == plugin && d.themeName == theme; });
if (it == m_plugins.cend())
{
return false;
}
return (*it).isAuroraeTheme;
}
bool DecorationsModel::decorationExists(const QString &plugin, const QString &theme)
{
auto it = std::find_if(m_plugins.cbegin(), m_plugins.cend(), [plugin, theme](const Data &d) { return d.pluginName == plugin && d.themeName == theme; });
if (it == m_plugins.cend())
{
return false;
}
return true;
}
bool DecorationsModel::pluginExists(const QString &plugin)
{
auto it = std::find_if(m_plugins.cbegin(), m_plugins.cend(), [plugin](const Data &d) { return d.pluginName == plugin; });
if (it == m_plugins.cend())
{
return false;
}
return true;
}
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);
}