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