better handling of log messages (internal stuff only)
[quassel.git] / src / qtui / desktopnotificationbackend.cpp
1 /***************************************************************************
2 *   Copyright (C) 2005-08 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) : AbstractNotificationBackend(parent) {
30   _configWidget = new ConfigWidget();
31
32   _dbusInterface = new org::freedesktop::Notifications(
33     "org.freedesktop.Notifications",
34     "/org/freedesktop/Notifications",
35     QDBusConnection::sessionBus(), this);
36
37   QStringList desktopCapabilities = _dbusInterface->GetCapabilities();
38   _daemonSupportsMarkup = desktopCapabilities.contains("body-markup");
39
40   _lastDbusId = 0;
41   connect(_dbusInterface, SIGNAL(NotificationClosed(uint, uint)), SLOT(desktopNotificationClosed(uint, uint)));
42   connect(_dbusInterface, SIGNAL(ActionInvoked(uint, const QString &)), SLOT(desktopNotificationInvoked(uint, const QString&)));
43
44   NotificationSettings notificationSettings;
45   _enabled = notificationSettings.value("DesktopNotification/Enabled", false).toBool();
46   _useHints = notificationSettings.value("DesktopNotification/UseHints", false).toBool();
47   _xHint = notificationSettings.value("DesktopNotification/XHint", 0).toInt();
48   _yHint = notificationSettings.value("DesktopNotification/YHint", 0).toInt();
49   _queueNotifications = notificationSettings.value("DesktopNotification/QueueNotifications", true).toBool();
50   _timeout = notificationSettings.value("DesktopNotification/Timeout", 10000).toInt();
51   _useTimeout = notificationSettings.value("DesktopNotification/UseTimeout", true).toBool();
52
53   notificationSettings.notify("DesktopNotification/Enabled", this, SLOT(enabledChanged(const QVariant &)));
54   notificationSettings.notify("DesktopNotification/UseHints", this, SLOT(useHintsChanged(const QVariant &)));
55   notificationSettings.notify("DesktopNotification/XHint", this, SLOT(xHintChanged(const QVariant &)));
56   notificationSettings.notify("DesktopNotification/YHint", this, SLOT(yHintChanged(const QVariant &)));
57   notificationSettings.notify("DesktopNotification/Timeout", this, SLOT(timeoutChanged(const QVariant &)));
58   notificationSettings.notify("DesktopNotification/UseTimeout", this, SLOT(useTimeoutChanged(const QVariant &)));
59   notificationSettings.notify("DesktopNotification/QueueNotifications", this, SLOT(queueNotificationsChanged(const QVariant &)));
60 }
61
62 DesktopNotificationBackend::~DesktopNotificationBackend() {
63   delete _configWidget;
64 }
65
66 void DesktopNotificationBackend::enabledChanged(const QVariant &v) {
67   _enabled = v.toBool();
68 }
69
70 void DesktopNotificationBackend::useHintsChanged(const QVariant &v) {
71   _useHints = v.toBool();
72 }
73
74 void DesktopNotificationBackend::xHintChanged(const QVariant &v) {
75   _xHint = v.toInt();
76 }
77
78 void DesktopNotificationBackend::yHintChanged(const QVariant &v) {
79   _yHint = v.toInt();
80 }
81
82 void DesktopNotificationBackend::queueNotificationsChanged(const QVariant &v) {
83   _queueNotifications = v.toBool();
84 }
85
86 void DesktopNotificationBackend::timeoutChanged(const QVariant &v) {
87   _timeout = v.toInt();
88 }
89
90 void DesktopNotificationBackend::useTimeoutChanged(const QVariant &v) {
91   _useTimeout = v.toBool();
92 }
93
94 void DesktopNotificationBackend::notify(const Notification &n) {
95   if(_enabled) {
96     QStringList actions;
97     QMap<QString, QVariant> hints;
98
99     if(_useHints) {
100       hints["x"] = _xHint; // Standard hint: x location for the popup to show up
101       hints["y"] = _yHint; // Standard hint: y location for the popup to show up
102     }
103
104     uint oldId = _queueNotifications ? 0 : _lastDbusId;
105
106     // actions << "click" << "Click Me!";
107
108     QString title = Client::networkModel()->networkName(n.bufferId) + " - " + Client::networkModel()->bufferName(n.bufferId);
109     QString message = QString("<%1> %2").arg(n.sender, n.message);
110
111     if(_daemonSupportsMarkup)
112       message = Qt::escape(message);
113
114     QDBusReply<uint> reply = _dbusInterface->Notify(
115       "Quassel IRC", // Application name
116       oldId, // ID of previous notification to replace
117       "quassel", // Icon to display
118       title, // Summary / Header of the message to display
119       message, // Body of the message to display
120       actions, // Actions from which the user may choose
121       hints, // Hints to the server displaying the message
122       _useTimeout? _timeout : 0 // Timeout in milliseconds
123     );
124
125     if(!reply.isValid()) {
126       /* ERROR */
127       // could also happen if no notification service runs, so... whatever :)
128       // qDebug() << "Error on sending notification..." << reply.error();
129       return;
130     }
131     uint dbusid = reply.value();
132     _idMap.insert(n.notificationId, dbusid);
133     _lastDbusId = dbusid;
134   }
135 }
136
137 void DesktopNotificationBackend::close(uint notificationId) {
138   uint dbusId = _idMap.value(notificationId, 0);
139   if(dbusId) {
140     _idMap.remove(notificationId);
141     _dbusInterface->CloseNotification(dbusId);
142   }
143   _lastDbusId = 0;
144 }
145
146 void DesktopNotificationBackend::desktopNotificationClosed(uint id, uint reason) {
147   Q_UNUSED(reason);
148   _idMap.remove(_idMap.key(id));
149   _lastDbusId = 0;
150 }
151
152
153 void DesktopNotificationBackend::desktopNotificationInvoked(uint id, const QString & action) {
154   Q_UNUSED(id); Q_UNUSED(action);
155 }
156
157 SettingsPage *DesktopNotificationBackend::configWidget() const {
158   return _configWidget;
159 }
160
161 /***************************************************************************/
162
163 DesktopNotificationBackend::ConfigWidget::ConfigWidget(QWidget *parent) : SettingsPage("Internal", "DesktopNotification", parent) {
164   ui.setupUi(this);
165
166   connect(ui.enabled, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
167   connect(ui.useHints, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
168   connect(ui.xHint, SIGNAL(valueChanged(int)), SLOT(widgetChanged()));
169   connect(ui.yHint, SIGNAL(valueChanged(int)), SLOT(widgetChanged()));
170   connect(ui.queueNotifications, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
171   connect(ui.useTimeout, SIGNAL(toggled(bool)), SLOT(widgetChanged()));
172   connect(ui.timeout, SIGNAL(valueChanged(int)), SLOT(widgetChanged()));
173 }
174
175 void DesktopNotificationBackend::ConfigWidget::widgetChanged() {
176   bool changed =
177        enabled != ui.enabled->isChecked()
178     || useHints != ui.useHints->isChecked()
179     || xHint != ui.xHint->value()
180     || yHint != ui.yHint->value()
181     || queueNotifications != ui.queueNotifications->isChecked()
182     || timeout/1000 != ui.timeout->value()
183     || useTimeout != ui.useTimeout->isChecked();
184   if(changed != hasChanged()) setChangedState(changed);
185 }
186
187 bool DesktopNotificationBackend::ConfigWidget::hasDefaults() const {
188   return true;
189 }
190
191 void DesktopNotificationBackend::ConfigWidget::defaults() {
192   ui.enabled->setChecked(false);
193   ui.useTimeout->setChecked(true);
194   ui.timeout->setValue(10);
195   ui.useHints->setChecked(false);
196   ui.xHint->setValue(0);
197   ui.yHint->setValue(0);
198   ui.queueNotifications->setChecked(true);
199   widgetChanged();
200 }
201
202 void DesktopNotificationBackend::ConfigWidget::load() {
203   NotificationSettings s;
204   enabled = s.value("DesktopNotification/Enabled", false).toBool();
205   useTimeout = s.value("DesktopNotification/UseTimeout", true).toBool();
206   timeout = s.value("DesktopNotification/Timeout", 10000).toInt();
207   useHints = s.value("DesktopNotification/UseHints", false).toBool();
208   xHint = s.value("DesktopNotification/XHint", 0).toInt();
209   yHint = s.value("DesktopNotification/YHint", 0).toInt();
210   queueNotifications = s.value("DesktopNotification/QueueNotifications", true).toBool();
211
212   ui.enabled->setChecked(enabled);
213   ui.useTimeout->setChecked(useTimeout);
214   ui.timeout->setValue(timeout/1000);
215   ui.useHints->setChecked(useHints);
216   ui.xHint->setValue(xHint);
217   ui.yHint->setValue(yHint);
218   ui.queueNotifications->setChecked(queueNotifications);
219
220   setChangedState(false);
221 }
222
223 void DesktopNotificationBackend::ConfigWidget::save() {
224   NotificationSettings s;
225   s.setValue("DesktopNotification/Enabled", ui.enabled->isChecked());
226   s.setValue("DesktopNotification/UseTimeout", ui.useTimeout->isChecked());
227   s.setValue("DesktopNotification/Timeout", ui.timeout->value() * 1000);
228   s.setValue("DesktopNotification/UseHints", ui.useHints->isChecked());
229   s.setValue("DesktopNotification/XHint", ui.xHint->value());
230   s.setValue("DesktopNotification/YHint", ui.yHint->value());
231   s.setValue("DesktopNotification/QueueNotifications", ui.queueNotifications->isChecked());
232
233   load();
234 }