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:
parent
61c2055da7
commit
b5a58f83ee
6 changed files with 190 additions and 204 deletions
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue