/*
* Copyright (c) 2004 Lubos Lunak
* Copyright (c) 2020 Ismael Asensio
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "kcmrules.h"
#include
#include
#include
#include
#include
#include
namespace KWin
{
KCMKWinRules::KCMKWinRules(QObject *parent, const QVariantList &arguments)
: KQuickAddons::ConfigModule(parent, arguments)
, m_ruleBookModel(new RuleBookModel(this))
, m_rulesModel(new RulesModel(this))
{
auto about = new KAboutData(QStringLiteral("kcm_kwinrules"),
i18n("Window Rules"),
QStringLiteral("1.0"),
QString(),
KAboutLicense::GPL);
about->addAuthor(i18n("Ismael Asensio"),
i18n("Author"),
QStringLiteral("isma.af@gmail.com"));
setAboutData(about);
setQuickHelp(i18n("Window-specific Settings
Here you can customize window settings specifically only"
" for some windows.
"
" Please note that this configuration will not take effect if you do not use"
" KWin as your window manager. If you do use a different window manager, please refer to its documentation"
" for how to customize window behavior.
"));
connect(m_rulesModel, &RulesModel::descriptionChanged, this, [this]{
if (m_editIndex.isValid()) {
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);
}
void KCMKWinRules::load()
{
m_ruleBookModel->load();
m_editIndex = QModelIndex();
emit editIndexChanged();
setNeedsSave(false);
}
void KCMKWinRules::save()
{
saveCurrentRule();
m_ruleBookModel->save();
// Notify kwin to reload configuration
QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
QDBusConnection::sessionBus().send(message);
}
void KCMKWinRules::updateNeedsSave()
{
setNeedsSave(true);
emit needsSaveChanged();
}
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()) {
return -1;
}
return m_editIndex.row();
}
void KCMKWinRules::setRuleDescription(int index, const QString &description)
{
if (index < 0 || index >= m_ruleBookModel->rowCount()) {
return;
}
if (m_editIndex.row() == index) {
m_rulesModel->setDescription(description);
return;
}
m_ruleBookModel->setDescriptionAt(index, description);
updateNeedsSave();
}
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()));
// Set the active page to rules editor (0:RulesList, 1:RulesEditor)
setCurrentIndex(1);
}
void KCMKWinRules::createRule()
{
const int newIndex = m_ruleBookModel->rowCount();
m_ruleBookModel->insertRow(newIndex);
updateNeedsSave();
editRule(newIndex);
}
void KCMKWinRules::removeRule(int index)
{
if (index < 0 || index >= m_ruleBookModel->rowCount()) {
return;
}
m_ruleBookModel->removeRow(index);
emit editIndexChanged();
updateNeedsSave();
}
void KCMKWinRules::moveRule(int sourceIndex, int destIndex)
{
const int lastIndex = m_ruleBookModel->rowCount() - 1;
if (sourceIndex == destIndex
|| (sourceIndex < 0 || sourceIndex > lastIndex)
|| (destIndex < 0 || destIndex > lastIndex)) {
return;
}
m_ruleBookModel->moveRow(QModelIndex(), sourceIndex, QModelIndex(), destIndex);
emit editIndexChanged();
updateNeedsSave();
}
void KCMKWinRules::exportToFile(const QUrl &path, const QList &indexes)
{
if (indexes.isEmpty()) {
return;
}
saveCurrentRule();
const auto config = KSharedConfig::openConfig(path.toLocalFile(), KConfig::SimpleConfig);
for (const QString &groupName : config->groupList()) {
config->deleteGroup(groupName);
}
for (int index : 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();
}
}
void KCMKWinRules::importFromFile(const QUrl &path)
{
const auto config = KSharedConfig::openConfig(path.toLocalFile(), KConfig::SimpleConfig);
const QStringList groups = config->groupList();
if (groups.isEmpty()) {
return;
}
for (const QString &groupName : groups) {
RuleSettings settings(config, groupName);
const bool remove = settings.deleteRule();
const QString importDescription = settings.description();
if (importDescription.isEmpty()) {
continue;
}
// Try to find a rule with the same description to replace
int newIndex = -2;
for (int index = 0; index < m_ruleBookModel->rowCount(); index++) {
if (m_ruleBookModel->descriptionAt(index) == importDescription) {
newIndex = index;
break;
}
}
if (remove) {
m_ruleBookModel->removeRow(newIndex);
continue;
}
if (newIndex < 0) {
newIndex = m_ruleBookModel->rowCount();
m_ruleBookModel->insertRow(newIndex);
}
m_ruleBookModel->setRuleAt(newIndex, new Rules(&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()));
}
}
updateNeedsSave();
}
K_PLUGIN_CLASS_WITH_JSON(KCMKWinRules, "kcm_kwinrules.json");
} // namespace
#include "kcmrules.moc"