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 &notification) {
0034         onNotificationAdded(notification);
0035     });
0036     connect(&Server::self(), &Server::notificationReplaced, this, [this](uint replacedId, const Notification &notification) {
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 &notification : 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 &notification = 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 &notification = 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 &notification = 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 &notification = 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 &notifyRcName, 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 }