Commit 6d12d2d6 authored by Cyril Rossi's avatar Cyril Rossi

KCM Notifications : Manage app-specific notifications with KCconfigXT's magic

Summary:
App-specific notifications' behavior are now managed with KConfigXT. The default values are set in plasmanotifyrc shipped with the libnotificationmanager and can be override.
Immutability can be set at applicatioin level in plasmanotifyrc.
Reinitialize button reset all modifications not applied. Default button reset to default applications' behavior.

Require D27059 D27133 D27155

Test Plan:
To set immutable an application or a service specific notifications, add [$i] after an element in `plasmanotifyrc`

* Set immutability for all services (same for applications)
```
[Services][$i]
```
* Set immutability for an app (same for a service)
```
[Applications][org.kde.kdevelop][$i]
```
* Set immutability for a specific entry
```
[Applications][org.kde.kdevelop]
ShowBadges=false
ShowPopupsInDndMode[$i]=true
```

Reviewers: #plasma, ervin, broulik, bport, meven

Reviewed By: #plasma, ervin, broulik, bport

Subscribers: plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D27188
parent e64a3cb2
......@@ -44,11 +44,11 @@
#include "sourcesmodel.h"
#include "filterproxymodel.h"
#include <notificationmanager/settings.h>
#include <notificationmanager/donotdisturbsettings.h>
#include <notificationmanager/notificationsettings.h>
#include <notificationmanager/jobsettings.h>
#include <notificationmanager/badgesettings.h>
#include <notificationmanager/behaviorsettings.h>
K_PLUGIN_FACTORY_WITH_JSON(KCMNotificationsFactory, "kcm_notifications.json", registerPlugin<KCMNotifications>();)
......@@ -56,7 +56,6 @@ KCMNotifications::KCMNotifications(QObject *parent, const QVariantList &args)
: KQuickAddons::ManagedConfigModule(parent, args)
, m_sourcesModel(new SourcesModel(this))
, m_filteredModel(new FilterProxyModel(this))
, m_settings(new NotificationManager::Settings(this))
, m_dndSettings(new NotificationManager::DoNotDisturbSettings(this))
, m_notificationSettings(new NotificationManager::NotificationSettings(this))
, m_jobSettings(new NotificationManager::JobSettings(this))
......@@ -67,12 +66,14 @@ KCMNotifications::KCMNotifications(QObject *parent, const QVariantList &args)
const char uri[] = "org.kde.private.kcms.notifications";
qmlRegisterUncreatableType<SourcesModel>(uri, 1, 0, "SourcesModel",
QStringLiteral("Cannot create instances of SourcesModel"));
qmlRegisterType<FilterProxyModel>();
qmlRegisterType<QKeySequence>();
qmlRegisterType<NotificationManager::DoNotDisturbSettings>();
qmlRegisterType<NotificationManager::NotificationSettings>();
qmlRegisterType<NotificationManager::JobSettings>();
qmlRegisterType<NotificationManager::BadgeSettings>();
qmlRegisterType<NotificationManager::BehaviorSettings>();
qmlProtectModule(uri, 1);
KAboutData *about = new KAboutData(QStringLiteral("kcm_notifications"), i18n("Notifications"),
......@@ -111,6 +112,8 @@ KCMNotifications::KCMNotifications(QObject *parent, const QVariantList &args)
setInitialDesktopEntry(parser.value(desktopEntryOption));
setInitialNotifyRcName(parser.value(notifyRcNameOption));
setInitialEventId(parser.value(eventIdOption));
connect(this, &KCMNotifications::toggleDoNotDisturbShortcutChanged, this, &KCMNotifications::settingsChanged);
}
KCMNotifications::~KCMNotifications()
......@@ -128,11 +131,6 @@ FilterProxyModel *KCMNotifications::filteredModel() const
return m_filteredModel;
}
NotificationManager::Settings *KCMNotifications::settings() const
{
return m_settings;
}
NotificationManager::DoNotDisturbSettings *KCMNotifications::dndSettings() const
{
return m_dndSettings;
......@@ -167,7 +165,6 @@ void KCMNotifications::setToggleDoNotDisturbShortcut(const QKeySequence &shortcu
m_toggleDoNotDisturbShortcut = shortcut;
m_toggleDoNotDisturbShortcutDirty = true;
emit toggleDoNotDisturbShortcutChanged();
setNeedsSave(true);
}
QString KCMNotifications::initialDesktopEntry() const
......@@ -251,10 +248,46 @@ void KCMNotifications::configureEvents(const QString &notifyRcName, const QStrin
dialog->show();
}
NotificationManager::BehaviorSettings *KCMNotifications::behaviorSettings(const QModelIndex &index)
{
if (!index.isValid()) {
return nullptr;
}
return m_behaviorSettingsList.value(index.row());
}
void KCMNotifications::load()
{
ManagedConfigModule::load();
m_settings->load();
if (m_firstLoad) {
m_firstLoad = false;
m_sourcesModel->load();
for (int i = 0; i < m_sourcesModel->rowCount(); ++i) {
const QModelIndex index = m_sourcesModel->index(i, 0);
if (!index.isValid()) {
continue;
}
QString typeName;
QString groupName;
if (m_sourcesModel->data(index, SourcesModel::SourceTypeRole) == SourcesModel::ApplicationType) {
typeName = QStringLiteral("Applications");
groupName = m_sourcesModel->data(index, SourcesModel::DesktopEntryRole).toString();
} else {
typeName = QStringLiteral("Services");
groupName = m_sourcesModel->data(index, SourcesModel::NotifyRcNameRole).toString();
}
auto *toAdd = new NotificationManager::BehaviorSettings(typeName, groupName, this);
m_behaviorSettingsList[index.row()] = toAdd;
createConnections(toAdd);
}
}
for (auto *behaviorSettings : qAsConst(m_behaviorSettingsList)) {
behaviorSettings->load();
}
const QKeySequence toggleDoNotDisturbShortcut = KGlobalAccel::self()->globalShortcut(
m_toggleDoNotDisturbAction->property("componentName").toString(),
......@@ -266,13 +299,14 @@ void KCMNotifications::load()
}
m_toggleDoNotDisturbShortcutDirty = false;
setNeedsSave(false);
}
void KCMNotifications::save()
{
ManagedConfigModule::save();
m_settings->save();
for (auto *behaviorSettings : qAsConst(m_behaviorSettingsList)) {
behaviorSettings->save();
}
if (m_toggleDoNotDisturbShortcutDirty) {
// KeySequenceItem will already have checked whether the shortcut is available
......@@ -280,16 +314,45 @@ void KCMNotifications::save()
{m_toggleDoNotDisturbShortcut},
KGlobalAccel::NoAutoloading);
}
setNeedsSave(false);
}
void KCMNotifications::defaults()
{
ManagedConfigModule::defaults();
m_settings->defaults();
for (auto *behaviorSettings : qAsConst(m_behaviorSettingsList)) {
behaviorSettings->setDefaults();
}
setToggleDoNotDisturbShortcut(QKeySequence());
}
bool KCMNotifications::isSaveNeeded() const
{
bool needSave = std::any_of(m_behaviorSettingsList.cbegin(),
m_behaviorSettingsList.cend(),
[](const NotificationManager::BehaviorSettings *settings) {
return settings->isSaveNeeded();
});
return needSave || m_toggleDoNotDisturbShortcutDirty;
}
bool KCMNotifications::isDefaults() const
{
bool notDefault = std::any_of(m_behaviorSettingsList.cbegin(),
m_behaviorSettingsList.cend(),
[](const NotificationManager::BehaviorSettings *settings) {
return !settings->isDefaults();
});
return !notDefault;
}
void KCMNotifications::createConnections(NotificationManager::BehaviorSettings *settings)
{
connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsChanged, this, &KCMNotifications::settingsChanged);
connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsInDndModeChanged, this, &KCMNotifications::settingsChanged);
connect(settings, &NotificationManager::BehaviorSettings::ShowInHistoryChanged, this, &KCMNotifications::settingsChanged);
connect(settings, &NotificationManager::BehaviorSettings::ShowBadgesChanged, this, &KCMNotifications::settingsChanged);
}
#include "kcm.moc"
......@@ -23,6 +23,7 @@
#include <KQuickAddons/ManagedConfigModule>
#include <QKeySequence>
#include <QHash>
class QAction;
......@@ -30,11 +31,11 @@ class SourcesModel;
class FilterProxyModel;
namespace NotificationManager {
class Settings;
class DoNotDisturbSettings;
class NotificationSettings;
class JobSettings;
class BadgeSettings;
class BehaviorSettings;
}
class KCMNotifications : public KQuickAddons::ManagedConfigModule
......@@ -44,7 +45,6 @@ class KCMNotifications : public KQuickAddons::ManagedConfigModule
Q_PROPERTY(SourcesModel *sourcesModel READ sourcesModel CONSTANT)
Q_PROPERTY(FilterProxyModel *filteredModel READ filteredModel CONSTANT)
Q_PROPERTY(NotificationManager::Settings *settings READ settings CONSTANT)
Q_PROPERTY(NotificationManager::DoNotDisturbSettings *dndSettings READ dndSettings CONSTANT)
Q_PROPERTY(NotificationManager::NotificationSettings *notificationSettings READ notificationSettings CONSTANT)
Q_PROPERTY(NotificationManager::JobSettings *jobSettings READ jobSettings CONSTANT)
......@@ -67,7 +67,6 @@ public:
SourcesModel *sourcesModel() const;
FilterProxyModel *filteredModel() const;
NotificationManager::Settings *settings() const;
NotificationManager::DoNotDisturbSettings *dndSettings() const;
NotificationManager::NotificationSettings *notificationSettings() const;
NotificationManager::JobSettings *jobSettings() const;
......@@ -88,6 +87,8 @@ public:
Q_INVOKABLE void configureEvents(const QString &notifyRcName, const QString &eventId, QQuickItem *ctx = nullptr);
Q_INVOKABLE NotificationManager::BehaviorSettings *behaviorSettings(const QModelIndex &index);
public Q_SLOTS:
void load() override;
void save() override;
......@@ -100,22 +101,25 @@ signals:
private:
void processPendingDeletions();
bool isSaveNeeded() const override;
bool isDefaults() const override;
void createConnections(NotificationManager::BehaviorSettings *settings);
SourcesModel *m_sourcesModel;
FilterProxyModel *m_filteredModel;
NotificationManager::Settings *m_settings;
NotificationManager::DoNotDisturbSettings *m_dndSettings;
NotificationManager::NotificationSettings *m_notificationSettings;
NotificationManager::JobSettings *m_jobSettings;
NotificationManager::BadgeSettings *m_badgeSettings;
QHash<int, NotificationManager::BehaviorSettings *> m_behaviorSettingsList;
QAction *m_toggleDoNotDisturbAction;
QKeySequence m_toggleDoNotDisturbShortcut;
bool m_toggleDoNotDisturbShortcutDirty = false;
bool m_firstLoad = true;
QString m_initialDesktopEntry;
QString m_initialNotifyRcName;
QString m_initialEventId;
};
......@@ -34,6 +34,7 @@ ColumnLayout {
id: configColumn
property var rootIndex
property var behaviorSettings: rootIndex ? kcm.behaviorSettings(rootIndex) : null
readonly property string otherAppsId: "@other"
......@@ -42,29 +43,7 @@ ColumnLayout {
readonly property string desktopEntry: rootIndex ? kcm.sourcesModel.data(rootIndex, Private.SourcesModel.DesktopEntryRole) || "" : ""
readonly property string notifyRcName: rootIndex ? kcm.sourcesModel.data(rootIndex, Private.SourcesModel.NotifyRcNameRole) || "" : ""
function behavior() {
if (configColumn.desktopEntry) {
return kcm.settings.applicationBehavior(configColumn.desktopEntry);
} else if (configColumn.notifyRcName) {
return kcm.settings.serviceBehavior(configColumn.notifyRcName);
}
return -1;
}
function setBehavior(flag, enable) {
var newBehavior = behavior();
if (enable) {
newBehavior |= flag;
} else {
newBehavior &= ~flag;
}
if (configColumn.desktopEntry) {
return kcm.settings.setApplicationBehavior(configColumn.desktopEntry, newBehavior);
} else if (configColumn.notifyRcName) {
return kcm.settings.setServiceBehavior(configColumn.notifyRcName, newBehavior);
}
}
readonly property bool isOtherApp: configColumn.desktopEntry === configColumn.otherAppsId
function configureEvents(eventId) {
kcm.configureEvents(configColumn.notifyRcName, eventId, this)
......@@ -96,8 +75,9 @@ ColumnLayout {
QtControls.CheckBox {
id: showPopupsCheck
text: i18n("Show popups")
checked: configColumn.behavior() & NotificationManager.Settings.ShowPopups
onClicked: configColumn.setBehavior(NotificationManager.Settings.ShowPopups, checked)
enabled: !!behaviorSettings && !behaviorSettings.isShowPopupsImmutable
checked: !!behaviorSettings && behaviorSettings.showPopups
onClicked: behaviorSettings.showPopups = checked
}
RowLayout { // just for indentation
......@@ -105,23 +85,24 @@ ColumnLayout {
Layout.leftMargin: mirrored ? 0 : indicator.width
Layout.rightMargin: mirrored ? indicator.width : 0
text: i18n("Show in do not disturb mode")
enabled: showPopupsCheck.checked
checked: configColumn.behavior() & NotificationManager.Settings.ShowPopupsInDoNotDisturbMode
onClicked: configColumn.setBehavior(NotificationManager.Settings.ShowPopupsInDoNotDisturbMode, checked)
enabled: showPopupsCheck.checked && !behaviorSettings.isShowPopupsInDndModeImmutable
checked: !!behaviorSettings && behaviorSettings.showPopupsInDndMode
onClicked: behaviorSettings.showPopupsInDndMode = checked
}
}
QtControls.CheckBox {
text: i18n("Show in history")
checked: configColumn.behavior() & NotificationManager.Settings.ShowInHistory
onClicked: configColumn.setBehavior(NotificationManager.Settings.ShowInHistory, checked)
enabled: !!behaviorSettings && !behaviorSettings.isShowInHistoryImmutable
checked: !!behaviorSettings && behaviorSettings.showInHistory
onClicked: behaviorSettings.showInHistory = checked
}
QtControls.CheckBox {
text: i18n("Show notification badges")
enabled: !!configColumn.desktopEntry && configColumn.desktopEntry !== configColumn.otherAppsId
checked: configColumn.behavior() & NotificationManager.Settings.ShowBadges
onClicked: configColumn.setBehavior(NotificationManager.Settings.ShowBadges, checked)
enabled: !!configColumn.desktopEntry && !configColumn.isOtherApp && !!behaviorSettings && !behaviorSettings.isShowBadgesImmutable
checked: !!behaviorSettings && behaviorSettings.showBadges
onClicked: behaviorSettings.showBadges = checked
}
Kirigami.Separator {
......@@ -144,7 +125,7 @@ ColumnLayout {
Layout.preferredWidth: form.implicitWidth
text: i18n("This application does not support configuring notifications on a per-event basis.");
wrapMode: Text.WordWrap
visible: !configColumn.notifyRcName && configColumn.desktopEntry !== configColumn.otherAppsId
visible: !configColumn.notifyRcName && !configColumn.isOtherApp
}
// compact layout
......
......@@ -32,8 +32,6 @@ Kirigami.Page {
title: i18n("Application Settings")
Component.onCompleted: {
kcm.sourcesModel.load();
var idx = kcm.sourcesModel.persistentIndexForDesktopEntry(kcm.initialDesktopEntry);
if (!idx.valid) {
idx = kcm.sourcesModel.persistentIndexForNotifyRcName(kcm.initialNotifyRcName);
......
......@@ -48,12 +48,6 @@ KCM.SimpleKCM {
kcm.push("SourcesPage.qml");
}
Binding {
target: kcm
property: "needsSave"
value: kcm.settings.dirty // TODO or other stuff
}
Kirigami.FormLayout {
Kirigami.InlineMessage {
Kirigami.FormData.isSection: true
......
......@@ -82,7 +82,7 @@ public:
Q_INVOKABLE QPersistentModelIndex persistentIndexForNotifyRcName(const QString &notifyRcName) const;
int columnCount(const QModelIndex &parent) const override;
int rowCount(const QModelIndex &parent) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment