fixed focus when switching to plain topic view
[quassel.git] / src / qtui / desktopnotificationbackend.cpp
1 /***************************************************************************
2 *   Copyright (C) 2005-09 by the Quassel Project                          *
3 *   devel@quassel-irc.org                                                 *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) version 3.                                           *
9 *                                                                         *
10 *   This program is distributed in the hope that it will be useful,       *
11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13 *   GNU General Public License for more details.                          *
14 *                                                                         *
15 *   You should have received a copy of the GNU General Public License     *
16 *   along with this program; if not, write to the                         *
17 *   Free Software Foundation, Inc.,                                       *
18 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19 ***************************************************************************/
20
21 #include "desktopnotificationbackend.h"
22
23 #include <QTextDocument>
24
25 #include "client.h"
26 #include "clientsettings.h"
27 #include "networkmodel.h"
28
29 DesktopNotificationBackend::DesktopNotificationBackend(QObject *parent)
30   : AbstractNotificationBackend(parent),
31   _lastDbusId(0)
32 {
33   _dbusInterface = new org::freedesktop::Notifications(
34     "org.freedesktop.Notifications",
35     "/org/freedesktop/Notifications",
36     QDBusConnection::sessionBus(), this);
37
38   if(!_dbusInterface->isValid()) {
39     qWarning() << "DBus notification service not available!";
40     return;
41   }
42
43   QStringList desktopCapabilities = _dbusInterface->GetCapabilities();
44   _daemonSupportsMarkup = desktopCapabilities.contains("body-markup");
45
46   connect(_dbusInterface, SIGNAL(NotificationClosed(uint, uint)), SLOT(desktopNotificationClosed(uint, uint)));
47   connect(_dbusInterface, SIGNAL(ActionInvoked(uint, const QString &)), SLOT(desktopNotificationInvoked(uint, const QString&)));
48
49   NotificationSettings notificationSettings;
50   _enabled = notificationSettings.value("DesktopNotification/Enabled", false).toBool();
51   _useHints = notificationSettings.value("DesktopNotification/UseHints", false).toBool();
52   _xHint = notificationSettings.value("DesktopNotification/XHint", 0).toInt();
53   _yHint = notificationSettings.value("DesktopNotification/YHint", 0).toInt();
54   _queueNotifications = notificationSettings.value("DesktopNotification/QueueNotifications", true).toBool();
55   _timeout = notificationSettings.value("DesktopNotification/Timeout", 10000).toInt();
56   _useTimeout = notificationSettings.value("DesktopNotification/UseTimeout", true).toBool();
57
58   notificationSettings.notify("DesktopNotification/Enabled", this, SLOT(enabledChanged(const QVariant &)));
59   notificationSettings.notify("DesktopNotification/UseHints", this, SLOT(useHintsChanged(const QVariant &)));
60   notificationSettings.notify("DesktopNotification/XHint", this, SLOT(xHintChanged(const QVariant &)));
61   notificationSettings.notify("DesktopNotification/YHint", this, SLOT(yHintChanged(const QVariant &)));
62   notificationSettings.notify("DesktopNotification/Timeout", this, SLOT(timeoutChanged(const QVariant &)));
63   notificationSettings.notify("DesktopNotification/UseTimeout", this, SLOT(useTimeoutChanged(const QVariant &)));
64   notificationSettings.notify("DesktopNotification/QueueNotifications", this, SLOT(queueNotificationsChanged(const QVariant &)));
65 }
66
67 void DesktopNotificationBackend::enabledChanged(const QVariant &v) {
68   _enabled = v.toBool();
69 }
70
71 void DesktopNotificationBackend::useHintsChanged(const QVariant &v) {
72   _useHints = v.toBool();
73 }
74
75 void DesktopNotificationBackend::xHintChanged(const QVariant &v) {
76   _xHint = v.toInt();
77 }
78
79 void DesktopNotificationBackend::yHintChanged(const QVariant &v) {
80   _yHint = v.toInt();
81 }
82
83 void DesktopNotificationBackend::queueNotificationsChanged(const QVariant &v) {
84   _queueNotifications = v.toBool();
85 }
86
87 void DesktopNotificationBackend::timeoutChanged(const QVariant &v) {
88   _timeout = v.toInt();
89 }
90
91 void DesktopNotificationBackend::useTimeoutChanged(const QVariant &v) {
92   _useTimeout = v.toBool();
93 }
94
95 void DesktopNotificationBackend::notify(const Notification &n) {
96   if(_enabled && _dbusInterface->isValid() && (n.type == Highlight || n.type == PrivMsg)) {
97     QStringList actions;
98     QMap<QString, QVariant> hints;
99
100     if(_useHints) {
101       hints["x"] = _xHint; // Standard hint: x location for the popup to show up
102       hints["y"] = _yHint; // Standard hint: y location for the popup to show up
103     }
104
105     uint oldId = _queueNotifications ? 0 : _lastDbusId;
106
107     actions << "activate" << "View";
108
109     QString title = Client::networkModel()->networkName(n.bufferId) + " - " + Client::networkModel()->bufferName(n.bufferId);
110     QString message = QString("<%1> %2").arg(n.sender, n.message);
111
112     if(_daemonSupportsMarkup)
113       message = Qt::escape(message);
114
115     QDBusReply<uint> reply = _dbusInterface->Notify(
116       "Quassel IRC", // Application name
117       oldId, // ID of previous notification to replace
118       "quassel", // Icon to display
119       title, // Summary / Header of the message to display
120       message, // Body of the message to display
121       actions, // Actions from which the user may choose
122       hints, // Hints to the server displaying the message
123       _useTimeout? _timeout : 0 // Timeout in milliseconds
124     );
125
126     if(!reply.isValid()) {
127       /* ERROR */
128       // could also happen if no notification service runs, so... whatever :)
129       // qDebug() << "Error on sending notification..." << reply.error();
130       return;
131     }
132     uint dbusid = reply.value();
133     _idMap.insert(n.notificationId, dbusid);
134     _lastDbusId = dbusid;
135   }
136 }
137
138 void DesktopNotificationBackend::close(uint notificationId) {
139   uint dbusId = _idMap.value(notificationId, 0);
140   if(dbusId) {
141     _idMap.remove(notificationId);
142     _dbusInterface->CloseNotification(dbusId);
143   }
144   _lastDbusId = 0;
145 }
146
147 void DesktopNotificationBackend::desktopNotificationClosed(uint id, uint reason) {
148   Q_UNUSED(reason);
149   _idMap.remove(_idMap.key(id));
150   _lastDbusId = 0;
151 }
152
153
154 void DesktopNotificationBackend::desktopNotificationInvoked(uint id, const QString & action) {
155   Q_UNUSED(action);
156   foreach(uint ourid, _idMap.keys()) {
157     if(_idMap.value(ourid) != id)
158       continue;
159     emit activated(ourid);
160     return;
161   }
162
163   emit activated();
164 }
165
166 SettingsPage *DesktopNotificationBackend::createConfigWidget() const {
167   return new ConfigWidget();
168 }
169
170 /***************************************************************************/
171
172 DesktopNotificationBackend::ConfigWidget::ConfigWidget(QWidget *parent) : SettingsPage("Internal", "DesktopNotification", parent) {
173   ui.setupUi(this);
174
175   connect(ui.enabled, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
176   connect(ui.useHints, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
177   connect(ui.xHint, SIGNAL(valueChanged(int)), SLOT(widgetChanged()));
178   connect(ui.yHint, SIGNAL(valueChanged(int)), SLOT(widgetChanged()));
179   connect(ui.queueNotifications, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
180   connect(ui.useTimeout, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
181   connect(ui.timeout, SIGNAL(valueChanged(int)), SLOT(widgetChanged()));
182 }
183
184 void DesktopNotificationBackend::ConfigWidget::widgetChanged() {
185   bool changed =
186        enabled != ui.enabled->isChecked()
187     || useHints != ui.useHints->isChecked()
188     || xHint != ui.xHint->value()
189     || yHint != ui.yHint->value()
190     || queueNotifications != ui.queueNotifications->isChecked()
191     || timeout/1000 != ui.timeout->value()
192     || useTimeout != ui.useTimeout->isChecked();
193   if(changed != hasChanged()) setChangedState(changed);
194 }
195
196 bool DesktopNotificationBackend::ConfigWidget::hasDefaults() const {
197   return true;
198 }
199
200 void DesktopNotificationBackend::ConfigWidget::defaults() {
201   ui.enabled->setChecked(false);
202   ui.useTimeout->setChecked(true);
203   ui.timeout->setValue(10);
204   ui.useHints->setChecked(false);
205   ui.xHint->setValue(0);
206   ui.yHint->setValue(0);
207   ui.queueNotifications->setChecked(true);
208   widgetChanged();
209 }
210
211 void DesktopNotificationBackend::ConfigWidget::load() {
212   NotificationSettings s;
213   enabled = s.value("DesktopNotification/Enabled", false).toBool();
214   useTimeout = s.value("DesktopNotification/UseTimeout", true).toBool();
215   timeout = s.value("DesktopNotification/Timeout", 10000).toInt();
216   useHints = s.value("DesktopNotification/UseHints", false).toBool();
217   xHint = s.value("DesktopNotification/XHint", 0).toInt();
218   yHint = s.value("DesktopNotification/YHint", 0).toInt();
219   queueNotifications = s.value("DesktopNotification/QueueNotifications", true).toBool();
220
221   ui.enabled->setChecked(enabled);
222   ui.useTimeout->setChecked(useTimeout);
223   ui.timeout->setValue(timeout/1000);
224   ui.useHints->setChecked(useHints);
225   ui.xHint->setValue(xHint);
226   ui.yHint->setValue(yHint);
227   ui.queueNotifications->setChecked(queueNotifications);
228
229   setChangedState(false);
230 }
231
232 void DesktopNotificationBackend::ConfigWidget::save() {
233   NotificationSettings s;
234   s.setValue("DesktopNotification/Enabled", ui.enabled->isChecked());
235   s.setValue("DesktopNotification/UseTimeout", ui.useTimeout->isChecked());
236   s.setValue("DesktopNotification/Timeout", ui.timeout->value() * 1000);
237   s.setValue("DesktopNotification/UseHints", ui.useHints->isChecked());
238   s.setValue("DesktopNotification/XHint", ui.xHint->value());
239   s.setValue("DesktopNotification/YHint", ui.yHint->value());
240   s.setValue("DesktopNotification/QueueNotifications", ui.queueNotifications->isChecked());
241
242   load();
243 }