kcm/kwinrules: Manage RuleSettings instead of Rules objects

The KCM now manages the RuleSettings config objects directly,
instead of using a list of `Rules` objects as an intermediary.

This highly reduces the overhead, improving loading and saving
times, and also enables a better use of KConfig capabilites.

The config state is now automatically tracked by KConfigXT
objects. Whenever the user edits either the rule list, or any
specific property within a rule, the `needsSave` state is
updated accordingly.

BUG: 421564
FIXED-IN: 5.23
This commit is contained in:
Ismael Asensio 2021-03-06 21:14:08 +01:00
parent 61c2055da7
commit b5a58f83ee
6 changed files with 190 additions and 204 deletions

View file

@ -6,6 +6,7 @@
*/
#include "kcmrules.h"
#include "rulesettings.h"
#include <QDBusConnection>
#include <QDBusMessage>
@ -51,8 +52,10 @@ KCMKWinRules::KCMKWinRules(QObject *parent, const QVariantList &arguments)
m_ruleBookModel->setDescriptionAt(m_editIndex.row(), m_rulesModel->description());
}
} );
connect(m_rulesModel, &RulesModel::dataChanged, this, &KCMKWinRules::updateNeedsSave);
connect(m_ruleBookModel, &RulesModel::dataChanged, this, &KCMKWinRules::updateNeedsSave);
connect(m_rulesModel, &RulesModel::dataChanged, this, [this]{
Q_EMIT m_ruleBookModel->dataChanged(m_editIndex, m_editIndex, {});
} );
connect(m_ruleBookModel, &RuleBookModel::dataChanged, this, &KCMKWinRules::updateNeedsSave);
}
void KCMKWinRules::parseArguments(const QStringList &args)
@ -108,7 +111,6 @@ void KCMKWinRules::parseArguments(const QStringList &args)
void KCMKWinRules::load()
{
m_ruleBookModel->load();
setNeedsSave(false);
if (!m_winProperties.isEmpty() && !m_alreadyLoaded) {
createRuleFromProperties();
@ -118,12 +120,12 @@ void KCMKWinRules::load()
}
m_alreadyLoaded = true;
updateNeedsSave();
}
void KCMKWinRules::save()
{
saveCurrentRule();
m_ruleBookModel->save();
// Notify kwin to reload configuration
@ -133,7 +135,7 @@ void KCMKWinRules::save()
void KCMKWinRules::updateNeedsSave()
{
setNeedsSave(true);
setNeedsSave(m_ruleBookModel->isSaveNeeded());
emit needsSaveChanged();
}
@ -146,7 +148,7 @@ void KCMKWinRules::createRuleFromProperties()
QModelIndex matchedIndex = findRuleWithProperties(m_winProperties, m_wholeApp);
if (!matchedIndex.isValid()) {
m_ruleBookModel->insertRow(0);
m_ruleBookModel->setRuleAt(0, ruleForProperties(m_winProperties, m_wholeApp));
fillSettingsFromProperties(m_ruleBookModel->ruleSettingsAt(0), m_winProperties, m_wholeApp);
matchedIndex = m_ruleBookModel->index(0);
updateNeedsSave();
}
@ -157,13 +159,6 @@ void KCMKWinRules::createRuleFromProperties()
m_winProperties.clear();
}
void KCMKWinRules::saveCurrentRule()
{
if (m_editIndex.isValid() && needsSave()) {
m_ruleBookModel->setRuleAt(m_editIndex.row(), m_rulesModel->exportToRules());
}
}
int KCMKWinRules::editIndex() const
{
if (!m_editIndex.isValid()) {
@ -194,12 +189,11 @@ void KCMKWinRules::editRule(int index)
if (index < 0 || index >= m_ruleBookModel->rowCount()) {
return;
}
saveCurrentRule();
m_editIndex = m_ruleBookModel->index(index);
emit editIndexChanged();
m_rulesModel->importFromRules(m_ruleBookModel->ruleAt(m_editIndex.row()));
m_rulesModel->setSettings(m_ruleBookModel->ruleSettingsAt(m_editIndex.row()));
// Set the active page to rules editor (0:RulesList, 1:RulesEditor)
setCurrentIndex(1);
@ -248,12 +242,12 @@ void KCMKWinRules::duplicateRule(int index)
return;
}
Rules *newRule = new Rules(*(m_ruleBookModel->ruleAt(index)));
const int newIndex = index + 1;
const QString newDescription = i18n("Copy of %1", m_ruleBookModel->descriptionAt(index));
m_ruleBookModel->insertRow(index + 1);
m_ruleBookModel->setRuleAt(index + 1, newRule);
m_ruleBookModel->setDescriptionAt(index + 1, newDescription);
m_ruleBookModel->insertRow(newIndex);
m_ruleBookModel->setRuleSettingsAt(newIndex, *(m_ruleBookModel->ruleSettingsAt(index)));
m_ruleBookModel->setDescriptionAt(newIndex, newDescription);
updateNeedsSave();
}
@ -263,7 +257,6 @@ void KCMKWinRules::exportToFile(const QUrl &path, const QList<int> &indexes)
if (indexes.isEmpty()) {
return;
}
saveCurrentRule();
const auto config = KSharedConfig::openConfig(path.toLocalFile(), KConfig::SimpleConfig);
@ -275,11 +268,11 @@ void KCMKWinRules::exportToFile(const QUrl &path, const QList<int> &indexes)
if (index < 0 || index > m_ruleBookModel->rowCount()) {
continue;
}
const Rules *rule = m_ruleBookModel->ruleAt(index);
RuleSettings settings(config, rule->description);
settings.setDefaults();
rule->write(&settings);
settings.save();
const RuleSettings *origin = m_ruleBookModel->ruleSettingsAt(index);
RuleSettings exported(config, origin->description());
RuleBookModel::copySettingsTo(&exported, *origin);
exported.save();
}
}
@ -319,11 +312,11 @@ void KCMKWinRules::importFromFile(const QUrl &path)
m_ruleBookModel->insertRow(newIndex);
}
m_ruleBookModel->setRuleAt(newIndex, new Rules(&settings));
m_ruleBookModel->setRuleSettingsAt(newIndex, settings);
// Reset rule editor if the current rule changed when importing
if (m_editIndex.row() == newIndex) {
m_rulesModel->importFromRules(m_ruleBookModel->ruleAt(m_editIndex.row()));
m_rulesModel->setSettings(m_ruleBookModel->ruleSettingsAt(newIndex));
}
}
@ -345,20 +338,21 @@ QModelIndex KCMKWinRules::findRuleWithProperties(const QVariantMap &info, bool w
int bestMatchScore = 0;
for (int row = 0; row < m_ruleBookModel->rowCount(); row++) {
Rules *rule = m_ruleBookModel->ruleAt(row);
const RuleSettings *settings = m_ruleBookModel->ruleSettingsAt(row);
/* clang-format off */
// If the rule doesn't match try the next one
if (!rule->matchWMClass(wmclass_class, wmclass_name)
|| !rule->matchType(type)
|| !rule->matchRole(role)
|| !rule->matchTitle(title)
|| !rule->matchClientMachine(machine, isLocalHost)) {
const Rules rule = Rules(settings);
/* clang-format off */
if (!rule.matchWMClass(wmclass_class, wmclass_name)
|| !rule.matchType(type)
|| !rule.matchRole(role)
|| !rule.matchTitle(title)
|| !rule.matchClientMachine(machine, isLocalHost)) {
continue;
}
/* clang-format on */
if (rule->wmclassmatch != Rules::ExactMatch) {
if (settings->wmclassmatch() != Rules::ExactMatch) {
continue; // too generic
}
@ -368,24 +362,24 @@ QModelIndex KCMKWinRules::findRuleWithProperties(const QVariantMap &info, bool w
bool generic = true;
// from now on, it matches the app - now try to match for a specific window
if (rule->wmclasscomplete) {
if (settings->wmclasscomplete()) {
score += 1;
generic = false; // this can be considered specific enough (old X apps)
}
if (!wholeApp) {
if (rule->windowrolematch != Rules::UnimportantMatch) {
score += rule->windowrolematch == Rules::ExactMatch ? 5 : 1;
if (settings->windowrolematch() != Rules::UnimportantMatch) {
score += settings->windowrolematch() == Rules::ExactMatch ? 5 : 1;
generic = false;
}
if (rule->titlematch != Rules::UnimportantMatch) {
score += rule->titlematch == Rules::ExactMatch ? 3 : 1;
if (settings->titlematch() != Rules::UnimportantMatch) {
score += settings->titlematch() == Rules::ExactMatch ? 3 : 1;
generic = false;
}
if (rule->types != NET::AllTypesMask) {
if (settings->types() != NET::AllTypesMask) {
// Checks that type fits the mask, and only one of the types
int bits = 0;
for (unsigned int bit = 1; bit < 1U << 31; bit <<= 1) {
if (rule->types & bit) {
if (settings->types() & bit) {
++bits;
}
}
@ -397,7 +391,7 @@ QModelIndex KCMKWinRules::findRuleWithProperties(const QVariantMap &info, bool w
continue;
}
} else {
if (rule->types == NET::AllTypesMask) {
if (settings->types() == NET::AllTypesMask) {
score += 2;
}
}
@ -415,7 +409,7 @@ QModelIndex KCMKWinRules::findRuleWithProperties(const QVariantMap &info, bool w
}
// Code adapted from original `findRule()` method in `kwin_rules_dialog::main.cpp`
Rules *KCMKWinRules::ruleForProperties(const QVariantMap &info, bool wholeApp) const
void KCMKWinRules::fillSettingsFromProperties(RuleSettings *settings, const QVariantMap &info, bool wholeApp) const
{
const QByteArray wmclass_class = info.value("resourceClass").toByteArray().toLower();
const QByteArray wmclass_name = info.value("resourceName").toByteArray().toLower();
@ -424,57 +418,58 @@ Rules *KCMKWinRules::ruleForProperties(const QVariantMap &info, bool wholeApp) c
const QString title = info.value("caption").toString();
const QByteArray machine = info.value("clientMachine").toByteArray();
Rules *rule = new Rules();
settings->setDefaults();
if (wholeApp) {
rule->description = i18n("Application settings for %1", QString::fromLatin1(wmclass_class));
settings->setDescription(i18n("Application settings for %1", QString::fromLatin1(wmclass_class)));
// TODO maybe exclude some types? If yes, then also exclude them when searching.
rule->types = NET::AllTypesMask;
rule->titlematch = Rules::UnimportantMatch;
rule->clientmachine = machine; // set, but make unimportant
rule->clientmachinematch = Rules::UnimportantMatch;
rule->windowrolematch = Rules::UnimportantMatch;
settings->setTypes(NET::AllTypesMask);
settings->setTitlematch(Rules::UnimportantMatch);
settings->setClientmachine(machine); // set, but make unimportant
settings->setClientmachinematch(Rules::UnimportantMatch);
settings->setWindowrolematch(Rules::UnimportantMatch);
if (wmclass_name == wmclass_class) {
rule->wmclasscomplete = false;
rule->wmclass = wmclass_class;
rule->wmclassmatch = Rules::ExactMatch;
settings->setWmclasscomplete(false);
settings->setWmclass(wmclass_class);
settings->setWmclassmatch(Rules::ExactMatch);
} else {
// WM_CLASS components differ - perhaps the app got -name argument
rule->wmclasscomplete = true;
rule->wmclass = wmclass_name + ' ' + wmclass_class;
rule->wmclassmatch = Rules::ExactMatch;
settings->setWmclasscomplete(true);
settings->setWmclass(QStringLiteral("%1 %2").arg(wmclass_name, wmclass_class));
settings->setWmclassmatch(Rules::ExactMatch);
}
return rule;
return;
}
rule->description = i18n("Window settings for %1", QString::fromLatin1(wmclass_class));
settings->setDescription(i18n("Window settings for %1", QString::fromLatin1(wmclass_class)));
if (type == NET::Unknown) {
rule->types = NET::NormalMask;
settings->setTypes(NET::NormalMask);
} else {
rule->types = NET::WindowTypeMask(1 << type); // convert type to its mask
settings->setTypes(NET::WindowTypeMask(1 << type)); // convert type to its mask
}
rule->title = title; // set, but make unimportant
rule->titlematch = Rules::UnimportantMatch;
rule->clientmachine = machine; // set, but make unimportant
rule->clientmachinematch = Rules::UnimportantMatch;
settings->setTitle(title); // set, but make unimportant
settings->setTitlematch(Rules::UnimportantMatch);
settings->setClientmachine(machine); // set, but make unimportant
settings->setClientmachinematch(Rules::UnimportantMatch);
if (!role.isEmpty() && role != "unknown" && role != "unnamed") { // Qt sets this if not specified
rule->windowrole = role;
rule->windowrolematch = Rules::ExactMatch;
settings->setWindowrole(role);
settings->setWindowrolematch(Rules::ExactMatch);
if (wmclass_name == wmclass_class) {
rule->wmclasscomplete = false;
rule->wmclass = wmclass_class;
rule->wmclassmatch = Rules::ExactMatch;
settings->setWmclasscomplete(false);
settings->setWmclass(wmclass_class);
settings->setWmclassmatch(Rules::ExactMatch);
} else {
// WM_CLASS components differ - perhaps the app got -name argument
rule->wmclasscomplete = true;
rule->wmclass = wmclass_name + ' ' + wmclass_class;
rule->wmclassmatch = Rules::ExactMatch;
settings->setWmclasscomplete(true);
settings->setWmclass(QStringLiteral("%1 %2").arg(wmclass_name, wmclass_class));
settings->setWmclassmatch(Rules::ExactMatch);
}
} else { // no role set
if (wmclass_name != wmclass_class) {
rule->wmclasscomplete = true;
rule->wmclass = wmclass_name + ' ' + wmclass_class;
rule->wmclassmatch = Rules::ExactMatch;
// WM_CLASS components differ - perhaps the app got -name argument
settings->setWmclasscomplete(true);
settings->setWmclass(QStringLiteral("%1 %2").arg(wmclass_name, wmclass_class));
settings->setWmclassmatch(Rules::ExactMatch);
} else {
// This is a window that has no role set, and both components of WM_CLASS
// match (possibly only differing in case), which most likely means either
@ -483,13 +478,13 @@ Rules *KCMKWinRules::ruleForProperties(const QVariantMap &info, bool wholeApp) c
// lacks it for some reason. Use non-complete WM_CLASS matching, also
// include window title in the matching, and pray it causes many more positive
// matches than negative matches.
rule->titlematch = Rules::ExactMatch;
rule->wmclasscomplete = false;
rule->wmclass = wmclass_class;
rule->wmclassmatch = Rules::ExactMatch;
// WM_CLASS components differ - perhaps the app got -name argument
settings->setTitlematch(Rules::ExactMatch);
settings->setWmclasscomplete(false);
settings->setWmclass(wmclass_class);
settings->setWmclassmatch(Rules::ExactMatch);
}
}
return rule;
}
K_PLUGIN_CLASS_WITH_JSON(KCMKWinRules, "kcm_kwinrules.json");

View file

@ -6,7 +6,6 @@
#pragma once
#include <rules.h>
#include "rulebookmodel.h"
#include "rulesmodel.h"
@ -15,6 +14,7 @@
namespace KWin
{
class RuleSettings;
class KCMKWinRules : public KQuickAddons::ConfigModule
{
@ -50,12 +50,11 @@ private slots:
private:
int editIndex() const;
void saveCurrentRule();
void parseArguments(const QStringList &args);
void createRuleFromProperties();
QModelIndex findRuleWithProperties(const QVariantMap &info, bool wholeApp) const;
Rules *ruleForProperties(const QVariantMap &info, bool wholeApp) const;
void fillSettingsFromProperties(RuleSettings *settings, const QVariantMap &info, bool wholeApp) const;
private:
RuleBookModel *m_ruleBookModel;

View file

@ -6,8 +6,6 @@
#include "rulebookmodel.h"
#include <KLocalizedString>
namespace KWin
{
@ -19,13 +17,20 @@ RuleBookModel::RuleBookModel(QObject *parent)
RuleBookModel::~RuleBookModel()
{
qDeleteAll(m_rules);
}
QHash<int, QByteArray> RuleBookModel::roleNames() const
{
static auto roles = QHash<int, QByteArray> {
{ DescriptionRole, QByteArray("display") },
}.unite(QAbstractListModel::roleNames());
return roles;
}
int RuleBookModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_rules.count();
return m_ruleBook->ruleCount();
}
QVariant RuleBookModel::data(const QModelIndex &index, int role) const
@ -34,12 +39,18 @@ QVariant RuleBookModel::data(const QModelIndex &index, int role) const
return QVariant();
}
switch (role) {
case Qt::DisplayRole:
return descriptionAt(index.row());
default:
if (index.row() < 0 || index.row() >= rowCount()) {
return QVariant();
}
const RuleSettings *settings = m_ruleBook->ruleSettingsAt(index.row());
switch (role) {
case RuleBookModel::DescriptionRole:
return settings->description();
}
return QVariant();
}
bool RuleBookModel::setData(const QModelIndex &index, const QVariant &value, int role)
@ -48,13 +59,22 @@ bool RuleBookModel::setData(const QModelIndex &index, const QVariant &value, int
return false;
}
RuleSettings *settings = m_ruleBook->ruleSettingsAt(index.row());
switch (role) {
case Qt::DisplayRole:
setDescriptionAt(index.row(), value.toString());
return true;
case RuleBookModel::DescriptionRole:
if (settings->description() == value.toString()) {
return true;
}
settings->setDescription(value.toString());
break;
default:
return false;
}
Q_EMIT dataChanged(index, index, {role});
return true;
}
bool RuleBookModel::insertRows(int row, int count, const QModelIndex &parent)
@ -62,18 +82,14 @@ bool RuleBookModel::insertRows(int row, int count, const QModelIndex &parent)
if (row < 0 || row > rowCount() || parent.isValid()) {
return false;
}
beginInsertRows(parent, row, row + count - 1);
for (int i = 0; i < count; i++) {
Rules *newRule = new Rules();
// HACK: Improve integration with RuleSettings and use directly its defaults
newRule->wmclassmatch = Rules::ExactMatch;
m_rules.insert(row + i, newRule);
RuleSettings *settings = m_ruleBook->insertRuleSettingsAt(row + i);
settings->setWmclassmatch(Rules::ExactMatch); // We want ExactMatch as default for new rules in the UI
}
m_ruleBook->setCount(m_rules.count());
endInsertRows();
return true;
}
@ -82,15 +98,13 @@ bool RuleBookModel::removeRows(int row, int count, const QModelIndex &parent)
if (row < 0 || row > rowCount() || parent.isValid()) {
return false;
}
beginRemoveRows(parent, row, row + count - 1);
for (int i = 0; i < count; i++) {
delete m_rules.at(row + i);
m_ruleBook->removeRuleSettingsAt(row + i);
}
m_rules.remove(row, count);
m_ruleBook->setCount(m_rules.count());
endRemoveRows();
return true;
}
@ -110,8 +124,7 @@ bool RuleBookModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int
}
for (int i = 0; i < count; i++) {
m_rules.insert(destinationChild + i,
m_rules.takeAt(isMoveDown ? sourceRow : sourceRow + i));
m_ruleBook->moveRuleSettings(isMoveDown ? sourceRow : sourceRow + i, destinationChild);
}
endMoveRows();
@ -121,54 +134,62 @@ bool RuleBookModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int
QString RuleBookModel::descriptionAt(int row) const
{
Q_ASSERT (row >= 0 && row < m_rules.count());
return m_rules.at(row)->description;
Q_ASSERT(row >= 0 && row < rowCount());
return m_ruleBook->ruleSettingsAt(row)->description();
}
Rules *RuleBookModel::ruleAt(int row) const
RuleSettings *RuleBookModel::ruleSettingsAt(int row) const
{
Q_ASSERT (row >= 0 && row < m_rules.count());
return m_rules.at(row);
Q_ASSERT(row >= 0 && row < rowCount());
return m_ruleBook->ruleSettingsAt(row);
}
void RuleBookModel::setDescriptionAt(int row, const QString &description)
{
Q_ASSERT (row >= 0 && row < m_rules.count());
if (description == m_rules.at(row)->description) {
Q_ASSERT(row >= 0 && row < rowCount());
if (description == m_ruleBook->ruleSettingsAt(row)->description()) {
return;
}
m_rules.at(row)->description = description;
m_ruleBook->ruleSettingsAt(row)->setDescription(description);
emit dataChanged(index(row), index(row), QVector<int>{Qt::DisplayRole});
emit dataChanged(index(row), index(row), {});
}
void RuleBookModel::setRuleAt(int row, Rules *rule)
void RuleBookModel::setRuleSettingsAt(int row, const RuleSettings &settings)
{
Q_ASSERT (row >= 0 && row < m_rules.count());
Q_ASSERT(row >= 0 && row < rowCount());
delete m_rules.at(row);
m_rules[row] = rule;
copySettingsTo(ruleSettingsAt(row), settings);
emit dataChanged(index(row), index(row), QVector<int>{Qt::DisplayRole});
emit dataChanged(index(row), index(row), {});
}
void RuleBookModel::load()
{
beginResetModel();
m_ruleBook->load();
qDeleteAll(m_rules);
m_rules = m_ruleBook->rules();
endResetModel();
}
void RuleBookModel::save()
{
m_ruleBook->setRules(m_rules);
m_ruleBook->save();
}
bool RuleBookModel::isSaveNeeded()
{
return m_ruleBook->usrIsSaveNeeded();
}
void RuleBookModel::copySettingsTo(RuleSettings *dest, const RuleSettings &source)
{
dest->setDefaults();
for (const KConfigSkeletonItem *item : source.items()) {
dest->findItem(item->name())->setProperty(item->property());
}
}
} // namespace

View file

@ -7,7 +7,7 @@
#pragma once
#include "rulebooksettings.h"
#include <rules.h>
#include "rulesettings.h"
#include <QAbstractListModel>
@ -20,11 +20,15 @@ class RuleBookModel : public QAbstractListModel
Q_OBJECT
public:
enum {
DescriptionRole = Qt::DisplayRole,
};
explicit RuleBookModel(QObject *parent = nullptr);
~RuleBookModel();
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
@ -36,15 +40,18 @@ public:
QString descriptionAt(int row) const;
void setDescriptionAt(int row, const QString &description);
Rules *ruleAt(int row) const;
void setRuleAt(int row, Rules *rule);
RuleSettings *ruleSettingsAt(int row) const;
void setRuleSettingsAt(int row, const RuleSettings &settings);
void load();
void save();
bool isSaveNeeded();
// Helper function to copy RuleSettings properties
static void copySettingsTo(RuleSettings *dest, const RuleSettings &source);
private:
RuleBookSettings *m_ruleBook;
QVector<Rules *> m_rules;
};
} // namespace

View file

@ -11,10 +11,8 @@
#include "activities.h"
#endif
#include <QFileInfo>
#include <QIcon>
#include <QQmlEngine>
#include <QTemporaryFile>
#include <QtDBus>
#include <KColorSchemeManager>
@ -156,8 +154,9 @@ bool RulesModel::setData(const QModelIndex &index, const QVariant &value, int ro
return false;
}
emit dataChanged(index, index, QVector<int>{role});
writeToSettings(rule);
emit dataChanged(index, index, QVector<int>{role});
if (rule->hasFlag(RuleItem::AffectsDescription)) {
emit descriptionChanged();
}
@ -286,13 +285,24 @@ bool RulesModel::geometryWarning() const
return (!ignoregeometry && (initialPos || initialSize || initialPlacement));
}
void RulesModel::readFromSettings(RuleSettings *settings)
RuleSettings *RulesModel::settings() const
{
return m_settings;
}
void RulesModel::setSettings(RuleSettings *settings)
{
if (m_settings == settings) {
return;
}
beginResetModel();
m_settings = settings;
for (RuleItem *rule : qAsConst(m_ruleList)) {
const KConfigSkeletonItem *configItem = settings->findItem(rule->key());
const KConfigSkeletonItem *configPolicyItem = settings->findItem(rule->policyKey());
const KConfigSkeletonItem *configItem = m_settings->findItem(rule->key());
const KConfigSkeletonItem *configPolicyItem = m_settings->findItem(rule->policyKey());
rule->reset();
@ -319,73 +329,28 @@ void RulesModel::readFromSettings(RuleSettings *settings)
emit warningMessagesChanged();
}
void RulesModel::writeToSettings(RuleSettings *settings) const
void RulesModel::writeToSettings(RuleItem *rule)
{
const QString description = m_rules["description"]->value().toString();
if (description.isEmpty()) {
m_rules["description"]->setValue(defaultDescription());
}
KConfigSkeletonItem *configItem = m_settings->findItem(rule->key());
KConfigSkeletonItem *configPolicyItem = m_settings->findItem(rule->policyKey());
for (const RuleItem *rule : qAsConst(m_ruleList)) {
KConfigSkeletonItem *configItem = settings->findItem(rule->key());
KConfigSkeletonItem *configPolicyItem = settings->findItem(rule->policyKey());
if (!configItem) {
continue;
}
if (rule->isEnabled()) {
configItem->setProperty(rule->value());
if (configPolicyItem) {
configPolicyItem->setProperty(rule->policy());
}
} else {
if (configPolicyItem) {
configPolicyItem->setProperty(Rules::Unused);
} else {
// Rules without policy gets deactivated by an empty string
configItem->setProperty(QString());
}
}
}
}
void RulesModel::importFromRules(Rules* rules)
{
QTemporaryFile tempFile;
if (!tempFile.open()) {
if (!configItem) {
return;
}
const auto cfg = KSharedConfig::openConfig(tempFile.fileName(), KConfig::SimpleConfig);
RuleSettings *settings = new RuleSettings(cfg, QStringLiteral("tempSettings"));
settings->setDefaults();
if (rules) {
rules->write(settings);
if (rule->isEnabled()) {
configItem->setProperty(rule->value());
if (configPolicyItem) {
configPolicyItem->setProperty(rule->policy());
}
} else {
configItem->setDefault();
if (configPolicyItem) {
configPolicyItem->setDefault();
}
}
readFromSettings(settings);
delete(settings);
}
Rules *RulesModel::exportToRules() const
{
QTemporaryFile tempFile;
if (!tempFile.open()) {
return nullptr;
}
const auto cfg = KSharedConfig::openConfig(tempFile.fileName(), KConfig::SimpleConfig);
RuleSettings *settings = new RuleSettings(cfg, QStringLiteral("tempSettings"));
writeToSettings(settings);
Rules *rules = new Rules(settings);
delete(settings);
return rules;
}
void RulesModel::populateRuleList()
{
qDeleteAll(m_ruleList);

View file

@ -64,11 +64,8 @@ public:
bool hasRule(const QString &key) const;
RuleItem *ruleItem(const QString &key) const;
void readFromSettings(RuleSettings *settings);
void writeToSettings(RuleSettings *settings) const;
void importFromRules(Rules *rules);
Rules *exportToRules() const;
RuleSettings *settings() const;
void setSettings(RuleSettings *settings);
void setSuggestedProperties(const QVariantMap &info);
@ -90,6 +87,7 @@ signals:
private:
void populateRuleList();
RuleItem *addRule(RuleItem *rule);
void writeToSettings(RuleItem *rule);
QString defaultDescription() const;
void processSuggestion(const QString &key, const QVariant &value);
@ -117,6 +115,7 @@ private:
#ifdef KWIN_BUILD_ACTIVITIES
KActivities::Consumer *m_activities;
#endif
RuleSettings *m_settings;
};
}