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