1 /*
2     SPDX-FileCopyrightText: 2020 Shah Bhushan <bshah@kde.org>
3 
4     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 
7 #include "watchednotificationsmodel.h"
8 
9 #include <QDBusConnection>
10 #include <QDBusConnectionInterface>
11 #include <QDBusMetaType>
12 #include <QDBusServiceWatcher>
13 
14 #include <QDebug>
15 
16 #include "fdonotifications_interface.h"
17 
18 using namespace NotificationManager;
19 
20 class WatchedNotificationsModel::Private : public QObject
21 {
22     Q_OBJECT
23 public:
24     explicit Private(WatchedNotificationsModel *q, QObject *parent = nullptr);
25     ~Private();
26     bool valid = false;
27 
28 public Q_SLOTS:
29     Q_SCRIPTABLE void Notify(uint id,
30                              const QString &app_name,
31                              uint replaces_id,
32                              const QString &app_icon,
33                              const QString &summary,
34                              const QString &body,
35                              const QStringList &actions,
36                              const QVariantMap &hints,
37                              int timeout);
38     Q_SCRIPTABLE void CloseNotification(uint id);
39     void NotificationClosed(uint id, uint reason);
40 
41 private:
42     WatchedNotificationsModel *q;
43     OrgFreedesktopNotificationsInterface *fdoNotificationsInterface;
44 };
45 
Private(WatchedNotificationsModel * q,QObject * parent)46 WatchedNotificationsModel::Private::Private(WatchedNotificationsModel *q, QObject *parent)
47     : QObject(parent)
48     , q(q)
49 {
50     QDBusConnection dbus = QDBusConnection::sessionBus();
51     fdoNotificationsInterface =
52         new OrgFreedesktopNotificationsInterface(QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("/org/freedesktop/Notifications"), dbus, this);
53     connect(fdoNotificationsInterface,
54             &OrgFreedesktopNotificationsInterface::NotificationClosed,
55             this,
56             &WatchedNotificationsModel::Private::NotificationClosed);
57     dbus.registerObject("/NotificationWatcher", QStringLiteral("org.kde.NotificationWatcher"), this, QDBusConnection::ExportScriptableSlots);
58     QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.Notifications"),
59                                                       QStringLiteral("/org/freedesktop/Notifications"),
60                                                       QStringLiteral("org.kde.NotificationManager"),
61                                                       QStringLiteral("RegisterWatcher"));
62     QDBusMessage reply = QDBusConnection::sessionBus().call(msg, QDBus::NoBlock);
63     if (reply.type() != QDBusMessage::ErrorMessage) {
64         valid = true;
65         Q_EMIT q->validChanged(valid);
66     }
67 }
68 
~Private()69 WatchedNotificationsModel::Private::~Private()
70 {
71     QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.Notifications"),
72                                                       QStringLiteral("/org/freedesktop/Notifications"),
73                                                       QStringLiteral("org.kde.NotificationManager"),
74                                                       QStringLiteral("UnRegisterWatcher"));
75     QDBusConnection::sessionBus().call(msg, QDBus::NoBlock);
76 }
77 
Notify(uint id,const QString & app_name,uint replaces_id,const QString & app_icon,const QString & summary,const QString & body,const QStringList & actions,const QVariantMap & hints,int timeout)78 void WatchedNotificationsModel::Private::Notify(uint id,
79                                                 const QString &app_name,
80                                                 uint replaces_id,
81                                                 const QString &app_icon,
82                                                 const QString &summary,
83                                                 const QString &body,
84                                                 const QStringList &actions,
85                                                 const QVariantMap &hints,
86                                                 int timeout)
87 {
88     const bool wasReplaced = replaces_id > 0;
89 
90     Notification notification(id);
91     notification.setSummary(summary);
92     notification.setBody(body);
93     notification.setApplicationName(app_name);
94 
95     notification.setActions(actions);
96     notification.setTimeout(timeout);
97     notification.setHints(hints);
98     notification.setIcon(app_icon);
99     notification.processHints(hints);
100 
101     if (wasReplaced) {
102         q->onNotificationReplaced(replaces_id, notification);
103     } else {
104         q->onNotificationAdded(notification);
105     }
106 }
107 
CloseNotification(uint id)108 void WatchedNotificationsModel::Private::CloseNotification(uint id)
109 {
110     q->onNotificationRemoved(id, Server::CloseReason::Expired);
111 }
112 
NotificationClosed(uint id,uint reason)113 void WatchedNotificationsModel::Private::NotificationClosed(uint id, uint reason)
114 {
115     q->onNotificationRemoved(id, static_cast<Server::CloseReason>(reason));
116 }
117 
WatchedNotificationsModel()118 WatchedNotificationsModel::WatchedNotificationsModel()
119     : AbstractNotificationsModel()
120     , d(new Private(this, nullptr))
121 {
122 }
123 
~WatchedNotificationsModel()124 WatchedNotificationsModel::~WatchedNotificationsModel()
125 {
126 }
127 
close(uint notificationId)128 void WatchedNotificationsModel::close(uint notificationId)
129 {
130     onNotificationRemoved(notificationId, Server::CloseReason::DismissedByUser);
131 }
132 
expire(uint notificationId)133 void WatchedNotificationsModel::expire(uint notificationId)
134 {
135     onNotificationRemoved(notificationId, Server::CloseReason::Expired);
136 }
137 
invokeDefaultAction(uint notificationId)138 void WatchedNotificationsModel::invokeDefaultAction(uint notificationId)
139 {
140     this->invokeAction(notificationId, QStringLiteral("default"));
141 }
142 
invokeAction(uint notificationId,const QString & actionName)143 void WatchedNotificationsModel::invokeAction(uint notificationId, const QString &actionName)
144 {
145     QDBusConnection dbus = QDBusConnection::sessionBus();
146     dbus.registerObject("/NotificationWatcher", this, QDBusConnection::ExportScriptableSlots);
147     QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.Notifications"),
148                                                       QStringLiteral("/org/freedesktop/Notifications"),
149                                                       QStringLiteral("org.kde.NotificationManager"),
150                                                       QStringLiteral("InvokeAction"));
151     msg.setArguments({notificationId, actionName});
152     QDBusConnection::sessionBus().call(msg, QDBus::NoBlock);
153 }
154 
reply(uint notificationId,const QString & text)155 void WatchedNotificationsModel::reply(uint notificationId, const QString &text)
156 {
157     // todo
158     Q_UNUSED(notificationId)
159     Q_UNUSED(text)
160 }
161 
valid()162 bool WatchedNotificationsModel::valid()
163 {
164     return d->valid;
165 }
166 
167 #include "watchednotificationsmodel.moc"
168