diff --git a/kcmkwin/common/CMakeLists.txt b/kcmkwin/common/CMakeLists.txt index c9eaf7107..f6e211a54 100644 --- a/kcmkwin/common/CMakeLists.txt +++ b/kcmkwin/common/CMakeLists.txt @@ -1,32 +1,32 @@ # KI18N Translation Domain for this library add_definitions(-DTRANSLATION_DOMAIN=\"kcmkwincommon\") include_directories(${KWIN_SOURCE_DIR}/effects) set(kcmkwincommon_SRC - effectmodel.cpp + effectsmodel.cpp ) qt5_add_dbus_interface(kcmkwincommon_SRC ${KWIN_SOURCE_DIR}/org.kde.kwin.Effects.xml kwin_effects_interface ) add_library(kcmkwincommon SHARED ${kcmkwincommon_SRC}) target_link_libraries(kcmkwincommon Qt5::Core Qt5::DBus KF5::CoreAddons KF5::ConfigCore KF5::I18n KF5::Package KF5::KCMUtils kwin4_effect_builtins ) set_target_properties(kcmkwincommon PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} ) install(TARGETS kcmkwincommon ${INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) diff --git a/kcmkwin/common/effectmodel.cpp b/kcmkwin/common/effectsmodel.cpp similarity index 94% rename from kcmkwin/common/effectmodel.cpp rename to kcmkwin/common/effectsmodel.cpp index 9725c8b56..7998c4477 100644 --- a/kcmkwin/common/effectmodel.cpp +++ b/kcmkwin/common/effectsmodel.cpp @@ -1,644 +1,644 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2013 Antonis Tsiapaliokas Copyright (C) 2018 Vlad Zagorodniy 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) any later version. 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 "effectmodel.h" +#include "effectsmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KWin { static QString translatedCategory(const QString &category) { static const QVector knownCategories = { QStringLiteral("Accessibility"), QStringLiteral("Appearance"), QStringLiteral("Candy"), QStringLiteral("Focus"), QStringLiteral("Show Desktop Animation"), QStringLiteral("Tools"), QStringLiteral("Virtual Desktop Switching Animation"), QStringLiteral("Window Management"), QStringLiteral("Window Open/Close Animation") }; static const QVector translatedCategories = { i18nc("Category of Desktop Effects, used as section header", "Accessibility"), i18nc("Category of Desktop Effects, used as section header", "Appearance"), i18nc("Category of Desktop Effects, used as section header", "Candy"), i18nc("Category of Desktop Effects, used as section header", "Focus"), i18nc("Category of Desktop Effects, used as section header", "Show Desktop Animation"), i18nc("Category of Desktop Effects, used as section header", "Tools"), i18nc("Category of Desktop Effects, used as section header", "Virtual Desktop Switching Animation"), i18nc("Category of Desktop Effects, used as section header", "Window Management"), i18nc("Category of Desktop Effects, used as section header", "Window Open/Close Animation") }; const int index = knownCategories.indexOf(category); if (index == -1) { qDebug() << "Unknown category '" << category << "' and thus not translated"; return category; } return translatedCategories[index]; } -static EffectModel::Status effectStatus(bool enabled) +static EffectsModel::Status effectStatus(bool enabled) { - return enabled ? EffectModel::Status::Enabled : EffectModel::Status::Disabled; + return enabled ? EffectsModel::Status::Enabled : EffectsModel::Status::Disabled; } -EffectModel::EffectModel(QObject *parent) +EffectsModel::EffectsModel(QObject *parent) : QAbstractItemModel(parent) { } -QHash EffectModel::roleNames() const +QHash EffectsModel::roleNames() const { QHash roleNames; roleNames[NameRole] = "NameRole"; roleNames[DescriptionRole] = "DescriptionRole"; roleNames[AuthorNameRole] = "AuthorNameRole"; roleNames[AuthorEmailRole] = "AuthorEmailRole"; roleNames[LicenseRole] = "LicenseRole"; roleNames[VersionRole] = "VersionRole"; roleNames[CategoryRole] = "CategoryRole"; roleNames[ServiceNameRole] = "ServiceNameRole"; roleNames[IconNameRole] = "IconNameRole"; roleNames[StatusRole] = "StatusRole"; roleNames[VideoRole] = "VideoRole"; roleNames[WebsiteRole] = "WebsiteRole"; roleNames[SupportedRole] = "SupportedRole"; roleNames[ExclusiveRole] = "ExclusiveRole"; roleNames[ConfigurableRole] = "ConfigurableRole"; roleNames[ScriptedRole] = QByteArrayLiteral("ScriptedRole"); roleNames[EnabledByDefaultRole] = "EnabledByDefaultRole"; return roleNames; } -QModelIndex EffectModel::index(int row, int column, const QModelIndex &parent) const +QModelIndex EffectsModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid() || column > 0 || column < 0 || row < 0 || row >= m_effectsList.count()) { return {}; } return createIndex(row, column); } -QModelIndex EffectModel::parent(const QModelIndex &child) const +QModelIndex EffectsModel::parent(const QModelIndex &child) const { Q_UNUSED(child) return {}; } -int EffectModel::columnCount(const QModelIndex &parent) const +int EffectsModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) return 1; } -int EffectModel::rowCount(const QModelIndex &parent) const +int EffectsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return m_effectsList.count(); } -QVariant EffectModel::data(const QModelIndex &index, int role) const +QVariant EffectsModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return {}; } const EffectData effect = m_effectsList.at(index.row()); switch (role) { case Qt::DisplayRole: case NameRole: return effect.name; case DescriptionRole: return effect.description; case AuthorNameRole: return effect.authorName; case AuthorEmailRole: return effect.authorEmail; case LicenseRole: return effect.license; case VersionRole: return effect.version; case CategoryRole: return effect.category; case ServiceNameRole: return effect.serviceName; case IconNameRole: return effect.iconName; case StatusRole: return static_cast(effect.status); case VideoRole: return effect.video; case WebsiteRole: return effect.website; case SupportedRole: return effect.supported; case ExclusiveRole: return effect.exclusiveGroup; case InternalRole: return effect.internal; case ConfigurableRole: return effect.configurable; case ScriptedRole: return effect.kind == Kind::Scripted; case EnabledByDefaultRole: return effect.enabledByDefault; default: return {}; } } -bool EffectModel::setData(const QModelIndex &index, const QVariant &value, int role) +bool EffectsModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) { return QAbstractItemModel::setData(index, value, role); } if (role == StatusRole) { // note: whenever the StatusRole is modified (even to the same value) the entry // gets marked as changed and will get saved to the config file. This means the // config file could get polluted EffectData &data = m_effectsList[index.row()]; data.status = Status(value.toInt()); data.changed = data.status != data.originalStatus; emit dataChanged(index, index); if (data.status == Status::Enabled && !data.exclusiveGroup.isEmpty()) { // need to disable all other exclusive effects in the same category for (int i = 0; i < m_effectsList.size(); ++i) { if (i == index.row()) { continue; } EffectData &otherData = m_effectsList[i]; if (otherData.exclusiveGroup == data.exclusiveGroup) { otherData.status = Status::Disabled; otherData.changed = otherData.status != otherData.originalStatus; emit dataChanged(this->index(i, 0), this->index(i, 0)); } } } return true; } return QAbstractItemModel::setData(index, value, role); } -void EffectModel::loadBuiltInEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs) +void EffectsModel::loadBuiltInEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs) { const auto builtins = BuiltInEffects::availableEffects(); for (auto builtin : builtins) { const BuiltInEffects::EffectData &data = BuiltInEffects::effectData(builtin); EffectData effect; effect.name = data.displayName; effect.description = data.comment; effect.authorName = i18n("KWin development team"); effect.authorEmail = QString(); // not used at all effect.license = QStringLiteral("GPL"); effect.version = QStringLiteral(KWIN_VERSION_STRING); effect.untranslatedCategory = data.category; effect.category = translatedCategory(data.category); effect.serviceName = data.name; effect.iconName = QStringLiteral("preferences-system-windows"); effect.enabledByDefault = data.enabled; effect.enabledByDefaultFunction = (data.enabledFunction != nullptr); const QString enabledKey = QStringLiteral("%1Enabled").arg(effect.serviceName); if (kwinConfig.hasKey(enabledKey)) { effect.status = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", effect.enabledByDefault)); } else if (data.enabledFunction != nullptr) { effect.status = Status::EnabledUndeterminded; } else { effect.status = effectStatus(effect.enabledByDefault); } effect.originalStatus = effect.status; effect.video = data.video; effect.website = QUrl(); effect.supported = true; effect.exclusiveGroup = data.exclusiveCategory; effect.internal = data.internal; effect.kind = Kind::BuiltIn; effect.configurable = std::any_of(configs.constBegin(), configs.constEnd(), [data](const KPluginInfo &info) { return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == data.name; } ); if (shouldStore(effect)) { m_effectsList << effect; } } } -void EffectModel::loadJavascriptEffects(const KConfigGroup &kwinConfig) +void EffectsModel::loadJavascriptEffects(const KConfigGroup &kwinConfig) { const auto plugins = KPackage::PackageLoader::self()->listPackages( QStringLiteral("KWin/Effect"), QStringLiteral("kwin/effects") ); for (const KPluginMetaData &metaData : plugins) { KPluginInfo plugin(metaData); EffectData effect; effect.name = plugin.name(); effect.description = plugin.comment(); effect.authorName = plugin.author(); effect.authorEmail = plugin.email(); effect.license = plugin.license(); effect.version = plugin.version(); effect.untranslatedCategory = plugin.category(); effect.category = translatedCategory(plugin.category()); effect.serviceName = plugin.pluginName(); effect.iconName = plugin.icon(); effect.status = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", plugin.isPluginEnabledByDefault())); effect.originalStatus = effect.status; effect.enabledByDefault = plugin.isPluginEnabledByDefault(); effect.enabledByDefaultFunction = false; effect.video = plugin.property(QStringLiteral("X-KWin-Video-Url")).toUrl(); effect.website = QUrl(plugin.website()); effect.supported = true; effect.exclusiveGroup = plugin.property(QStringLiteral("X-KWin-Exclusive-Category")).toString(); effect.internal = plugin.property(QStringLiteral("X-KWin-Internal")).toBool(); effect.kind = Kind::Scripted; const QString pluginKeyword = plugin.property(QStringLiteral("X-KDE-PluginKeyword")).toString(); if (!pluginKeyword.isEmpty()) { // scripted effects have their pluginName() as the keyword effect.configurable = plugin.property(QStringLiteral("X-KDE-ParentComponents")).toString() == pluginKeyword; } else { effect.configurable = false; } if (shouldStore(effect)) { m_effectsList << effect; } } } -void EffectModel::loadPluginEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs) +void EffectsModel::loadPluginEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs) { const auto pluginEffects = KPluginLoader::findPlugins( QStringLiteral("kwin/effects/plugins/"), [](const KPluginMetaData &data) { return data.serviceTypes().contains(QStringLiteral("KWin/Effect")); } ); for (const KPluginMetaData &pluginEffect : pluginEffects) { if (!pluginEffect.isValid()) { continue; } EffectData effect; effect.name = pluginEffect.name(); effect.description = pluginEffect.description(); effect.license = pluginEffect.license(); effect.version = pluginEffect.version(); effect.untranslatedCategory = pluginEffect.category(); effect.category = translatedCategory(pluginEffect.category()); effect.serviceName = pluginEffect.pluginId(); effect.iconName = pluginEffect.iconName(); effect.enabledByDefault = pluginEffect.isEnabledByDefault(); effect.supported = true; effect.enabledByDefaultFunction = false; effect.internal = false; effect.kind = Kind::Binary; for (int i = 0; i < pluginEffect.authors().count(); ++i) { effect.authorName.append(pluginEffect.authors().at(i).name()); effect.authorEmail.append(pluginEffect.authors().at(i).emailAddress()); if (i+1 < pluginEffect.authors().count()) { effect.authorName.append(", "); effect.authorEmail.append(", "); } } if (pluginEffect.rawData().contains("org.kde.kwin.effect")) { const QJsonObject d(pluginEffect.rawData().value("org.kde.kwin.effect").toObject()); effect.exclusiveGroup = d.value("exclusiveGroup").toString(); effect.video = QUrl::fromUserInput(d.value("video").toString()); effect.enabledByDefaultFunction = d.value("enabledByDefaultMethod").toBool(); } effect.website = QUrl(pluginEffect.website()); const QString enabledKey = QStringLiteral("%1Enabled").arg(effect.serviceName); if (kwinConfig.hasKey(enabledKey)) { effect.status = effectStatus(kwinConfig.readEntry(effect.serviceName + "Enabled", effect.enabledByDefault)); } else if (effect.enabledByDefaultFunction) { effect.status = Status::EnabledUndeterminded; } else { effect.status = effectStatus(effect.enabledByDefault); } effect.originalStatus = effect.status; effect.configurable = std::any_of(configs.constBegin(), configs.constEnd(), [pluginEffect](const KPluginInfo &info) { return info.property(QStringLiteral("X-KDE-ParentComponents")).toString() == pluginEffect.pluginId(); } ); if (shouldStore(effect)) { m_effectsList << effect; } } } -void EffectModel::load(LoadOptions options) +void EffectsModel::load(LoadOptions options) { KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Plugins"); const QVector oldEffects = m_effectsList; beginResetModel(); m_effectsList.clear(); const KPluginInfo::List configs = KPluginTrader::self()->query(QStringLiteral("kwin/effects/configs/")); loadBuiltInEffects(kwinConfig, configs); loadJavascriptEffects(kwinConfig); loadPluginEffects(kwinConfig, configs); if (options == LoadOptions::KeepDirty) { for (const EffectData &oldEffect : oldEffects) { if (!oldEffect.changed) { continue; } auto effectIt = std::find_if(m_effectsList.begin(), m_effectsList.end(), [serviceName = oldEffect.serviceName](const EffectData &data) { return data.serviceName == serviceName; } ); if (effectIt == m_effectsList.end()) { continue; } effectIt->status = oldEffect.status; effectIt->changed = effectIt->status != effectIt->originalStatus; } } qSort(m_effectsList.begin(), m_effectsList.end(), [](const EffectData &a, const EffectData &b) { if (a.category == b.category) { if (a.exclusiveGroup == b.exclusiveGroup) { return a.name < b.name; } return a.exclusiveGroup < b.exclusiveGroup; } return a.category < b.category; }); OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Effects"), QDBusConnection::sessionBus()); if (interface.isValid()) { QStringList effectNames; effectNames.reserve(m_effectsList.count()); for (const EffectData &data : m_effectsList) { effectNames.append(data.serviceName); } QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(interface.areEffectsSupported(effectNames), this); watcher->setProperty("effectNames", effectNames); connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher *self) { const QStringList effectNames = self->property("effectNames").toStringList(); const QDBusPendingReply > reply = *self; QList supportValues; if (reply.isValid()) { supportValues.append(reply.value()); } if (effectNames.size() == supportValues.size()) { for (int i = 0; i < effectNames.size(); ++i) { const bool supportedValue = supportValues.at(i); const QString &effectName = effectNames.at(i); auto it = std::find_if(m_effectsList.begin(), m_effectsList.end(), [effectName](const EffectData &data) { return data.serviceName == effectName; }); if (it != m_effectsList.end()) { if ((*it).supported != supportedValue) { (*it).supported = supportedValue; QModelIndex i = findByPluginId(effectName); if (i.isValid()) { emit dataChanged(i, i, QVector() << SupportedRole); } } } } } self->deleteLater(); }); } endResetModel(); } -void EffectModel::updateEffectStatus(const QModelIndex &rowIndex, Status effectState) +void EffectsModel::updateEffectStatus(const QModelIndex &rowIndex, Status effectState) { setData(rowIndex, static_cast(effectState), StatusRole); } -void EffectModel::save() +void EffectsModel::save() { KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Plugins"); QVector dirtyEffects; for (EffectData &effect : m_effectsList) { if (!effect.changed) { continue; } effect.changed = false; effect.originalStatus = effect.status; const QString key = effect.serviceName + QStringLiteral("Enabled"); const bool shouldEnable = (effect.status != Status::Disabled); const bool restoreToDefault = effect.enabledByDefaultFunction ? effect.status == Status::EnabledUndeterminded : shouldEnable == effect.enabledByDefault; if (restoreToDefault) { kwinConfig.deleteEntry(key); } else { kwinConfig.writeEntry(key, shouldEnable); } dirtyEffects.append(effect); } if (dirtyEffects.isEmpty()) { return; } kwinConfig.sync(); OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Effects"), QDBusConnection::sessionBus()); if (!interface.isValid()) { return; } for (const EffectData &effect : dirtyEffects) { if (effect.status != Status::Disabled) { interface.loadEffect(effect.serviceName); } else { interface.unloadEffect(effect.serviceName); } } } -void EffectModel::defaults() +void EffectsModel::defaults() { for (int i = 0; i < m_effectsList.count(); ++i) { const auto &effect = m_effectsList.at(i); if (effect.enabledByDefaultFunction && effect.status != Status::EnabledUndeterminded) { updateEffectStatus(index(i, 0), Status::EnabledUndeterminded); } else if ((bool)effect.status != effect.enabledByDefault) { updateEffectStatus(index(i, 0), effect.enabledByDefault ? Status::Enabled : Status::Disabled); } } } -bool EffectModel::needsSave() const +bool EffectsModel::needsSave() const { return std::any_of(m_effectsList.constBegin(), m_effectsList.constEnd(), [](const EffectData &data) { return data.changed; } ); } -QModelIndex EffectModel::findByPluginId(const QString &pluginId) const +QModelIndex EffectsModel::findByPluginId(const QString &pluginId) const { auto it = std::find_if(m_effectsList.constBegin(), m_effectsList.constEnd(), [pluginId](const EffectData &data) { return data.serviceName == pluginId; } ); if (it == m_effectsList.constEnd()) { return {}; } return index(std::distance(m_effectsList.constBegin(), it), 0); } static KCModule *findBinaryConfig(const QString &pluginId, QObject *parent) { return KPluginTrader::createInstanceFromQuery( QStringLiteral("kwin/effects/configs/"), QString(), QStringLiteral("'%1' in [X-KDE-ParentComponents]").arg(pluginId), parent ); } static KCModule *findScriptedConfig(const QString &pluginId, QObject *parent) { const auto offers = KPluginTrader::self()->query( QStringLiteral("kwin/effects/configs/"), QString(), QStringLiteral("[X-KDE-Library] == 'kcm_kwin4_genericscripted'") ); if (offers.isEmpty()) { return nullptr; } const KPluginInfo &generic = offers.first(); KPluginLoader loader(generic.libraryPath()); KPluginFactory *factory = loader.factory(); if (!factory) { return nullptr; } return factory->create(pluginId, parent); } -void EffectModel::requestConfigure(const QModelIndex &index, QWindow *transientParent) +void EffectsModel::requestConfigure(const QModelIndex &index, QWindow *transientParent) { if (!index.isValid()) { return; } QPointer dialog = new QDialog(); KCModule *module = index.data(ScriptedRole).toBool() ? findScriptedConfig(index.data(ServiceNameRole).toString(), dialog) : findBinaryConfig(index.data(ServiceNameRole).toString(), dialog); if (!module) { delete dialog; return; } dialog->setWindowTitle(index.data(NameRole).toString()); dialog->winId(); dialog->windowHandle()->setTransientParent(transientParent); auto buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults, dialog ); connect(buttons, &QDialogButtonBox::accepted, dialog, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, dialog, &QDialog::reject); connect(buttons->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, module, &KCModule::defaults); auto layout = new QVBoxLayout(dialog); layout->addWidget(module); layout->addWidget(buttons); dialog->exec(); delete dialog; } -bool EffectModel::shouldStore(const EffectData &data) const +bool EffectsModel::shouldStore(const EffectData &data) const { Q_UNUSED(data) return true; } } diff --git a/kcmkwin/common/effectmodel.h b/kcmkwin/common/effectsmodel.h similarity index 97% rename from kcmkwin/common/effectmodel.h rename to kcmkwin/common/effectsmodel.h index ea81466d0..68b9981ab 100644 --- a/kcmkwin/common/effectmodel.h +++ b/kcmkwin/common/effectsmodel.h @@ -1,260 +1,260 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2013 Antonis Tsiapaliokas Copyright (C) 2018 Vlad Zagorodniy 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) any later version. 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 . *********************************************************************/ #pragma once #include #include #include #include #include #include #include namespace KWin { -class KWIN_EXPORT EffectModel : public QAbstractItemModel +class KWIN_EXPORT EffectsModel : public QAbstractItemModel { Q_OBJECT public: /** * This enum type is used to specify data roles. **/ enum AdditionalRoles { /** * The user-friendly name of the effect. **/ NameRole = Qt::UserRole + 1, /** * The description of the effect. **/ DescriptionRole, /** * The name of the effect's author. If there are several authors, they * will be comma separated. **/ AuthorNameRole, /** * The email of the effect's author. If there are several authors, the * emails will be comma separated. **/ AuthorEmailRole, /** * The license of the effect. **/ LicenseRole, /** * The version of the effect. **/ VersionRole, /** * The category of the effect. **/ CategoryRole, /** * The service name(plugin name) of the effect. **/ ServiceNameRole, /** * The icon name of the effect. **/ IconNameRole, /** * Whether the effect is enabled or disabled. **/ StatusRole, /** * Link to a video demonstration of the effect. **/ VideoRole, /** * Link to the home page of the effect. **/ WebsiteRole, /** * Whether the effect is supported. **/ SupportedRole, /** * The exclusive group of the effect. **/ ExclusiveRole, /** * Whether the effect is internal. **/ InternalRole, /** * Whether the effect has a KCM. **/ ConfigurableRole, /** * Whether this is a scripted effect. **/ ScriptedRole, /** * Whether the effect is enabled by default. **/ EnabledByDefaultRole }; /** * This enum type is used to specify the status of a given effect. **/ enum class Status { /** * The effect is disabled. **/ Disabled = Qt::Unchecked, /** * An enable function is used to determine whether the effect is enabled. * For example, such function can be useful to disable the blur effect * when running in a virtual machine. **/ EnabledUndeterminded = Qt::PartiallyChecked, /** * The effect is enabled. **/ Enabled = Qt::Checked }; - explicit EffectModel(QObject *parent = nullptr); + explicit EffectsModel(QObject *parent = nullptr); // Reimplemented from QAbstractItemModel. QHash roleNames() const override; QModelIndex index(int row, int column, const QModelIndex &parent = {}) const override; QModelIndex parent(const QModelIndex &child) const override; int rowCount(const QModelIndex &parent = {}) const override; int columnCount(const QModelIndex &parent = {}) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; /** * Changes the status of a given effect. * * @param rowIndex An effect represented by the given index. * @param effectState The new state. * @note In order to actually apply the change, you have to call save(). **/ void updateEffectStatus(const QModelIndex &rowIndex, Status effectState); /** * This enum type is used to specify load options. **/ enum class LoadOptions { None, /** * Do not discard unsaved changes when reloading the model. **/ KeepDirty }; /** * Loads effects. * * You have to call this method in order to populate the model. **/ void load(LoadOptions options = LoadOptions::None); /** * Saves status of each modified effect. **/ void save(); /** * Resets the status of each effect to the default state. * * @note In order to actually apply the change, you have to call save(). **/ void defaults(); /** * Whether the model has unsaved changes. **/ bool needsSave() const; /** * Finds an effect with the given plugin id. **/ QModelIndex findByPluginId(const QString &pluginId) const; /** * Shows a configuration dialog for a given effect. * * @param index An effect represented by the given index. * @param transientParent The transient parent of the configuration dialog. **/ void requestConfigure(const QModelIndex &index, QWindow *transientParent); protected: enum class Kind { BuiltIn, Binary, Scripted }; struct EffectData { QString name; QString description; QString authorName; QString authorEmail; QString license; QString version; QString untranslatedCategory; QString category; QString serviceName; QString iconName; Status status; Status originalStatus; bool enabledByDefault; bool enabledByDefaultFunction; QUrl video; QUrl website; bool supported; QString exclusiveGroup; bool internal; bool configurable; Kind kind; bool changed = false; }; /** * Returns whether the given effect should be stored in the model. * * @param data The effect. * @returns @c true if the effect should be stored, otherwise @c false. **/ virtual bool shouldStore(const EffectData &data) const; private: void loadBuiltInEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs); void loadJavascriptEffects(const KConfigGroup &kwinConfig); void loadPluginEffects(const KConfigGroup &kwinConfig, const KPluginInfo::List &configs); QVector m_effectsList; - Q_DISABLE_COPY(EffectModel) + Q_DISABLE_COPY(EffectsModel) }; } diff --git a/kcmkwin/kwindesktop/animationsmodel.cpp b/kcmkwin/kwindesktop/animationsmodel.cpp index ccab2809b..17e31dfdf 100644 --- a/kcmkwin/kwindesktop/animationsmodel.cpp +++ b/kcmkwin/kwindesktop/animationsmodel.cpp @@ -1,154 +1,154 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2018 Vlad Zagorodniy 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) any later version. 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 "animationsmodel.h" namespace KWin { AnimationsModel::AnimationsModel(QObject *parent) - : EffectModel(parent) + : EffectsModel(parent) { connect(this, &AnimationsModel::currentIndexChanged, this, [this] { const QModelIndex index_ = index(m_currentIndex, 0); if (!index_.isValid()) { return; } const bool configurable = index_.data(ConfigurableRole).toBool(); if (configurable != m_currentConfigurable) { m_currentConfigurable = configurable; emit currentConfigurableChanged(); } } ); } bool AnimationsModel::enabled() const { return m_enabled; } void AnimationsModel::setEnabled(bool enabled) { if (m_enabled != enabled) { m_enabled = enabled; emit enabledChanged(); } } int AnimationsModel::currentIndex() const { return m_currentIndex; } void AnimationsModel::setCurrentIndex(int index) { if (m_currentIndex != index) { m_currentIndex = index; emit currentIndexChanged(); } } bool AnimationsModel::currentConfigurable() const { return m_currentConfigurable; } bool AnimationsModel::shouldStore(const EffectData &data) const { return data.untranslatedCategory.contains( QStringLiteral("Virtual Desktop Switching Animation"), Qt::CaseInsensitive); } -EffectModel::Status AnimationsModel::status(int row) const +EffectsModel::Status AnimationsModel::status(int row) const { return Status(data(index(row, 0), static_cast(StatusRole)).toInt()); } bool AnimationsModel::modelCurrentEnabled() const { for (int i = 0; i < rowCount(); ++i) { if (status(i) != Status::Disabled) { return true; } } return false; } int AnimationsModel::modelCurrentIndex() const { for (int i = 0; i < rowCount(); ++i) { if (status(i) != Status::Disabled) { return i; } } return 0; } void AnimationsModel::load() { - EffectModel::load(); + EffectsModel::load(); setEnabled(modelCurrentEnabled()); setCurrentIndex(modelCurrentIndex()); } void AnimationsModel::save() { for (int i = 0; i < rowCount(); ++i) { const auto status = (m_enabled && i == m_currentIndex) - ? EffectModel::Status::Enabled - : EffectModel::Status::Disabled; + ? EffectsModel::Status::Enabled + : EffectsModel::Status::Disabled; updateEffectStatus(index(i, 0), status); } - EffectModel::save(); + EffectsModel::save(); } void AnimationsModel::defaults() { - EffectModel::defaults(); + EffectsModel::defaults(); setEnabled(modelCurrentEnabled()); setCurrentIndex(modelCurrentIndex()); } bool AnimationsModel::needsSave() const { KConfigGroup kwinConfig(KSharedConfig::openConfig("kwinrc"), "Plugins"); for (int i = 0; i < rowCount(); ++i) { const QModelIndex index_ = index(i, 0); const bool enabledConfig = kwinConfig.readEntry( index_.data(ServiceNameRole).toString() + QLatin1String("Enabled"), index_.data(EnabledByDefaultRole).toBool() ); const bool enabled = (m_enabled && i == m_currentIndex); if (enabled != enabledConfig) { return true; } } return false; } } diff --git a/kcmkwin/kwindesktop/animationsmodel.h b/kcmkwin/kwindesktop/animationsmodel.h index 36b579edd..10d4acc3e 100644 --- a/kcmkwin/kwindesktop/animationsmodel.h +++ b/kcmkwin/kwindesktop/animationsmodel.h @@ -1,71 +1,71 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2018 Vlad Zagorodniy 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) any later version. 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 . *********************************************************************/ #pragma once -#include "effectmodel.h" +#include "effectsmodel.h" namespace KWin { -class AnimationsModel : public EffectModel +class AnimationsModel : public EffectsModel { Q_OBJECT Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) Q_PROPERTY(bool currentConfigurable READ currentConfigurable NOTIFY currentConfigurableChanged) public: explicit AnimationsModel(QObject *parent = nullptr); bool enabled() const; void setEnabled(bool enabled); int currentIndex() const; void setCurrentIndex(int index); bool currentConfigurable() const; void load(); void save(); void defaults(); bool needsSave() const; Q_SIGNALS: void enabledChanged(); void currentIndexChanged(); void currentConfigurableChanged(); protected: bool shouldStore(const EffectData &data) const override; private: Status status(int row) const; bool modelCurrentEnabled() const; int modelCurrentIndex() const; bool m_enabled = false; int m_currentIndex = -1; bool m_currentConfigurable = false; Q_DISABLE_COPY(AnimationsModel) }; } diff --git a/kcmkwin/kwineffects/effectsfilterproxymodel.cpp b/kcmkwin/kwineffects/effectsfilterproxymodel.cpp index dfa7b98a1..6edc647b4 100644 --- a/kcmkwin/kwineffects/effectsfilterproxymodel.cpp +++ b/kcmkwin/kwineffects/effectsfilterproxymodel.cpp @@ -1,104 +1,104 @@ /* * Copyright (C) 2019 Vlad Zagorodniy * * 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) any later version. * * 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 "effectsfilterproxymodel.h" -#include "effectmodel.h" +#include "effectsmodel.h" namespace KWin { EffectsFilterProxyModel::EffectsFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent) { } EffectsFilterProxyModel::~EffectsFilterProxyModel() { } QString EffectsFilterProxyModel::query() const { return m_query; } void EffectsFilterProxyModel::setQuery(const QString &query) { if (m_query != query) { m_query = query; emit queryChanged(); invalidateFilter(); } } bool EffectsFilterProxyModel::excludeInternal() const { return m_excludeInternal; } void EffectsFilterProxyModel::setExcludeInternal(bool exclude) { if (m_excludeInternal != exclude) { m_excludeInternal = exclude; emit excludeInternalChanged(); invalidateFilter(); } } bool EffectsFilterProxyModel::excludeUnsupported() const { return m_excludeUnsupported; } void EffectsFilterProxyModel::setExcludeUnsupported(bool exclude) { if (m_excludeUnsupported != exclude) { m_excludeUnsupported = exclude; emit excludeUnsupportedChanged(); invalidateFilter(); } } bool EffectsFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { const QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent); if (!m_query.isEmpty()) { - const bool matches = idx.data(EffectModel::NameRole).toString().contains(m_query, Qt::CaseInsensitive) || - idx.data(EffectModel::DescriptionRole).toString().contains(m_query, Qt::CaseInsensitive) || - idx.data(EffectModel::CategoryRole).toString().contains(m_query, Qt::CaseInsensitive); + const bool matches = idx.data(EffectsModel::NameRole).toString().contains(m_query, Qt::CaseInsensitive) || + idx.data(EffectsModel::DescriptionRole).toString().contains(m_query, Qt::CaseInsensitive) || + idx.data(EffectsModel::CategoryRole).toString().contains(m_query, Qt::CaseInsensitive); if (!matches) { return false; } } if (m_excludeInternal) { - if (idx.data(EffectModel::InternalRole).toBool()) { + if (idx.data(EffectsModel::InternalRole).toBool()) { return false; } } if (m_excludeUnsupported) { - if (!idx.data(EffectModel::SupportedRole).toBool()) { + if (!idx.data(EffectsModel::SupportedRole).toBool()) { return false; } } return true; } } // namespace KWin diff --git a/kcmkwin/kwineffects/kcm.cpp b/kcmkwin/kwineffects/kcm.cpp index 1bac16512..64df43640 100644 --- a/kcmkwin/kwineffects/kcm.cpp +++ b/kcmkwin/kwineffects/kcm.cpp @@ -1,122 +1,122 @@ /* * Copyright (C) 2019 Vlad Zagorodniy * * 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) any later version. * * 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 "kcm.h" -#include "effectmodel.h" #include "effectsfilterproxymodel.h" +#include "effectsmodel.h" #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(DesktopEffectsKCMFactory, "kcm_kwin_effects.json", registerPlugin();) namespace KWin { DesktopEffectsKCM::DesktopEffectsKCM(QObject *parent, const QVariantList &args) : KQuickAddons::ConfigModule(parent, args) - , m_model(new EffectModel(this)) + , m_model(new EffectsModel(this)) { qmlRegisterType("org.kde.private.kcms.kwin.effects", 1, 0, "EffectsFilterProxyModel"); auto about = new KAboutData( QStringLiteral("kcm_kwin_effects"), i18n("Configure Desktop Effects"), QStringLiteral("2.0"), QString(), KAboutLicense::GPL ); about->addAuthor(i18n("Vlad Zagorodniy"), QString(), QStringLiteral("vladzzag@gmail.com")); setAboutData(about); setButtons(Apply | Default); - connect(m_model, &EffectModel::dataChanged, this, &DesktopEffectsKCM::updateNeedsSave); + connect(m_model, &EffectsModel::dataChanged, this, &DesktopEffectsKCM::updateNeedsSave); } DesktopEffectsKCM::~DesktopEffectsKCM() { } QAbstractItemModel *DesktopEffectsKCM::effectsModel() const { return m_model; } void DesktopEffectsKCM::load() { m_model->load(); setNeedsSave(false); } void DesktopEffectsKCM::save() { m_model->save(); setNeedsSave(false); } void DesktopEffectsKCM::defaults() { m_model->defaults(); updateNeedsSave(); } void DesktopEffectsKCM::openGHNS(QQuickItem *context) { QPointer dialog = new KNS3::DownloadDialog(QStringLiteral("kwineffect.knsrc")); dialog->setWindowTitle(i18n("Download New Desktop Effects")); dialog->winId(); if (context && context->window()) { dialog->windowHandle()->setTransientParent(context->window()); } if (dialog->exec() == QDialog::Accepted) { if (!dialog->changedEntries().isEmpty()) { - m_model->load(EffectModel::LoadOptions::KeepDirty); + m_model->load(EffectsModel::LoadOptions::KeepDirty); } } delete dialog; } void DesktopEffectsKCM::configure(const QString &pluginId, QQuickItem *context) { const QModelIndex index = m_model->findByPluginId(pluginId); QWindow *transientParent = nullptr; if (context && context->window()) { transientParent = context->window(); } m_model->requestConfigure(index, transientParent); } void DesktopEffectsKCM::updateNeedsSave() { setNeedsSave(m_model->needsSave()); } } // namespace KWin #include "kcm.moc" diff --git a/kcmkwin/kwineffects/kcm.h b/kcmkwin/kwineffects/kcm.h index c8d8239d3..788ba3c3c 100644 --- a/kcmkwin/kwineffects/kcm.h +++ b/kcmkwin/kwineffects/kcm.h @@ -1,58 +1,58 @@ /* * Copyright (C) 2019 Vlad Zagorodniy * * 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) any later version. * * 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 . */ #pragma once #include #include #include namespace KWin { -class EffectModel; +class EffectsModel; class DesktopEffectsKCM : public KQuickAddons::ConfigModule { Q_OBJECT Q_PROPERTY(QAbstractItemModel *effectsModel READ effectsModel CONSTANT) public: explicit DesktopEffectsKCM(QObject *parent = nullptr, const QVariantList &list = {}); ~DesktopEffectsKCM() override; QAbstractItemModel *effectsModel() const; public Q_SLOTS: void load() override; void save() override; void defaults() override; void openGHNS(QQuickItem *context); void configure(const QString &pluginId, QQuickItem *context); private Q_SLOTS: void updateNeedsSave(); private: - EffectModel *m_model; + EffectsModel *m_model; Q_DISABLE_COPY(DesktopEffectsKCM) }; } // namespace KWin