Merge lp:~mzanetti/unity8/rework-launcher-backend into lp:unity8
- rework-launcher-backend
- Merge into trunk
Status: | Merged | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | Albert Astals Cid | ||||||||||||||||||||
Approved revision: | 1221 | ||||||||||||||||||||
Merged at revision: | 1276 | ||||||||||||||||||||
Proposed branch: | lp:~mzanetti/unity8/rework-launcher-backend | ||||||||||||||||||||
Merge into: | lp:unity8 | ||||||||||||||||||||
Prerequisite: | lp:~aacid/unity8/gettext_textdomain | ||||||||||||||||||||
Diff against target: |
2617 lines (+982/-1126) 29 files modified
data/unity8-filewatcher.conf (+8/-0) debian/control (+4/-4) debian/unity8.install (+1/-0) plugins/Unity/Launcher/CMakeLists.txt (+5/-3) plugins/Unity/Launcher/backend/launcherbackend.cpp (+0/-591) plugins/Unity/Launcher/backend/launcherbackend.h (+0/-196) plugins/Unity/Launcher/dbusinterface.cpp (+232/-0) plugins/Unity/Launcher/dbusinterface.h (+50/-0) plugins/Unity/Launcher/desktopfilehandler.cpp (+151/-0) plugins/Unity/Launcher/desktopfilehandler.h (+56/-0) plugins/Unity/Launcher/gsettings.cpp (+66/-0) plugins/Unity/Launcher/gsettings.h (+37/-0) plugins/Unity/Launcher/launcheritem.cpp (+30/-0) plugins/Unity/Launcher/launcheritem.h (+20/-21) plugins/Unity/Launcher/launchermodel.cpp (+86/-16) plugins/Unity/Launcher/launchermodel.h (+15/-8) plugins/Unity/Launcher/quicklistmodel.h (+1/-1) qml/Launcher/LauncherDelegate.qml (+4/-2) qml/Launcher/LauncherPanel.qml (+1/-0) tests/mocks/Unity/Launcher/CMakeLists.txt (+1/-1) tests/mocks/Unity/Launcher/MockLauncherItem.cpp (+14/-0) tests/mocks/Unity/Launcher/MockLauncherItem.h (+19/-18) tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+10/-0) tests/plugins/Unity/Launcher/CMakeLists.txt (+9/-24) tests/plugins/Unity/Launcher/gsettings.cpp (+40/-0) tests/plugins/Unity/Launcher/gsettings.h (+38/-0) tests/plugins/Unity/Launcher/launcherbackendtest.cpp (+0/-239) tests/plugins/Unity/Launcher/launchermodeltest.cpp (+81/-1) tests/qmltests/Launcher/tst_Launcher.qml (+3/-1) |
||||||||||||||||||||
To merge this branch: | bzr merge lp:~mzanetti/unity8/rework-launcher-backend | ||||||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Albert Astals Cid (community) | Approve | ||
Michał Sawicz | packaging | Approve | |
Ubuntu Unity PS integration team | packaging | Pending | |
Review via email: mp+232921@code.launchpad.net |
This proposal supersedes a proposal from 2014-08-26.
Commit message
Rework LauncherBackend
* This splits the LauncherBackend class into 3 separate classes: DBusInterface, GSettings and DesktopFileHandler in order to reduce complexity
* Fixes all currently known backend related bugs
* Moves storage from AccountService to DConf (drops AS support for now)
* Add support for in .desktop file translations
* This breaks split greeter support in the launcher for now. We need a second LauncherPlugin for the session greeter which doesn't try to access .desktop files and ready its config from AccountsService
Description of the change
* Are there any related MPs required for this MP to build/function as expected? Please list.
https:/
https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
yes (in phone-right-edge ppa)
* Did you make sure that your branch does not contain spurious tags?
yes
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
yes
* If you changed the UI, has there been a design review?
no
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1208
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1209
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1211
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Please add override to all the virtuals of plugins/
Albert Astals Cid (aacid) wrote : | # |
And i guess also for tests/mocks/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1213
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
> Please add override to all the virtuals of
> plugins/
> LauncherItemInt
> And i guess also for tests/mocks/
done
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1214
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1217
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1218
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
You need to bump the unity-launcher-
Michael Zanetti (mzanetti) wrote : | # |
> You need to bump the unity-launcher-
Done.
Michał Sawicz (saviq) : | # |
Albert Astals Cid (aacid) wrote : | # |
* Did you perform an exploratory manual test run of the code change and any related functionality?
Yes
* Did CI run pass? If not, please explain why.
No, it needs extra packages, running the tests locally now.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1219
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
FAIL! : qmltestrunner:
Actual (): false
Expected (): true
Loc: [/home/
- 1220. By Michael Zanetti
-
improve countEmblem test and fix some warnings along the way
- 1221. By Michael Zanetti
-
make some count emblems visible in the mock
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1220
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1221
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1222. By Michael Zanetti
-
don't load unity7 favorites but only work with the new items key
- 1223. By Michael Zanetti
-
merge trunk
- 1224. By Michael Zanetti
-
fix dependency on unity-schemas
- 1225. By Michael Zanetti
-
fix schema to reflect change in unity-schemas
Preview Diff
1 | === added file 'data/unity8-filewatcher.conf' |
2 | --- data/unity8-filewatcher.conf 1970-01-01 00:00:00 +0000 |
3 | +++ data/unity8-filewatcher.conf 2014-09-18 21:04:46 +0000 |
4 | @@ -0,0 +1,8 @@ |
5 | +description "File system watcher for unity8" |
6 | +author "Michael Zanetti <michael.zanetti@canonical.com>" |
7 | + |
8 | +# Workaround for bug 1360208. ~ and * in one expression doesn't work currently |
9 | +start on (file FILE=/home/phablet/.local/share/applications/*.desktop) or (file FILE=/usr/share/applications/*.desktop) |
10 | + |
11 | +exec dbus-send --type=method_call --dest=com.canonical.Unity.Launcher /com/canonical/Unity/Launcher com.canonical.Unity.Launcher.Refresh |
12 | + |
13 | |
14 | === modified file 'debian/control' |
15 | --- debian/control 2014-09-03 07:58:32 +0000 |
16 | +++ debian/control 2014-09-18 21:04:46 +0000 |
17 | @@ -24,7 +24,7 @@ |
18 | libpulse-dev, |
19 | libqmenumodel-dev (>= 0.2.8), |
20 | libqt5xmlpatterns5-dev, |
21 | - libunity-api-dev (>= 7.89), |
22 | + libunity-api-dev (>= 7.90), |
23 | libusermetricsoutput1-dev, |
24 | libxcb1-dev, |
25 | pkg-config, |
26 | @@ -87,7 +87,7 @@ |
27 | qtdeclarative5-gsettings1.0, |
28 | qtdeclarative5-qtmir-plugin (>= 0.4.3), |
29 | qtdeclarative5-ubuntu-telephony0.1, |
30 | - unity-launcher-impl-3, |
31 | + unity-launcher-impl-4, |
32 | unity8-common (= ${source:Version}), |
33 | unity8-private (= ${binary:Version}), |
34 | unity8-private | unity-launcher-impl, |
35 | @@ -171,12 +171,12 @@ |
36 | Depends: accountsservice-ubuntu-schemas (>= 0.0.3), |
37 | gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815), |
38 | libhardware2, |
39 | - libunity-core-6.0-9, |
40 | + unity-schemas (>= 7.3.1+14.10.20140915), |
41 | pay-service, |
42 | ${misc:Depends}, |
43 | ${shlibs:Depends}, |
44 | Provides: unity-launcher-impl, |
45 | - unity-launcher-impl-3, |
46 | + unity-launcher-impl-4, |
47 | Description: Unity 8 private libs |
48 | The Unity 8 shell is the primary user interface for Ubuntu devices. |
49 | . |
50 | |
51 | === modified file 'debian/unity8.install' |
52 | --- debian/unity8.install 2014-08-27 07:57:54 +0000 |
53 | +++ debian/unity8.install 2014-09-18 21:04:46 +0000 |
54 | @@ -1,5 +1,6 @@ |
55 | data/unity8.conf usr/share/upstart/sessions/ |
56 | data/unity8-dash.conf usr/share/upstart/sessions/ |
57 | +data/unity8-filewatcher.conf usr/share/upstart/sessions/ |
58 | usr/bin/unity8 |
59 | usr/bin/unity8-dash |
60 | usr/share/applications/unity8.desktop |
61 | |
62 | === modified file 'plugins/Unity/Launcher/CMakeLists.txt' |
63 | --- plugins/Unity/Launcher/CMakeLists.txt 2014-09-02 11:11:01 +0000 |
64 | +++ plugins/Unity/Launcher/CMakeLists.txt 2014-09-18 21:04:46 +0000 |
65 | @@ -1,5 +1,5 @@ |
66 | include(FindPkgConfig) |
67 | -pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3) |
68 | +pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=4) |
69 | pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=3) |
70 | pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt) |
71 | |
72 | @@ -16,8 +16,10 @@ |
73 | launchermodel.cpp |
74 | launcheritem.cpp |
75 | quicklistmodel.cpp |
76 | - common/quicklistentry.cpp |
77 | - backend/launcherbackend.cpp |
78 | + quicklistentry.cpp |
79 | + dbusinterface.cpp |
80 | + gsettings.cpp |
81 | + desktopfilehandler.cpp |
82 | ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp |
83 | ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h |
84 | ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h |
85 | |
86 | === removed directory 'plugins/Unity/Launcher/backend' |
87 | === removed file 'plugins/Unity/Launcher/backend/launcherbackend.cpp' |
88 | --- plugins/Unity/Launcher/backend/launcherbackend.cpp 2014-09-01 15:24:00 +0000 |
89 | +++ plugins/Unity/Launcher/backend/launcherbackend.cpp 1970-01-01 00:00:00 +0000 |
90 | @@ -1,591 +0,0 @@ |
91 | -/* |
92 | - * Copyright (C) 2013 Canonical, Ltd. |
93 | - * |
94 | - * Authors: |
95 | - * Michael Terry <michael.terry@canonical.com> |
96 | - * Michael Zanetti <michael.zanetti@canonical.com> |
97 | - * |
98 | - * This program is free software; you can redistribute it and/or modify |
99 | - * it under the terms of the GNU General Public License as published by |
100 | - * the Free Software Foundation; version 3. |
101 | - * |
102 | - * This program is distributed in the hope that it will be useful, |
103 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
104 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
105 | - * GNU General Public License for more details. |
106 | - * |
107 | - * You should have received a copy of the GNU General Public License |
108 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
109 | - */ |
110 | - |
111 | -#include "AccountsServiceDBusAdaptor.h" |
112 | -#include "launcherbackend.h" |
113 | - |
114 | -#include <QDir> |
115 | -#include <QDBusArgument> |
116 | -#include <QFileInfo> |
117 | -#include <QGSettings> |
118 | -#include <QDebug> |
119 | -#include <QStandardPaths> |
120 | - |
121 | -#include <libintl.h> |
122 | - |
123 | -class LauncherBackendItem |
124 | -{ |
125 | -public: |
126 | - QString displayName; |
127 | - QString icon; |
128 | - int count; |
129 | - bool countVisible; |
130 | -}; |
131 | - |
132 | -LauncherBackend::LauncherBackend(QObject *parent): |
133 | - QDBusVirtualObject(parent), |
134 | - m_accounts(nullptr) |
135 | -{ |
136 | -#ifndef LAUNCHER_TESTING |
137 | - m_accounts = new AccountsServiceDBusAdaptor(this); |
138 | -#endif |
139 | - m_user = qgetenv("USER"); |
140 | - syncFromAccounts(); |
141 | - |
142 | - /* Set up ourselves on DBus */ |
143 | - QDBusConnection con = QDBusConnection::sessionBus(); |
144 | - if (!con.registerService("com.canonical.Unity.Launcher")) { |
145 | - qDebug() << "Unable to register launcher name"; |
146 | - } |
147 | - if (!con.registerVirtualObject("/com/canonical/Unity/Launcher", this, QDBusConnection::VirtualObjectRegisterOption::SubPath)) { |
148 | - qDebug() << "Unable to register launcher object"; |
149 | - } |
150 | -} |
151 | - |
152 | -LauncherBackend::~LauncherBackend() |
153 | -{ |
154 | - /* Remove oursevles from DBus */ |
155 | - QDBusConnection con = QDBusConnection::sessionBus(); |
156 | - con.unregisterService("com.canonical.Unity.Launcher"); |
157 | - con.unregisterObject("/com/canonical/Unity/Launcher"); |
158 | - |
159 | - /* Clear data */ |
160 | - m_storedApps.clear(); |
161 | - |
162 | - Q_FOREACH(LauncherBackendItem *item, m_itemCache) { |
163 | - delete item; |
164 | - } |
165 | - m_itemCache.clear(); |
166 | -} |
167 | - |
168 | -QStringList LauncherBackend::storedApplications() const |
169 | -{ |
170 | - return m_storedApps; |
171 | -} |
172 | - |
173 | -void LauncherBackend::setStoredApplications(const QStringList &appIds) |
174 | -{ |
175 | - if (appIds.count() < m_storedApps.count()) { |
176 | - Q_FOREACH(const QString &appId, m_storedApps) { |
177 | - if (!appIds.contains(appId)) { |
178 | - delete m_itemCache.take(appId); |
179 | - } |
180 | - } |
181 | - } |
182 | - m_storedApps = appIds; |
183 | - Q_FOREACH(const QString &appId, appIds) { |
184 | - if (!m_itemCache.contains(appId)) { |
185 | - QString df = findDesktopFile(appId); |
186 | - if (!df.isEmpty()) { |
187 | - LauncherBackendItem *item = parseDesktopFile(df); |
188 | - m_itemCache.insert(appId, item); |
189 | - } else { |
190 | - // Cannot find any data for that app... ignoring it. |
191 | - qWarning() << "cannot find desktop file for" << appId << ". discarding app."; |
192 | - m_storedApps.removeAll(appId); |
193 | - } |
194 | - } |
195 | - } |
196 | - syncToAccounts(); |
197 | -} |
198 | - |
199 | -QString LauncherBackend::desktopFile(const QString &appId) const |
200 | -{ |
201 | - return findDesktopFile(appId); |
202 | -} |
203 | - |
204 | -QString LauncherBackend::displayName(const QString &appId) const |
205 | -{ |
206 | - LauncherBackendItem *item = m_itemCache.value(appId, nullptr); |
207 | - if (item) { |
208 | - return item->displayName; |
209 | - } |
210 | - |
211 | - QString df = findDesktopFile(appId); |
212 | - if (!df.isEmpty()) { |
213 | - LauncherBackendItem *item = parseDesktopFile(df); |
214 | - m_itemCache.insert(appId, item); |
215 | - return item->displayName; |
216 | - } |
217 | - |
218 | - return QString(); |
219 | -} |
220 | - |
221 | -QString LauncherBackend::icon(const QString &appId) const |
222 | -{ |
223 | - QString iconName; |
224 | - LauncherBackendItem *item = getItem(appId); |
225 | - if (item) { |
226 | - iconName = item->icon; |
227 | - } |
228 | - |
229 | - return iconName; |
230 | -} |
231 | - |
232 | -QList<QuickListEntry> LauncherBackend::quickList(const QString &appId) const |
233 | -{ |
234 | - // TODO: Get static (from .desktop file) and dynamic (from the app itself) |
235 | - // entries and return them here. Frontend related entries (like "Pin to launcher") |
236 | - // don't matter here. This is just the backend part. |
237 | - // TODO: emit quickListChanged() when the dynamic part changes |
238 | - Q_UNUSED(appId) |
239 | - return QList<QuickListEntry>(); |
240 | -} |
241 | - |
242 | -int LauncherBackend::progress(const QString &appId) const |
243 | -{ |
244 | - // TODO: Return value for progress emblem. |
245 | - // TODO: emit progressChanged() when this value changes. |
246 | - Q_UNUSED(appId) |
247 | - return -1; |
248 | -} |
249 | - |
250 | -int LauncherBackend::count(const QString &appId) const |
251 | -{ |
252 | - int count = -1; |
253 | - LauncherBackendItem *item = getItem(appId); |
254 | - |
255 | - if (item) { |
256 | - if (item->countVisible) { |
257 | - count = item->count; |
258 | - } |
259 | - } |
260 | - |
261 | - return count; |
262 | -} |
263 | - |
264 | -void LauncherBackend::setCount(const QString &appId, int count) const |
265 | -{ |
266 | - LauncherBackendItem *item = getItem(appId); |
267 | - |
268 | - bool emitchange = false; |
269 | - if (item) { |
270 | - emitchange = (item->count != count); |
271 | - item->count = count; |
272 | - } |
273 | - |
274 | - if (emitchange) { |
275 | - /* TODO: This needs to use the accessor to handle the visibility |
276 | - correctly, but when we have the two properties we can just use |
277 | - the local value */ |
278 | - Q_EMIT countChanged(appId, this->count(appId)); |
279 | - QVariant vcount(item->count); |
280 | - emitPropChangedDbus(appId, "count", vcount); |
281 | - } |
282 | -} |
283 | - |
284 | -bool LauncherBackend::countVisible(const QString &appId) const |
285 | -{ |
286 | - bool visible = false; |
287 | - LauncherBackendItem *item = getItem(appId); |
288 | - |
289 | - if (item) { |
290 | - visible = item->countVisible; |
291 | - } |
292 | - |
293 | - return visible; |
294 | -} |
295 | - |
296 | -void LauncherBackend::setCountVisible(const QString &appId, bool visible) const |
297 | -{ |
298 | - LauncherBackendItem *item = getItem(appId); |
299 | - |
300 | - bool emitchange = false; |
301 | - if (item) { |
302 | - emitchange = (item->countVisible != visible); |
303 | - item->countVisible = visible; |
304 | - } else { |
305 | - qDebug() << "Unable to find:" << appId; |
306 | - } |
307 | - |
308 | - if (emitchange) { |
309 | - /* TODO: Because we're using visible in determining the |
310 | - count we need to emit a count changed as well */ |
311 | - Q_EMIT countChanged(appId, this->count(appId)); |
312 | - Q_EMIT countVisibleChanged(appId, item->countVisible); |
313 | - QVariant vCountVisible(item->countVisible); |
314 | - emitPropChangedDbus(appId, "countVisible", vCountVisible); |
315 | - } |
316 | -} |
317 | - |
318 | -void LauncherBackend::setUser(const QString &username) |
319 | -{ |
320 | - if (qgetenv("USER") == "lightdm" && m_user != username) { |
321 | - m_user = username; |
322 | - syncFromAccounts(); |
323 | - } |
324 | -} |
325 | - |
326 | -void LauncherBackend::triggerQuickListAction(const QString &appId, const QString &quickListId) |
327 | -{ |
328 | - // TODO: execute the given quicklist action |
329 | - Q_UNUSED(appId) |
330 | - Q_UNUSED(quickListId) |
331 | -} |
332 | - |
333 | -void LauncherBackend::syncFromAccounts() |
334 | -{ |
335 | - QList<QVariantMap> apps; |
336 | - bool defaults = true; |
337 | - |
338 | - m_storedApps.clear(); |
339 | - |
340 | - if (m_accounts && !m_user.isEmpty()) { |
341 | - QVariant variant = m_accounts->getUserProperty(m_user, "com.canonical.unity.AccountsService", "launcher-items"); |
342 | - if (variant.isValid() && variant.canConvert<QDBusArgument>()) { |
343 | - apps = qdbus_cast<QList<QVariantMap>>(variant.value<QDBusArgument>()); |
344 | - defaults = isDefaultsItem(apps); |
345 | - } |
346 | - } |
347 | - |
348 | - if (m_accounts && defaults) { // Checking accounts as it'll be null when !useStorage |
349 | - QGSettings gSettings("com.canonical.Unity.Launcher", "/com/canonical/unity/launcher/"); |
350 | - Q_FOREACH(const QString &entry, gSettings.get("favorites").toStringList()) { |
351 | - if (entry.startsWith("application://")) { |
352 | - QString appId = entry; |
353 | - // Transform "application://foobar.desktop" to "application://foobar" |
354 | - appId.remove("application://"); |
355 | - if (appId.endsWith(".desktop")) { |
356 | - appId.chop(8); |
357 | - } |
358 | - QString df = findDesktopFile(appId); |
359 | - |
360 | - if (!df.isEmpty()) { |
361 | - m_storedApps << appId; |
362 | - |
363 | - if (!m_itemCache.contains(appId)) { |
364 | - m_itemCache.insert(appId, parseDesktopFile(df)); |
365 | - } |
366 | - } |
367 | - } |
368 | - if (entry.startsWith("appid://")) { |
369 | - QString appId = entry; |
370 | - appId.remove("appid://"); |
371 | - // Strip hook name and current-user-version in case its there |
372 | - |
373 | - if (appId.split('/').count() != 3) { |
374 | - qWarning() << "ignoring entry " + appId + ". Not a valid appId."; |
375 | - continue; |
376 | - } |
377 | - appId = appId.split('/').first() + "_" + appId.split('/').at(1); |
378 | - QString df = findDesktopFile(appId); |
379 | - |
380 | - if (!df.isEmpty()) { |
381 | - m_storedApps << appId; |
382 | - |
383 | - if (!m_itemCache.contains(appId)) { |
384 | - m_itemCache.insert(appId, parseDesktopFile(df)); |
385 | - } |
386 | - } |
387 | - } |
388 | - } |
389 | - } else { |
390 | - for (const QVariant &app: apps) { |
391 | - loadFromVariant(app.toMap()); |
392 | - } |
393 | - } |
394 | -} |
395 | - |
396 | -void LauncherBackend::syncToAccounts() |
397 | -{ |
398 | - if (m_accounts && !m_user.isEmpty()) { |
399 | - QList<QVariantMap> items; |
400 | - |
401 | - Q_FOREACH(const QString &appId, m_storedApps) { |
402 | - items << itemToVariant(appId); |
403 | - } |
404 | - |
405 | - m_accounts->setUserProperty(m_user, "com.canonical.unity.AccountsService", "launcher-items", QVariant::fromValue(items)); |
406 | - } |
407 | -} |
408 | - |
409 | -QString LauncherBackend::findDesktopFile(const QString &appId) const |
410 | -{ |
411 | - int dashPos = -1; |
412 | - QString helper = appId; |
413 | - |
414 | - QStringList searchDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); |
415 | -#ifdef LAUNCHER_TESTING |
416 | - searchDirs << ""; |
417 | -#endif |
418 | - |
419 | - do { |
420 | - if (dashPos != -1) { |
421 | - helper = helper.replace(dashPos, 1, '/'); |
422 | - } |
423 | - |
424 | - Q_FOREACH(const QString &searchDirName, searchDirs) { |
425 | - QDir searchDir(searchDirName); |
426 | - Q_FOREACH(const QString &desktopFile, searchDir.entryList(QStringList() << "*.desktop")) { |
427 | - if (desktopFile.startsWith(helper)) { |
428 | - QFileInfo fileInfo(searchDir, desktopFile); |
429 | - return fileInfo.absoluteFilePath(); |
430 | - } |
431 | - } |
432 | - } |
433 | - |
434 | - dashPos = helper.indexOf("-"); |
435 | - } while (dashPos != -1); |
436 | - |
437 | - return QString(); |
438 | -} |
439 | - |
440 | -LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFile) const |
441 | -{ |
442 | - QSettings settings(desktopFile, QSettings::IniFormat); |
443 | - |
444 | - LauncherBackendItem* item = new LauncherBackendItem(); |
445 | - |
446 | - item->displayName = settings.value("Desktop Entry/Name").toString(); |
447 | - const QString domain = settings.value("Desktop Entry/X-Ubuntu-Gettext-Domain").toString(); |
448 | - if (!domain.isEmpty()) { |
449 | - item->displayName = dgettext(domain.toUtf8().constData(), item->displayName.toUtf8().constData()); |
450 | - } |
451 | - |
452 | - QString iconString = settings.value("Desktop Entry/Icon").toString(); |
453 | - QString pathString = settings.value("Desktop Entry/Path").toString(); |
454 | - if (QFileInfo(iconString).exists()) { |
455 | - item->icon = QFileInfo(iconString).absoluteFilePath(); |
456 | - } else if (QFileInfo(pathString + '/' + iconString).exists()) { |
457 | - item->icon = pathString + '/' + iconString; |
458 | - } else { |
459 | - item->icon = "image://theme/" + iconString; |
460 | - } |
461 | - |
462 | - /* TODO: These should be looked up in a cache somewhere */ |
463 | - item->count = 0; |
464 | - item->countVisible = false; |
465 | - |
466 | - return item; |
467 | -} |
468 | - |
469 | -/* Gets an item, and tries to create a new one if we need it to */ |
470 | -LauncherBackendItem* LauncherBackend::getItem(const QString &appId) const |
471 | -{ |
472 | - LauncherBackendItem *item = m_itemCache.value(appId, nullptr); |
473 | - if (!item) { |
474 | - QString df = findDesktopFile(appId); |
475 | - if (!df.isEmpty()) { |
476 | - item = parseDesktopFile(df); |
477 | - if (item) { |
478 | - m_itemCache[appId] = item; |
479 | - } else { |
480 | - qWarning() << "Unable to parse desktop file for" << appId << "path" << df; |
481 | - } |
482 | - } else { |
483 | - qWarning() << "Unable to find desktop file for:" << appId; |
484 | - } |
485 | - } |
486 | - |
487 | - if (!item) |
488 | - qWarning() << "Unable to find item for: " << appId; |
489 | - |
490 | - return item; |
491 | -} |
492 | - |
493 | -void LauncherBackend::loadFromVariant(const QVariantMap &details) |
494 | -{ |
495 | - if (!details.contains("id")) { |
496 | - return; |
497 | - } |
498 | - QString appId = details.value("id").toString(); |
499 | - |
500 | - LauncherBackendItem *item = m_itemCache.value(appId, nullptr); |
501 | - if (item) { |
502 | - delete item; |
503 | - } |
504 | - |
505 | - item = new LauncherBackendItem(); |
506 | - |
507 | - item->displayName = details.value("name").toString(); |
508 | - item->icon = details.value("icon").toString(); |
509 | - item->count = details.value("count").toInt(); |
510 | - item->countVisible = details.value("countVisible").toBool(); |
511 | - |
512 | - m_itemCache.insert(appId, item); |
513 | - m_storedApps.append(appId); |
514 | -} |
515 | - |
516 | -QVariantMap LauncherBackend::itemToVariant(const QString &appId) const |
517 | -{ |
518 | - LauncherBackendItem *item = m_itemCache.value(appId); |
519 | - QVariantMap details; |
520 | - details.insert("id", appId); |
521 | - details.insert("name", item->displayName); |
522 | - details.insert("icon", item->icon); |
523 | - details.insert("count", item->count); |
524 | - details.insert("countVisible", item->countVisible); |
525 | - return details; |
526 | -} |
527 | - |
528 | -bool LauncherBackend::isDefaultsItem(const QList<QVariantMap> &apps) const |
529 | -{ |
530 | - // To differentiate between an empty list and a list that hasn't been set |
531 | - // yet (and should thus be populated with the defaults), we use a special |
532 | - // list of one item with the 'defaults' field set to true. |
533 | - return (apps.size() == 1 && apps[0].value("defaults").toBool()); |
534 | -} |
535 | - |
536 | -bool LauncherBackend::handleMessage(const QDBusMessage& message, const QDBusConnection& connection) |
537 | -{ |
538 | - /* Check to make sure we're getting properties on our interface */ |
539 | - if (message.type() != QDBusMessage::MessageType::MethodCallMessage) { |
540 | - return false; |
541 | - } |
542 | - if (message.interface() != "org.freedesktop.DBus.Properties") { |
543 | - return false; |
544 | - } |
545 | - if (message.arguments()[0].toString() != "com.canonical.Unity.Launcher.Item") { |
546 | - return false; |
547 | - } |
548 | - |
549 | - /* Break down the path to just the app id */ |
550 | - QString pathtemp = message.path(); |
551 | - if (!pathtemp.startsWith("/com/canonical/Unity/Launcher/")) { |
552 | - return false; |
553 | - } |
554 | - pathtemp.remove("/com/canonical/Unity/Launcher/"); |
555 | - if (pathtemp.indexOf('/') >= 0) { |
556 | - return false; |
557 | - } |
558 | - |
559 | - /* Find ourselves an appid */ |
560 | - QString appid = decodeAppId(pathtemp); |
561 | - QVariantList retval; |
562 | - |
563 | - if (message.member() == "Get") { |
564 | - if (message.arguments()[1].toString() == "count") { |
565 | - retval.append(QVariant::fromValue(QDBusVariant(this->count(appid)))); |
566 | - } else if (message.arguments()[1].toString() == "countVisible") { |
567 | - retval.append(QVariant::fromValue(QDBusVariant(this->countVisible(appid)))); |
568 | - } |
569 | - } else if (message.member() == "Set") { |
570 | - if (message.arguments()[1].toString() == "count") { |
571 | - this->setCount(appid, message.arguments()[2].value<QDBusVariant>().variant().toInt()); |
572 | - } else if (message.arguments()[1].toString() == "countVisible") { |
573 | - this->setCountVisible(appid, message.arguments()[2].value<QDBusVariant>().variant().toBool()); |
574 | - } |
575 | - } else if (message.member() == "GetAll") { |
576 | - retval.append(this->itemToVariant(appid)); |
577 | - } else { |
578 | - return false; |
579 | - } |
580 | - |
581 | - QDBusMessage reply = message.createReply(retval); |
582 | - return connection.send(reply); |
583 | -} |
584 | - |
585 | -QString LauncherBackend::introspect(const QString &path) const |
586 | -{ |
587 | - /* This case we should just list the nodes */ |
588 | - if (path == "/com/canonical/Unity/Launcher/" || path == "/com/canonical/Unity/Launcher") { |
589 | - QString nodes; |
590 | - |
591 | - Q_FOREACH(const QString &appId, m_itemCache.keys()) { |
592 | - nodes.append("<node name=\""); |
593 | - nodes.append(encodeAppId(appId)); |
594 | - nodes.append("\"/>\n"); |
595 | - } |
596 | - |
597 | - return nodes; |
598 | - } |
599 | - |
600 | - /* Should not happen, but let's handle it */ |
601 | - if (!path.startsWith("/com/canonical/Unity/Launcher")) { |
602 | - return ""; |
603 | - } |
604 | - |
605 | - /* Now we should be looking at a node */ |
606 | - QString nodeiface = |
607 | - "<interface name=\"com.canonical.Unity.Launcher.Item\">" |
608 | - "<property name=\"count\" type=\"i\" access=\"readwrite\" />" |
609 | - "<property name=\"countVisible\" type=\"b\" access=\"readwrite\" />" |
610 | - "</interface>"; |
611 | - return nodeiface; |
612 | -} |
613 | - |
614 | -QString LauncherBackend::decodeAppId(const QString& path) |
615 | -{ |
616 | - QByteArray bytes = path.toUtf8(); |
617 | - QByteArray decoded; |
618 | - |
619 | - for (int i = 0; i < bytes.size(); ++i) { |
620 | - char chr = bytes.at(i); |
621 | - |
622 | - if (chr == '_') { |
623 | - QString number; |
624 | - number.append(bytes.at(i+1)); |
625 | - number.append(bytes.at(i+2)); |
626 | - |
627 | - bool okay; |
628 | - char newchar = number.toUInt(&okay, 16); |
629 | - if (okay) |
630 | - decoded.append(newchar); |
631 | - |
632 | - i += 2; |
633 | - } else { |
634 | - decoded.append(chr); |
635 | - } |
636 | - } |
637 | - |
638 | - return QString::fromUtf8(decoded); |
639 | -} |
640 | - |
641 | -QString LauncherBackend::encodeAppId(const QString& appId) |
642 | -{ |
643 | - QByteArray bytes = appId.toUtf8(); |
644 | - QString encoded; |
645 | - |
646 | - for (int i = 0; i < bytes.size(); ++i) { |
647 | - uchar chr = bytes.at(i); |
648 | - |
649 | - if ((chr >= 'a' && chr <= 'z') || |
650 | - (chr >= 'A' && chr <= 'Z') || |
651 | - (chr >= '0' && chr <= '9'&& i != 0)) { |
652 | - encoded.append(chr); |
653 | - } else { |
654 | - QString hexval = QString("_%1").arg(chr, 2, 16, QChar('0')); |
655 | - encoded.append(hexval.toUpper()); |
656 | - } |
657 | - } |
658 | - |
659 | - return encoded; |
660 | -} |
661 | - |
662 | -void LauncherBackend::emitPropChangedDbus(const QString& appId, const QString& property, QVariant &value) const |
663 | -{ |
664 | - QString path("/com/canonical/Unity/Launcher/"); |
665 | - path.append(encodeAppId(appId)); |
666 | - |
667 | - QDBusMessage message = QDBusMessage::createSignal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"); |
668 | - |
669 | - QList<QVariant> arguments; |
670 | - QVariantHash changedprops; |
671 | - changedprops[property] = QVariant::fromValue(QDBusVariant(value)); |
672 | - QVariantList deletedprops; |
673 | - |
674 | - arguments.append(changedprops); |
675 | - arguments.append(deletedprops); |
676 | - |
677 | - message.setArguments(arguments); |
678 | - |
679 | - QDBusConnection con = QDBusConnection::sessionBus(); |
680 | - con.send(message); |
681 | -} |
682 | |
683 | === removed file 'plugins/Unity/Launcher/backend/launcherbackend.h' |
684 | --- plugins/Unity/Launcher/backend/launcherbackend.h 2014-06-11 15:36:51 +0000 |
685 | +++ plugins/Unity/Launcher/backend/launcherbackend.h 1970-01-01 00:00:00 +0000 |
686 | @@ -1,196 +0,0 @@ |
687 | -/* Copyright (C) 2013 Canonical, Ltd. |
688 | - * |
689 | - * Authors: |
690 | - * Michael Zanetti <michael.zanetti@canonical.com> |
691 | - * |
692 | - * This program is free software; you can redistribute it and/or modify |
693 | - * it under the terms of the GNU General Public License as published by |
694 | - * the Free Software Foundation; version 3. |
695 | - * |
696 | - * This program is distributed in the hope that it will be useful, |
697 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
698 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
699 | - * GNU General Public License for more details. |
700 | - * |
701 | - * You should have received a copy of the GNU General Public License |
702 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
703 | - */ |
704 | - |
705 | -#ifndef LAUNCHERBACKEND_H |
706 | -#define LAUNCHERBACKEND_H |
707 | - |
708 | -#include "common/quicklistentry.h" |
709 | - |
710 | -#include <QObject> |
711 | -#include <QSettings> |
712 | -#include <QStringList> |
713 | -#include <QDBusVirtualObject> |
714 | - |
715 | -class AccountsServiceDBusAdaptor; |
716 | - |
717 | -/** |
718 | - * @brief An interface that provides all the data needed by the launcher. |
719 | - */ |
720 | - |
721 | -class LauncherBackendItem; |
722 | -class LauncherBackendTest; |
723 | - |
724 | -class LauncherBackend : public QDBusVirtualObject |
725 | -{ |
726 | - Q_OBJECT |
727 | - |
728 | - friend LauncherBackendTest; |
729 | - |
730 | -public: |
731 | - LauncherBackend(QObject *parent = 0); |
732 | - virtual ~LauncherBackend(); |
733 | - |
734 | - /** |
735 | - * @brief Returns a list of stored applications. |
736 | - * @returns A list of application IDs. |
737 | - */ |
738 | - QStringList storedApplications() const; |
739 | - |
740 | - /** |
741 | - * @brief Set the list of stored applications. |
742 | - * |
743 | - * Any previously stored information for apps not contained |
744 | - * in the list any more, e.g. the pinned state, will be |
745 | - * discarded. |
746 | - * |
747 | - * @param appIds The new list of stored applications. |
748 | - */ |
749 | - void setStoredApplications(const QStringList &appIds); |
750 | - |
751 | - /** |
752 | - * @brief Get the full path to the .desktop file. |
753 | - * |
754 | - * The application does not need to be in the list of stored applications. |
755 | - * |
756 | - * @returns The full path to the .dekstop file. |
757 | - */ |
758 | - QString desktopFile(const QString &appId) const; |
759 | - |
760 | - /** |
761 | - * @brief Get the user friendly name of an application. |
762 | - * |
763 | - * The application does not need to be in the list of stored applications. |
764 | - * |
765 | - * @param appId The ID of the application. |
766 | - * @returns The user friendly name of the application. |
767 | - */ |
768 | - QString displayName(const QString &appId) const; |
769 | - |
770 | - /** |
771 | - * @brief Get the icon of an application. |
772 | - * |
773 | - * The application does not need to be in the list of stored applications. |
774 | - * |
775 | - * @param appId The ID of the application. |
776 | - * @returns The full path to the icon for the application. |
777 | - */ |
778 | - QString icon(const QString &appId) const; |
779 | - |
780 | - /** |
781 | - * @brief Get the QuickList for an application. |
782 | - * @param appId The ID of the application. |
783 | - * @returns A QuickListModelInterface containing the QuickList. |
784 | - */ |
785 | - QList<QuickListEntry> quickList(const QString &appId) const; |
786 | - |
787 | - /** |
788 | - * @brief Execute an action from the quickList |
789 | - * @param appId The app ID for which the action was triggered |
790 | - * @param the quicklist ID of the action that was triggered |
791 | - */ |
792 | - void triggerQuickListAction(const QString &appId, const QString &entryId); |
793 | - |
794 | - /** |
795 | - * @brief Get the progress for the progress overlay of an application. |
796 | - * @param appId The ID of the application. |
797 | - * @returns The percentage of the overlay progress bar. -1 if no progress bar available. |
798 | - */ |
799 | - int progress(const QString &appId) const; |
800 | - |
801 | - /** |
802 | - * @brief Get the count of the count overlay of an application. |
803 | - * @param appId The ID of the application. |
804 | - * @returns The number to be displayed in the overlay. -1 if no count overlay is available. |
805 | - */ |
806 | - int count(const QString &appId) const; |
807 | - |
808 | - /** |
809 | - * @brief Set the count on an item |
810 | - * @param appId The ID of the application |
811 | - * @param count Count to show on the application |
812 | - */ |
813 | - void setCount(const QString &appId, int count) const; |
814 | - |
815 | - /** |
816 | - * @brief Get whether the count should be visible |
817 | - * @param appId The ID of the application. |
818 | - * @returns Whether to show a count on the launcher |
819 | - */ |
820 | - bool countVisible(const QString &appId) const; |
821 | - |
822 | - /** |
823 | - * @brief Set the visibility of the count item |
824 | - * @param appId The ID of the application |
825 | - * @param visible Whether the count should be visible |
826 | - */ |
827 | - void setCountVisible(const QString &appId, bool visible) const; |
828 | - |
829 | - /** |
830 | - * @brief Sets the username for which to look up launcher items. |
831 | - * @param username The username to use. |
832 | - */ |
833 | - void setUser(const QString &username); |
834 | - |
835 | - /** |
836 | - * @brief Handle a message to an application node |
837 | - * @param message DBus message to handle |
838 | - * @param connection DBus connection that we're using |
839 | - * @returns whether the message was handled |
840 | - */ |
841 | - virtual bool handleMessage(const QDBusMessage& message, const QDBusConnection& connection); |
842 | - |
843 | - /** |
844 | - * @brief Get introspection information on the objects we're exporting |
845 | - * @param path the dbus path containing the appid |
846 | - * @returns Introspection information for that node in the tree |
847 | - */ |
848 | - virtual QString introspect (const QString &path) const; |
849 | - |
850 | -Q_SIGNALS: |
851 | - void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList) const; |
852 | - void progressChanged(const QString &appId, int progress) const; |
853 | - void countChanged(const QString &appId, int count) const; |
854 | - void countVisibleChanged(const QString &appId, bool visible) const; |
855 | - |
856 | -private: |
857 | - QString findDesktopFile(const QString &appId) const; |
858 | - LauncherBackendItem* parseDesktopFile(const QString &desktopFile) const; |
859 | - |
860 | - QVariantMap itemToVariant(const QString &appId) const; |
861 | - void loadFromVariant(const QVariantMap &details); |
862 | - |
863 | - bool isDefaultsItem(const QList<QVariantMap> &apps) const; |
864 | - void syncFromAccounts(); |
865 | - void syncToAccounts(); |
866 | - |
867 | - QList<QString> m_storedApps; |
868 | - mutable QHash<QString, LauncherBackendItem*> m_itemCache; |
869 | - |
870 | - AccountsServiceDBusAdaptor *m_accounts; |
871 | - QString m_user; |
872 | - |
873 | - void emitPropChangedDbus(const QString& appId, const QString& property, QVariant &value) const; |
874 | - |
875 | -protected: /* Protected to allow testing */ |
876 | - LauncherBackendItem* getItem(const QString& appId) const; |
877 | - |
878 | - static QString decodeAppId(const QString& path); |
879 | - static QString encodeAppId(const QString& appId); |
880 | -}; |
881 | - |
882 | -#endif // LAUNCHERBACKEND_H |
883 | |
884 | === removed directory 'plugins/Unity/Launcher/common' |
885 | === added file 'plugins/Unity/Launcher/dbusinterface.cpp' |
886 | --- plugins/Unity/Launcher/dbusinterface.cpp 1970-01-01 00:00:00 +0000 |
887 | +++ plugins/Unity/Launcher/dbusinterface.cpp 2014-09-18 21:04:46 +0000 |
888 | @@ -0,0 +1,232 @@ |
889 | +/* |
890 | + * Copyright 2014 Canonical Ltd. |
891 | + * |
892 | + * This program is free software; you can redistribute it and/or modify |
893 | + * it under the terms of the GNU Lesser General Public License as published by |
894 | + * the Free Software Foundation; version 3. |
895 | + * |
896 | + * This program is distributed in the hope that it will be useful, |
897 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
898 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
899 | + * GNU Lesser General Public License for more details. |
900 | + * |
901 | + * You should have received a copy of the GNU Lesser General Public License |
902 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
903 | + * |
904 | + * Authors: |
905 | + * Michael Zanetti <michael.zanetti@canonical.com> |
906 | + */ |
907 | + |
908 | +#include "dbusinterface.h" |
909 | +#include "launchermodel.h" |
910 | +#include "launcheritem.h" |
911 | + |
912 | +#include <QDBusArgument> |
913 | +#include <QDBusConnection> |
914 | +#include <QDBusMessage> |
915 | +#include <QDebug> |
916 | + |
917 | +DBusInterface::DBusInterface(LauncherModel *parent): |
918 | + QDBusVirtualObject(parent), |
919 | + m_launcherModel(parent) |
920 | +{ |
921 | + /* Set up ourselves on DBus */ |
922 | + QDBusConnection con = QDBusConnection::sessionBus(); |
923 | + if (!con.registerService("com.canonical.Unity.Launcher")) { |
924 | + qWarning() << "Unable to register launcher name"; |
925 | + } |
926 | + if (!con.registerVirtualObject("/com/canonical/Unity/Launcher", this, QDBusConnection::VirtualObjectRegisterOption::SubPath)) { |
927 | + qWarning() << "Unable to register launcher object"; |
928 | + } |
929 | +} |
930 | + |
931 | +DBusInterface::~DBusInterface() |
932 | +{ |
933 | + /* Remove oursevles from DBus */ |
934 | + QDBusConnection con = QDBusConnection::sessionBus(); |
935 | + con.unregisterService("com.canonical.Unity.Launcher"); |
936 | + con.unregisterObject("/com/canonical/Unity/Launcher"); |
937 | +} |
938 | + |
939 | +QString DBusInterface::introspect(const QString &path) const |
940 | +{ |
941 | + /* This case we should just list the nodes */ |
942 | + if (path == "/com/canonical/Unity/Launcher/" || path == "/com/canonical/Unity/Launcher") { |
943 | + QString nodes; |
944 | + |
945 | + // Add Refresh to introspect |
946 | + nodes = "<interface name=\"com.canonical.Unity.Launcher\">" |
947 | + "<method name=\"Refresh\"/>" |
948 | + "</interface>"; |
949 | + |
950 | + // Add dynamic properties for launcher emblems |
951 | + for (int i = 0; i < m_launcherModel->rowCount(); i++) { |
952 | + nodes.append("<node name=\""); |
953 | + nodes.append(encodeAppId(m_launcherModel->get(i)->appId())); |
954 | + nodes.append("\"/>\n"); |
955 | + } |
956 | + return nodes; |
957 | + } |
958 | + |
959 | + /* Should not happen, but let's handle it */ |
960 | + if (!path.startsWith("/com/canonical/Unity/Launcher")) { |
961 | + return ""; |
962 | + } |
963 | + |
964 | + /* Now we should be looking at a node */ |
965 | + QString nodeiface = |
966 | + "<interface name=\"com.canonical.Unity.Launcher.Item\">" |
967 | + "<property name=\"count\" type=\"i\" access=\"readwrite\" />" |
968 | + "<property name=\"countVisible\" type=\"b\" access=\"readwrite\" />" |
969 | + "</interface>"; |
970 | + return nodeiface; |
971 | +} |
972 | + |
973 | + |
974 | +QString DBusInterface::decodeAppId(const QString& path) |
975 | +{ |
976 | + QByteArray bytes = path.toUtf8(); |
977 | + QByteArray decoded; |
978 | + |
979 | + for (int i = 0; i < bytes.size(); ++i) { |
980 | + char chr = bytes.at(i); |
981 | + |
982 | + if (chr == '_') { |
983 | + QString number; |
984 | + number.append(bytes.at(i+1)); |
985 | + number.append(bytes.at(i+2)); |
986 | + |
987 | + bool okay; |
988 | + char newchar = number.toUInt(&okay, 16); |
989 | + if (okay) |
990 | + decoded.append(newchar); |
991 | + |
992 | + i += 2; |
993 | + } else { |
994 | + decoded.append(chr); |
995 | + } |
996 | + } |
997 | + |
998 | + return QString::fromUtf8(decoded); |
999 | +} |
1000 | + |
1001 | +QString DBusInterface::encodeAppId(const QString& appId) |
1002 | +{ |
1003 | + QByteArray bytes = appId.toUtf8(); |
1004 | + QString encoded; |
1005 | + |
1006 | + for (int i = 0; i < bytes.size(); ++i) { |
1007 | + uchar chr = bytes.at(i); |
1008 | + |
1009 | + if ((chr >= 'a' && chr <= 'z') || |
1010 | + (chr >= 'A' && chr <= 'Z') || |
1011 | + (chr >= '0' && chr <= '9'&& i != 0)) { |
1012 | + encoded.append(chr); |
1013 | + } else { |
1014 | + QString hexval = QString("_%1").arg(chr, 2, 16, QChar('0')); |
1015 | + encoded.append(hexval.toUpper()); |
1016 | + } |
1017 | + } |
1018 | + |
1019 | + return encoded; |
1020 | +} |
1021 | + |
1022 | +bool DBusInterface::handleMessage(const QDBusMessage& message, const QDBusConnection& connection) |
1023 | +{ |
1024 | + /* Check to make sure we're getting properties on our interface */ |
1025 | + if (message.type() != QDBusMessage::MessageType::MethodCallMessage) { |
1026 | + return false; |
1027 | + } |
1028 | + |
1029 | + // First handle methods of the Launcher interface |
1030 | + if (message.interface() == "com.canonical.Unity.Launcher") { |
1031 | + if (message.member() == "Refresh") { |
1032 | + QDBusMessage reply = message.createReply(); |
1033 | + Q_EMIT refreshCalled(); |
1034 | + return connection.send(reply); |
1035 | + } |
1036 | + } |
1037 | + |
1038 | + // Now handle dynamic properties (for launcher emblems) |
1039 | + if (message.interface() != "org.freedesktop.DBus.Properties") { |
1040 | + return false; |
1041 | + } |
1042 | + |
1043 | + if (message.member() != "GetAll" && message.arguments()[0].toString() != "com.canonical.Unity.Launcher.Item") { |
1044 | + return false; |
1045 | + } |
1046 | + |
1047 | + /* Break down the path to just the app id */ |
1048 | + QString pathtemp = message.path(); |
1049 | + if (!pathtemp.startsWith("/com/canonical/Unity/Launcher/")) { |
1050 | + return false; |
1051 | + } |
1052 | + pathtemp.remove("/com/canonical/Unity/Launcher/"); |
1053 | + if (pathtemp.indexOf('/') >= 0) { |
1054 | + return false; |
1055 | + } |
1056 | + |
1057 | + /* Find ourselves an appid */ |
1058 | + QString appid = decodeAppId(pathtemp); |
1059 | + int index = m_launcherModel->findApplication(appid); |
1060 | + LauncherItem *item = static_cast<LauncherItem*>(m_launcherModel->get(index)); |
1061 | + |
1062 | + QVariantList retval; |
1063 | + if (message.member() == "Get") { |
1064 | + if (!item) { |
1065 | + return false; |
1066 | + } |
1067 | + if (message.arguments()[1].toString() == "count") { |
1068 | + retval.append(QVariant::fromValue(QDBusVariant(item->count()))); |
1069 | + } else if (message.arguments()[1].toString() == "countVisible") { |
1070 | + retval.append(QVariant::fromValue(QDBusVariant(item->countVisible()))); |
1071 | + } |
1072 | + } else if (message.member() == "Set") { |
1073 | + if (message.arguments()[1].toString() == "count") { |
1074 | + int newCount = message.arguments()[2].toInt(); |
1075 | + if (!item || newCount != item->count()) { |
1076 | + Q_EMIT countChanged(appid, newCount); |
1077 | + emitPropChangedDbus(appid, "count", QVariant(newCount)); |
1078 | + } |
1079 | + } else if (message.arguments()[1].toString() == "countVisible") { |
1080 | + bool newVisible = message.arguments()[2].toBool(); |
1081 | + if (!item || newVisible != item->countVisible()) { |
1082 | + Q_EMIT countVisibleChanged(appid, newVisible); |
1083 | + emitPropChangedDbus(appid, "countVisible", newVisible); |
1084 | + } |
1085 | + } |
1086 | + } else if (message.member() == "GetAll") { |
1087 | + if (item) { |
1088 | + QVariantMap all; |
1089 | + all.insert("count", item->count()); |
1090 | + all.insert("countVisible", item->countVisible()); |
1091 | + retval.append(all); |
1092 | + } |
1093 | + } else { |
1094 | + return false; |
1095 | + } |
1096 | + |
1097 | + QDBusMessage reply = message.createReply(retval); |
1098 | + return connection.send(reply); |
1099 | +} |
1100 | + |
1101 | +void DBusInterface::emitPropChangedDbus(const QString& appId, const QString& property, const QVariant &value) |
1102 | +{ |
1103 | + QString path("/com/canonical/Unity/Launcher/"); |
1104 | + path.append(encodeAppId(appId)); |
1105 | + |
1106 | + QDBusMessage message = QDBusMessage::createSignal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"); |
1107 | + |
1108 | + QList<QVariant> arguments; |
1109 | + QVariantHash changedprops; |
1110 | + changedprops[property] = QVariant::fromValue(QDBusVariant(value)); |
1111 | + QVariantList deletedprops; |
1112 | + |
1113 | + arguments.append(changedprops); |
1114 | + arguments.append(deletedprops); |
1115 | + |
1116 | + message.setArguments(arguments); |
1117 | + |
1118 | + QDBusConnection con = QDBusConnection::sessionBus(); |
1119 | + con.send(message); |
1120 | +} |
1121 | |
1122 | === added file 'plugins/Unity/Launcher/dbusinterface.h' |
1123 | --- plugins/Unity/Launcher/dbusinterface.h 1970-01-01 00:00:00 +0000 |
1124 | +++ plugins/Unity/Launcher/dbusinterface.h 2014-09-18 21:04:46 +0000 |
1125 | @@ -0,0 +1,50 @@ |
1126 | +/* |
1127 | + * Copyright 2014 Canonical Ltd. |
1128 | + * |
1129 | + * This program is free software; you can redistribute it and/or modify |
1130 | + * it under the terms of the GNU Lesser General Public License as published by |
1131 | + * the Free Software Foundation; version 3. |
1132 | + * |
1133 | + * This program is distributed in the hope that it will be useful, |
1134 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1135 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1136 | + * GNU Lesser General Public License for more details. |
1137 | + * |
1138 | + * You should have received a copy of the GNU Lesser General Public License |
1139 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1140 | + * |
1141 | + * Authors: |
1142 | + * Michael Zanetti <michael.zanetti@canonical.com> |
1143 | + */ |
1144 | + |
1145 | +#include "launcheritem.h" |
1146 | + |
1147 | +#include <QDBusVirtualObject> |
1148 | + |
1149 | +class LauncherModel; |
1150 | + |
1151 | +class DBusInterface: public QDBusVirtualObject |
1152 | +{ |
1153 | + Q_OBJECT |
1154 | +public: |
1155 | + DBusInterface(LauncherModel *parent); |
1156 | + ~DBusInterface(); |
1157 | + |
1158 | + // QDBusVirtualObject implementaition |
1159 | + QString introspect (const QString &path) const override; |
1160 | + bool handleMessage(const QDBusMessage& message, const QDBusConnection& connection) override; |
1161 | + |
1162 | +Q_SIGNALS: |
1163 | + void countChanged(const QString &appId, int count); |
1164 | + void countVisibleChanged(const QString &appId, bool countVisible); |
1165 | + void refreshCalled(); |
1166 | + |
1167 | +private: |
1168 | + static QString decodeAppId(const QString& path); |
1169 | + static QString encodeAppId(const QString& appId); |
1170 | + |
1171 | + void emitPropChangedDbus(const QString& appId, const QString& property, const QVariant &value); |
1172 | + |
1173 | + LauncherModel *m_launcherModel; |
1174 | + |
1175 | +}; |
1176 | |
1177 | === added file 'plugins/Unity/Launcher/desktopfilehandler.cpp' |
1178 | --- plugins/Unity/Launcher/desktopfilehandler.cpp 1970-01-01 00:00:00 +0000 |
1179 | +++ plugins/Unity/Launcher/desktopfilehandler.cpp 2014-09-18 21:04:46 +0000 |
1180 | @@ -0,0 +1,151 @@ |
1181 | +/* |
1182 | + * Copyright 2014 Canonical Ltd. |
1183 | + * |
1184 | + * This program is free software; you can redistribute it and/or modify |
1185 | + * it under the terms of the GNU Lesser General Public License as published by |
1186 | + * the Free Software Foundation; version 3. |
1187 | + * |
1188 | + * This program is distributed in the hope that it will be useful, |
1189 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1190 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1191 | + * GNU Lesser General Public License for more details. |
1192 | + * |
1193 | + * You should have received a copy of the GNU Lesser General Public License |
1194 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1195 | + * |
1196 | + * Authors: |
1197 | + * Michael Zanetti <michael.zanetti@canonical.com> |
1198 | + */ |
1199 | + |
1200 | +#include "desktopfilehandler.h" |
1201 | + |
1202 | +#include <QStringList> |
1203 | +#include <QStandardPaths> |
1204 | +#include <QDir> |
1205 | +#include <QSettings> |
1206 | +#include <QLocale> |
1207 | + |
1208 | +#include <libintl.h> |
1209 | + |
1210 | +DesktopFileHandler::DesktopFileHandler(const QString &appId, QObject *parent): |
1211 | + QObject(parent), |
1212 | + m_appId(appId) |
1213 | +{ |
1214 | + load(); |
1215 | +} |
1216 | + |
1217 | +QString DesktopFileHandler::appId() const |
1218 | +{ |
1219 | + return m_appId; |
1220 | +} |
1221 | + |
1222 | +void DesktopFileHandler::setAppId(const QString &appId) |
1223 | +{ |
1224 | + if (m_appId != appId) { |
1225 | + m_appId = appId; |
1226 | + load(); |
1227 | + } |
1228 | +} |
1229 | + |
1230 | +QString DesktopFileHandler::filename() const |
1231 | +{ |
1232 | + return m_filename; |
1233 | +} |
1234 | + |
1235 | +bool DesktopFileHandler::isValid() const |
1236 | +{ |
1237 | + return !m_filename.isEmpty(); |
1238 | +} |
1239 | + |
1240 | +void DesktopFileHandler::load() |
1241 | +{ |
1242 | + m_filename.clear(); |
1243 | + |
1244 | + if (m_appId.isEmpty()) { |
1245 | + return; |
1246 | + } |
1247 | + |
1248 | + int dashPos = -1; |
1249 | + QString helper = m_appId; |
1250 | + |
1251 | + QStringList searchDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); |
1252 | +#ifdef LAUNCHER_TESTING |
1253 | + searchDirs << ""; |
1254 | +#endif |
1255 | + |
1256 | + QString path; |
1257 | + do { |
1258 | + if (dashPos != -1) { |
1259 | + helper.replace(dashPos, 1, '/'); |
1260 | + } |
1261 | + |
1262 | + if (helper.contains("/")) { |
1263 | + path += helper.split('/').first() + '/'; |
1264 | + helper.remove(QRegExp("^" + path)); |
1265 | + } |
1266 | + |
1267 | + Q_FOREACH(const QString &searchDirName, searchDirs) { |
1268 | + QDir searchDir(searchDirName + "/" + path); |
1269 | + Q_FOREACH(const QString &desktopFile, searchDir.entryList(QStringList() << "*.desktop")) { |
1270 | + if (desktopFile.startsWith(helper)) { |
1271 | + QFileInfo fileInfo(searchDir, desktopFile); |
1272 | + m_filename = fileInfo.absoluteFilePath(); |
1273 | + return; |
1274 | + } |
1275 | + } |
1276 | + } |
1277 | + |
1278 | + dashPos = helper.indexOf("-"); |
1279 | + } while (dashPos != -1); |
1280 | +} |
1281 | + |
1282 | +QString DesktopFileHandler::displayName() const |
1283 | +{ |
1284 | + if (!isValid()) { |
1285 | + return QString(); |
1286 | + } |
1287 | + |
1288 | + QSettings settings(m_filename, QSettings::IniFormat); |
1289 | + settings.beginGroup("Desktop Entry"); |
1290 | + |
1291 | + // First try to find Name[xx_YY] and Name[xx] in .desktop file |
1292 | + QString locale = QLocale::system().name(); |
1293 | + QString shortLocale = locale.split('_').first(); |
1294 | + |
1295 | + if (locale != shortLocale && settings.contains(QString("Name[%1]").arg(locale))) { |
1296 | + return settings.value(QString("Name[%1]").arg(locale)).toString(); |
1297 | + } |
1298 | + |
1299 | + if (settings.contains(QString("Name[%1]").arg(shortLocale))) { |
1300 | + return settings.value(QString("Name[%1]").arg(shortLocale)).toString(); |
1301 | + } |
1302 | + |
1303 | + // No translation found in desktop file. Get the untranslated one and have a go with gettext. |
1304 | + QString displayName = settings.value("Name").toString(); |
1305 | + |
1306 | + if (settings.contains("X-Ubuntu-Gettext-Domain")) { |
1307 | + const QString domain = settings.value("X-Ubuntu-Gettext-Domain").toString(); |
1308 | + return dgettext(domain.toUtf8().constData(), displayName.toUtf8().constData()); |
1309 | + } |
1310 | + |
1311 | + return displayName; |
1312 | +} |
1313 | + |
1314 | +QString DesktopFileHandler::icon() const |
1315 | +{ |
1316 | + if (!isValid()) { |
1317 | + return QString(); |
1318 | + } |
1319 | + |
1320 | + QSettings settings(m_filename, QSettings::IniFormat); |
1321 | + settings.beginGroup("Desktop Entry"); |
1322 | + QString iconString = settings.value("Icon").toString(); |
1323 | + QString pathString = settings.value("Path").toString(); |
1324 | + |
1325 | + if (QFileInfo(iconString).exists()) { |
1326 | + return QFileInfo(iconString).absoluteFilePath(); |
1327 | + } else if (QFileInfo(pathString + '/' + iconString).exists()) { |
1328 | + return pathString + '/' + iconString; |
1329 | + } |
1330 | + return "image://theme/" + iconString; |
1331 | +} |
1332 | |
1333 | === added file 'plugins/Unity/Launcher/desktopfilehandler.h' |
1334 | --- plugins/Unity/Launcher/desktopfilehandler.h 1970-01-01 00:00:00 +0000 |
1335 | +++ plugins/Unity/Launcher/desktopfilehandler.h 2014-09-18 21:04:46 +0000 |
1336 | @@ -0,0 +1,56 @@ |
1337 | +/* |
1338 | + * Copyright 2014 Canonical Ltd. |
1339 | + * |
1340 | + * This program is free software; you can redistribute it and/or modify |
1341 | + * it under the terms of the GNU Lesser General Public License as published by |
1342 | + * the Free Software Foundation; version 3. |
1343 | + * |
1344 | + * This program is distributed in the hope that it will be useful, |
1345 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1346 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1347 | + * GNU Lesser General Public License for more details. |
1348 | + * |
1349 | + * You should have received a copy of the GNU Lesser General Public License |
1350 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1351 | + * |
1352 | + * Authors: |
1353 | + * Michael Zanetti <michael.zanetti@canonical.com> |
1354 | + */ |
1355 | + |
1356 | +#ifndef DESKTOPFILEHANDLER_H |
1357 | +#define DESKTOPFILEHANDLER_H |
1358 | + |
1359 | +#include <QObject> |
1360 | + |
1361 | +/** |
1362 | + * When an object of this class is created or whenever setAppId(appId) is called, |
1363 | + * this will search for a .desktop file matching the give appId. If a file is |
1364 | + * found, isValid() will return true and the other methods return the contents |
1365 | + * of the .desktop file. |
1366 | + * |
1367 | + * Note that this class will consider the user's locale and do a best effort |
1368 | + * to return localized values. |
1369 | + */ |
1370 | + |
1371 | +class DesktopFileHandler: public QObject |
1372 | +{ |
1373 | + Q_OBJECT |
1374 | +public: |
1375 | + DesktopFileHandler(const QString &appId = QString(), QObject *parent = nullptr); |
1376 | + |
1377 | + QString appId() const; |
1378 | + void setAppId(const QString &appId); |
1379 | + |
1380 | + bool isValid() const; |
1381 | + QString filename() const; |
1382 | + QString displayName() const; |
1383 | + QString icon() const; |
1384 | + |
1385 | +private: |
1386 | + void load(); |
1387 | + |
1388 | + QString m_appId; |
1389 | + QString m_filename; |
1390 | +}; |
1391 | + |
1392 | +#endif |
1393 | |
1394 | === added file 'plugins/Unity/Launcher/gsettings.cpp' |
1395 | --- plugins/Unity/Launcher/gsettings.cpp 1970-01-01 00:00:00 +0000 |
1396 | +++ plugins/Unity/Launcher/gsettings.cpp 2014-09-18 21:04:46 +0000 |
1397 | @@ -0,0 +1,66 @@ |
1398 | +/* |
1399 | + * Copyright 2014 Canonical Ltd. |
1400 | + * |
1401 | + * This program is free software; you can redistribute it and/or modify |
1402 | + * it under the terms of the GNU Lesser General Public License as published by |
1403 | + * the Free Software Foundation; version 3. |
1404 | + * |
1405 | + * This program is distributed in the hope that it will be useful, |
1406 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1407 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1408 | + * GNU Lesser General Public License for more details. |
1409 | + * |
1410 | + * You should have received a copy of the GNU Lesser General Public License |
1411 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1412 | + * |
1413 | + * Authors: |
1414 | + * Michael Zanetti <michael.zanetti@canonical.com> |
1415 | + */ |
1416 | + |
1417 | +#include "gsettings.h" |
1418 | + |
1419 | +#include <QGSettings> |
1420 | +#include <QVariant> |
1421 | + |
1422 | +GSettings::GSettings(QObject *parent): |
1423 | + QObject(parent) |
1424 | +{ |
1425 | + |
1426 | +} |
1427 | + |
1428 | +QStringList GSettings::storedApplications() const |
1429 | +{ |
1430 | + QStringList storedApps; |
1431 | + |
1432 | + QGSettings gSettings("com.canonical.Unity.Launcher", "/com/canonical/unity/launcher/"); |
1433 | + |
1434 | + Q_FOREACH(const QString &entry, gSettings.get("items").toStringList()) { |
1435 | + if (entry.startsWith("application:///")) { |
1436 | + // convert legacy entries to new world appids |
1437 | + QString appId = entry; |
1438 | + // Transform "application://foobar.desktop" to "foobar" |
1439 | + appId.remove(QRegExp("^application:///")); |
1440 | + appId.remove(QRegExp(".desktop$")); |
1441 | + storedApps << appId; |
1442 | + } else if (entry.startsWith("appid://")) { |
1443 | + QString appId = entry; |
1444 | + appId.remove("appid://"); |
1445 | + if (appId.split('/').count() == 3) { |
1446 | + // Strip current-user-version in case its there |
1447 | + appId = appId.split('/').first() + "_" + appId.split('/').at(1); |
1448 | + } |
1449 | + storedApps << appId; |
1450 | + } |
1451 | + } |
1452 | + return storedApps; |
1453 | +} |
1454 | + |
1455 | +void GSettings::setStoredApplications(const QStringList &storedApplications) |
1456 | +{ |
1457 | + QGSettings gSettings("com.canonical.Unity.Launcher", "/com/canonical/unity/launcher/"); |
1458 | + QStringList gSettingsList; |
1459 | + Q_FOREACH(const QString &entry, storedApplications) { |
1460 | + gSettingsList << QString("appid://%1").arg(entry); |
1461 | + } |
1462 | + gSettings.set("items", gSettingsList); |
1463 | +} |
1464 | |
1465 | === added file 'plugins/Unity/Launcher/gsettings.h' |
1466 | --- plugins/Unity/Launcher/gsettings.h 1970-01-01 00:00:00 +0000 |
1467 | +++ plugins/Unity/Launcher/gsettings.h 2014-09-18 21:04:46 +0000 |
1468 | @@ -0,0 +1,37 @@ |
1469 | +/* |
1470 | + * Copyright 2014 Canonical Ltd. |
1471 | + * |
1472 | + * This program is free software; you can redistribute it and/or modify |
1473 | + * it under the terms of the GNU Lesser General Public License as published by |
1474 | + * the Free Software Foundation; version 3. |
1475 | + * |
1476 | + * This program is distributed in the hope that it will be useful, |
1477 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1478 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1479 | + * GNU Lesser General Public License for more details. |
1480 | + * |
1481 | + * You should have received a copy of the GNU Lesser General Public License |
1482 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1483 | + * |
1484 | + * Authors: |
1485 | + * Michael Zanetti <michael.zanetti@canonical.com> |
1486 | + */ |
1487 | + |
1488 | +#ifndef GSETTINGS_H |
1489 | +#define GSETTINGS_H |
1490 | + |
1491 | +#include <QObject> |
1492 | +#include <QStringList> |
1493 | + |
1494 | + |
1495 | +class GSettings: public QObject |
1496 | +{ |
1497 | + Q_OBJECT |
1498 | +public: |
1499 | + GSettings(QObject *parent = nullptr); |
1500 | + |
1501 | + QStringList storedApplications() const; |
1502 | + void setStoredApplications(const QStringList &storedApplications); |
1503 | +}; |
1504 | + |
1505 | +#endif |
1506 | |
1507 | === modified file 'plugins/Unity/Launcher/launcheritem.cpp' |
1508 | --- plugins/Unity/Launcher/launcheritem.cpp 2014-09-02 11:11:01 +0000 |
1509 | +++ plugins/Unity/Launcher/launcheritem.cpp 2014-09-18 21:04:46 +0000 |
1510 | @@ -32,6 +32,7 @@ |
1511 | m_recent(false), |
1512 | m_progress(-1), |
1513 | m_count(0), |
1514 | + m_countVisible(false), |
1515 | m_focused(false), |
1516 | m_quickList(new QuickListModel(this)) |
1517 | { |
1518 | @@ -55,11 +56,27 @@ |
1519 | return m_name; |
1520 | } |
1521 | |
1522 | +void LauncherItem::setName(const QString &name) |
1523 | +{ |
1524 | + if (m_name != name) { |
1525 | + m_name = name; |
1526 | + Q_EMIT nameChanged(name); |
1527 | + } |
1528 | +} |
1529 | + |
1530 | QString LauncherItem::icon() const |
1531 | { |
1532 | return m_icon; |
1533 | } |
1534 | |
1535 | +void LauncherItem::setIcon(const QString &icon) |
1536 | +{ |
1537 | + if (m_icon != icon) { |
1538 | + m_icon = icon; |
1539 | + Q_EMIT iconChanged(icon); |
1540 | + } |
1541 | +} |
1542 | + |
1543 | bool LauncherItem::pinned() const |
1544 | { |
1545 | return m_pinned; |
1546 | @@ -129,6 +146,19 @@ |
1547 | } |
1548 | } |
1549 | |
1550 | +bool LauncherItem::countVisible() const |
1551 | +{ |
1552 | + return m_countVisible; |
1553 | +} |
1554 | + |
1555 | +void LauncherItem::setCountVisible(bool countVisible) |
1556 | +{ |
1557 | + if (m_countVisible != countVisible) { |
1558 | + m_countVisible = countVisible; |
1559 | + Q_EMIT countVisibleChanged(countVisible); |
1560 | + } |
1561 | +} |
1562 | + |
1563 | bool LauncherItem::focused() const |
1564 | { |
1565 | return m_focused; |
1566 | |
1567 | === modified file 'plugins/Unity/Launcher/launcheritem.h' |
1568 | --- plugins/Unity/Launcher/launcheritem.h 2014-06-11 15:36:51 +0000 |
1569 | +++ plugins/Unity/Launcher/launcheritem.h 2014-09-18 21:04:46 +0000 |
1570 | @@ -34,34 +34,30 @@ |
1571 | public: |
1572 | LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent = 0); |
1573 | |
1574 | - QString appId() const; |
1575 | - QString name() const; |
1576 | - QString icon() const; |
1577 | - |
1578 | - bool pinned() const; |
1579 | + QString appId() const override; |
1580 | + QString name() const override; |
1581 | + QString icon() const override; |
1582 | + bool pinned() const override; |
1583 | + bool running() const override; |
1584 | + bool recent() const override; |
1585 | + int progress() const override; |
1586 | + int count() const override; |
1587 | + bool countVisible() const override; |
1588 | + bool focused() const override; |
1589 | + |
1590 | + unity::shell::launcher::QuickListModelInterface *quickList() const override; |
1591 | + |
1592 | +private: |
1593 | + void setName(const QString &name); |
1594 | + void setIcon(const QString &icon); |
1595 | void setPinned(bool pinned); |
1596 | - |
1597 | - bool running() const; |
1598 | void setRunning(bool running); |
1599 | - |
1600 | - bool recent() const; |
1601 | void setRecent(bool recent); |
1602 | - |
1603 | - int progress() const; |
1604 | void setProgress(int progress); |
1605 | - |
1606 | - int count() const; |
1607 | void setCount(int count); |
1608 | - |
1609 | - bool focused() const; |
1610 | + void setCountVisible(bool countVisible); |
1611 | void setFocused(bool focused); |
1612 | |
1613 | - unity::shell::launcher::QuickListModelInterface *quickList() const; |
1614 | - |
1615 | -Q_SIGNALS: |
1616 | - void favoriteChanged(bool favorite); |
1617 | - void runningChanged(bool running); |
1618 | - |
1619 | private: |
1620 | QString m_appId; |
1621 | QString m_name; |
1622 | @@ -71,8 +67,11 @@ |
1623 | bool m_recent; |
1624 | int m_progress; |
1625 | int m_count; |
1626 | + bool m_countVisible; |
1627 | bool m_focused; |
1628 | QuickListModel *m_quickList; |
1629 | + |
1630 | + friend class LauncherModel; |
1631 | }; |
1632 | |
1633 | #endif // LAUNCHERITEM_H |
1634 | |
1635 | === modified file 'plugins/Unity/Launcher/launchermodel.cpp' |
1636 | --- plugins/Unity/Launcher/launchermodel.cpp 2014-09-02 11:11:01 +0000 |
1637 | +++ plugins/Unity/Launcher/launchermodel.cpp 2014-09-18 21:04:46 +0000 |
1638 | @@ -19,7 +19,9 @@ |
1639 | |
1640 | #include "launchermodel.h" |
1641 | #include "launcheritem.h" |
1642 | -#include "backend/launcherbackend.h" |
1643 | +#include "gsettings.h" |
1644 | +#include "desktopfilehandler.h" |
1645 | +#include "dbusinterface.h" |
1646 | |
1647 | #include <unity/shell/application/ApplicationInfoInterface.h> |
1648 | |
1649 | @@ -30,16 +32,24 @@ |
1650 | |
1651 | LauncherModel::LauncherModel(QObject *parent): |
1652 | LauncherModelInterface(parent), |
1653 | - m_backend(new LauncherBackend(this)), |
1654 | + m_settings(new GSettings(this)), |
1655 | + m_dbusIface(new DBusInterface(this)), |
1656 | m_appManager(0) |
1657 | { |
1658 | - connect(m_backend, SIGNAL(countChanged(QString,int)), SLOT(countChanged(QString,int))); |
1659 | - connect(m_backend, SIGNAL(progressChanged(QString,int)), SLOT(progressChanged(QString,int))); |
1660 | - |
1661 | - Q_FOREACH (const QString &entry, m_backend->storedApplications()) { |
1662 | + connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged); |
1663 | + connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged); |
1664 | + connect(m_dbusIface, &DBusInterface::refreshCalled, this, &LauncherModel::refresh); |
1665 | + |
1666 | + Q_FOREACH (const QString &entry, m_settings->storedApplications()) { |
1667 | + DesktopFileHandler desktopFile(entry); |
1668 | + if (!desktopFile.isValid()) { |
1669 | + qWarning() << "Couldn't find a .desktop file for" << entry << ". Skipping..."; |
1670 | + continue; |
1671 | + } |
1672 | + |
1673 | LauncherItem *item = new LauncherItem(entry, |
1674 | - m_backend->displayName(entry), |
1675 | - m_backend->icon(entry), |
1676 | + desktopFile.displayName(), |
1677 | + desktopFile.icon(), |
1678 | this); |
1679 | item->setPinned(true); |
1680 | m_list.append(item); |
1681 | @@ -73,6 +83,8 @@ |
1682 | return item->pinned(); |
1683 | case RoleCount: |
1684 | return item->count(); |
1685 | + case RoleCountVisible: |
1686 | + return item->countVisible(); |
1687 | case RoleProgress: |
1688 | return item->progress(); |
1689 | case RoleFocused: |
1690 | @@ -139,10 +151,17 @@ |
1691 | if (index == -1) { |
1692 | index = m_list.count(); |
1693 | } |
1694 | + |
1695 | + DesktopFileHandler desktopFile(appId); |
1696 | + if (!desktopFile.isValid()) { |
1697 | + qWarning() << "Can't pin this application, there is no .destkop file available."; |
1698 | + return; |
1699 | + } |
1700 | + |
1701 | beginInsertRows(QModelIndex(), index, index); |
1702 | LauncherItem *item = new LauncherItem(appId, |
1703 | - m_backend->displayName(appId), |
1704 | - m_backend->icon(appId), |
1705 | + desktopFile.displayName(), |
1706 | + desktopFile.icon(), |
1707 | this); |
1708 | item->setPinned(true); |
1709 | m_list.insert(index, item); |
1710 | @@ -197,25 +216,27 @@ |
1711 | |
1712 | // Nope, we don't know this action, let the backend forward it to the application |
1713 | } else { |
1714 | - m_backend->triggerQuickListAction(appId, actionId); |
1715 | + // TODO: forward quicklist action to app, possibly via m_dbusIface |
1716 | } |
1717 | } |
1718 | } |
1719 | |
1720 | void LauncherModel::setUser(const QString &username) |
1721 | { |
1722 | - m_backend->setUser(username); |
1723 | + Q_UNUSED(username) |
1724 | + qWarning() << "This backend doesn't support multiple users"; |
1725 | } |
1726 | |
1727 | QString LauncherModel::getUrlForAppId(const QString &appId) const |
1728 | { |
1729 | // appId is either an appId or a legacy app name. Let's find out which |
1730 | - if (appId.isEmpty()) |
1731 | + if (appId.isEmpty()) { |
1732 | return QString(); |
1733 | + } |
1734 | |
1735 | - QString df = m_backend->desktopFile(appId + ".desktop"); |
1736 | - if (!df.isEmpty()) |
1737 | + if (!appId.contains("_")) { |
1738 | return "application:///" + appId + ".desktop"; |
1739 | + } |
1740 | |
1741 | QStringList parts = appId.split('_'); |
1742 | QString package = parts.value(0); |
1743 | @@ -275,7 +296,7 @@ |
1744 | appIds << item->appId(); |
1745 | } |
1746 | } |
1747 | - m_backend->setStoredApplications(appIds); |
1748 | + m_settings->setStoredApplications(appIds); |
1749 | } |
1750 | |
1751 | int LauncherModel::findApplication(const QString &appId) |
1752 | @@ -310,6 +331,55 @@ |
1753 | } |
1754 | } |
1755 | |
1756 | +void LauncherModel::countVisibleChanged(const QString &appId, int countVisible) |
1757 | +{ |
1758 | + int idx = findApplication(appId); |
1759 | + if (idx >= 0) { |
1760 | + LauncherItem *item = m_list.at(idx); |
1761 | + item->setCountVisible(countVisible); |
1762 | + Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCountVisible); |
1763 | + |
1764 | + // If countVisible goes to false, and the item is neither pinned nor recent we can drop it |
1765 | + if (!countVisible && !item->pinned() && !item->recent()) { |
1766 | + beginRemoveRows(QModelIndex(), idx, idx); |
1767 | + m_list.takeAt(idx)->deleteLater(); |
1768 | + endRemoveRows(); |
1769 | + } |
1770 | + } else { |
1771 | + // Need to create a new LauncherItem and show the highlight |
1772 | + DesktopFileHandler desktopFile(appId); |
1773 | + if (countVisible && desktopFile.isValid()) { |
1774 | + LauncherItem *item = new LauncherItem(appId, |
1775 | + desktopFile.displayName(), |
1776 | + desktopFile.icon()); |
1777 | + item->setCountVisible(true); |
1778 | + beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); |
1779 | + m_list.append(item); |
1780 | + endInsertRows(); |
1781 | + } |
1782 | + } |
1783 | +} |
1784 | + |
1785 | +void LauncherModel::refresh() |
1786 | +{ |
1787 | + QList<LauncherItem*> toBeRemoved; |
1788 | + Q_FOREACH (LauncherItem* item, m_list) { |
1789 | + DesktopFileHandler desktopFile(item->appId()); |
1790 | + if (!desktopFile.isValid()) { |
1791 | + toBeRemoved << item; |
1792 | + } else { |
1793 | + int idx = m_list.indexOf(item); |
1794 | + item->setName(desktopFile.displayName()); |
1795 | + item->setIcon(desktopFile.icon()); |
1796 | + Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleName << RoleIcon); |
1797 | + } |
1798 | + } |
1799 | + |
1800 | + Q_FOREACH (LauncherItem* item, toBeRemoved) { |
1801 | + requestRemove(item->appId()); |
1802 | + } |
1803 | +} |
1804 | + |
1805 | void LauncherModel::applicationAdded(const QModelIndex &parent, int row) |
1806 | { |
1807 | Q_UNUSED(parent); |
1808 | |
1809 | === modified file 'plugins/Unity/Launcher/launchermodel.h' |
1810 | --- plugins/Unity/Launcher/launchermodel.h 2014-06-11 15:36:51 +0000 |
1811 | +++ plugins/Unity/Launcher/launchermodel.h 2014-09-18 21:04:46 +0000 |
1812 | @@ -20,15 +20,14 @@ |
1813 | #ifndef LAUNCHERMODEL_H |
1814 | #define LAUNCHERMODEL_H |
1815 | |
1816 | -// unity-api |
1817 | #include <unity/shell/launcher/LauncherModelInterface.h> |
1818 | #include <unity/shell/application/ApplicationManagerInterface.h> |
1819 | |
1820 | -// Qt |
1821 | #include <QAbstractListModel> |
1822 | |
1823 | class LauncherItem; |
1824 | -class LauncherBackend; |
1825 | +class GSettings; |
1826 | +class DBusInterface; |
1827 | |
1828 | using namespace unity::shell::launcher; |
1829 | using namespace unity::shell::application; |
1830 | @@ -41,14 +40,13 @@ |
1831 | LauncherModel(QObject *parent = 0); |
1832 | ~LauncherModel(); |
1833 | |
1834 | - int rowCount(const QModelIndex &parent) const; |
1835 | + int rowCount(const QModelIndex &parent = QModelIndex()) const; |
1836 | |
1837 | QVariant data(const QModelIndex &index, int role) const; |
1838 | |
1839 | Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const; |
1840 | Q_INVOKABLE void move(int oldIndex, int newIndex); |
1841 | Q_INVOKABLE void pin(const QString &appId, int index = -1); |
1842 | - Q_INVOKABLE void requestRemove(const QString &appId); |
1843 | Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex); |
1844 | Q_INVOKABLE void setUser(const QString &username); |
1845 | Q_INVOKABLE QString getUrlForAppId(const QString &appId) const; |
1846 | @@ -56,13 +54,19 @@ |
1847 | unity::shell::application::ApplicationManagerInterface* applicationManager() const; |
1848 | void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager); |
1849 | |
1850 | + int findApplication(const QString &appId); |
1851 | + |
1852 | +public Q_SLOTS: |
1853 | + void requestRemove(const QString &appId); |
1854 | + |
1855 | private: |
1856 | void storeAppList(); |
1857 | - int findApplication(const QString &appId); |
1858 | |
1859 | private Q_SLOTS: |
1860 | + void countChanged(const QString &appId, int count); |
1861 | + void countVisibleChanged(const QString &appId, int count); |
1862 | void progressChanged(const QString &appId, int progress); |
1863 | - void countChanged(const QString &appId, int count); |
1864 | + void refresh(); |
1865 | |
1866 | void applicationAdded(const QModelIndex &parent, int row); |
1867 | void applicationRemoved(const QModelIndex &parent, int row); |
1868 | @@ -70,7 +74,10 @@ |
1869 | |
1870 | private: |
1871 | QList<LauncherItem*> m_list; |
1872 | - LauncherBackend *m_backend; |
1873 | + |
1874 | + GSettings *m_settings; |
1875 | + DBusInterface *m_dbusIface; |
1876 | + |
1877 | ApplicationManagerInterface *m_appManager; |
1878 | }; |
1879 | |
1880 | |
1881 | === renamed file 'plugins/Unity/Launcher/common/quicklistentry.cpp' => 'plugins/Unity/Launcher/quicklistentry.cpp' |
1882 | === renamed file 'plugins/Unity/Launcher/common/quicklistentry.h' => 'plugins/Unity/Launcher/quicklistentry.h' |
1883 | === modified file 'plugins/Unity/Launcher/quicklistmodel.h' |
1884 | --- plugins/Unity/Launcher/quicklistmodel.h 2013-07-24 10:42:00 +0000 |
1885 | +++ plugins/Unity/Launcher/quicklistmodel.h 2014-09-18 21:04:46 +0000 |
1886 | @@ -20,7 +20,7 @@ |
1887 | #ifndef QUICKLISTMODEL_H |
1888 | #define QUICKLISTMODEL_H |
1889 | |
1890 | -#include "common/quicklistentry.h" |
1891 | +#include "quicklistentry.h" |
1892 | |
1893 | #include <unity/shell/launcher/QuickListModelInterface.h> |
1894 | |
1895 | |
1896 | === modified file 'qml/Launcher/LauncherDelegate.qml' |
1897 | --- qml/Launcher/LauncherDelegate.qml 2014-08-11 15:54:10 +0000 |
1898 | +++ qml/Launcher/LauncherDelegate.qml 2014-09-18 21:04:46 +0000 |
1899 | @@ -21,7 +21,8 @@ |
1900 | id: root |
1901 | |
1902 | property string iconName |
1903 | - property int count: -1 |
1904 | + property int count: 0 |
1905 | + property bool countVisible: false |
1906 | property int progress: -1 |
1907 | property bool itemFocused: false |
1908 | property real maxAngle: 0 |
1909 | @@ -80,11 +81,12 @@ |
1910 | width: Math.min(root.itemWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1))) |
1911 | height: units.gu(2) |
1912 | color: UbuntuColors.orange |
1913 | - visible: root.count > 0 |
1914 | + visible: root.countVisible |
1915 | borderSource: "none" |
1916 | |
1917 | Label { |
1918 | id: countLabel |
1919 | + objectName: "countLabel" |
1920 | text: root.count |
1921 | anchors.centerIn: parent |
1922 | // FIXME: verticalCenter seems to be off wee bit and QML doesn't have a centerLine |
1923 | |
1924 | === modified file 'qml/Launcher/LauncherPanel.qml' |
1925 | --- qml/Launcher/LauncherPanel.qml 2014-08-12 16:21:21 +0000 |
1926 | +++ qml/Launcher/LauncherPanel.qml 2014-09-18 21:04:46 +0000 |
1927 | @@ -156,6 +156,7 @@ |
1928 | height: itemHeight |
1929 | iconName: model.icon |
1930 | count: model.count |
1931 | + countVisible: model.countVisible |
1932 | progress: model.progress |
1933 | clipCorner: model.pinned |
1934 | itemFocused: model.focused |
1935 | |
1936 | === modified file 'tests/mocks/Unity/Launcher/CMakeLists.txt' |
1937 | --- tests/mocks/Unity/Launcher/CMakeLists.txt 2014-06-17 18:23:44 +0000 |
1938 | +++ tests/mocks/Unity/Launcher/CMakeLists.txt 2014-09-18 21:04:46 +0000 |
1939 | @@ -1,4 +1,4 @@ |
1940 | -pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3) |
1941 | +pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=4) |
1942 | |
1943 | include_directories( |
1944 | ${CMAKE_CURRENT_SOURCE_DIR} |
1945 | |
1946 | === modified file 'tests/mocks/Unity/Launcher/MockLauncherItem.cpp' |
1947 | --- tests/mocks/Unity/Launcher/MockLauncherItem.cpp 2014-06-17 18:23:44 +0000 |
1948 | +++ tests/mocks/Unity/Launcher/MockLauncherItem.cpp 2014-09-18 21:04:46 +0000 |
1949 | @@ -35,6 +35,7 @@ |
1950 | m_recent(false), |
1951 | m_progress(-1), |
1952 | m_count(0), |
1953 | + m_countVisible(false), |
1954 | m_focused(false), |
1955 | m_quickList(new MockQuickListModel(this)) |
1956 | { |
1957 | @@ -131,6 +132,19 @@ |
1958 | } |
1959 | } |
1960 | |
1961 | +bool MockLauncherItem::countVisible() const |
1962 | +{ |
1963 | + return m_countVisible; |
1964 | +} |
1965 | + |
1966 | +void MockLauncherItem::setCountVisible(bool countVisible) |
1967 | +{ |
1968 | + if (m_countVisible != countVisible) { |
1969 | + m_countVisible = countVisible; |
1970 | + Q_EMIT countVisibleChanged(countVisible); |
1971 | + } |
1972 | +} |
1973 | + |
1974 | bool MockLauncherItem::focused() const |
1975 | { |
1976 | return m_focused; |
1977 | |
1978 | === modified file 'tests/mocks/Unity/Launcher/MockLauncherItem.h' |
1979 | --- tests/mocks/Unity/Launcher/MockLauncherItem.h 2013-09-04 22:44:01 +0000 |
1980 | +++ tests/mocks/Unity/Launcher/MockLauncherItem.h 2014-09-18 21:04:46 +0000 |
1981 | @@ -32,32 +32,30 @@ |
1982 | public: |
1983 | MockLauncherItem(const QString &appId, const QString& desktopFile, const QString& name, const QString& icon, QObject* parent = 0); |
1984 | |
1985 | - QString appId() const; |
1986 | + QString appId() const override; |
1987 | QString desktopFile() const; |
1988 | - QString name() const; |
1989 | - QString icon() const; |
1990 | - |
1991 | - bool pinned() const; |
1992 | + QString name() const override; |
1993 | + QString icon() const override; |
1994 | + |
1995 | + bool pinned() const override; |
1996 | + bool running() const override; |
1997 | + bool recent() const override; |
1998 | + int progress() const override; |
1999 | + int count() const override; |
2000 | + bool countVisible() const override; |
2001 | + bool focused() const; |
2002 | + |
2003 | + unity::shell::launcher::QuickListModelInterface *quickList() const; |
2004 | + |
2005 | +private: |
2006 | void setPinned(bool pinned); |
2007 | - |
2008 | - bool running() const; |
2009 | void setRunning(bool running); |
2010 | - |
2011 | - bool recent() const; |
2012 | void setRecent(bool recent); |
2013 | - |
2014 | - int progress() const; |
2015 | void setProgress(int progress); |
2016 | - |
2017 | - int count() const; |
2018 | void setCount(int count); |
2019 | - |
2020 | - bool focused() const; |
2021 | + void setCountVisible(bool countVisible); |
2022 | void setFocused(bool focused); |
2023 | |
2024 | - unity::shell::launcher::QuickListModelInterface *quickList() const; |
2025 | - |
2026 | -private: |
2027 | QString m_appId; |
2028 | QString m_desktopFile; |
2029 | QString m_name; |
2030 | @@ -67,8 +65,11 @@ |
2031 | bool m_recent; |
2032 | int m_progress; |
2033 | int m_count; |
2034 | + bool m_countVisible; |
2035 | bool m_focused; |
2036 | MockQuickListModel *m_quickList; |
2037 | + |
2038 | + friend class MockLauncherModel; |
2039 | }; |
2040 | |
2041 | #endif // MOCKLAUNCHERITEM_H |
2042 | |
2043 | === modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.cpp' |
2044 | --- tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2014-07-11 16:01:44 +0000 |
2045 | +++ tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2014-09-18 21:04:46 +0000 |
2046 | @@ -33,26 +33,32 @@ |
2047 | m_list.append(item); |
2048 | item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this); |
2049 | item->setProgress(50); |
2050 | + item->setCountVisible(true); |
2051 | m_list.append(item); |
2052 | item = new MockLauncherItem("facebook-webapp", "/usr/share/applications/facebook-webapp.desktop", "Facebook", "facebook", this); |
2053 | item->setProgress(150); |
2054 | m_list.append(item); |
2055 | item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this); |
2056 | item->setCount(1); |
2057 | + item->setCountVisible(true); |
2058 | m_list.append(item); |
2059 | item = new MockLauncherItem("twitter-webapp", "/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter", this); |
2060 | item->setCount(12); |
2061 | + item->setCountVisible(true); |
2062 | item->setPinned(true); |
2063 | m_list.append(item); |
2064 | item = new MockLauncherItem("gmail-webapp", "/usr/share/applications/gmail-webapp.desktop", "GMail", "gmail", this); |
2065 | item->setCount(123); |
2066 | + item->setCountVisible(true); |
2067 | m_list.append(item); |
2068 | item = new MockLauncherItem("ubuntu-weather-app", "/usr/share/applications/ubuntu-weather-app.desktop", "Weather", "weather", this); |
2069 | item->setCount(1234567890); |
2070 | + item->setCountVisible(true); |
2071 | m_list.append(item); |
2072 | item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this); |
2073 | item->setProgress(50); |
2074 | item->setCount(5); |
2075 | + item->setCountVisible(true); |
2076 | item->setFocused(true); |
2077 | item->setPinned(true); |
2078 | m_list.append(item); |
2079 | @@ -76,6 +82,8 @@ |
2080 | LauncherItemInterface *item = m_list.at(index.row()); |
2081 | switch(role) |
2082 | { |
2083 | + case RoleAppId: |
2084 | + return item->appId(); |
2085 | case RoleName: |
2086 | return item->name(); |
2087 | case RoleIcon: |
2088 | @@ -90,6 +98,8 @@ |
2089 | return item->progress(); |
2090 | case RoleCount: |
2091 | return item->count(); |
2092 | + case RoleCountVisible: |
2093 | + return item->countVisible(); |
2094 | case RoleFocused: |
2095 | return item->focused(); |
2096 | } |
2097 | |
2098 | === modified file 'tests/plugins/Unity/Launcher/CMakeLists.txt' |
2099 | --- tests/plugins/Unity/Launcher/CMakeLists.txt 2014-09-02 11:11:01 +0000 |
2100 | +++ tests/plugins/Unity/Launcher/CMakeLists.txt 2014-09-18 21:04:46 +0000 |
2101 | @@ -1,12 +1,11 @@ |
2102 | pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt) |
2103 | -pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3) |
2104 | +pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=4) |
2105 | pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=3) |
2106 | |
2107 | include_directories( |
2108 | ${CMAKE_CURRENT_BINARY_DIR} |
2109 | ${CMAKE_SOURCE_DIR}/plugins/AccountsService |
2110 | ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher |
2111 | - ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend |
2112 | ${GSETTINGS_QT_INCLUDE_DIRS} |
2113 | ) |
2114 | |
2115 | @@ -14,35 +13,21 @@ |
2116 | add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}") |
2117 | add_definitions(-DLAUNCHER_TESTING) |
2118 | |
2119 | -### LauncherBackendTest |
2120 | -set(testBackendCommand dbus-test-runner --task ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec |
2121 | - --parameter -o --parameter ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml |
2122 | +### LauncherModelTest |
2123 | +set(testModelCommand dbus-test-runner --task ${CMAKE_CURRENT_BINARY_DIR}/launchermodeltestExec |
2124 | + --parameter -o --parameter ${CMAKE_BINARY_DIR}/launchermodeltest.xml,xunitxml |
2125 | --parameter -o --parameter -,txt) |
2126 | -add_test(NAME launcherbackendtest COMMAND ${testBackendCommand}) |
2127 | -add_custom_target(launcherbackendtest ${testBackendCommand}) |
2128 | -add_executable(launcherbackendtestExec |
2129 | - launcherbackendtest.cpp |
2130 | - ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp |
2131 | - ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp |
2132 | - ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp |
2133 | - ) |
2134 | -target_link_libraries(launcherbackendtestExec ${GSETTINGS_QT_LDFLAGS}) |
2135 | -qt5_use_modules(launcherbackendtestExec Test Core DBus) |
2136 | - |
2137 | -### LauncherModelTest |
2138 | -set(testModelCommand ${CMAKE_CURRENT_BINARY_DIR}/launchermodeltestExec |
2139 | - -o ${CMAKE_BINARY_DIR}/launchermodeltest.xml,xunitxml |
2140 | - -o -,txt) |
2141 | add_test(NAME launchermodeltest COMMAND ${testModelCommand}) |
2142 | add_custom_target(launchermodeltest ${testModelCommand}) |
2143 | add_executable(launchermodeltestExec |
2144 | launchermodeltest.cpp |
2145 | + gsettings.cpp |
2146 | ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launchermodel.cpp |
2147 | ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launcheritem.cpp |
2148 | ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistmodel.cpp |
2149 | - ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp |
2150 | - ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp |
2151 | - ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp |
2152 | + ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/dbusinterface.cpp |
2153 | + ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/desktopfilehandler.cpp |
2154 | + ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistentry.cpp |
2155 | ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h |
2156 | ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h |
2157 | ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h |
2158 | @@ -50,7 +35,7 @@ |
2159 | ${LAUNCHER_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h |
2160 | ) |
2161 | target_link_libraries(launchermodeltestExec ${GSETTINGS_QT_LDFLAGS}) |
2162 | -qt5_use_modules(launchermodeltestExec Test Core DBus Gui) |
2163 | +qt5_use_modules(launchermodeltestExec Test Core DBus Xml Gui) |
2164 | |
2165 | # copy .desktop files into build directory for shadow builds |
2166 | file(GLOB DESKTOP_FILES *.desktop) |
2167 | |
2168 | === added file 'tests/plugins/Unity/Launcher/gsettings.cpp' |
2169 | --- tests/plugins/Unity/Launcher/gsettings.cpp 1970-01-01 00:00:00 +0000 |
2170 | +++ tests/plugins/Unity/Launcher/gsettings.cpp 2014-09-18 21:04:46 +0000 |
2171 | @@ -0,0 +1,40 @@ |
2172 | +/* |
2173 | + * Copyright 2014 Canonical Ltd. |
2174 | + * |
2175 | + * This program is free software; you can redistribute it and/or modify |
2176 | + * it under the terms of the GNU Lesser General Public License as published by |
2177 | + * the Free Software Foundation; version 3. |
2178 | + * |
2179 | + * This program is distributed in the hope that it will be useful, |
2180 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2181 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2182 | + * GNU Lesser General Public License for more details. |
2183 | + * |
2184 | + * You should have received a copy of the GNU Lesser General Public License |
2185 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2186 | + * |
2187 | + * Authors: |
2188 | + * Michael Zanetti <michael.zanetti@canonical.com> |
2189 | + */ |
2190 | + |
2191 | +#include "gsettings.h" |
2192 | + |
2193 | +#include <QDebug> |
2194 | + |
2195 | +// This is a mock implementation to not touch GSettings for real during tests |
2196 | + |
2197 | +GSettings::GSettings(QObject *parent): |
2198 | + QObject(parent) |
2199 | +{ |
2200 | + |
2201 | +} |
2202 | + |
2203 | +QStringList GSettings::storedApplications() const |
2204 | +{ |
2205 | + return QStringList(); |
2206 | +} |
2207 | + |
2208 | +void GSettings::setStoredApplications(const QStringList &storedApplications) |
2209 | +{ |
2210 | + Q_UNUSED(storedApplications) |
2211 | +} |
2212 | |
2213 | === added file 'tests/plugins/Unity/Launcher/gsettings.h' |
2214 | --- tests/plugins/Unity/Launcher/gsettings.h 1970-01-01 00:00:00 +0000 |
2215 | +++ tests/plugins/Unity/Launcher/gsettings.h 2014-09-18 21:04:46 +0000 |
2216 | @@ -0,0 +1,38 @@ |
2217 | +/* |
2218 | + * Copyright 2014 Canonical Ltd. |
2219 | + * |
2220 | + * This program is free software; you can redistribute it and/or modify |
2221 | + * it under the terms of the GNU Lesser General Public License as published by |
2222 | + * the Free Software Foundation; version 3. |
2223 | + * |
2224 | + * This program is distributed in the hope that it will be useful, |
2225 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2226 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2227 | + * GNU Lesser General Public License for more details. |
2228 | + * |
2229 | + * You should have received a copy of the GNU Lesser General Public License |
2230 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2231 | + * |
2232 | + * Authors: |
2233 | + * Michael Zanetti <michael.zanetti@canonical.com> |
2234 | + */ |
2235 | + |
2236 | +#ifndef GSETTINGS_H |
2237 | +#define GSETTINGS_H |
2238 | + |
2239 | +#include <QObject> |
2240 | +#include <QStringList> |
2241 | + |
2242 | +// This is a mock implementation to not touch GSettings for real during tests |
2243 | + |
2244 | +class GSettings: public QObject |
2245 | +{ |
2246 | + Q_OBJECT |
2247 | +public: |
2248 | + GSettings(QObject *parent = nullptr); |
2249 | + |
2250 | + QStringList storedApplications() const; |
2251 | + void setStoredApplications(const QStringList &storedApplications); |
2252 | +}; |
2253 | + |
2254 | +#endif |
2255 | |
2256 | === removed file 'tests/plugins/Unity/Launcher/launcherbackendtest.cpp' |
2257 | --- tests/plugins/Unity/Launcher/launcherbackendtest.cpp 2014-04-29 14:19:41 +0000 |
2258 | +++ tests/plugins/Unity/Launcher/launcherbackendtest.cpp 1970-01-01 00:00:00 +0000 |
2259 | @@ -1,239 +0,0 @@ |
2260 | -/* |
2261 | - * Copyright 2013 Canonical Ltd. |
2262 | - * |
2263 | - * This program is free software; you can redistribute it and/or modify |
2264 | - * it under the terms of the GNU Lesser General Public License as published by |
2265 | - * the Free Software Foundation; version 3. |
2266 | - * |
2267 | - * This program is distributed in the hope that it will be useful, |
2268 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2269 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2270 | - * GNU Lesser General Public License for more details. |
2271 | - * |
2272 | - * You should have received a copy of the GNU Lesser General Public License |
2273 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2274 | - * |
2275 | - * Authors: |
2276 | - * Michael Terry <michael.terry@canonical.com> |
2277 | - */ |
2278 | - |
2279 | -#include "launcherbackend.h" |
2280 | - |
2281 | -#include <QtTest> |
2282 | -#include <QDBusConnection> |
2283 | -#include <QDBusMessage> |
2284 | -#include <QDBusVariant> |
2285 | - |
2286 | - |
2287 | -class LauncherBackendTest : public QObject |
2288 | -{ |
2289 | - Q_OBJECT |
2290 | - |
2291 | -private Q_SLOTS: |
2292 | - |
2293 | - void initTestCase() |
2294 | - { |
2295 | - // As we want to test absolute file paths in the .desktop file, we need to modify the |
2296 | - // sample file and replace the path in there with the current build dir. |
2297 | - QSettings settings(QDir::currentPath() + "/click-icon.desktop", QSettings::IniFormat); |
2298 | - settings.setValue("Desktop Entry/Path", QDir::currentPath()); |
2299 | - } |
2300 | - |
2301 | - void testFileNames() |
2302 | - { |
2303 | - LauncherBackend backend; |
2304 | - |
2305 | - backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon" << "invalid"); |
2306 | - QCOMPARE(backend.storedApplications(), QStringList() << "rel-icon" << "abs-icon"); |
2307 | - } |
2308 | - |
2309 | - void testIcon_data() { |
2310 | - QTest::addColumn<QString>("appId"); |
2311 | - QTest::addColumn<QString>("expectedIcon"); |
2312 | - |
2313 | - // Needs to expand a relative icon to the absolute path |
2314 | - QTest::newRow("relative icon path") << "rel-icon" << QDir::currentPath() + "/rel-icon.svg"; |
2315 | - |
2316 | - // In case an icon is not found on disk, it needs to fallback on image://theme/ for it |
2317 | - QTest::newRow("fallback on theme") << "abs-icon" << "image://theme//path/to/icon.png"; |
2318 | - |
2319 | - // Click packages have a relative icon path but an absolute path as a separate entry |
2320 | - QTest::newRow("click package icon") << "click-icon" << QDir::currentPath() + "/click-icon.svg"; |
2321 | - } |
2322 | - |
2323 | - void testIcon() { |
2324 | - QFETCH(QString, appId); |
2325 | - QFETCH(QString, expectedIcon); |
2326 | - |
2327 | - LauncherBackend backend; |
2328 | - backend.setStoredApplications(QStringList() << appId); |
2329 | - |
2330 | - QCOMPARE(backend.icon(appId), expectedIcon); |
2331 | - } |
2332 | - |
2333 | - void testGetItem_data() { |
2334 | - QTest::addColumn<QString>("appId"); |
2335 | - QTest::addColumn<bool>("exists"); |
2336 | - |
2337 | - QTest::newRow("Exists") << "rel-icon" << true; |
2338 | - QTest::newRow("Doesn't Exist") << "does-not-exist" << false; |
2339 | - } |
2340 | - |
2341 | - void testGetItem() { |
2342 | - QFETCH(QString, appId); |
2343 | - QFETCH(bool, exists); |
2344 | - |
2345 | - LauncherBackend backend; |
2346 | - auto item = backend.getItem(appId); |
2347 | - |
2348 | - if (exists) { |
2349 | - QVERIFY(item != nullptr); |
2350 | - } else { |
2351 | - QVERIFY(item == nullptr); |
2352 | - } |
2353 | - } |
2354 | - |
2355 | - void testCount_data() { |
2356 | - QTest::addColumn<QString>("appId"); |
2357 | - QTest::addColumn<bool>("setCount"); |
2358 | - QTest::addColumn<int>("inCount"); |
2359 | - QTest::addColumn<bool>("countVisible"); |
2360 | - QTest::addColumn<int>("expectedCount"); |
2361 | - |
2362 | - /* Get baseline data on things working */ |
2363 | - QTest::newRow("Baseline") << "rel-icon" << false << 0 << false << -1; |
2364 | - |
2365 | - /* Valid count, but not visible */ |
2366 | - QTest::newRow("Not visible") << "rel-icon" << true << 42 << false << -1; |
2367 | - |
2368 | - /* Turn it on */ |
2369 | - QTest::newRow("Visible Count") << "rel-icon" << true << 42 << true << 42; |
2370 | - |
2371 | - /* Invalide app to load */ |
2372 | - QTest::newRow("Invalid App ID") << "this-app-doesnt-exist" << true << 42 << true << -1; |
2373 | - } |
2374 | - |
2375 | - void testCount() { |
2376 | - QFETCH(QString, appId); |
2377 | - QFETCH(bool, setCount); |
2378 | - QFETCH(int, inCount); |
2379 | - QFETCH(bool, countVisible); |
2380 | - QFETCH(int, expectedCount); |
2381 | - |
2382 | - LauncherBackend backend; |
2383 | - |
2384 | - if (setCount) |
2385 | - backend.setCount(appId, inCount); |
2386 | - backend.setCountVisible(appId, countVisible); |
2387 | - |
2388 | - QCOMPARE(backend.count(appId), expectedCount); |
2389 | - } |
2390 | - |
2391 | - void testDbusName_data() { |
2392 | - QTest::addColumn<QString>("decoded"); |
2393 | - QTest::addColumn<QString>("encoded"); |
2394 | - |
2395 | - /* Passthrough test */ |
2396 | - QTest::newRow("Passthrough") << "fine" << "fine"; |
2397 | - |
2398 | - /* Number as first characeter */ |
2399 | - QTest::newRow("Number first") << "31337" << "_331337"; |
2400 | - |
2401 | - /* Underscore test */ |
2402 | - QTest::newRow("Underscore test") << "this_is_c_style_namespacing" << "this_5Fis_5Fc_5Fstyle_5Fnamespacing"; |
2403 | - |
2404 | - /* Hyphen test */ |
2405 | - QTest::newRow("Hyphen test") << "typical-application" << "typical_2Dapplication"; |
2406 | - |
2407 | - /* Japanese test */ |
2408 | - QTest::newRow("日本語 test") << "日本語" << "_E6_97_A5_E6_9C_AC_E8_AA_9E"; |
2409 | - } |
2410 | - |
2411 | - void testDbusName() { |
2412 | - QFETCH(QString, decoded); |
2413 | - QFETCH(QString, encoded); |
2414 | - |
2415 | - QString encodeOut = LauncherBackend::encodeAppId(decoded); |
2416 | - QCOMPARE(encoded, encodeOut); |
2417 | - |
2418 | - QString decodeOut = LauncherBackend::decodeAppId(encoded); |
2419 | - QCOMPARE(decoded, decodeOut); |
2420 | - } |
2421 | - |
2422 | - void testDbusIface_data() { |
2423 | - QTest::addColumn<QString>("appId"); |
2424 | - QTest::addColumn<bool>("setCount"); |
2425 | - QTest::addColumn<int>("inCount"); |
2426 | - QTest::addColumn<bool>("countVisible"); |
2427 | - QTest::addColumn<int>("expectedCount"); |
2428 | - |
2429 | - /* Get baseline data on things working */ |
2430 | - QTest::newRow("Baseline") << "rel-icon" << false << 0 << false << -1; |
2431 | - |
2432 | - /* Turn it on */ |
2433 | - QTest::newRow("Visible Count") << "rel-icon" << true << 42 << true << 42; |
2434 | - |
2435 | - /* Invalide app to load */ |
2436 | - QTest::newRow("Invalid App ID") << "this-app-doesnt-exist" << true << 42 << true << -1; |
2437 | - } |
2438 | - |
2439 | - void testDbusIface() { |
2440 | - QFETCH(QString, appId); |
2441 | - QFETCH(bool, setCount); |
2442 | - QFETCH(int, inCount); |
2443 | - QFETCH(bool, countVisible); |
2444 | - QFETCH(int, expectedCount); |
2445 | - |
2446 | - QDBusConnection con = QDBusConnection::sessionBus(); |
2447 | - QDBusMessage message; |
2448 | - QDBusMessage reply; |
2449 | - |
2450 | - LauncherBackend backend; |
2451 | - |
2452 | - if (setCount) { |
2453 | - message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher", |
2454 | - "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId), |
2455 | - "org.freedesktop.DBus.Properties", |
2456 | - "Set"); |
2457 | - QVariantList cargs; |
2458 | - cargs.append(QString("com.canonical.Unity.Launcher.Item")); |
2459 | - cargs.append(QString("count")); |
2460 | - cargs.append(QVariant::fromValue(QDBusVariant(inCount))); |
2461 | - |
2462 | - message.setArguments(cargs); |
2463 | - reply = con.call(message); |
2464 | - QCOMPARE(reply.type(), QDBusMessage::ReplyMessage); |
2465 | - } |
2466 | - |
2467 | - /* Set countVisible */ |
2468 | - message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher", |
2469 | - "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId), |
2470 | - "org.freedesktop.DBus.Properties", |
2471 | - "Set"); |
2472 | - QVariantList cvargs; |
2473 | - cvargs.append(QString("com.canonical.Unity.Launcher.Item")); |
2474 | - cvargs.append(QString("countVisible")); |
2475 | - cvargs.append(QVariant::fromValue(QDBusVariant(countVisible))); |
2476 | - |
2477 | - message.setArguments(cvargs); |
2478 | - reply = con.call(message); |
2479 | - QCOMPARE(reply.type(), QDBusMessage::ReplyMessage); |
2480 | - |
2481 | - /* Get value */ |
2482 | - message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher", |
2483 | - "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId), |
2484 | - "org.freedesktop.DBus.Properties", |
2485 | - "Get"); |
2486 | - QVariantList getargs; |
2487 | - getargs.append(QString("com.canonical.Unity.Launcher.Item")); |
2488 | - getargs.append(QString("count")); |
2489 | - |
2490 | - message.setArguments(getargs); |
2491 | - reply = con.call(message); |
2492 | - QCOMPARE(reply.type(), QDBusMessage::ReplyMessage); |
2493 | - QCOMPARE(reply.arguments()[0].value<QDBusVariant>().variant().toInt(), expectedCount); |
2494 | - } |
2495 | -}; |
2496 | - |
2497 | -QTEST_GUILESS_MAIN(LauncherBackendTest) |
2498 | -#include "launcherbackendtest.moc" |
2499 | |
2500 | === modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp' |
2501 | --- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2014-08-13 19:50:09 +0000 |
2502 | +++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2014-09-18 21:04:46 +0000 |
2503 | @@ -23,8 +23,12 @@ |
2504 | |
2505 | #include "launcheritem.h" |
2506 | #include "launchermodel.h" |
2507 | +#include "dbusinterface.h" |
2508 | |
2509 | #include <QtTest> |
2510 | +#include <QDBusInterface> |
2511 | +#include <QDBusReply> |
2512 | +#include <QDomDocument> |
2513 | |
2514 | // This is a mock, specifically to test the LauncherModel |
2515 | class MockApp: public unity::shell::application::ApplicationInfoInterface |
2516 | @@ -287,10 +291,86 @@ |
2517 | QCOMPARE(launcherModel->getUrlForAppId(QString()), QString()); |
2518 | QCOMPARE(launcherModel->getUrlForAppId(""), QString()); |
2519 | QCOMPARE(launcherModel->getUrlForAppId("no-name"), QString("application:///no-name.desktop")); |
2520 | - QCOMPARE(launcherModel->getUrlForAppId("com.test.good"), QString("appid://com.test.good/first-listed-app/current-user-version")); |
2521 | + QCOMPARE(launcherModel->getUrlForAppId("com.test.good"), QString("application:///com.test.good.desktop")); |
2522 | QCOMPARE(launcherModel->getUrlForAppId("com.test.good_application"), QString("appid://com.test.good/application/current-user-version")); |
2523 | QCOMPARE(launcherModel->getUrlForAppId("com.test.good_application_1.2.3"), QString("appid://com.test.good/application/current-user-version")); |
2524 | } |
2525 | + |
2526 | + void testIntrospection() { |
2527 | + QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher", "org.freedesktop.DBus.Introspectable"); |
2528 | + QDBusReply<QString> reply = interface.call("Introspect"); |
2529 | + QStringList nodes = extractNodes(reply.value()); |
2530 | + QCOMPARE(nodes.count(), launcherModel->rowCount()); |
2531 | + |
2532 | + appManager->addApplication(new MockApp("foobar")); |
2533 | + reply = interface.call("Introspect"); |
2534 | + nodes = extractNodes(reply.value()); |
2535 | + QCOMPARE(nodes.contains("foobar"), true); |
2536 | + |
2537 | + appManager->removeApplication(2); |
2538 | + reply = interface.call("Introspect"); |
2539 | + nodes = extractNodes(reply.value()); |
2540 | + QCOMPARE(nodes.contains("foobar"), false); |
2541 | + } |
2542 | + |
2543 | + QStringList extractNodes(const QString &introspectionXml) { |
2544 | + QXmlStreamReader introspectReply(introspectionXml); |
2545 | + |
2546 | + QStringList ret; |
2547 | + while (!introspectReply.atEnd() && !introspectReply.hasError()) { |
2548 | + QXmlStreamReader::TokenType token = introspectReply.readNext(); |
2549 | + |
2550 | + if (token == QXmlStreamReader::StartElement) { |
2551 | + if (introspectReply.name() == "node" && introspectReply.attributes().count() > 0) { |
2552 | + ret << introspectReply.attributes().value("name").toString(); |
2553 | + } |
2554 | + } |
2555 | + } |
2556 | + return ret; |
2557 | + } |
2558 | + |
2559 | + void testCountEmblems() { |
2560 | + // Call GetAll on abs-icon |
2561 | + QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher/abs_2Dicon", "org.freedesktop.DBus.Properties"); |
2562 | + QDBusReply<QVariantMap> reply = interface.call("GetAll"); |
2563 | + QVariantMap map = reply.value(); |
2564 | + |
2565 | + // Make sure GetAll returns a map with count and countVisible props |
2566 | + QCOMPARE(map.contains("count"), true); |
2567 | + QCOMPARE(map.contains("countVisible"), true); |
2568 | + |
2569 | + // Make sure count is intitilized to 0 and non-visible |
2570 | + QCOMPARE(map.value("count").toInt(), 0); |
2571 | + QCOMPARE(map.value("countVisible").toBool(), false); |
2572 | + |
2573 | + // Now make it visible and set it to 55 through D-Bus |
2574 | + interface.call("Set", "com.canonical.Unity.Launcher.Item", "count", 55); |
2575 | + interface.call("Set", "com.canonical.Unity.Launcher.Item", "countVisible", true); |
2576 | + |
2577 | + // Fetch it again using GetAll |
2578 | + reply = interface.call("GetAll"); |
2579 | + map = reply.value(); |
2580 | + |
2581 | + // Make sure values have changed on the D-Bus interface |
2582 | + QCOMPARE(map.value("count").toInt(), 55); |
2583 | + QCOMPARE(map.value("countVisible").toBool(), true); |
2584 | + |
2585 | + // Now the item on the upper side of the API |
2586 | + int index = launcherModel->findApplication("abs-icon"); |
2587 | + QCOMPARE(index >= 0, true); |
2588 | + |
2589 | + // And make sure values have changed there as well |
2590 | + QCOMPARE(launcherModel->get(index)->countVisible(), true); |
2591 | + QCOMPARE(launcherModel->get(index)->count(), 55); |
2592 | + } |
2593 | + |
2594 | + void testRefresh() { |
2595 | + QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher", "com.canonical.Unity.Launcher"); |
2596 | + QDBusReply<void> reply = interface.call("Refresh"); |
2597 | + |
2598 | + // Make sure the call to Refresh returned without error. |
2599 | + QCOMPARE(reply.isValid(), true); |
2600 | + } |
2601 | }; |
2602 | |
2603 | QTEST_GUILESS_MAIN(LauncherModelTest) |
2604 | |
2605 | === modified file 'tests/qmltests/Launcher/tst_Launcher.qml' |
2606 | --- tests/qmltests/Launcher/tst_Launcher.qml 2014-07-24 22:37:26 +0000 |
2607 | +++ tests/qmltests/Launcher/tst_Launcher.qml 2014-09-18 21:04:46 +0000 |
2608 | @@ -194,7 +194,9 @@ |
2609 | var launcherListView = findChild(launcher, "launcherListView"); |
2610 | for (var i = 0; i < launcherListView.count; ++i) { |
2611 | var delegate = findChild(launcherListView, "launcherDelegate" + i) |
2612 | - compare(findChild(delegate, "countEmblem").visible, LauncherModel.get(i).count > 0) |
2613 | + compare(findChild(delegate, "countEmblem").visible, LauncherModel.get(i).countVisible) |
2614 | + // Intentionally allow type coercion (string/number) |
2615 | + compare(findChild(delegate, "countLabel").text == LauncherModel.get(i).count, true) |
2616 | } |
2617 | } |
2618 |
FAILED: Continuous integration, rev:1205 jenkins. qa.ubuntu. com/job/ unity8- ci/4179/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- utopic- touch/4243/ console jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- utopic/ 1180/console jenkins. qa.ubuntu. com/job/ unity8- utopic- amd64-ci/ 1273/console jenkins. qa.ubuntu. com/job/ unity8- utopic- i386-ci/ 1273/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/5495/ console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/4179/ rebuild
http://