2a6ea9bffd2623d8dbb3443c8e1fea90819098bf
[quassel.git] / src / qtui / dockmanagernotificationbackend.cpp
1 /***************************************************************************
2  *   Copyright (C) 2013-2018 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  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include "dockmanagernotificationbackend.h"
22
23 #include <QHBoxLayout>
24 #include <QCheckBox>
25 #include <QDBusReply>
26
27 #include "client.h"
28 #include "clientsettings.h"
29 #include "coreconnection.h"
30 #include "clientbacklogmanager.h"
31 #include "util.h"
32
33 DockManagerNotificationBackend::DockManagerNotificationBackend(QObject *parent)
34     : AbstractNotificationBackend(parent), _bus(QDBusConnection::sessionBus())
35 {
36     NotificationSettings notificationSettings;
37     _enabled = notificationSettings.value("DockManager/Enabled", false).toBool();
38
39     notificationSettings.notify("DockManager/Enabled", this, SLOT(enabledChanged(const QVariant &)));
40
41     _dock = new QDBusInterface("net.launchpad.DockManager", "/net/launchpad/DockManager", "net.launchpad.DockManager", _bus, this);
42     if (_dock->isValid()) {
43         _bus.connect("net.launchpad.DockManager", "/net/launchpad/DockManager", "net.launchpad.DockManager", "ItemAdded", this, SLOT(itemAdded(QDBusObjectPath)));
44     } else {
45         // evil implementations (awn) use fd.o
46         _dock = new QDBusInterface("org.freedesktop.DockManager", "/org/freedesktop/DockManager", "org.freedesktop.DockManager", _bus, this);
47         if (_dock->isValid()) {
48             _bus.connect("org.freedesktop.DockManager", "/org/freedesktop/DockManager", "org.freedesktop.DockManager", "ItemAdded", this, SLOT(itemAdded(QDBusObjectPath)));
49         } else {
50             _available = _enabled = false;
51             return;
52         }
53     }
54     _available = true;
55
56     itemAdded(QDBusObjectPath());
57
58     connect(Client::coreConnection(), &CoreConnection::progressValueChanged, this, selectOverload<int>(&DockManagerNotificationBackend::updateProgress));
59     connect(Client::coreConnection(), &CoreConnection::synchronized, this, &DockManagerNotificationBackend::synchronized);
60 }
61
62
63 void DockManagerNotificationBackend::itemAdded(QDBusObjectPath p)
64 {
65     Q_UNUSED(p);
66
67     if (_item)
68         return;
69
70     // stupid implementations (awn; kde?) use wrong casing of PID, but proper type
71     QDBusReply<QList<QDBusObjectPath> > paths = _dock->call("GetItemsByPid", (int)QCoreApplication::applicationPid());
72     if (!paths.isValid()) {
73         // stupid implementations (i.e. docky) use uint, but proper casing
74         paths = _dock->call("GetItemsByPID", (unsigned int)QCoreApplication::applicationPid());
75         if (!paths.isValid()) {
76             qDebug() << "DBus error:" << paths.error().message();
77             return;
78         }
79     }
80     if (paths.value().count() == 0) { // no icon for this instance
81         return;
82     }
83
84     QString path = paths.value()[0].path(); // no sense in using multiple icons for one instance
85     _item = new QDBusInterface("org.freedesktop.DockManager", path, "org.freedesktop.DockItem", _bus, this);
86 }
87
88
89 void DockManagerNotificationBackend::updateProgress(int progress)
90 {
91     if (!_enabled || !_item)
92         return;
93
94     CoreConnection *c = Client::instance()->coreConnection();
95     int perc = 0;
96     if (c->progressMaximum() == c->progressMinimum())
97         perc = 0;
98     else
99         perc = (progress - c->progressMinimum()) * 100 / (c->progressMaximum() - c->progressMinimum());
100
101     QHash<QString, QVariant> args;
102     args["progress"] = perc;
103     _item->call("UpdateDockItem", args);
104 }
105
106
107 void DockManagerNotificationBackend::updateProgress(int done, int total)
108 {
109     if (!_enabled || !_item)
110         return;
111
112     int perc = 0;
113     if (done == total) {
114         disconnect(Client::backlogManager(), nullptr, this, nullptr);
115         perc = -1;
116     } else
117         perc = (done * 100) / total;
118
119     QHash<QString, QVariant> args;
120     args["progress"] = perc;
121     _item->call("UpdateDockItem", args);
122 }
123
124
125 void DockManagerNotificationBackend::synchronized()
126 {
127     connect(Client::backlogManager(), &ClientBacklogManager::updateProgress, this, selectOverload<int, int>(&DockManagerNotificationBackend::updateProgress));
128 }
129
130
131 void DockManagerNotificationBackend::notify(const Notification &notification)
132 {
133     if (!_enabled || !_item) {
134         return;
135     }
136     if (notification.type != Highlight && notification.type != PrivMsg) {
137         return;
138     }
139
140     QHash<QString, QVariant> args;
141     args["attention"] = true;
142     args["badge"] = QString::number(++_count);
143     _item->call("UpdateDockItem", args);
144 }
145
146
147 void DockManagerNotificationBackend::close(uint notificationId)
148 {
149     Q_UNUSED(notificationId);
150     if (!_item)
151         return;
152
153     QHash<QString, QVariant> args;
154     args["attention"] = false;
155     args["badge"] = --_count == 0 ? QString() : QString::number(_count);
156     _item->call("UpdateDockItem", args);
157 }
158
159
160 void DockManagerNotificationBackend::enabledChanged(const QVariant &v)
161 {
162     _enabled = v.toBool();
163
164     if (!_enabled && _item) {
165         QHash<QString, QVariant> args;
166         args["attention"] = false;
167         args["badge"] = QString();
168         _item->call("UpdateDockItem", args);
169     }
170 }
171
172
173 SettingsPage *DockManagerNotificationBackend::createConfigWidget() const
174 {
175     return new ConfigWidget(_available);
176 }
177
178
179 /***************************************************************************/
180
181 DockManagerNotificationBackend::ConfigWidget::ConfigWidget(bool enabled, QWidget *parent)
182     : SettingsPage("Internal", "DockManagerNotification", parent)
183 {
184     auto *layout = new QHBoxLayout(this);
185     layout->addWidget(enabledBox = new QCheckBox(tr("Mark dockmanager entry"), this));
186     enabledBox->setVisible(enabled);
187
188     connect(enabledBox, &QAbstractButton::toggled, this, &ConfigWidget::widgetChanged);
189 }
190
191
192 void DockManagerNotificationBackend::ConfigWidget::widgetChanged()
193 {
194     bool changed = enabled != enabledBox->isChecked();
195
196     if (changed != hasChanged()) setChangedState(changed);
197 }
198
199
200 bool DockManagerNotificationBackend::ConfigWidget::hasDefaults() const
201 {
202     return true;
203 }
204
205
206 void DockManagerNotificationBackend::ConfigWidget::defaults()
207 {
208     enabledBox->setChecked(false);
209     widgetChanged();
210 }
211
212
213 void DockManagerNotificationBackend::ConfigWidget::load()
214 {
215     NotificationSettings s;
216     enabled = s.value("DockManager/Enabled", false).toBool();
217
218     enabledBox->setChecked(enabled);
219     setChangedState(false);
220 }
221
222
223 void DockManagerNotificationBackend::ConfigWidget::save()
224 {
225     NotificationSettings s;
226     s.setValue("DockManager/Enabled", enabledBox->isChecked());
227     load();
228 }