Merge lp:~mzanetti/unity8/launcher-defaults-from-dconf into lp:unity8

Proposed by Michael Zanetti
Status: Merged
Approved by: Michael Zanetti
Approved revision: 283
Merged at revision: 281
Proposed branch: lp:~mzanetti/unity8/launcher-defaults-from-dconf
Merge into: lp:unity8
Diff against target: 531 lines (+187/-153)
6 files modified
debian/control (+1/-0)
plugins/Unity/Launcher/CMakeLists.txt (+4/-0)
plugins/Unity/Launcher/backend/launcherbackend.cpp (+165/-105)
plugins/Unity/Launcher/backend/launcherbackend.h (+12/-14)
tests/plugins/Unity/Launcher/CMakeLists.txt (+4/-0)
tests/plugins/Unity/Launcher/launcherbackendtest.cpp (+1/-34)
To merge this branch: bzr merge lp:~mzanetti/unity8/launcher-defaults-from-dconf
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Gerry Boland (community) Approve
Albert Astals Cid (community) Needs Fixing
Sebastien Bacher Pending
Review via email: mp+183420@code.launchpad.net

Commit message

load launcher default config from existing dconf key

Description of the change

To clear your accountsservice settings (restore the default) call:

gdbus call --system --dest org.freedesktop.Accounts --object-path /org/freedesktop/Accounts/User32011 --method org.freedesktop.DBus.Properties.Set com.canonical.unity.AccountsService launcher-items "<[{'defaults' : <true>}]>"

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

I'm always upset a bit by stuff like

+ if (m_itemCache.contains(appId)) {
+ return m_itemCache.value(appId)->desktopFile;
+ }

Since we end up seraching appId twice in the hash. Maybe you can use something like

auto lala = m_itemCache.value(appId);
if (lala) return lala->desktopFile;
..do rest of stuf..

Also, the setStoredApplications code is filling the cache with LauncherBackendItem for the new appIds but just empty, what's the reasoning behind that? Shouldn't that be a nullptr so the code above works?

review: Needs Fixing
Revision history for this message
Michael Zanetti (mzanetti) wrote :

> I'm always upset a bit by stuff like
>
> + if (m_itemCache.contains(appId)) {
> + return m_itemCache.value(appId)->desktopFile;
> + }
>
> Since we end up seraching appId twice in the hash. Maybe you can use something
> like
>
> auto lala = m_itemCache.value(appId);
> if (lala) return lala->desktopFile;
> ..do rest of stuf..

Given that m_itemCache is a QHash I don't think its much of a problem. It's not that we would need to iterate twice over the whole list. But sure, some small tuning can be done...

> Also, the setStoredApplications code is filling the cache with
> LauncherBackendItem for the new appIds but just empty, what's the reasoning
> behind that? Shouldn't that be a nullptr so the code above works?

Ouch... That happens when there is a weekend between writing the code and updating the tests... Will fix.

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)
Revision history for this message
Sebastien Bacher (seb128) wrote :

the default configuration landed on the current image

Revision history for this message
Gerry Boland (gerboland) wrote :

Works, and code fine. Approving

review: Approve
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) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2013-08-21 21:33:59 +0000
3+++ debian/control 2013-09-02 15:18:56 +0000
4@@ -9,6 +9,7 @@
5 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
6 libgl1-mesa-dri,
7 libgles2-mesa-dev[armhf],
8+ libgsettings-qt-dev,
9 libhud-client2-dev,
10 libjson-perl,
11 libnih-dbus-dev,
12
13=== modified file 'plugins/Unity/Launcher/CMakeLists.txt'
14--- plugins/Unity/Launcher/CMakeLists.txt 2013-08-19 01:35:45 +0000
15+++ plugins/Unity/Launcher/CMakeLists.txt 2013-09-02 15:18:56 +0000
16@@ -1,11 +1,13 @@
17 include(FindPkgConfig)
18 pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=2)
19+pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
20
21 add_definitions(-DSM_BUSNAME=systemBus)
22
23 include_directories(
24 ${CMAKE_CURRENT_SOURCE_DIR}
25 ${CMAKE_SOURCE_DIR}/plugins/AccountsService
26+ ${GSETTINGS_QT_INCLUDE_DIRS}
27 )
28
29 set(QMLLAUNCHERPLUGIN_SRC
30@@ -25,6 +27,8 @@
31 ${QMLLAUNCHERPLUGIN_SRC}
32 )
33
34+target_link_libraries(UnityLauncher-qml ${GSETTINGS_QT_LDFLAGS})
35+
36 qt5_use_modules(UnityLauncher-qml DBus Qml)
37
38 # export the qmldir and qmltypes files
39
40=== modified file 'plugins/Unity/Launcher/backend/launcherbackend.cpp'
41--- plugins/Unity/Launcher/backend/launcherbackend.cpp 2013-08-29 13:56:15 +0000
42+++ plugins/Unity/Launcher/backend/launcherbackend.cpp 2013-09-02 15:18:56 +0000
43@@ -24,6 +24,18 @@
44 #include <QDir>
45 #include <QDBusArgument>
46 #include <QFileInfo>
47+#include <QGSettings>
48+
49+class LauncherBackendItem
50+{
51+public:
52+ LauncherBackendItem(): pinned(false) {}
53+
54+ QString desktopFile;
55+ QString displayName;
56+ QString icon;
57+ bool pinned;
58+};
59
60 LauncherBackend::LauncherBackend(bool useStorage, QObject *parent):
61 QObject(parent),
62@@ -32,95 +44,109 @@
63 if (useStorage) {
64 m_accounts = new AccountsService(this);
65 }
66- setUser(qgetenv("USER"));
67+ m_user = qgetenv("USER");
68+ syncFromAccounts();
69 }
70
71 LauncherBackend::~LauncherBackend()
72 {
73- clearItems();
74-}
75+ m_storedApps.clear();
76
77-void LauncherBackend::clearItems()
78-{
79- for (LauncherBackendItem &app: m_storedApps) {
80- delete app.settings;
81+ Q_FOREACH(LauncherBackendItem *item, m_itemCache) {
82+ delete item;
83 }
84- m_storedApps.clear();
85+ m_itemCache.clear();
86 }
87
88 QStringList LauncherBackend::storedApplications() const
89 {
90- auto files = QStringList();
91- for (const LauncherBackendItem &app: m_storedApps) {
92- files << app.settings->fileName();
93- }
94- return files;
95+ return m_storedApps;
96 }
97
98 void LauncherBackend::setStoredApplications(const QStringList &appIds)
99 {
100- // Record all existing pinned apps, so we can notice them in new list
101- auto pinnedItems = QStringList();
102- for (LauncherBackendItem &app: m_storedApps) {
103- if (app.pinned) {
104- pinnedItems.append(app.settings->fileName());
105+ if (appIds.count() < m_storedApps.count()) {
106+ Q_FOREACH(const QString &appId, m_storedApps) {
107+ if (!appIds.contains(appId)) {
108+ delete m_itemCache.take(appId);
109+ }
110 }
111 }
112-
113- clearItems();
114-
115- for (const QString &appId: appIds) {
116- loadApp(makeAppDetails(appId, pinnedItems.contains(desktopFile(appId))));
117- }
118-
119+ m_storedApps = appIds;
120 syncToAccounts();
121 }
122
123 QString LauncherBackend::desktopFile(const QString &appId) const
124 {
125- QFileInfo fileInfo(QDir("/usr/share/applications"), appId);
126- return fileInfo.absoluteFilePath();
127+ LauncherBackendItem *item = m_itemCache.value(appId);
128+ if (item) {
129+ return item->desktopFile;
130+ }
131+
132+ return findDesktopFile(appId);
133 }
134
135 QString LauncherBackend::displayName(const QString &appId) const
136 {
137- auto desktopFile = parseDesktopFile(appId);
138- auto displayName = desktopFile->value("Desktop Entry/Name").toString();
139- delete desktopFile;
140- return displayName;
141+ LauncherBackendItem *item = m_itemCache.value(appId);
142+ if (item) {
143+ return item->displayName;
144+ }
145+
146+ QString df = findDesktopFile(appId);
147+ if (!df.isEmpty()) {
148+ LauncherBackendItem *item = parseDesktopFile(df);
149+ m_itemCache.insert(appId, item);
150+ return item->displayName;
151+ }
152+
153+ return QString();
154 }
155
156 QString LauncherBackend::icon(const QString &appId) const
157 {
158- auto desktopFile = parseDesktopFile(appId);
159- auto iconName = desktopFile->value("Desktop Entry/Icon").toString();
160- delete desktopFile;
161-
162- if (!iconName.isEmpty()) {
163- QFileInfo iconFileInfo(iconName);
164- if (iconFileInfo.isRelative()) {
165- iconName = "image://gicon/" + iconName;
166+ QString iconName;
167+ LauncherBackendItem *item = m_itemCache.value(appId);
168+ if (item) {
169+ iconName = item->icon;
170+ } else {
171+ QString df = findDesktopFile(appId);
172+ if (!df.isEmpty()) {
173+ LauncherBackendItem *item = parseDesktopFile(df);
174+ m_itemCache.insert(appId, item);
175+ iconName = item->icon;
176 }
177 }
178
179- return iconName;
180+ QFileInfo info(iconName);
181+ if (info.exists()) {
182+ return info.absoluteFilePath();
183+ }
184+ return "image://theme/" + iconName;
185 }
186
187 bool LauncherBackend::isPinned(const QString &appId) const
188 {
189- auto index = findItem(appId);
190- if (index < 0) {
191- return false;
192- } else {
193- return m_storedApps[index].pinned;
194+ LauncherBackendItem *item = m_itemCache.value(appId);
195+ if (item) {
196+ return item->pinned;
197 }
198+ return false;
199 }
200
201 void LauncherBackend::setPinned(const QString &appId, bool pinned)
202 {
203- auto index = findItem(appId);
204- if (index >= 0 && !m_storedApps[index].pinned) {
205- m_storedApps[index].pinned = pinned;
206+ if (!m_storedApps.contains(appId)) {
207+ return;
208+ }
209+
210+ LauncherBackendItem *item = m_itemCache.value(appId);
211+ if (!item) {
212+ item = new LauncherBackendItem();
213+ m_itemCache.insert(appId, item);
214+ }
215+ if (item->pinned != pinned) {
216+ item->pinned = pinned;
217 syncToAccounts();
218 }
219 }
220@@ -153,8 +179,10 @@
221
222 void LauncherBackend::setUser(const QString &username)
223 {
224- m_user = username;
225- syncFromAccounts();
226+ if (qgetenv("USER") == "lightdm" && m_user != username) {
227+ m_user = username;
228+ syncFromAccounts();
229+ }
230 }
231
232 void LauncherBackend::triggerQuickListAction(const QString &appId, const QString &quickListId)
233@@ -169,75 +197,118 @@
234 QList<QVariantMap> apps;
235 bool defaults = true;
236
237- clearItems();
238+ m_storedApps.clear();
239
240- if (m_user != "" && m_accounts != nullptr) {
241- auto variant = m_accounts->getUserProperty(m_user, "launcher-items");
242+ if (m_accounts && m_user.isEmpty()) {
243+ QVariant variant = m_accounts->getUserProperty(m_user, "launcher-items");
244 apps = qdbus_cast<QList<QVariantMap>>(variant.value<QDBusArgument>());
245 defaults = isDefaultsItem(apps);
246 }
247
248- // TODO: load default pinned ones from default config, instead of hardcoding here...
249- if (defaults) {
250- apps <<
251- makeAppDetails("dialer-app.desktop", true) <<
252- makeAppDetails("messaging-app.desktop", true) <<
253- makeAppDetails("address-book-app.desktop", true) <<
254- makeAppDetails("camera-app.desktop", true) <<
255- makeAppDetails("gallery-app.desktop", true) <<
256- makeAppDetails("facebook-webapp.desktop", true) <<
257- makeAppDetails("webbrowser-app.desktop", true) <<
258- makeAppDetails("twitter-webapp.desktop", true) <<
259- makeAppDetails("gmail-webapp.desktop", true) <<
260- makeAppDetails("ubuntu-weather-app.desktop", true) <<
261- makeAppDetails("notes-app.desktop", true) <<
262- makeAppDetails("calendar-app.desktop", true);
263- }
264-
265- for (const QVariant &app: apps) {
266- loadApp(app.toMap());
267+ if (m_accounts && defaults) { // Checking accounts as it'll be null when !useStorage
268+ QGSettings gSettings("com.canonical.Unity.Launcher", "/com/canonical/unity/launcher/");
269+ Q_FOREACH(const QString &entry, gSettings.get("favorites").toStringList()) {
270+ if (entry.startsWith("application://")) {
271+ QString appId = entry;
272+ appId.remove("application://");
273+ QString df = findDesktopFile(appId);
274+
275+ if (!df.isEmpty()) {
276+ m_storedApps << appId;
277+
278+ if (!m_itemCache.contains(appId)) {
279+ m_itemCache.insert(appId, parseDesktopFile(df));
280+ }
281+ m_itemCache.value(appId)->pinned = true;
282+ }
283+ }
284+ }
285+ } else {
286+ for (const QVariant &app: apps) {
287+ loadFromVariant(app.toMap());
288+ }
289 }
290 }
291
292 void LauncherBackend::syncToAccounts()
293 {
294- if (m_user != "" && m_accounts != nullptr) {
295+ if (m_accounts && !m_user.isEmpty()) {
296 QList<QVariantMap> items;
297
298- for (LauncherBackendItem &app: m_storedApps) {
299- items << makeAppDetails(app.settings->fileName(), app.pinned);
300+ Q_FOREACH(const QString &appId, m_storedApps) {
301+ items << itemToVariant(appId);
302 }
303
304 m_accounts->setUserProperty(m_user, "launcher-items", QVariant::fromValue(items));
305 }
306 }
307
308-QSettings *LauncherBackend::parseDesktopFile(const QString &appId) const
309-{
310- auto fullAppId = desktopFile(appId);
311- return new QSettings(fullAppId, QSettings::IniFormat);
312-}
313-
314-void LauncherBackend::loadApp(const QVariantMap &details)
315-{
316- auto appId = details.value("id").toString();
317- auto isPinned = details.value("is-pinned").toBool();
318-
319- if (appId.isEmpty()) {
320+QString LauncherBackend::findDesktopFile(const QString &appId) const
321+{
322+ int dashPos = -1;
323+ QString helper = appId;
324+
325+ do {
326+ if (dashPos != -1) {
327+ helper = helper.replace(dashPos, 1, '/');
328+ }
329+
330+ QFileInfo fileInfo(QDir("/usr/share/applications"), helper);
331+ if (fileInfo.exists()) {
332+ return fileInfo.absoluteFilePath();
333+ }
334+
335+ dashPos = helper.indexOf("-");
336+ } while (dashPos != -1);
337+
338+ return QString();
339+}
340+
341+LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFile) const
342+{
343+ QSettings settings(desktopFile, QSettings::IniFormat);
344+
345+
346+ LauncherBackendItem* item = new LauncherBackendItem();
347+ item->desktopFile = desktopFile;
348+ item->displayName = settings.value("Desktop Entry/Name").toString();
349+ item->icon = settings.value("Desktop Entry/Icon").toString();
350+ item->pinned = false;
351+ return item;
352+}
353+
354+void LauncherBackend::loadFromVariant(const QVariantMap &details)
355+{
356+ if (!details.contains("id")) {
357 return;
358 }
359-
360- LauncherBackendItem item;
361- item.settings = parseDesktopFile(appId);
362- item.pinned = isPinned;
363- m_storedApps.append(item);
364+ QString appId = details.value("id").toString();
365+
366+ LauncherBackendItem *item = m_itemCache.value(appId);
367+ if (item) {
368+ delete item;
369+ }
370+
371+ item = new LauncherBackendItem();
372+
373+ item->desktopFile = details.value("desktopFile").toString();
374+ item->displayName = details.value("name").toString();
375+ item->icon = details.value("icon").toString();
376+ item->pinned = details.value("is-pinned").toBool();
377+
378+ m_itemCache.insert(appId, item);
379+ m_storedApps.append(appId);
380 }
381
382-QVariantMap LauncherBackend::makeAppDetails(const QString &appId, bool pinned) const
383+QVariantMap LauncherBackend::itemToVariant(const QString &appId) const
384 {
385+ LauncherBackendItem *item = m_itemCache.value(appId);
386 QVariantMap details;
387 details.insert("id", appId);
388- details.insert("is-pinned", pinned);
389+ details.insert("name", item->displayName);
390+ details.insert("icon", item->icon);
391+ details.insert("desktopFile", item->desktopFile);
392+ details.insert("is-pinned", item->pinned);
393 return details;
394 }
395
396@@ -248,14 +319,3 @@
397 // list of one item with the 'defaults' field set to true.
398 return (apps.size() == 1 && apps[0].value("defaults").toBool());
399 }
400-
401-int LauncherBackend::findItem(const QString &appId) const
402-{
403- auto fullAppId = desktopFile(appId);
404- for (int i = 0; i < m_storedApps.size(); ++i) {
405- if (m_storedApps[i].settings->fileName() == fullAppId) {
406- return i;
407- }
408- }
409- return -1;
410-}
411
412=== modified file 'plugins/Unity/Launcher/backend/launcherbackend.h'
413--- plugins/Unity/Launcher/backend/launcherbackend.h 2013-08-23 19:49:18 +0000
414+++ plugins/Unity/Launcher/backend/launcherbackend.h 2013-09-02 15:18:56 +0000
415@@ -31,6 +31,8 @@
416 * @brief An interface that provides all the data needed by the launcher.
417 */
418
419+class LauncherBackendItem;
420+
421 class LauncherBackend : public QObject
422 {
423 Q_OBJECT
424@@ -141,23 +143,19 @@
425 void countChanged(const QString &appId, int count);
426
427 private:
428- QSettings *parseDesktopFile(const QString &appId) const;
429- QVariantMap makeAppDetails(const QString &appId, bool pinned) const;
430- void loadApp(const QVariantMap &details);
431- int findItem(const QString &appId) const;
432+ QString findDesktopFile(const QString &appId) const;
433+ LauncherBackendItem* parseDesktopFile(const QString &desktopFile) const;
434+
435+ QVariantMap itemToVariant(const QString &appId) const;
436+ void loadFromVariant(const QVariantMap &details);
437+
438 bool isDefaultsItem(const QList<QVariantMap> &apps) const;
439 void syncFromAccounts();
440 void syncToAccounts();
441- void clearItems();
442-
443- class LauncherBackendItem
444- {
445- public:
446- QSettings *settings;
447- bool pinned;
448- };
449-
450- QList<LauncherBackendItem> m_storedApps;
451+
452+ QList<QString> m_storedApps;
453+ mutable QHash<QString, LauncherBackendItem*> m_itemCache;
454+
455 AccountsService *m_accounts;
456 QString m_user;
457 };
458
459=== modified file 'tests/plugins/Unity/Launcher/CMakeLists.txt'
460--- tests/plugins/Unity/Launcher/CMakeLists.txt 2013-08-20 17:57:08 +0000
461+++ tests/plugins/Unity/Launcher/CMakeLists.txt 2013-09-02 15:18:56 +0000
462@@ -1,8 +1,11 @@
463+pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
464+
465 include_directories(
466 ${CMAKE_CURRENT_BINARY_DIR}
467 ${CMAKE_SOURCE_DIR}/plugins/AccountsService
468 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher
469 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend
470+ ${GSETTINGS_QT_INCLUDE_DIRS}
471 )
472
473 add_definitions(-DSM_BUSNAME=sessionBus)
474@@ -19,4 +22,5 @@
475 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp
476 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp
477 )
478+target_link_libraries(launcherbackendtestExec ${GSETTINGS_QT_LDFLAGS})
479 qt5_use_modules(launcherbackendtestExec Test Core DBus)
480
481=== modified file 'tests/plugins/Unity/Launcher/launcherbackendtest.cpp'
482--- tests/plugins/Unity/Launcher/launcherbackendtest.cpp 2013-08-22 21:56:18 +0000
483+++ tests/plugins/Unity/Launcher/launcherbackendtest.cpp 2013-09-02 15:18:56 +0000
484@@ -32,46 +32,13 @@
485 LauncherBackend backend(false);
486
487 backend.setStoredApplications(QStringList() << "relative.path" << "/full/path");
488- QCOMPARE(backend.storedApplications(), QStringList() << "/usr/share/applications/relative.path" << "/full/path");
489-
490- QCOMPARE(backend.desktopFile("one.desktop"), QString("/usr/share/applications/one.desktop"));
491- QCOMPARE(backend.desktopFile("two"), QString("/usr/share/applications/two"));
492- QCOMPARE(backend.desktopFile("/full"), QString("/full"));
493-
494- QCOMPARE(backend.desktopFile("/usr/share/applications/one.desktop"), QString("/usr/share/applications/one.desktop"));
495- }
496-
497- void testDesktopReading()
498- {
499- LauncherBackend backend(false);
500-
501- QCOMPARE(backend.displayName(SRCDIR "/rel-icon.desktop"), QString("Relative Icon"));
502- QCOMPARE(backend.icon(SRCDIR "/rel-icon.desktop"), QString("image://gicon/rel-icon"));
503-
504- QCOMPARE(backend.displayName(SRCDIR "/abs-icon.desktop"), QString("Absolute Icon"));
505- QCOMPARE(backend.icon(SRCDIR "/abs-icon.desktop"), QString("/path/to/icon.png"));
506-
507- QCOMPARE(backend.displayName(SRCDIR "/no-icon.desktop"), QString("No Icon"));
508- QCOMPARE(backend.icon(SRCDIR "/no-icon.desktop"), QString(""));
509-
510- QCOMPARE(backend.displayName(SRCDIR "/no-name.desktop"), QString(""));
511- QCOMPARE(backend.icon(SRCDIR "/no-name.desktop"), QString("image://gicon/no-name"));
512-
513- QCOMPARE(backend.displayName(SRCDIR "/no-exist.desktop"), QString(""));
514- QCOMPARE(backend.icon(SRCDIR "/no-exist.desktop"), QString(""));
515+ QCOMPARE(backend.storedApplications(), QStringList() << "relative.path" << "/full/path");
516 }
517
518 void testPinning()
519 {
520 LauncherBackend backend(false);
521
522- // Confirm that default entries are all pinned
523- auto defaultApps = backend.storedApplications();
524- QVERIFY(defaultApps.size() > 0);
525- for (auto app: defaultApps) {
526- QCOMPARE(backend.isPinned(app), true);
527- }
528-
529 backend.setStoredApplications(QStringList() << "one" << "two");
530 QCOMPARE(backend.isPinned("one"), false);
531 QCOMPARE(backend.isPinned("two"), false);

Subscribers

People subscribed via source and target branches