diff --git a/kcms/notifications/kcm.cpp b/kcms/notifications/kcm.cpp index bcff75f19..bfb357878 100644 --- a/kcms/notifications/kcm.cpp +++ b/kcms/notifications/kcm.cpp @@ -1,358 +1,362 @@ /* * Copyright (C) 2019 Kai Uwe Broulik * * 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 "kcm.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sourcesmodel.h" #include "filterproxymodel.h" #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KCMNotificationsFactory, "kcm_notifications.json", registerPlugin();) KCMNotifications::KCMNotifications(QObject *parent, const QVariantList &args) : KQuickAddons::ManagedConfigModule(parent, args) , m_sourcesModel(new SourcesModel(this)) , m_filteredModel(new FilterProxyModel(this)) , m_dndSettings(new NotificationManager::DoNotDisturbSettings(this)) , m_notificationSettings(new NotificationManager::NotificationSettings(this)) , m_jobSettings(new NotificationManager::JobSettings(this)) , m_badgeSettings(new NotificationManager::BadgeSettings(this)) , m_toggleDoNotDisturbAction(new QAction(this)) { const char uri[] = "org.kde.private.kcms.notifications"; qmlRegisterUncreatableType(uri, 1, 0, "SourcesModel", QStringLiteral("Cannot create instances of SourcesModel")); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlRegisterType(); qmlProtectModule(uri, 1); KAboutData *about = new KAboutData(QStringLiteral("kcm_notifications"), i18n("Notifications"), QStringLiteral("5.0"), QString(), KAboutLicense::GPL); about->addAuthor(i18n("Kai Uwe Broulik"), QString(), QStringLiteral("kde@privat.broulik.de")); setAboutData(about); m_filteredModel->setSourceModel(m_sourcesModel); // for KGlobalAccel... // keep in sync with globalshortcuts.cpp in notification plasmoid! m_toggleDoNotDisturbAction->setObjectName(QStringLiteral("toggle do not disturb")); m_toggleDoNotDisturbAction->setProperty("componentName", QStringLiteral("plasmashell")); m_toggleDoNotDisturbAction->setText(i18n("Toggle do not disturb")); m_toggleDoNotDisturbAction->setIcon(QIcon::fromTheme(QStringLiteral("notifications-disabled"))); QStringList stringArgs; stringArgs.reserve(args.count() + 1); // need to add a fake argv[0] for QCommandLineParser stringArgs.append(QStringLiteral("kcm_notifications")); for (const QVariant &arg : args) { stringArgs.append(arg.toString()); } QCommandLineParser parser; QCommandLineOption desktopEntryOption(QStringLiteral("desktop-entry"), QString(), QStringLiteral("desktop-entry")); parser.addOption(desktopEntryOption); QCommandLineOption notifyRcNameOption(QStringLiteral("notifyrc"), QString(), QStringLiteral("notifyrcname")); parser.addOption(notifyRcNameOption); QCommandLineOption eventIdOption(QStringLiteral("event-id"), QString(), QStringLiteral("event-id")); parser.addOption(eventIdOption); parser.parse(stringArgs); setInitialDesktopEntry(parser.value(desktopEntryOption)); setInitialNotifyRcName(parser.value(notifyRcNameOption)); setInitialEventId(parser.value(eventIdOption)); connect(this, &KCMNotifications::toggleDoNotDisturbShortcutChanged, this, &KCMNotifications::settingsChanged); } KCMNotifications::~KCMNotifications() { } SourcesModel *KCMNotifications::sourcesModel() const { return m_sourcesModel; } FilterProxyModel *KCMNotifications::filteredModel() const { return m_filteredModel; } NotificationManager::DoNotDisturbSettings *KCMNotifications::dndSettings() const { return m_dndSettings; } NotificationManager::NotificationSettings *KCMNotifications::notificationSettings() const { return m_notificationSettings; } NotificationManager::JobSettings *KCMNotifications::jobSettings() const { return m_jobSettings; } NotificationManager::BadgeSettings *KCMNotifications::badgeSettings() const { return m_badgeSettings; } QKeySequence KCMNotifications::toggleDoNotDisturbShortcut() const { return m_toggleDoNotDisturbShortcut; } void KCMNotifications::setToggleDoNotDisturbShortcut(const QKeySequence &shortcut) { if (m_toggleDoNotDisturbShortcut == shortcut) { return; } m_toggleDoNotDisturbShortcut = shortcut; m_toggleDoNotDisturbShortcutDirty = true; emit toggleDoNotDisturbShortcutChanged(); } QString KCMNotifications::initialDesktopEntry() const { return m_initialDesktopEntry; } void KCMNotifications::setInitialDesktopEntry(const QString &desktopEntry) { if (m_initialDesktopEntry != desktopEntry) { m_initialDesktopEntry = desktopEntry; emit initialDesktopEntryChanged(); } } QString KCMNotifications::initialNotifyRcName() const { return m_initialNotifyRcName; } void KCMNotifications::setInitialNotifyRcName(const QString ¬ifyRcName) { if (m_initialNotifyRcName != notifyRcName) { m_initialNotifyRcName = notifyRcName; emit initialNotifyRcNameChanged(); } } QString KCMNotifications::initialEventId() const { return m_initialEventId; } void KCMNotifications::setInitialEventId(const QString &eventId) { if (m_initialEventId != eventId) { m_initialEventId = eventId; emit initialEventIdChanged(); } } void KCMNotifications::configureEvents(const QString ¬ifyRcName, const QString &eventId, QQuickItem *ctx) { // We're not using KNotifyConfigWidget::configure here as we want to handle the // saving ourself (so we Apply with all other KCM settings) but there's no way // to access the config object :( // We also need access to the QDialog so we can set the KCM as transient parent. QDialog *dialog = new QDialog(nullptr); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setWindowTitle(i18n("Configure Notifications")); if (ctx && ctx->window()) { dialog->winId(); // so it creates windowHandle dialog->windowHandle()->setTransientParent(QQuickRenderControl::renderWindowFor(ctx->window())); dialog->setModal(true); } KNotifyConfigWidget *w = new KNotifyConfigWidget(dialog); QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog); buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel); buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(w); layout->addWidget(buttonBox); dialog->setLayout(layout); // TODO we should only save settings when clicking Apply in the main UI connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, w, &KNotifyConfigWidget::save); connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, w, &KNotifyConfigWidget::save); connect(w, &KNotifyConfigWidget::changed, buttonBox->button(QDialogButtonBox::Apply), &QPushButton::setEnabled); connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); w->setApplication(notifyRcName); w->selectEvent(eventId); 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(); + bool firstLoad = m_firstLoad; 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(), m_toggleDoNotDisturbAction->objectName()).value(0); if (m_toggleDoNotDisturbShortcut != toggleDoNotDisturbShortcut) { m_toggleDoNotDisturbShortcut = toggleDoNotDisturbShortcut; emit toggleDoNotDisturbShortcutChanged(); } m_toggleDoNotDisturbShortcutDirty = false; + if (firstLoad) { + emit firstLoadDone(); + } } void KCMNotifications::save() { ManagedConfigModule::save(); for (auto *behaviorSettings : qAsConst(m_behaviorSettingsList)) { behaviorSettings->save(); } if (m_toggleDoNotDisturbShortcutDirty) { // KeySequenceItem will already have checked whether the shortcut is available KGlobalAccel::self()->setShortcut(m_toggleDoNotDisturbAction, {m_toggleDoNotDisturbShortcut}, KGlobalAccel::NoAutoloading); } } void KCMNotifications::defaults() { ManagedConfigModule::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" diff --git a/kcms/notifications/kcm.h b/kcms/notifications/kcm.h index f01593b4a..c34d23f36 100644 --- a/kcms/notifications/kcm.h +++ b/kcms/notifications/kcm.h @@ -1,125 +1,126 @@ /* * Copyright (c) 2019 Kai Uwe Broulik * * 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 . */ #pragma once #include #include #include class QAction; class SourcesModel; class FilterProxyModel; namespace NotificationManager { class DoNotDisturbSettings; class NotificationSettings; class JobSettings; class BadgeSettings; class BehaviorSettings; } class KCMNotifications : public KQuickAddons::ManagedConfigModule { Q_OBJECT Q_PROPERTY(SourcesModel *sourcesModel READ sourcesModel CONSTANT) Q_PROPERTY(FilterProxyModel *filteredModel READ filteredModel 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) Q_PROPERTY(NotificationManager::BadgeSettings *badgeSettings READ badgeSettings CONSTANT) Q_PROPERTY(QKeySequence toggleDoNotDisturbShortcut READ toggleDoNotDisturbShortcut WRITE setToggleDoNotDisturbShortcut NOTIFY toggleDoNotDisturbShortcutChanged) // So it can show the respective settings module right away Q_PROPERTY(QString initialDesktopEntry READ initialDesktopEntry WRITE setInitialDesktopEntry NOTIFY initialDesktopEntryChanged) Q_PROPERTY(QString initialNotifyRcName READ initialNotifyRcName WRITE setInitialNotifyRcName NOTIFY initialNotifyRcNameChanged) Q_PROPERTY(QString initialEventId READ initialEventId WRITE setInitialEventId NOTIFY initialEventIdChanged) public: KCMNotifications(QObject *parent, const QVariantList &args); ~KCMNotifications() override; SourcesModel *sourcesModel() const; FilterProxyModel *filteredModel() const; NotificationManager::DoNotDisturbSettings *dndSettings() const; NotificationManager::NotificationSettings *notificationSettings() const; NotificationManager::JobSettings *jobSettings() const; NotificationManager::BadgeSettings *badgeSettings() const; QKeySequence toggleDoNotDisturbShortcut() const; void setToggleDoNotDisturbShortcut(const QKeySequence &shortcut); Q_SIGNAL void toggleDoNotDisturbShortcutChanged(); QString initialDesktopEntry() const; void setInitialDesktopEntry(const QString &desktopEntry); QString initialNotifyRcName() const; void setInitialNotifyRcName(const QString ¬ifyRcName); QString initialEventId() const; void setInitialEventId(const QString &eventId); Q_INVOKABLE void configureEvents(const QString ¬ifyRcName, const QString &eventId, QQuickItem *ctx = nullptr); Q_INVOKABLE NotificationManager::BehaviorSettings *behaviorSettings(const QModelIndex &index); public Q_SLOTS: void load() override; void save() override; void defaults() override; signals: void initialDesktopEntryChanged(); void initialNotifyRcNameChanged(); void initialEventIdChanged(); + void firstLoadDone(); private: void processPendingDeletions(); bool isSaveNeeded() const override; bool isDefaults() const override; void createConnections(NotificationManager::BehaviorSettings *settings); SourcesModel *m_sourcesModel; FilterProxyModel *m_filteredModel; NotificationManager::DoNotDisturbSettings *m_dndSettings; NotificationManager::NotificationSettings *m_notificationSettings; NotificationManager::JobSettings *m_jobSettings; NotificationManager::BadgeSettings *m_badgeSettings; QHash 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; }; diff --git a/kcms/notifications/package/contents/ui/main.qml b/kcms/notifications/package/contents/ui/main.qml index 3f0f3a0c2..9b49d3bbd 100644 --- a/kcms/notifications/package/contents/ui/main.qml +++ b/kcms/notifications/package/contents/ui/main.qml @@ -1,275 +1,277 @@ /* * Copyright 2019 Kai Uwe Broulik * * 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 . */ import QtQuick 2.9 import QtQuick.Layouts 1.1 import QtQuick.Controls 2.3 as QtControls import org.kde.kirigami 2.4 as Kirigami import org.kde.kquickcontrols 2.0 as KQuickControls import org.kde.kcm 1.2 as KCM import org.kde.notificationmanager 1.0 as NotificationManager KCM.SimpleKCM { id: root KCM.ConfigModule.quickHelp: i18n("This module lets you manage application and system notifications.") // Sidebar on SourcesPage is 1/3 of the width at a minimum of 12, so assume 3 * 12 = 36 as preferred implicitWidth: Kirigami.Units.gridUnit * 36 readonly property string ourServerVendor: "KDE" readonly property string ourServerName: "Plasma" readonly property NotificationManager.ServerInfo currentOwnerInfo: NotificationManager.Server.currentOwner readonly property bool notificationsAvailable: currentOwnerInfo.status === NotificationManager.ServerInfo.Running && currentOwnerInfo.vendor === ourServerVendor && currentOwnerInfo.name === ourServerName function openSourcesSettings() { // TODO would be nice to re-use the current SourcesPage instead of pushing a new one that lost all state // but there's no pageAt(index) method in KConfigModuleQml kcm.push("SourcesPage.qml"); } Kirigami.FormLayout { Kirigami.InlineMessage { Kirigami.FormData.isSection: true Layout.fillWidth: true type: Kirigami.MessageType.Error text: i18n("Could not find a 'Notifications' widget which is required for displaying notifications."); visible: currentOwnerInfo.status === NotificationManager.ServerInfo.NotRunning } Kirigami.InlineMessage { Kirigami.FormData.isSection: true Layout.fillWidth: true type: Kirigami.MessageType.Information text: { if (currentOwnerInfo.vendor && currentOwnerInfo.name) { return i18nc("Vendor and product name", "Notifications are currently provided by '%1 %2' instead of Plasma.", currentOwnerInfo.vendor, currentOwnerInfo.name); } return i18n("Notifications are currently not provided by Plasma."); } visible: root.currentOwnerInfo.status === NotificationManager.ServerInfo.Running && (currentOwnerInfo.vendor !== root.ourServerVendor || currentOwnerInfo.name !== root.ourServerName) } QtControls.CheckBox { Kirigami.FormData.label: i18n("Do Not Disturb mode:") text: i18nc("Do not disturb when screens are mirrored", "Enable when screens are mirrored") checked: kcm.dndSettings.whenScreensMirrored onClicked: kcm.dndSettings.whenScreensMirrored = checked enabled: root.notificationsAvailable && !kcm.dndSettings.isImmutable("WhenScreensMirrored") } QtControls.CheckBox { text: i18n("Show critical notifications") checked: kcm.notificationSettings.criticalInDndMode onClicked: kcm.notificationSettings.criticalInDndMode = checked enabled: root.notificationsAvailable && !kcm.notificationSettings.isImmutable("CriticalInDndMode") } RowLayout { enabled: root.notificationsAvailable QtControls.Label { text: i18nc("Turn do not disturb mode on/off with keyboard shortcut", "Toggle with:") } KQuickControls.KeySequenceItem { keySequence: kcm.toggleDoNotDisturbShortcut onKeySequenceChanged: kcm.toggleDoNotDisturbShortcut = keySequence } } Kirigami.Separator { Kirigami.FormData.isSection: true } QtControls.CheckBox { Kirigami.FormData.label: i18n("Critical notifications:") text: i18n("Always keep on top") checked: kcm.notificationSettings.criticalAlwaysOnTop onClicked: kcm.notificationSettings.criticalAlwaysOnTop = checked enabled: root.notificationsAvailable && !kcm.notificationSettings.isImmutable("CriticalAlwaysOnTop") } Item { Kirigami.FormData.isSection: true } QtControls.CheckBox { Kirigami.FormData.label: i18n("Low priority notifications:") text: i18n("Show popup") checked: kcm.notificationSettings.lowPriorityPopups onClicked: kcm.notificationSettings.lowPriorityPopups = checked enabled: root.notificationsAvailable && !kcm.notificationSettings.isImmutable("LowPriorityPopups") } QtControls.CheckBox { text: i18n("Show in history") checked: kcm.notificationSettings.lowPriorityHistory onClicked: kcm.notificationSettings.lowPriorityHistory = checked enabled: root.notificationsAvailable && !kcm.notificationSettings.isImmutable("LowPriorityHistory") } QtControls.ButtonGroup { id: positionGroup buttons: [positionCloseToWidget, positionCustomPosition] } Kirigami.Separator { Kirigami.FormData.isSection: true } QtControls.RadioButton { id: positionCloseToWidget Kirigami.FormData.label: i18n("Popup:") text: i18nc("Popup position near notification plasmoid", "Show near notification icon") // "widget" checked: kcm.notificationSettings.popupPosition === NotificationManager.Settings.CloseToWidget // Force binding re-evaluation when user returns from position selector + kcm.currentIndex * 0 onClicked: kcm.notificationSettings.popupPosition = NotificationManager.Settings.CloseToWidget enabled: root.notificationsAvailable && !kcm.notificationSettings.isImmutable("PopupPosition") } RowLayout { spacing: 0 enabled: root.notificationsAvailable && !kcm.notificationSettings.isImmutable("PopupPosition") QtControls.RadioButton { id: positionCustomPosition checked: kcm.notificationSettings.popupPosition !== NotificationManager.Settings.CloseToWidget + kcm.currentIndex * 0 activeFocusOnTab: false MouseArea { anchors.fill: parent onClicked: positionCustomButton.clicked() } } QtControls.Button { id: positionCustomButton text: i18n("Choose Custom Position...") icon.name: "preferences-desktop-display" onClicked: kcm.push("PopupPositionPage.qml") } } TextMetrics { id: timeoutSpinnerMetrics font: timeoutSpinner.font text: i18np("%1 second", "%1 seconds", 888) } Item { Kirigami.FormData.isSection: true } RowLayout { QtControls.Label { text: i18nc("Part of a sentence like, 'Hide popup after n seconds'", "Hide after:") } QtControls.SpinBox { id: timeoutSpinner Layout.preferredWidth: timeoutSpinnerMetrics.width + leftPadding + rightPadding from: 1000 // 1 second to: 120000 // 2 minutes stepSize: 1000 value: kcm.notificationSettings.popupTimeout enabled: root.notificationsAvailable && !kcm.notificationSettings.isImmutable("PopupTimeout") editable: true valueFromText: function(text, locale) { return parseInt(text) * 1000; } textFromValue: function(value, locale) { return i18np("%1 second", "%1 seconds", Math.round(value / 1000)); } onValueModified: kcm.notificationSettings.popupTimeout = value } } Kirigami.Separator { Kirigami.FormData.isSection: true } QtControls.CheckBox { Kirigami.FormData.label: i18n("Application progress:") text: i18n("Show in task manager") checked: kcm.jobSettings.inTaskManager onClicked: kcm.jobSettings.inTaskManager = checked enabled: !kcm.jobSettings.isImmutable("InTaskManager") } QtControls.CheckBox { id: applicationJobsEnabledCheck text: i18nc("Show application jobs in notification widget", "Show in notifications") checked: kcm.jobSettings.inNotifications onClicked: kcm.jobSettings.inNotifications = checked enabled: !kcm.jobSettings.isImmutable("InNotifications") } RowLayout { // just for indentation QtControls.CheckBox { Layout.leftMargin: mirrored ? 0 : indicator.width Layout.rightMargin: mirrored ? indicator.width : 0 text: i18nc("Keep application job popup open for entire duration of job", "Keep popup open during progress") enabled: applicationJobsEnabledCheck.checked && !kcm.jobSettings.isImmutable("PermanentPopups") checked: kcm.jobSettings.permanentPopups onClicked: kcm.jobSettings.permanentPopups = checked } } Item { Kirigami.FormData.isSection: true } QtControls.CheckBox { Kirigami.FormData.label: i18n("Notification badges:") text: i18n("Show in task manager") checked: kcm.badgeSettings.inTaskManager onClicked: kcm.badgeSettings.inTaskManager = checked enabled: !kcm.badgeSettings.isImmutable("InTaskManager") } Kirigami.Separator { Kirigami.FormData.isSection: true } QtControls.Button { Kirigami.FormData.label: i18n("Applications:") text: i18n("Configure...") icon.name: "configure" enabled: root.notificationsAvailable onClicked: root.openSourcesSettings() } - } - Component.onCompleted: { - if (kcm.initialDesktopEntry || kcm.initialNotifyRcName) { - // FIXME doing that right in onCompleted doesn't work - Qt.callLater(root.openSourcesSettings); + Connections { + target: kcm + onFirstLoadDone: { + if (kcm.initialDesktopEntry || kcm.initialNotifyRcName) { + root.openSourcesSettings(); + } + } } } }