mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
616 lines
16 KiB
616 lines
16 KiB
/* |
|
SPDX-FileCopyrightText: 2019 Kai Uwe Broulik <[email protected]> |
|
|
|
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL |
|
*/ |
|
|
|
#include "settings.h" |
|
|
|
#include <QDebug> |
|
|
|
#include <KConfigWatcher> |
|
#include <KService> |
|
|
|
#include "debug.h" |
|
#include "mirroredscreenstracker_p.h" |
|
#include "server.h" |
|
|
|
// Settings |
|
#include "badgesettings.h" |
|
#include "donotdisturbsettings.h" |
|
#include "jobsettings.h" |
|
#include "notificationsettings.h" |
|
|
|
namespace NotificationManager |
|
{ |
|
constexpr const char s_configFile[] = "plasmanotifyrc"; |
|
} |
|
|
|
using namespace NotificationManager; |
|
|
|
class Q_DECL_HIDDEN Settings::Private |
|
{ |
|
public: |
|
explicit Private(Settings *q); |
|
~Private(); |
|
|
|
void setDirty(bool dirty); |
|
|
|
Settings::NotificationBehaviors groupBehavior(const KConfigGroup &group) const; |
|
void setGroupBehavior(KConfigGroup &group, const Settings::NotificationBehaviors &behavior); |
|
|
|
KConfigGroup servicesGroup() const; |
|
KConfigGroup applicationsGroup() const; |
|
|
|
QStringList behaviorMatchesList(const KConfigGroup &group, Settings::NotificationBehavior behavior, bool on) const; |
|
|
|
Settings *q; |
|
|
|
KSharedConfig::Ptr config; |
|
|
|
KConfigWatcher::Ptr watcher; |
|
QMetaObject::Connection watcherConnection; |
|
|
|
MirroredScreensTracker::Ptr mirroredScreensTracker; |
|
|
|
DoNotDisturbSettings dndSettings; |
|
NotificationSettings notificationSettings; |
|
JobSettings jobSettings; |
|
BadgeSettings badgeSettings; |
|
|
|
bool live = false; // set to true initially in constructor |
|
bool dirty = false; |
|
}; |
|
|
|
Settings::Private::Private(Settings *q) |
|
: q(q) |
|
{ |
|
} |
|
|
|
Settings::Private::~Private() = default; |
|
|
|
void Settings::Private::setDirty(bool dirty) |
|
{ |
|
if (this->dirty != dirty) { |
|
this->dirty = dirty; |
|
Q_EMIT q->dirtyChanged(); |
|
} |
|
} |
|
|
|
Settings::NotificationBehaviors Settings::Private::groupBehavior(const KConfigGroup &group) const |
|
{ |
|
Settings::NotificationBehaviors behaviors; |
|
behaviors.setFlag(Settings::ShowPopups, group.readEntry("ShowPopups", true)); |
|
// show popups in dnd mode implies the show popups |
|
behaviors.setFlag(Settings::ShowPopupsInDoNotDisturbMode, behaviors.testFlag(Settings::ShowPopups) && group.readEntry("ShowPopupsInDndMode", false)); |
|
behaviors.setFlag(Settings::ShowInHistory, group.readEntry("ShowInHistory", true)); |
|
behaviors.setFlag(Settings::ShowBadges, group.readEntry("ShowBadges", true)); |
|
return behaviors; |
|
} |
|
|
|
void Settings::Private::setGroupBehavior(KConfigGroup &group, const Settings::NotificationBehaviors &behavior) |
|
{ |
|
if (groupBehavior(group) == behavior) { |
|
return; |
|
} |
|
|
|
const bool showPopups = behavior.testFlag(Settings::ShowPopups); |
|
if (showPopups && !group.hasDefault("ShowPopups")) { |
|
group.revertToDefault("ShowPopups", KConfigBase::Notify); |
|
} else { |
|
group.writeEntry("ShowPopups", showPopups, KConfigBase::Notify); |
|
} |
|
|
|
const bool showPopupsInDndMode = behavior.testFlag(Settings::ShowPopupsInDoNotDisturbMode); |
|
if (!showPopupsInDndMode && !group.hasDefault("ShowPopupsInDndMode")) { |
|
group.revertToDefault("ShowPopupsInDndMode", KConfigBase::Notify); |
|
} else { |
|
group.writeEntry("ShowPopupsInDndMode", showPopupsInDndMode, KConfigBase::Notify); |
|
} |
|
|
|
const bool showInHistory = behavior.testFlag(Settings::ShowInHistory); |
|
if (showInHistory && !group.hasDefault("ShowInHistory")) { |
|
group.revertToDefault("ShowInHistory", KConfig::Notify); |
|
} else { |
|
group.writeEntry("ShowInHistory", showInHistory, KConfigBase::Notify); |
|
} |
|
|
|
const bool showBadges = behavior.testFlag(Settings::ShowBadges); |
|
if (showBadges && !group.hasDefault("ShowBadges")) { |
|
group.revertToDefault("ShowBadges", KConfigBase::Notify); |
|
} else { |
|
group.writeEntry("ShowBadges", showBadges, KConfigBase::Notify); |
|
} |
|
|
|
setDirty(true); |
|
} |
|
|
|
KConfigGroup Settings::Private::servicesGroup() const |
|
{ |
|
return config->group("Services"); |
|
} |
|
|
|
KConfigGroup Settings::Private::applicationsGroup() const |
|
{ |
|
return config->group("Applications"); |
|
} |
|
|
|
QStringList Settings::Private::behaviorMatchesList(const KConfigGroup &group, Settings::NotificationBehavior behavior, bool on) const |
|
{ |
|
QStringList matches; |
|
|
|
const QStringList apps = group.groupList(); |
|
for (const QString &app : apps) { |
|
if (groupBehavior(group.group(app)).testFlag(behavior) == on) { |
|
matches.append(app); |
|
} |
|
} |
|
|
|
return matches; |
|
} |
|
|
|
Settings::Settings(QObject *parent) |
|
: QObject(parent) |
|
, d(new Private(this)) |
|
{ |
|
d->config = KSharedConfig::openConfig(s_configFile); |
|
|
|
setLive(true); |
|
|
|
connect(&Server::self(), &Server::inhibitedByApplicationChanged, this, &Settings::notificationsInhibitedByApplicationChanged); |
|
connect(&Server::self(), &Server::inhibitionApplicationsChanged, this, &Settings::notificationInhibitionApplicationsChanged); |
|
|
|
if (d->dndSettings.whenScreensMirrored()) { |
|
d->mirroredScreensTracker = MirroredScreensTracker::createTracker(); |
|
connect(d->mirroredScreensTracker.data(), &MirroredScreensTracker::screensMirroredChanged, this, &Settings::screensMirroredChanged); |
|
} |
|
} |
|
|
|
Settings::Settings(const KSharedConfig::Ptr &config, QObject *parent) |
|
: Settings(parent) |
|
{ |
|
d->config = config; |
|
} |
|
|
|
Settings::~Settings() |
|
{ |
|
d->config->markAsClean(); |
|
} |
|
|
|
Settings::NotificationBehaviors Settings::applicationBehavior(const QString &desktopEntry) const |
|
{ |
|
return d->groupBehavior(d->applicationsGroup().group(desktopEntry)); |
|
} |
|
|
|
void Settings::setApplicationBehavior(const QString &desktopEntry, NotificationBehaviors behaviors) |
|
{ |
|
KConfigGroup group(d->applicationsGroup().group(desktopEntry)); |
|
d->setGroupBehavior(group, behaviors); |
|
} |
|
|
|
Settings::NotificationBehaviors Settings::serviceBehavior(const QString ¬ifyRcName) const |
|
{ |
|
return d->groupBehavior(d->servicesGroup().group(notifyRcName)); |
|
} |
|
|
|
void Settings::setServiceBehavior(const QString ¬ifyRcName, NotificationBehaviors behaviors) |
|
{ |
|
KConfigGroup group(d->servicesGroup().group(notifyRcName)); |
|
d->setGroupBehavior(group, behaviors); |
|
} |
|
|
|
void Settings::registerKnownApplication(const QString &desktopEntry) |
|
{ |
|
KService::Ptr service = KService::serviceByDesktopName(desktopEntry); |
|
if (!service) { |
|
qCDebug(NOTIFICATIONMANAGER) << "Application" << desktopEntry << "cannot be registered as seen application since there is no service for it"; |
|
return; |
|
} |
|
|
|
if (service->noDisplay()) { |
|
qCDebug(NOTIFICATIONMANAGER) << "Application" << desktopEntry << "will not be registered as seen application since it's marked as NoDisplay"; |
|
return; |
|
} |
|
|
|
if (knownApplications().contains(desktopEntry)) { |
|
return; |
|
} |
|
|
|
d->applicationsGroup().group(desktopEntry).writeEntry("Seen", true); |
|
|
|
Q_EMIT knownApplicationsChanged(); |
|
} |
|
|
|
void Settings::forgetKnownApplication(const QString &desktopEntry) |
|
{ |
|
if (!knownApplications().contains(desktopEntry)) { |
|
return; |
|
} |
|
|
|
// Only remove applications that were added through registerKnownApplication |
|
if (!d->applicationsGroup().group(desktopEntry).readEntry("Seen", false)) { |
|
qCDebug(NOTIFICATIONMANAGER) << "Application" << desktopEntry << "will not be removed from seen applications since it wasn't one."; |
|
return; |
|
} |
|
|
|
d->applicationsGroup().deleteGroup(desktopEntry); |
|
|
|
Q_EMIT knownApplicationsChanged(); |
|
} |
|
|
|
void Settings::load() |
|
{ |
|
d->config->markAsClean(); |
|
d->config->reparseConfiguration(); |
|
d->dndSettings.load(); |
|
d->notificationSettings.load(); |
|
d->jobSettings.load(); |
|
d->badgeSettings.load(); |
|
Q_EMIT settingsChanged(); |
|
d->setDirty(false); |
|
} |
|
|
|
void Settings::save() |
|
{ |
|
d->dndSettings.save(); |
|
d->notificationSettings.save(); |
|
d->jobSettings.save(); |
|
d->badgeSettings.save(); |
|
|
|
d->config->sync(); |
|
d->setDirty(false); |
|
} |
|
|
|
void Settings::defaults() |
|
{ |
|
d->dndSettings.setDefaults(); |
|
d->notificationSettings.setDefaults(); |
|
d->jobSettings.setDefaults(); |
|
d->badgeSettings.setDefaults(); |
|
Q_EMIT settingsChanged(); |
|
d->setDirty(false); |
|
} |
|
|
|
bool Settings::live() const |
|
{ |
|
return d->live; |
|
} |
|
|
|
void Settings::setLive(bool live) |
|
{ |
|
if (live == d->live) { |
|
return; |
|
} |
|
|
|
d->live = live; |
|
|
|
if (live) { |
|
d->watcher = KConfigWatcher::create(d->config); |
|
d->watcherConnection = connect(d->watcher.data(), &KConfigWatcher::configChanged, this, [this](const KConfigGroup &group, const QByteArrayList &names) { |
|
Q_UNUSED(names); |
|
|
|
if (group.name() == QLatin1String("DoNotDisturb")) { |
|
d->dndSettings.load(); |
|
|
|
bool emitScreensMirroredChanged = false; |
|
if (d->dndSettings.whenScreensMirrored()) { |
|
if (!d->mirroredScreensTracker) { |
|
d->mirroredScreensTracker = MirroredScreensTracker::createTracker(); |
|
emitScreensMirroredChanged = d->mirroredScreensTracker->screensMirrored(); |
|
connect(d->mirroredScreensTracker.data(), &MirroredScreensTracker::screensMirroredChanged, this, &Settings::screensMirroredChanged); |
|
} |
|
} else if (d->mirroredScreensTracker) { |
|
emitScreensMirroredChanged = d->mirroredScreensTracker->screensMirrored(); |
|
d->mirroredScreensTracker.reset(); |
|
} |
|
|
|
if (emitScreensMirroredChanged) { |
|
Q_EMIT screensMirroredChanged(); |
|
} |
|
} else if (group.name() == QLatin1String("Notifications")) { |
|
d->notificationSettings.load(); |
|
} else if (group.name() == QLatin1String("Jobs")) { |
|
d->jobSettings.load(); |
|
} else if (group.name() == QLatin1String("Badges")) { |
|
d->badgeSettings.load(); |
|
} |
|
|
|
Q_EMIT settingsChanged(); |
|
}); |
|
} else { |
|
disconnect(d->watcherConnection); |
|
d->watcherConnection = QMetaObject::Connection(); |
|
d->watcher.reset(); |
|
} |
|
|
|
Q_EMIT liveChanged(); |
|
} |
|
|
|
bool Settings::dirty() const |
|
{ |
|
// KConfigSkeleton doesn't write into the KConfig until calling save() |
|
// so we need to track d->config->isDirty() manually |
|
return d->dirty; |
|
} |
|
|
|
bool Settings::criticalPopupsInDoNotDisturbMode() const |
|
{ |
|
return d->notificationSettings.criticalInDndMode(); |
|
} |
|
|
|
void Settings::setCriticalPopupsInDoNotDisturbMode(bool enable) |
|
{ |
|
if (this->criticalPopupsInDoNotDisturbMode() == enable) { |
|
return; |
|
} |
|
d->notificationSettings.setCriticalInDndMode(enable); |
|
d->setDirty(true); |
|
} |
|
|
|
bool Settings::keepNormalAlwaysOnTop() const |
|
{ |
|
return d->notificationSettings.normalAlwaysOnTop(); |
|
} |
|
|
|
void Settings::setKeepNormalAlwaysOnTop(bool enable) |
|
{ |
|
if (this->keepNormalAlwaysOnTop() == enable) { |
|
return; |
|
} |
|
d->notificationSettings.setNormalAlwaysOnTop(enable); |
|
d->setDirty(true); |
|
} |
|
|
|
bool Settings::lowPriorityPopups() const |
|
{ |
|
return d->notificationSettings.lowPriorityPopups(); |
|
} |
|
|
|
void Settings::setLowPriorityPopups(bool enable) |
|
{ |
|
if (this->lowPriorityPopups() == enable) { |
|
return; |
|
} |
|
d->notificationSettings.setLowPriorityPopups(enable); |
|
d->setDirty(true); |
|
} |
|
|
|
bool Settings::lowPriorityHistory() const |
|
{ |
|
return d->notificationSettings.lowPriorityHistory(); |
|
} |
|
|
|
void Settings::setLowPriorityHistory(bool enable) |
|
{ |
|
if (this->lowPriorityHistory() == enable) { |
|
return; |
|
} |
|
d->notificationSettings.setLowPriorityHistory(enable); |
|
d->setDirty(true); |
|
} |
|
|
|
Settings::PopupPosition Settings::popupPosition() const |
|
{ |
|
return static_cast<Settings::PopupPosition>(d->notificationSettings.popupPosition()); |
|
} |
|
|
|
void Settings::setPopupPosition(Settings::PopupPosition position) |
|
{ |
|
if (this->popupPosition() == position) { |
|
return; |
|
} |
|
d->notificationSettings.setPopupPosition(position); |
|
d->setDirty(true); |
|
} |
|
|
|
int Settings::popupTimeout() const |
|
{ |
|
return d->notificationSettings.popupTimeout(); |
|
} |
|
|
|
void Settings::setPopupTimeout(int timeout) |
|
{ |
|
if (this->popupTimeout() == timeout) { |
|
return; |
|
} |
|
d->notificationSettings.setPopupTimeout(timeout); |
|
d->setDirty(true); |
|
} |
|
|
|
void Settings::resetPopupTimeout() |
|
{ |
|
setPopupTimeout(d->notificationSettings.defaultPopupTimeoutValue()); |
|
} |
|
|
|
bool Settings::jobsInTaskManager() const |
|
{ |
|
return d->jobSettings.inTaskManager(); |
|
} |
|
|
|
void Settings::setJobsInTaskManager(bool enable) |
|
{ |
|
if (jobsInTaskManager() == enable) { |
|
return; |
|
} |
|
d->jobSettings.setInTaskManager(enable); |
|
d->setDirty(true); |
|
} |
|
|
|
bool Settings::jobsInNotifications() const |
|
{ |
|
return d->jobSettings.inNotifications(); |
|
} |
|
void Settings::setJobsInNotifications(bool enable) |
|
{ |
|
if (jobsInNotifications() == enable) { |
|
return; |
|
} |
|
d->jobSettings.setInNotifications(enable); |
|
d->setDirty(true); |
|
} |
|
|
|
bool Settings::permanentJobPopups() const |
|
{ |
|
return d->jobSettings.permanentPopups(); |
|
} |
|
|
|
void Settings::setPermanentJobPopups(bool enable) |
|
{ |
|
if (permanentJobPopups() == enable) { |
|
return; |
|
} |
|
d->jobSettings.setPermanentPopups(enable); |
|
d->setDirty(true); |
|
} |
|
|
|
bool Settings::badgesInTaskManager() const |
|
{ |
|
return d->badgeSettings.inTaskManager(); |
|
} |
|
|
|
void Settings::setBadgesInTaskManager(bool enable) |
|
{ |
|
if (badgesInTaskManager() == enable) { |
|
return; |
|
} |
|
d->badgeSettings.setInTaskManager(enable); |
|
d->setDirty(true); |
|
} |
|
|
|
QStringList Settings::knownApplications() const |
|
{ |
|
return d->applicationsGroup().groupList(); |
|
} |
|
|
|
QStringList Settings::popupBlacklistedApplications() const |
|
{ |
|
return d->behaviorMatchesList(d->applicationsGroup(), ShowPopups, false); |
|
} |
|
|
|
QStringList Settings::popupBlacklistedServices() const |
|
{ |
|
return d->behaviorMatchesList(d->servicesGroup(), ShowPopups, false); |
|
} |
|
|
|
QStringList Settings::doNotDisturbPopupWhitelistedApplications() const |
|
{ |
|
return d->behaviorMatchesList(d->applicationsGroup(), ShowPopupsInDoNotDisturbMode, true); |
|
} |
|
|
|
QStringList Settings::doNotDisturbPopupWhitelistedServices() const |
|
{ |
|
return d->behaviorMatchesList(d->servicesGroup(), ShowPopupsInDoNotDisturbMode, true); |
|
} |
|
|
|
QStringList Settings::historyBlacklistedApplications() const |
|
{ |
|
return d->behaviorMatchesList(d->applicationsGroup(), ShowInHistory, false); |
|
} |
|
|
|
QStringList Settings::historyBlacklistedServices() const |
|
{ |
|
return d->behaviorMatchesList(d->servicesGroup(), ShowInHistory, false); |
|
} |
|
|
|
QStringList Settings::badgeBlacklistedApplications() const |
|
{ |
|
return d->behaviorMatchesList(d->applicationsGroup(), ShowBadges, false); |
|
} |
|
|
|
QDateTime Settings::notificationsInhibitedUntil() const |
|
{ |
|
return d->dndSettings.until(); |
|
} |
|
|
|
void Settings::setNotificationsInhibitedUntil(const QDateTime &time) |
|
{ |
|
d->dndSettings.setUntil(time); |
|
d->setDirty(true); |
|
} |
|
|
|
void Settings::resetNotificationsInhibitedUntil() |
|
{ |
|
setNotificationsInhibitedUntil(QDateTime()); // FIXME d->dndSettings.defaultUntilValue()); |
|
} |
|
|
|
bool Settings::notificationsInhibitedByApplication() const |
|
{ |
|
return Server::self().inhibitedByApplication(); |
|
} |
|
|
|
QStringList Settings::notificationInhibitionApplications() const |
|
{ |
|
return Server::self().inhibitionApplications(); |
|
} |
|
|
|
QStringList Settings::notificationInhibitionReasons() const |
|
{ |
|
return Server::self().inhibitionReasons(); |
|
} |
|
|
|
bool Settings::inhibitNotificationsWhenScreensMirrored() const |
|
{ |
|
return d->dndSettings.whenScreensMirrored(); |
|
} |
|
|
|
void Settings::setInhibitNotificationsWhenScreensMirrored(bool inhibit) |
|
{ |
|
if (inhibit == inhibitNotificationsWhenScreensMirrored()) { |
|
return; |
|
} |
|
|
|
d->dndSettings.setWhenScreensMirrored(inhibit); |
|
d->setDirty(true); |
|
} |
|
|
|
bool Settings::screensMirrored() const |
|
{ |
|
return d->mirroredScreensTracker && d->mirroredScreensTracker->screensMirrored(); |
|
} |
|
|
|
void Settings::setScreensMirrored(bool mirrored) |
|
{ |
|
if (mirrored) { |
|
qCWarning(NOTIFICATIONMANAGER) << "Cannot forcefully set screens mirrored"; |
|
return; |
|
} |
|
|
|
if (d->mirroredScreensTracker) { |
|
d->mirroredScreensTracker->setScreensMirrored(mirrored); |
|
} |
|
} |
|
|
|
bool Settings::inhibitNotificationsWhenScreenSharing() const |
|
{ |
|
return d->dndSettings.whenScreenSharing(); |
|
} |
|
|
|
void Settings::setInhibitNotificationsWhenScreenSharing(bool inhibit) |
|
{ |
|
if (inhibit == inhibitNotificationsWhenScreenSharing()) { |
|
return; |
|
} |
|
|
|
d->dndSettings.setWhenScreenSharing(inhibit); |
|
d->setDirty(true); |
|
} |
|
|
|
void Settings::revokeApplicationInhibitions() |
|
{ |
|
Server::self().clearInhibitions(); |
|
} |
|
|
|
bool Settings::notificationSoundsInhibited() const |
|
{ |
|
return d->dndSettings.notificationSoundsMuted(); |
|
} |
|
|
|
void Settings::setNotificationSoundsInhibited(bool inhibited) |
|
{ |
|
if (inhibited == notificationSoundsInhibited()) { |
|
return; |
|
} |
|
|
|
d->dndSettings.setNotificationSoundsMuted(inhibited); |
|
d->setDirty(true); |
|
}
|
|
|