File indexing completed on 2024-04-28 16:54:37
0001 /* 0002 SPDX-FileCopyrightText: 2020 Shah Bhushan <bshah@kde.org> 0003 SPDX-FileCopyrightText: 2018-2019 Kai Uwe Broulik <kde@privat.broulik.de> 0004 0005 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "notificationsmodel.h" 0009 #include "notification_p.h" 0010 #include "server.h" 0011 0012 #include "debug.h" 0013 0014 #include <QProcess> 0015 0016 #include <KShell> 0017 0018 using namespace NotificationManager; 0019 0020 NotificationsModel::Ptr NotificationsModel::createNotificationsModel() 0021 { 0022 static QWeakPointer<NotificationsModel> s_instance; 0023 if (!s_instance) { 0024 QSharedPointer<NotificationsModel> ptr(new NotificationsModel()); 0025 s_instance = ptr.toWeakRef(); 0026 return ptr; 0027 } 0028 return s_instance.toStrongRef(); 0029 } 0030 0031 NotificationsModel::NotificationsModel() 0032 { 0033 connect(&Server::self(), &Server::notificationAdded, this, [this](const Notification ¬ification) { 0034 onNotificationAdded(notification); 0035 }); 0036 connect(&Server::self(), &Server::notificationReplaced, this, [this](uint replacedId, const Notification ¬ification) { 0037 onNotificationReplaced(replacedId, notification); 0038 }); 0039 connect(&Server::self(), &Server::notificationRemoved, this, [this](uint removedId, Server::CloseReason reason) { 0040 onNotificationRemoved(removedId, reason); 0041 }); 0042 connect(&Server::self(), &Server::serviceOwnershipLost, this, [this] { 0043 // Expire all notifications as we're defunct now 0044 const auto notificationList = notifications(); 0045 for (const Notification ¬ification : notificationList) { 0046 if (!notification.expired()) { 0047 onNotificationRemoved(notification.id(), Server::CloseReason::Expired); 0048 } 0049 } 0050 }); 0051 Server::self().init(); 0052 } 0053 0054 void NotificationsModel::expire(uint notificationId) 0055 { 0056 if (rowOfNotification(notificationId) > -1) { 0057 Server::self().closeNotification(notificationId, Server::CloseReason::Expired); 0058 } 0059 } 0060 0061 void NotificationsModel::close(uint notificationId) 0062 { 0063 if (rowOfNotification(notificationId) > -1) { 0064 Server::self().closeNotification(notificationId, Server::CloseReason::DismissedByUser); 0065 } 0066 } 0067 0068 void NotificationsModel::invokeDefaultAction(uint notificationId, Notifications::InvokeBehavior behavior) 0069 { 0070 const int row = rowOfNotification(notificationId); 0071 if (row == -1) { 0072 return; 0073 } 0074 0075 const Notification ¬ification = notifications().at(row); 0076 if (!notification.hasDefaultAction()) { 0077 qCWarning(NOTIFICATIONMANAGER) << "Trying to invoke default action on notification" << notificationId << "which doesn't have one"; 0078 return; 0079 } 0080 0081 Server::self().invokeAction(notificationId, 0082 QStringLiteral("default"), // FIXME make a static Notification::defaultActionName() or something 0083 notification.d->xdgTokenAppId, 0084 behavior, 0085 window()); 0086 } 0087 0088 void NotificationsModel::invokeAction(uint notificationId, const QString &actionName, Notifications::InvokeBehavior behavior) 0089 { 0090 const int row = rowOfNotification(notificationId); 0091 if (row == -1) { 0092 return; 0093 } 0094 0095 const Notification ¬ification = notifications().at(row); 0096 if (!notification.actionNames().contains(actionName)) { 0097 qCWarning(NOTIFICATIONMANAGER) << "Trying to invoke action" << actionName << "on notification" << notificationId << "which it doesn't have"; 0098 return; 0099 } 0100 0101 Server::self().invokeAction(notificationId, actionName, notification.d->xdgTokenAppId, behavior, window()); 0102 } 0103 0104 void NotificationsModel::reply(uint notificationId, const QString &text, Notifications::InvokeBehavior behavior) 0105 { 0106 const int row = rowOfNotification(notificationId); 0107 if (row == -1) { 0108 return; 0109 } 0110 0111 const Notification ¬ification = notifications().at(row); 0112 if (!notification.hasReplyAction()) { 0113 qCWarning(NOTIFICATIONMANAGER) << "Trying to reply to a notification which doesn't have a reply action"; 0114 return; 0115 } 0116 0117 Server::self().reply(notification.dBusService(), notificationId, text, behavior); 0118 } 0119 0120 void NotificationsModel::configure(uint notificationId) 0121 { 0122 const int row = rowOfNotification(notificationId); 0123 if (row == -1) { 0124 return; 0125 } 0126 0127 const Notification ¬ification = notifications().at(row); 0128 0129 if (notification.d->hasConfigureAction) { 0130 Server::self().invokeAction(notificationId, 0131 QStringLiteral("settings"), 0132 notification.d->xdgTokenAppId, 0133 Notifications::None, // FIXME make a static Notification::configureActionName() or something 0134 window()); 0135 return; 0136 } 0137 0138 if (!notification.desktopEntry().isEmpty() || !notification.notifyRcName().isEmpty()) { 0139 configure(notification.desktopEntry(), notification.notifyRcName(), notification.eventId()); 0140 return; 0141 } 0142 0143 qCWarning(NOTIFICATIONMANAGER) << "Trying to configure notification" << notificationId << "which isn't configurable"; 0144 } 0145 0146 void NotificationsModel::configure(const QString &desktopEntry, const QString ¬ifyRcName, const QString &eventId) 0147 { 0148 // TODO would be nice to just have a signal but since NotificationsModel is shared, 0149 // if we connect to this from Notifications you would get a signal in every instance 0150 // and potentially open the config dialog multiple times. 0151 0152 QStringList args; 0153 if (!desktopEntry.isEmpty()) { 0154 args.append(QStringLiteral("--desktop-entry")); 0155 args.append(desktopEntry); 0156 } 0157 if (!notifyRcName.isEmpty()) { 0158 args.append(QStringLiteral("--notifyrc")); 0159 args.append(notifyRcName); 0160 } 0161 if (!eventId.isEmpty()) { 0162 args.append(QStringLiteral("--event-id")); 0163 args.append(eventId); 0164 } 0165 0166 QProcess::startDetached(QStringLiteral("kcmshell5"), {QStringLiteral("notifications"), QStringLiteral("--args"), KShell::joinArgs(args)}); 0167 }