Merge lp:~mzanetti/unity8/rework-launcher-backend into lp:unity8

Proposed by Michael Zanetti
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
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://code.launchpad.net/~mzanetti/unity-api/launcher-v4/+merge/232198
https://code.launchpad.net/~mzanetti/unity/new-key-in-launcher-schema/+merge/232199

 * 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

To post a comment you must log in.
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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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)

Subscribers

People subscribed via source and target branches