Commit 46a7f880 authored by Cyril Rossi's avatar Cyril Rossi
Browse files

KCM Notifications use KCModuleData to highlight the module when settings has changed

The particularity is in the per application/service's settings, which are created and loaded dynamically from the model in the KCM, meaning they are not yet available when KCModuleData check for isDefault.

Simple solution introduced here is to allow the KCModuleData derived class to load them from the plasmanotifyrc file since the non default settings are saved here.

Also, show the default indicator in the Applications / Services list and hihglight the "Configure..." button
parent a57104e7
...@@ -5,6 +5,7 @@ set(kcm_notifications_SRCS ...@@ -5,6 +5,7 @@ set(kcm_notifications_SRCS
kcm.cpp kcm.cpp
sourcesmodel.cpp sourcesmodel.cpp
filterproxymodel.cpp filterproxymodel.cpp
notificationsdata.cpp
) )
add_library(kcm_notifications MODULE ${kcm_notifications_SRCS}) add_library(kcm_notifications MODULE ${kcm_notifications_SRCS})
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include "sourcesmodel.h" #include "sourcesmodel.h"
#include "filterproxymodel.h" #include "filterproxymodel.h"
#include "notificationsdata.h"
#include <notificationmanager/donotdisturbsettings.h> #include <notificationmanager/donotdisturbsettings.h>
#include <notificationmanager/notificationsettings.h> #include <notificationmanager/notificationsettings.h>
...@@ -50,16 +51,13 @@ ...@@ -50,16 +51,13 @@
#include <notificationmanager/badgesettings.h> #include <notificationmanager/badgesettings.h>
#include <notificationmanager/behaviorsettings.h> #include <notificationmanager/behaviorsettings.h>
K_PLUGIN_FACTORY_WITH_JSON(KCMNotificationsFactory, "kcm_notifications.json", registerPlugin<KCMNotifications>();) K_PLUGIN_FACTORY_WITH_JSON(KCMNotificationsFactory, "kcm_notifications.json", registerPlugin<KCMNotifications>(); registerPlugin<NotificationsData>();)
KCMNotifications::KCMNotifications(QObject *parent, const QVariantList &args) KCMNotifications::KCMNotifications(QObject *parent, const QVariantList &args)
: KQuickAddons::ManagedConfigModule(parent, args) : KQuickAddons::ManagedConfigModule(parent, args)
, m_sourcesModel(new SourcesModel(this)) , m_sourcesModel(new SourcesModel(this))
, m_filteredModel(new FilterProxyModel(this)) , m_filteredModel(new FilterProxyModel(this))
, m_dndSettings(new NotificationManager::DoNotDisturbSettings(this)) , m_data(new NotificationsData(this))
, m_notificationSettings(new NotificationManager::NotificationSettings(this))
, m_jobSettings(new NotificationManager::JobSettings(this))
, m_badgeSettings(new NotificationManager::BadgeSettings(this))
, m_toggleDoNotDisturbAction(new QAction(this)) , m_toggleDoNotDisturbAction(new QAction(this))
{ {
...@@ -114,6 +112,7 @@ KCMNotifications::KCMNotifications(QObject *parent, const QVariantList &args) ...@@ -114,6 +112,7 @@ KCMNotifications::KCMNotifications(QObject *parent, const QVariantList &args)
setInitialEventId(parser.value(eventIdOption)); setInitialEventId(parser.value(eventIdOption));
connect(this, &KCMNotifications::toggleDoNotDisturbShortcutChanged, this, &KCMNotifications::settingsChanged); connect(this, &KCMNotifications::toggleDoNotDisturbShortcutChanged, this, &KCMNotifications::settingsChanged);
connect(this, &KCMNotifications::defaultsIndicatorsVisibleChanged, this, &KCMNotifications::onDefaultsIndicatorsVisibleChanged);
} }
KCMNotifications::~KCMNotifications() KCMNotifications::~KCMNotifications()
...@@ -133,22 +132,22 @@ FilterProxyModel *KCMNotifications::filteredModel() const ...@@ -133,22 +132,22 @@ FilterProxyModel *KCMNotifications::filteredModel() const
NotificationManager::DoNotDisturbSettings *KCMNotifications::dndSettings() const NotificationManager::DoNotDisturbSettings *KCMNotifications::dndSettings() const
{ {
return m_dndSettings; return m_data->dndSettings();
} }
NotificationManager::NotificationSettings *KCMNotifications::notificationSettings() const NotificationManager::NotificationSettings *KCMNotifications::notificationSettings() const
{ {
return m_notificationSettings; return m_data->notificationSettings();
} }
NotificationManager::JobSettings *KCMNotifications::jobSettings() const NotificationManager::JobSettings *KCMNotifications::jobSettings() const
{ {
return m_jobSettings; return m_data->jobSettings();
} }
NotificationManager::BadgeSettings *KCMNotifications::badgeSettings() const NotificationManager::BadgeSettings *KCMNotifications::badgeSettings() const
{ {
return m_badgeSettings; return m_data->badgeSettings();
} }
QKeySequence KCMNotifications::toggleDoNotDisturbShortcut() const QKeySequence KCMNotifications::toggleDoNotDisturbShortcut() const
...@@ -253,7 +252,12 @@ NotificationManager::BehaviorSettings *KCMNotifications::behaviorSettings(const ...@@ -253,7 +252,12 @@ NotificationManager::BehaviorSettings *KCMNotifications::behaviorSettings(const
if (!index.isValid()) { if (!index.isValid()) {
return nullptr; return nullptr;
} }
return m_behaviorSettingsList.value(index.row()); return m_data->behaviorSettings(index.row());
}
bool KCMNotifications::isDefaultsBehaviorSettings() const
{
return m_data->isDefaultsBehaviorSettings();
} }
void KCMNotifications::load() void KCMNotifications::load()
...@@ -281,14 +285,12 @@ void KCMNotifications::load() ...@@ -281,14 +285,12 @@ void KCMNotifications::load()
groupName = m_sourcesModel->data(index, SourcesModel::NotifyRcNameRole).toString(); groupName = m_sourcesModel->data(index, SourcesModel::NotifyRcNameRole).toString();
} }
auto *toAdd = new NotificationManager::BehaviorSettings(typeName, groupName, this); auto *toAdd = new NotificationManager::BehaviorSettings(typeName, groupName, this);
m_behaviorSettingsList[index.row()] = toAdd; m_data->insertBehaviorSettings(index.row(), toAdd);
createConnections(toAdd); createConnections(toAdd, index);
} }
} }
for (auto *behaviorSettings : qAsConst(m_behaviorSettingsList)) { m_data->loadBehaviorSettings();
behaviorSettings->load();
}
const QKeySequence toggleDoNotDisturbShortcut = KGlobalAccel::self()->globalShortcut( const QKeySequence toggleDoNotDisturbShortcut = KGlobalAccel::self()->globalShortcut(
m_toggleDoNotDisturbAction->property("componentName").toString(), m_toggleDoNotDisturbAction->property("componentName").toString(),
...@@ -308,9 +310,7 @@ void KCMNotifications::load() ...@@ -308,9 +310,7 @@ void KCMNotifications::load()
void KCMNotifications::save() void KCMNotifications::save()
{ {
ManagedConfigModule::save(); ManagedConfigModule::save();
for (auto *behaviorSettings : qAsConst(m_behaviorSettingsList)) { m_data->saveBehaviorSettings();
behaviorSettings->save();
}
if (m_toggleDoNotDisturbShortcutDirty) { if (m_toggleDoNotDisturbShortcutDirty) {
// KeySequenceItem will already have checked whether the shortcut is available // KeySequenceItem will already have checked whether the shortcut is available
...@@ -323,40 +323,56 @@ void KCMNotifications::save() ...@@ -323,40 +323,56 @@ void KCMNotifications::save()
void KCMNotifications::defaults() void KCMNotifications::defaults()
{ {
ManagedConfigModule::defaults(); ManagedConfigModule::defaults();
for (auto *behaviorSettings : qAsConst(m_behaviorSettingsList)) { m_data->defaultsBehaviorSettings();
behaviorSettings->setDefaults();
}
setToggleDoNotDisturbShortcut(QKeySequence()); setToggleDoNotDisturbShortcut(QKeySequence());
} }
bool KCMNotifications::isSaveNeeded() const void KCMNotifications::onDefaultsIndicatorsVisibleChanged()
{
for (int i = 0; i < m_sourcesModel->rowCount(); ++i) {
const QModelIndex index = m_sourcesModel->index(i, 0);
updateModelIsDefaultStatus(index);
}
}
void KCMNotifications::updateModelIsDefaultStatus(const QModelIndex &index)
{ {
bool needSave = std::any_of(m_behaviorSettingsList.cbegin(), if (index.isValid()) {
m_behaviorSettingsList.cend(), m_sourcesModel->setData(index, behaviorSettings(index)->isDefaults(), SourcesModel::IsDefaultRole);
[](const NotificationManager::BehaviorSettings *settings) { emit isDefaultsBehaviorSettingsChanged();
return settings->isSaveNeeded(); }
}); }
return needSave || m_toggleDoNotDisturbShortcutDirty; bool KCMNotifications::isSaveNeeded() const
{
return m_toggleDoNotDisturbShortcutDirty || m_data->isSaveNeededBehaviorSettings();
} }
bool KCMNotifications::isDefaults() const bool KCMNotifications::isDefaults() const
{ {
bool notDefault = std::any_of(m_behaviorSettingsList.cbegin(), return m_data->isDefaultsBehaviorSettings();
m_behaviorSettingsList.cend(),
[](const NotificationManager::BehaviorSettings *settings) {
return !settings->isDefaults();
});
return !notDefault;
} }
void KCMNotifications::createConnections(NotificationManager::BehaviorSettings *settings) void KCMNotifications::createConnections(NotificationManager::BehaviorSettings *settings, const QModelIndex &index)
{ {
connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsChanged, this, &KCMNotifications::settingsChanged); connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsChanged, this, &KCMNotifications::settingsChanged);
connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsInDndModeChanged, this, &KCMNotifications::settingsChanged); connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsInDndModeChanged, this, &KCMNotifications::settingsChanged);
connect(settings, &NotificationManager::BehaviorSettings::ShowInHistoryChanged, this, &KCMNotifications::settingsChanged); connect(settings, &NotificationManager::BehaviorSettings::ShowInHistoryChanged, this, &KCMNotifications::settingsChanged);
connect(settings, &NotificationManager::BehaviorSettings::ShowBadgesChanged, this, &KCMNotifications::settingsChanged); connect(settings, &NotificationManager::BehaviorSettings::ShowBadgesChanged, this, &KCMNotifications::settingsChanged);
connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsChanged, this, [this, index] {
updateModelIsDefaultStatus(index);
});
connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsInDndModeChanged, this, [this, index] {
updateModelIsDefaultStatus(index);
});
connect(settings, &NotificationManager::BehaviorSettings::ShowInHistoryChanged, this, [this, index] {
updateModelIsDefaultStatus(index);
});
connect(settings, &NotificationManager::BehaviorSettings::ShowBadgesChanged, this, [this, index] {
updateModelIsDefaultStatus(index);
});
} }
#include "kcm.moc" #include "kcm.moc"
...@@ -29,6 +29,7 @@ class QAction; ...@@ -29,6 +29,7 @@ class QAction;
class SourcesModel; class SourcesModel;
class FilterProxyModel; class FilterProxyModel;
class NotificationsData;
namespace NotificationManager { namespace NotificationManager {
class DoNotDisturbSettings; class DoNotDisturbSettings;
...@@ -49,6 +50,7 @@ class KCMNotifications : public KQuickAddons::ManagedConfigModule ...@@ -49,6 +50,7 @@ class KCMNotifications : public KQuickAddons::ManagedConfigModule
Q_PROPERTY(NotificationManager::NotificationSettings *notificationSettings READ notificationSettings CONSTANT) Q_PROPERTY(NotificationManager::NotificationSettings *notificationSettings READ notificationSettings CONSTANT)
Q_PROPERTY(NotificationManager::JobSettings *jobSettings READ jobSettings CONSTANT) Q_PROPERTY(NotificationManager::JobSettings *jobSettings READ jobSettings CONSTANT)
Q_PROPERTY(NotificationManager::BadgeSettings *badgeSettings READ badgeSettings CONSTANT) Q_PROPERTY(NotificationManager::BadgeSettings *badgeSettings READ badgeSettings CONSTANT)
Q_PROPERTY(bool isDefaultsBehaviorSettings READ isDefaultsBehaviorSettings NOTIFY isDefaultsBehaviorSettingsChanged)
Q_PROPERTY(QKeySequence toggleDoNotDisturbShortcut Q_PROPERTY(QKeySequence toggleDoNotDisturbShortcut
READ toggleDoNotDisturbShortcut READ toggleDoNotDisturbShortcut
...@@ -89,6 +91,8 @@ public: ...@@ -89,6 +91,8 @@ public:
Q_INVOKABLE NotificationManager::BehaviorSettings *behaviorSettings(const QModelIndex &index); Q_INVOKABLE NotificationManager::BehaviorSettings *behaviorSettings(const QModelIndex &index);
bool isDefaultsBehaviorSettings() const;
public Q_SLOTS: public Q_SLOTS:
void load() override; void load() override;
void save() override; void save() override;
...@@ -99,20 +103,21 @@ signals: ...@@ -99,20 +103,21 @@ signals:
void initialNotifyRcNameChanged(); void initialNotifyRcNameChanged();
void initialEventIdChanged(); void initialEventIdChanged();
void firstLoadDone(); void firstLoadDone();
void isDefaultsBehaviorSettingsChanged();
private Q_SLOTS:
void onDefaultsIndicatorsVisibleChanged();
void updateModelIsDefaultStatus(const QModelIndex &index);
private: private:
bool isSaveNeeded() const override; bool isSaveNeeded() const override;
bool isDefaults() const override; bool isDefaults() const override;
void createConnections(NotificationManager::BehaviorSettings *settings); void createConnections(NotificationManager::BehaviorSettings *settings, const QModelIndex &index);
SourcesModel *m_sourcesModel; SourcesModel *m_sourcesModel;
FilterProxyModel *m_filteredModel; FilterProxyModel *m_filteredModel;
NotificationManager::DoNotDisturbSettings *m_dndSettings; NotificationsData *m_data;
NotificationManager::NotificationSettings *m_notificationSettings;
NotificationManager::JobSettings *m_jobSettings;
NotificationManager::BadgeSettings *m_badgeSettings;
QHash<int, NotificationManager::BehaviorSettings *> m_behaviorSettingsList;
QAction *m_toggleDoNotDisturbAction; QAction *m_toggleDoNotDisturbAction;
QKeySequence m_toggleDoNotDisturbShortcut; QKeySequence m_toggleDoNotDisturbShortcut;
......
/*
* Copyright (c) 2020 Cyril Rossi <cyril.rossi@enioka.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "notificationsdata.h"
#include <notificationmanager/donotdisturbsettings.h>
#include <notificationmanager/notificationsettings.h>
#include <notificationmanager/jobsettings.h>
#include <notificationmanager/badgesettings.h>
#include <notificationmanager/behaviorsettings.h>
NotificationsData::NotificationsData(QObject *parent, const QVariantList &args)
: KCModuleData(parent, args)
, m_dndSettings(new NotificationManager::DoNotDisturbSettings(this))
, m_notificationSettings(new NotificationManager::NotificationSettings(this))
, m_jobSettings(new NotificationManager::JobSettings(this))
, m_badgeSettings(new NotificationManager::BadgeSettings(this))
{
autoRegisterSkeletons();
readBehaviorSettings();
}
NotificationManager::DoNotDisturbSettings *NotificationsData::dndSettings() const
{
return m_dndSettings;
}
NotificationManager::NotificationSettings *NotificationsData::notificationSettings() const
{
return m_notificationSettings;
}
NotificationManager::JobSettings *NotificationsData::jobSettings() const
{
return m_jobSettings;
}
NotificationManager::BadgeSettings *NotificationsData::badgeSettings() const
{
return m_badgeSettings;
}
NotificationManager::BehaviorSettings *NotificationsData::behaviorSettings(int index) const
{
return m_behaviorSettingsList.value(index);
}
void NotificationsData::insertBehaviorSettings(int index, NotificationManager::BehaviorSettings *settings)
{
m_behaviorSettingsList[index] = settings;
}
void NotificationsData::loadBehaviorSettings()
{
for (auto *behaviorSettings : qAsConst(m_behaviorSettingsList)) {
behaviorSettings->load();
}
}
void NotificationsData::saveBehaviorSettings()
{
for (auto *behaviorSettings : qAsConst(m_behaviorSettingsList)) {
behaviorSettings->save();
}
}
void NotificationsData::defaultsBehaviorSettings()
{
for (auto *behaviorSettings : qAsConst(m_behaviorSettingsList)) {
behaviorSettings->setDefaults();
}
}
bool NotificationsData::isSaveNeededBehaviorSettings() const
{
bool needSave = std::any_of(m_behaviorSettingsList.cbegin(),
m_behaviorSettingsList.cend(),
[](const NotificationManager::BehaviorSettings *settings) {
return settings->isSaveNeeded();
});
return needSave;
}
bool NotificationsData::isDefaultsBehaviorSettings() const
{
bool notDefault = std::any_of(m_behaviorSettingsList.cbegin(),
m_behaviorSettingsList.cend(),
[](const NotificationManager::BehaviorSettings *settings) {
return !settings->isDefaults();
});
return !notDefault;
}
void NotificationsData::readBehaviorSettings()
{
KConfig config("plasmanotifyrc", KConfig::SimpleConfig);
for (auto groupEntry : { QStringLiteral("Applications"), QStringLiteral("Services") }) {
KConfigGroup group(&config, groupEntry);
for (const QString &desktopEntry : group.groupList()) {
m_behaviorSettingsList.insert(m_behaviorSettingsList.count(), new NotificationManager::BehaviorSettings(groupEntry, desktopEntry, this));
}
}
}
bool NotificationsData::isDefaults() const
{
return KCModuleData::isDefaults() && isDefaultsBehaviorSettings();
}
/*
* Copyright (c) 2020 Cyril Rossi <cyril.rossi@enioka.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef NOTIFICATIONSDATA_H
#define NOTIFICATIONSDATA_H
#include <QObject>
#include <KCModuleData>
namespace NotificationManager {
class DoNotDisturbSettings;
class NotificationSettings;
class JobSettings;
class BadgeSettings;
class BehaviorSettings;
}
class NotificationsData : public KCModuleData
{
Q_OBJECT
public:
explicit NotificationsData(QObject *parent = nullptr, const QVariantList &args = QVariantList());
bool isDefaults() const override;
NotificationManager::DoNotDisturbSettings *dndSettings() const;
NotificationManager::NotificationSettings *notificationSettings() const;
NotificationManager::JobSettings *jobSettings() const;
NotificationManager::BadgeSettings *badgeSettings() const;
NotificationManager::BehaviorSettings *behaviorSettings(int index) const;
void insertBehaviorSettings(int index, NotificationManager::BehaviorSettings *settings);
void loadBehaviorSettings();
void saveBehaviorSettings();
void defaultsBehaviorSettings();
bool isSaveNeededBehaviorSettings() const;
bool isDefaultsBehaviorSettings() const;
private:
void readBehaviorSettings();
NotificationManager::DoNotDisturbSettings *m_dndSettings;
NotificationManager::NotificationSettings *m_notificationSettings;
NotificationManager::JobSettings *m_jobSettings;
NotificationManager::BadgeSettings *m_badgeSettings;
QHash<int, NotificationManager::BehaviorSettings *> m_behaviorSettingsList;
};
#endif // NOTIFICATIONSDATA_H
...@@ -122,6 +122,15 @@ Kirigami.Page { ...@@ -122,6 +122,15 @@ Kirigami.Page {
sourcesList.forceActiveFocus(); sourcesList.forceActiveFocus();
sourcesList.currentIndex = index; sourcesList.currentIndex = index;
} }
Rectangle {
id: defaultIndicator
radius: width * 0.5
implicitWidth: Kirigami.Units.largeSpacing
implicitHeight: Kirigami.Units.largeSpacing
visible: kcm.defaultsIndicatorsVisible
opacity: !model.isDefault
color: Kirigami.Theme.neutralTextColor
}
} }
Kirigami.PlaceholderMessage { Kirigami.PlaceholderMessage {
......
...@@ -23,7 +23,7 @@ import QtQuick.Layouts 1.1 ...@@ -23,7 +23,7 @@ import QtQuick.Layouts 1.1
import QtQuick.Controls 2.3 as QtControls import QtQuick.Controls 2.3 as QtControls
import org.kde.kirigami 2.4 as Kirigami import org.kde.kirigami 2.4 as Kirigami
import org.kde.kquickcontrols 2.0 as KQuickControls import org.kde.kquickcontrols 2.0 as KQuickControls
import org.kde.kcm 1.3 as KCM import org.kde.kcm 1.5 as KCM
import org.kde.notificationmanager 1.0 as NotificationManager import org.kde.notificationmanager 1.0 as NotificationManager
...@@ -322,6 +322,10 @@ KCM.SimpleKCM { ...@@ -322,6 +322,10 @@ KCM.SimpleKCM {
icon.name: "configure" icon.name: "configure"
enabled: root.notificationsAvailable enabled: root.notificationsAvailable
onClicked: root.openSourcesSettings() onClicked: root.openSourcesSettings()
KCM.SettingHighlighter {
highlight: !kcm.isDefaultsBehaviorSettings
}
} }
Connections { Connections {
......
...@@ -126,6 +126,7 @@ QVariant SourcesModel::data(const QModelIndex &index, int role) const ...@@ -126,6 +126,7 @@ QVariant SourcesModel::data(const QModelIndex &index, int role) const
case SourceTypeRole: return source.desktopEntry.isEmpty() ? ServiceType : ApplicationType; case SourceTypeRole: return source.desktopEntry.isEmpty() ? ServiceType : ApplicationType;
case NotifyRcNameRole: return source.notifyRcName; case NotifyRcNameRole: return source.notifyRcName;
case DesktopEntryRole: return source.desktopEntry; case DesktopEntryRole: return source.desktopEntry;
case IsDefaultRole: return source.isDefault;
} }
return QVariant(); return QVariant();
...@@ -153,6 +154,18 @@ bool SourcesModel::setData(const QModelIndex &index, const QVariant &value, int ...@@ -153,6 +154,18 @@ bool SourcesModel::setData(const QModelIndex &index, const QVariant &value, int
} }
} }
auto &source = m_data[index.row()];
switch (role) {
case IsDefaultRole: {
if (source.isDefault != value.toBool()) {
source.isDefault = value.toBool();
dirty = true;
}
break;
}
}