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