Warning, file /plasma/plasma-workspace/kcms/notifications/kcm.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2019 Kai Uwe Broulik <kde@privat.broulik.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "kcm.h" 0008 0009 #include <QAction> 0010 #include <QCommandLineParser> 0011 #include <QDialog> 0012 #include <QDialogButtonBox> 0013 #include <QPushButton> 0014 #include <QQuickItem> 0015 #include <QQuickRenderControl> 0016 #include <QQuickWindow> 0017 #include <QStandardPaths> 0018 #include <QVBoxLayout> 0019 #include <QWindow> 0020 0021 #include <KConfigGroup> 0022 #include <KGlobalAccel> 0023 #include <KLocalizedString> 0024 #include <KNotifyConfigWidget> 0025 #include <KPluginFactory> 0026 0027 #include <algorithm> 0028 0029 #include "notificationsdata.h" 0030 0031 #include <libnotificationmanager/badgesettings.h> 0032 #include <libnotificationmanager/behaviorsettings.h> 0033 #include <libnotificationmanager/donotdisturbsettings.h> 0034 #include <libnotificationmanager/jobsettings.h> 0035 #include <libnotificationmanager/notificationsettings.h> 0036 0037 K_PLUGIN_FACTORY_WITH_JSON(KCMNotificationsFactory, "kcm_notifications.json", registerPlugin<KCMNotifications>(); registerPlugin<NotificationsData>();) 0038 0039 KCMNotifications::KCMNotifications(QObject *parent, const KPluginMetaData &data, const QVariantList &args) 0040 : KQuickAddons::ManagedConfigModule(parent, data, args) 0041 , m_sourcesModel(new SourcesModel(this)) 0042 , m_filteredModel(new FilterProxyModel(this)) 0043 , m_data(new NotificationsData(this)) 0044 , m_toggleDoNotDisturbAction(new QAction(this)) 0045 { 0046 const char uri[] = "org.kde.private.kcms.notifications"; 0047 qmlRegisterUncreatableType<SourcesModel>(uri, 1, 0, "SourcesModel", QStringLiteral("Cannot create instances of SourcesModel")); 0048 0049 qmlRegisterAnonymousType<FilterProxyModel>("FilterProxyModel", 1); 0050 qmlRegisterAnonymousType<QKeySequence>("QKeySequence", 1); 0051 qmlRegisterAnonymousType<NotificationManager::DoNotDisturbSettings>("DoNotDisturbSettings", 1); 0052 qmlRegisterAnonymousType<NotificationManager::NotificationSettings>("NotificationSettings", 1); 0053 qmlRegisterAnonymousType<NotificationManager::JobSettings>("JobSettings", 1); 0054 qmlRegisterAnonymousType<NotificationManager::BadgeSettings>("BadgeSettings", 1); 0055 qmlRegisterAnonymousType<NotificationManager::BehaviorSettings>("BehaviorSettings", 1); 0056 qmlProtectModule(uri, 1); 0057 0058 m_filteredModel->setSourceModel(m_sourcesModel); 0059 0060 // for KGlobalAccel... 0061 // keep in sync with globalshortcuts.cpp in notification plasmoid! 0062 m_toggleDoNotDisturbAction->setObjectName(QStringLiteral("toggle do not disturb")); 0063 m_toggleDoNotDisturbAction->setProperty("componentName", QStringLiteral("plasmashell")); 0064 m_toggleDoNotDisturbAction->setText(i18n("Toggle do not disturb")); 0065 m_toggleDoNotDisturbAction->setIcon(QIcon::fromTheme(QStringLiteral("notifications-disabled"))); 0066 0067 QStringList stringArgs; 0068 stringArgs.reserve(args.count() + 1); 0069 // need to add a fake argv[0] for QCommandLineParser 0070 stringArgs.append(QStringLiteral("kcm_notifications")); 0071 for (const QVariant &arg : args) { 0072 stringArgs.append(arg.toString()); 0073 } 0074 0075 QCommandLineParser parser; 0076 0077 QCommandLineOption desktopEntryOption(QStringLiteral("desktop-entry"), QString(), QStringLiteral("desktop-entry")); 0078 parser.addOption(desktopEntryOption); 0079 QCommandLineOption notifyRcNameOption(QStringLiteral("notifyrc"), QString(), QStringLiteral("notifyrcname")); 0080 parser.addOption(notifyRcNameOption); 0081 QCommandLineOption eventIdOption(QStringLiteral("event-id"), QString(), QStringLiteral("event-id")); 0082 parser.addOption(eventIdOption); 0083 0084 parser.parse(stringArgs); 0085 0086 setInitialDesktopEntry(parser.value(desktopEntryOption)); 0087 setInitialNotifyRcName(parser.value(notifyRcNameOption)); 0088 setInitialEventId(parser.value(eventIdOption)); 0089 0090 connect(this, &KCMNotifications::toggleDoNotDisturbShortcutChanged, this, &KCMNotifications::settingsChanged); 0091 connect(this, &KCMNotifications::defaultsIndicatorsVisibleChanged, this, &KCMNotifications::onDefaultsIndicatorsVisibleChanged); 0092 } 0093 0094 KCMNotifications::~KCMNotifications() 0095 { 0096 } 0097 0098 SourcesModel *KCMNotifications::sourcesModel() const 0099 { 0100 return m_sourcesModel; 0101 } 0102 0103 FilterProxyModel *KCMNotifications::filteredModel() const 0104 { 0105 return m_filteredModel; 0106 } 0107 0108 NotificationManager::DoNotDisturbSettings *KCMNotifications::dndSettings() const 0109 { 0110 return m_data->dndSettings(); 0111 } 0112 0113 NotificationManager::NotificationSettings *KCMNotifications::notificationSettings() const 0114 { 0115 return m_data->notificationSettings(); 0116 } 0117 0118 NotificationManager::JobSettings *KCMNotifications::jobSettings() const 0119 { 0120 return m_data->jobSettings(); 0121 } 0122 0123 NotificationManager::BadgeSettings *KCMNotifications::badgeSettings() const 0124 { 0125 return m_data->badgeSettings(); 0126 } 0127 0128 QKeySequence KCMNotifications::toggleDoNotDisturbShortcut() const 0129 { 0130 return m_toggleDoNotDisturbShortcut; 0131 } 0132 0133 void KCMNotifications::setToggleDoNotDisturbShortcut(const QKeySequence &shortcut) 0134 { 0135 if (m_toggleDoNotDisturbShortcut == shortcut) { 0136 return; 0137 } 0138 0139 m_toggleDoNotDisturbShortcut = shortcut; 0140 m_toggleDoNotDisturbShortcutDirty = true; 0141 Q_EMIT toggleDoNotDisturbShortcutChanged(); 0142 } 0143 0144 QString KCMNotifications::initialDesktopEntry() const 0145 { 0146 return m_initialDesktopEntry; 0147 } 0148 0149 void KCMNotifications::setInitialDesktopEntry(const QString &desktopEntry) 0150 { 0151 if (m_initialDesktopEntry != desktopEntry) { 0152 m_initialDesktopEntry = desktopEntry; 0153 Q_EMIT initialDesktopEntryChanged(); 0154 } 0155 } 0156 0157 QString KCMNotifications::initialNotifyRcName() const 0158 { 0159 return m_initialNotifyRcName; 0160 } 0161 0162 void KCMNotifications::setInitialNotifyRcName(const QString ¬ifyRcName) 0163 { 0164 if (m_initialNotifyRcName != notifyRcName) { 0165 m_initialNotifyRcName = notifyRcName; 0166 Q_EMIT initialNotifyRcNameChanged(); 0167 } 0168 } 0169 0170 QString KCMNotifications::initialEventId() const 0171 { 0172 return m_initialEventId; 0173 } 0174 0175 void KCMNotifications::setInitialEventId(const QString &eventId) 0176 { 0177 if (m_initialEventId != eventId) { 0178 m_initialEventId = eventId; 0179 Q_EMIT initialEventIdChanged(); 0180 } 0181 } 0182 0183 void KCMNotifications::configureEvents(const QString ¬ifyRcName, const QString &eventId, QQuickItem *ctx) 0184 { 0185 // We're not using KNotifyConfigWidget::configure here as we want to handle the 0186 // saving ourself (so we Apply with all other KCM settings) but there's no way 0187 // to access the config object :( 0188 // We also need access to the QDialog so we can set the KCM as transient parent. 0189 0190 QDialog *dialog = new QDialog(nullptr); 0191 dialog->setAttribute(Qt::WA_DeleteOnClose); 0192 dialog->setWindowTitle(i18n("Configure Notifications")); 0193 0194 if (ctx && ctx->window()) { 0195 dialog->winId(); // so it creates windowHandle 0196 dialog->windowHandle()->setTransientParent(QQuickRenderControl::renderWindowFor(ctx->window())); 0197 dialog->setModal(true); 0198 } 0199 0200 KNotifyConfigWidget *w = new KNotifyConfigWidget(dialog); 0201 0202 QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); 0203 buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel); 0204 buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); 0205 0206 QVBoxLayout *layout = new QVBoxLayout; 0207 layout->addWidget(w); 0208 layout->addWidget(buttonBox); 0209 dialog->setLayout(layout); 0210 0211 // TODO we should only save settings when clicking Apply in the main UI 0212 connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, w, &KNotifyConfigWidget::save); 0213 connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, w, &KNotifyConfigWidget::save); 0214 connect(w, &KNotifyConfigWidget::changed, buttonBox->button(QDialogButtonBox::Apply), &QPushButton::setEnabled); 0215 0216 connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept); 0217 connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); 0218 0219 w->setApplication(notifyRcName); 0220 w->selectEvent(eventId); 0221 0222 dialog->show(); 0223 } 0224 0225 NotificationManager::BehaviorSettings *KCMNotifications::behaviorSettings(const QModelIndex &index) 0226 { 0227 if (!index.isValid()) { 0228 return nullptr; 0229 } 0230 return m_data->behaviorSettings(index.row()); 0231 } 0232 0233 bool KCMNotifications::isDefaultsBehaviorSettings() const 0234 { 0235 return m_data->isDefaultsBehaviorSettings(); 0236 } 0237 0238 void KCMNotifications::load() 0239 { 0240 ManagedConfigModule::load(); 0241 0242 bool firstLoad = m_firstLoad; 0243 if (m_firstLoad) { 0244 m_firstLoad = false; 0245 m_sourcesModel->load(); 0246 0247 for (int i = 0; i < m_sourcesModel->rowCount(); ++i) { 0248 const QModelIndex index = m_sourcesModel->index(i, 0); 0249 if (!index.isValid()) { 0250 continue; 0251 } 0252 0253 QString typeName; 0254 QString groupName; 0255 if (m_sourcesModel->data(index, SourcesModel::SourceTypeRole) == SourcesModel::ApplicationType) { 0256 typeName = QStringLiteral("Applications"); 0257 groupName = m_sourcesModel->data(index, SourcesModel::DesktopEntryRole).toString(); 0258 } else { 0259 typeName = QStringLiteral("Services"); 0260 groupName = m_sourcesModel->data(index, SourcesModel::NotifyRcNameRole).toString(); 0261 } 0262 auto *toAdd = new NotificationManager::BehaviorSettings(typeName, groupName, this); 0263 m_data->insertBehaviorSettings(index.row(), toAdd); 0264 createConnections(toAdd, index); 0265 } 0266 } 0267 0268 m_data->loadBehaviorSettings(); 0269 0270 const QKeySequence toggleDoNotDisturbShortcut = 0271 KGlobalAccel::self() 0272 ->globalShortcut(m_toggleDoNotDisturbAction->property("componentName").toString(), m_toggleDoNotDisturbAction->objectName()) 0273 .value(0); 0274 0275 if (m_toggleDoNotDisturbShortcut != toggleDoNotDisturbShortcut) { 0276 m_toggleDoNotDisturbShortcut = toggleDoNotDisturbShortcut; 0277 Q_EMIT toggleDoNotDisturbShortcutChanged(); 0278 } 0279 0280 m_toggleDoNotDisturbShortcutDirty = false; 0281 if (firstLoad) { 0282 Q_EMIT firstLoadDone(); 0283 } 0284 } 0285 0286 void KCMNotifications::save() 0287 { 0288 ManagedConfigModule::save(); 0289 m_data->saveBehaviorSettings(); 0290 0291 if (m_toggleDoNotDisturbShortcutDirty) { 0292 // KeySequenceItem will already have checked whether the shortcut is available 0293 KGlobalAccel::self()->setShortcut(m_toggleDoNotDisturbAction, {m_toggleDoNotDisturbShortcut}, KGlobalAccel::NoAutoloading); 0294 } 0295 } 0296 0297 void KCMNotifications::defaults() 0298 { 0299 ManagedConfigModule::defaults(); 0300 m_data->defaultsBehaviorSettings(); 0301 0302 setToggleDoNotDisturbShortcut(QKeySequence()); 0303 } 0304 0305 void KCMNotifications::onDefaultsIndicatorsVisibleChanged() 0306 { 0307 for (int i = 0; i < m_sourcesModel->rowCount(); ++i) { 0308 const QModelIndex index = m_sourcesModel->index(i, 0); 0309 updateModelIsDefaultStatus(index); 0310 } 0311 } 0312 0313 void KCMNotifications::updateModelIsDefaultStatus(const QModelIndex &index) 0314 { 0315 if (index.isValid()) { 0316 m_sourcesModel->setData(index, behaviorSettings(index)->isDefaults(), SourcesModel::IsDefaultRole); 0317 Q_EMIT isDefaultsBehaviorSettingsChanged(); 0318 } 0319 } 0320 0321 bool KCMNotifications::isSaveNeeded() const 0322 { 0323 return m_toggleDoNotDisturbShortcutDirty || m_data->isSaveNeededBehaviorSettings(); 0324 } 0325 0326 bool KCMNotifications::isDefaults() const 0327 { 0328 return m_data->isDefaultsBehaviorSettings(); 0329 } 0330 0331 void KCMNotifications::createConnections(NotificationManager::BehaviorSettings *settings, const QModelIndex &index) 0332 { 0333 connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsChanged, this, &KCMNotifications::settingsChanged); 0334 connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsInDndModeChanged, this, &KCMNotifications::settingsChanged); 0335 connect(settings, &NotificationManager::BehaviorSettings::ShowInHistoryChanged, this, &KCMNotifications::settingsChanged); 0336 connect(settings, &NotificationManager::BehaviorSettings::ShowBadgesChanged, this, &KCMNotifications::settingsChanged); 0337 0338 connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsChanged, this, [this, index] { 0339 updateModelIsDefaultStatus(index); 0340 }); 0341 connect(settings, &NotificationManager::BehaviorSettings::ShowPopupsInDndModeChanged, this, [this, index] { 0342 updateModelIsDefaultStatus(index); 0343 }); 0344 connect(settings, &NotificationManager::BehaviorSettings::ShowInHistoryChanged, this, [this, index] { 0345 updateModelIsDefaultStatus(index); 0346 }); 0347 connect(settings, &NotificationManager::BehaviorSettings::ShowBadgesChanged, this, [this, index] { 0348 updateModelIsDefaultStatus(index); 0349 }); 0350 } 0351 0352 #include "kcm.moc"