on xenial help sign in
add a AccountsService based launcher model to be used with split greeter
commit775a905bb5c41e349f54b9cbe62cdc307e59d5aa authorMichael Zanetti <michael.zanetti@canonical.com> dateFri 12 Dec 2014, 11:00 (12 years ago) parent1c9e60f
35 files changed+1700−1
plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+9 plugins/AccountsService/AccountsServiceDBusAdaptor.h+13 plugins/CMakeLists.txt+1 plugins/Greeter/CMakeLists.txt+1 plugins/Greeter/Unity/CMakeLists.txt+1 plugins/Greeter/Unity/Launcher/CMakeLists.txt+38 plugins/Greeter/Unity/Launcher/Launcher.qmltypes+179 plugins/Greeter/Unity/Launcher/launcheritem.cpp+174 plugins/Greeter/Unity/Launcher/launcheritem.h+77 plugins/Greeter/Unity/Launcher/launchermodelas.cpp+254 plugins/Greeter/Unity/Launcher/launchermodelas.h+74 plugins/Greeter/Unity/Launcher/plugin.cpp+49 plugins/Greeter/Unity/Launcher/plugin.h+34 plugins/Greeter/Unity/Launcher/qmldir+3 plugins/Greeter/Unity/Launcher/quicklistentry.cpp+59 plugins/Greeter/Unity/Launcher/quicklistentry.h+46 plugins/Greeter/Unity/Launcher/quicklistmodel.cpp+73 plugins/Greeter/Unity/Launcher/quicklistmodel.h+58 plugins/Unity/Launcher/CMakeLists.txt+1 plugins/Unity/Launcher/asadapter.cpp+44 plugins/Unity/Launcher/asadapter.h+30 plugins/Unity/Launcher/launchermodel.cpp+13 plugins/Unity/Launcher/launchermodel.h+2 tests/plugins/CMakeLists.txt+1 tests/plugins/Greeter/CMakeLists.txt+1 tests/plugins/Greeter/Unity/CMakeLists.txt+1 tests/plugins/Greeter/Unity/Launcher/AccountsServiceDBusAdaptor.cpp+51 tests/plugins/Greeter/Unity/Launcher/AccountsServiceDBusAdaptor.h+56 tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt+56 tests/plugins/Greeter/Unity/Launcher/launchermodelastest.cpp+139 tests/plugins/Unity/Launcher/AccountsServiceDBusAdaptor.cpp+46 tests/plugins/Unity/Launcher/AccountsServiceDBusAdaptor.h+49 tests/plugins/Unity/Launcher/CMakeLists.txt+2 tests/plugins/Unity/Launcher/launchermodeltest.cpp+64 tests/qmltests/CMakeLists.txt+1−1
plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+9
@@ -57,6 +57,15 @@ void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QStr
5757 }
5858}
5959
60+void AccountsServiceDBusAdaptor::setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value)
61+{
62+ QDBusInterface *iface = getUserInterface(user);
63+ if (iface != nullptr && iface->isValid()) {
64+ // The value needs to be carefully wrapped
65+ iface->asyncCall("Set", interface, property, QVariant::fromValue(QDBusVariant(value)));
66+ }
67+}
68+
6069void AccountsServiceDBusAdaptor::propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid)
6170{
6271 // Merge changed and invalidated together
plugins/AccountsService/AccountsServiceDBusAdaptor.h+13
@@ -24,6 +24,7 @@
2424#include <QMap>
2525#include <QObject>
2626#include <QString>
27+#include <QDBusArgument>
2728
2829class AccountsServiceDBusAdaptor: public QObject, public QDBusContext
2930{
@@ -33,7 +34,19 @@ public:
3334 explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
3435
3536 Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
37+
38+ template <typename T>
39+ inline T getUserProperty(const QString &user, const QString &interface, const QString &property) {
40+ QVariant variant = getUserProperty(user, interface, property);
41+ if (variant.isValid() && variant.canConvert<QDBusArgument>()) {
42+ qDebug() << "have variant:" << variant;
43+ return qdbus_cast<T>(variant.value<QDBusArgument>());
44+ }
45+ return T();
46+ }
47+
3648 Q_INVOKABLE void setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value);
49+ Q_INVOKABLE void setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value);
3750
3851Q_SIGNALS:
3952 void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
plugins/CMakeLists.txt+1
@@ -12,6 +12,7 @@ macro(add_unity8_plugin PLUGIN VERSION PATH)
1212endmacro()
1313
1414add_subdirectory(AccountsService)
15+add_subdirectory(Greeter)
1516add_subdirectory(LightDM)
1617add_subdirectory(Lights)
1718add_subdirectory(Dash)
plugins/Greeter/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_subdirectory(Unity)
plugins/Greeter/Unity/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_subdirectory(Launcher)
plugins/Greeter/Unity/Launcher/CMakeLists.txtnew file+38
@@ -0,0 +1,38 @@
1+include(FindPkgConfig)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=5)
3+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
4+pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
5+
6+add_definitions(-DSM_BUSNAME=systemBus)
7+
8+include_directories(
9+ ${CMAKE_CURRENT_SOURCE_DIR}
10+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService
11+ ${GSETTINGS_QT_INCLUDE_DIRS}
12+ ${libunity8-private_SOURCE_DIR}
13+)
14+
15+set(QMLLAUNCHERPLUGINAS_SRC
16+ plugin.cpp
17+ launchermodelas.cpp
18+ launcheritem.cpp
19+ quicklistmodel.cpp
20+ quicklistentry.cpp
21+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
22+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
23+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
24+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
25+ )
26+
27+add_library(UnityLauncherAS-qml MODULE
28+ ${QMLLAUNCHERPLUGINAS_SRC}
29+ )
30+
31+target_link_libraries(UnityLauncherAS-qml
32+ unity8-private
33+ ${GSETTINGS_QT_LDFLAGS}
34+ )
35+
36+qt5_use_modules(UnityLauncherAS-qml DBus Qml Gui)
37+
38+add_unity8_plugin(Unity.Launcher 0.1 Unity/Launcher TARGETS UnityLauncherAS-qml TARGET_PREFIX Greeter)
plugins/Greeter/Unity/Launcher/Launcher.qmltypesnew file+179
@@ -0,0 +1,179 @@
1+import QtQuick.tooling 1.1
2+
3+// This file describes the plugin-supplied types contained in the library.
4+// It is used for QML tooling purposes only.
5+//
6+// This file was auto-generated by:
7+// 'qmlplugindump -notrelocatable Unity.Launcher 0.1 plugins'
8+
9+Module {
10+ Component {
11+ name: "LauncherItem"
12+ prototype: "unity::shell::launcher::LauncherItemInterface"
13+ exports: ["Unity.Launcher/LauncherItem 0.1"]
14+ isCreatable: false
15+ exportMetaObjectRevisions: [0]
16+ }
17+ Component {
18+ name: "LauncherModel"
19+ prototype: "unity::shell::launcher::LauncherModelInterface"
20+ exports: ["Unity.Launcher/LauncherModel 0.1"]
21+ isCreatable: false
22+ isSingleton: true
23+ exportMetaObjectRevisions: [0]
24+ Method {
25+ name: "requestRemove"
26+ Parameter { name: "appId"; type: "string" }
27+ }
28+ Method {
29+ name: "get"
30+ type: "unity::shell::launcher::LauncherItemInterface*"
31+ Parameter { name: "index"; type: "int" }
32+ }
33+ Method {
34+ name: "move"
35+ Parameter { name: "oldIndex"; type: "int" }
36+ Parameter { name: "newIndex"; type: "int" }
37+ }
38+ Method {
39+ name: "pin"
40+ Parameter { name: "appId"; type: "string" }
41+ Parameter { name: "index"; type: "int" }
42+ }
43+ Method {
44+ name: "pin"
45+ Parameter { name: "appId"; type: "string" }
46+ }
47+ Method {
48+ name: "quickListActionInvoked"
49+ Parameter { name: "appId"; type: "string" }
50+ Parameter { name: "actionIndex"; type: "int" }
51+ }
52+ Method {
53+ name: "setUser"
54+ Parameter { name: "username"; type: "string" }
55+ }
56+ Method {
57+ name: "getUrlForAppId"
58+ type: "string"
59+ Parameter { name: "appId"; type: "string" }
60+ }
61+ }
62+ Component {
63+ name: "QuickListModel"
64+ prototype: "unity::shell::launcher::QuickListModelInterface"
65+ exports: ["Unity.Launcher/QuickListModel 0.1"]
66+ isCreatable: false
67+ exportMetaObjectRevisions: [0]
68+ }
69+ Component {
70+ name: "unity::shell::launcher::LauncherItemInterface"
71+ prototype: "QObject"
72+ exports: ["Unity.Launcher/LauncherItemInterface 0.1"]
73+ isCreatable: false
74+ exportMetaObjectRevisions: [0]
75+ Property { name: "appId"; type: "string"; isReadonly: true }
76+ Property { name: "name"; type: "string"; isReadonly: true }
77+ Property { name: "icon"; type: "string"; isReadonly: true }
78+ Property { name: "pinned"; type: "bool"; isReadonly: true }
79+ Property { name: "running"; type: "bool"; isReadonly: true }
80+ Property { name: "recent"; type: "bool"; isReadonly: true }
81+ Property { name: "progress"; type: "int"; isReadonly: true }
82+ Property { name: "count"; type: "int"; isReadonly: true }
83+ Property { name: "countVisible"; type: "bool"; isReadonly: true }
84+ Property { name: "focused"; type: "bool"; isReadonly: true }
85+ Property {
86+ name: "quickList"
87+ type: "unity::shell::launcher::QuickListModelInterface"
88+ isReadonly: true
89+ isPointer: true
90+ }
91+ Signal {
92+ name: "nameChanged"
93+ Parameter { name: "name"; type: "string" }
94+ }
95+ Signal {
96+ name: "iconChanged"
97+ Parameter { name: "icon"; type: "string" }
98+ }
99+ Signal {
100+ name: "pinnedChanged"
101+ Parameter { name: "pinned"; type: "bool" }
102+ }
103+ Signal {
104+ name: "runningChanged"
105+ Parameter { name: "running"; type: "bool" }
106+ }
107+ Signal {
108+ name: "recentChanged"
109+ Parameter { name: "running"; type: "bool" }
110+ }
111+ Signal {
112+ name: "progressChanged"
113+ Parameter { name: "progress"; type: "int" }
114+ }
115+ Signal {
116+ name: "countChanged"
117+ Parameter { name: "count"; type: "int" }
118+ }
119+ Signal {
120+ name: "countVisibleChanged"
121+ Parameter { name: "countVisible"; type: "bool" }
122+ }
123+ Signal {
124+ name: "focusedChanged"
125+ Parameter { name: "focused"; type: "bool" }
126+ }
127+ }
128+ Component {
129+ name: "unity::shell::launcher::LauncherModelInterface"
130+ prototype: "QAbstractListModel"
131+ exports: ["Unity.Launcher/LauncherModelInterface 0.1"]
132+ isCreatable: false
133+ exportMetaObjectRevisions: [0]
134+ Property {
135+ name: "applicationManager"
136+ type: "unity::shell::application::ApplicationManagerInterface"
137+ isPointer: true
138+ }
139+ Method {
140+ name: "move"
141+ Parameter { name: "oldIndex"; type: "int" }
142+ Parameter { name: "newIndex"; type: "int" }
143+ }
144+ Method {
145+ name: "get"
146+ type: "unity::shell::launcher::LauncherItemInterface*"
147+ Parameter { name: "index"; type: "int" }
148+ }
149+ Method {
150+ name: "pin"
151+ Parameter { name: "appId"; type: "string" }
152+ Parameter { name: "index"; type: "int" }
153+ }
154+ Method {
155+ name: "pin"
156+ Parameter { name: "appId"; type: "string" }
157+ }
158+ Method {
159+ name: "requestRemove"
160+ Parameter { name: "appId"; type: "string" }
161+ }
162+ Method {
163+ name: "quickListActionInvoked"
164+ Parameter { name: "appId"; type: "string" }
165+ Parameter { name: "actionIndex"; type: "int" }
166+ }
167+ Method {
168+ name: "setUser"
169+ Parameter { name: "username"; type: "string" }
170+ }
171+ }
172+ Component {
173+ name: "unity::shell::launcher::QuickListModelInterface"
174+ prototype: "QAbstractListModel"
175+ exports: ["Unity.Launcher/QuickListInterface 0.1"]
176+ isCreatable: false
177+ exportMetaObjectRevisions: [0]
178+ }
179+}
plugins/Greeter/Unity/Launcher/launcheritem.cppnew file+174
@@ -0,0 +1,174 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Zanetti <michael.zanetti@canonical.com>
18+ */
19+
20+#include "launcheritem.h"
21+#include "quicklistmodel.h"
22+
23+#include <libintl.h>
24+
25+LauncherItem::LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent) :
26+ LauncherItemInterface(parent),
27+ m_appId(appId),
28+ m_name(name),
29+ m_icon(icon),
30+ m_pinned(false),
31+ m_running(false),
32+ m_recent(false),
33+ m_progress(-1),
34+ m_count(0),
35+ m_countVisible(false),
36+ m_focused(false),
37+ m_quickList(new QuickListModel(this))
38+{
39+ QuickListEntry nameAction;
40+ nameAction.setActionId("launch_item");
41+ nameAction.setText(m_name);
42+ m_quickList->appendAction(nameAction);
43+}
44+
45+QString LauncherItem::appId() const
46+{
47+ return m_appId;
48+}
49+
50+QString LauncherItem::name() const
51+{
52+ return m_name;
53+}
54+
55+void LauncherItem::setName(const QString &name)
56+{
57+ if (m_name != name) {
58+ m_name = name;
59+ QuickListEntry entry;
60+ entry.setActionId("launch_item");
61+ entry.setText(m_name);
62+ m_quickList->updateAction(entry);
63+ Q_EMIT nameChanged(name);
64+ }
65+}
66+
67+QString LauncherItem::icon() const
68+{
69+ return m_icon;
70+}
71+
72+void LauncherItem::setIcon(const QString &icon)
73+{
74+ if (m_icon != icon) {
75+ m_icon = icon;
76+ Q_EMIT iconChanged(icon);
77+ }
78+}
79+
80+bool LauncherItem::pinned() const
81+{
82+ return m_pinned;
83+}
84+
85+void LauncherItem::setPinned(bool pinned)
86+{
87+ if (m_pinned != pinned) {
88+ m_pinned = pinned;
89+ Q_EMIT pinnedChanged(pinned);
90+ }
91+}
92+
93+bool LauncherItem::running() const
94+{
95+ return m_running;
96+}
97+
98+void LauncherItem::setRunning(bool running)
99+{
100+ if (m_running != running) {
101+ m_running = running;
102+ Q_EMIT runningChanged(running);
103+ }
104+}
105+
106+bool LauncherItem::recent() const
107+{
108+ return m_recent;
109+}
110+
111+void LauncherItem::setRecent(bool recent)
112+{
113+ if (m_recent != recent) {
114+ m_recent = recent;
115+ Q_EMIT recentChanged(recent);
116+ }
117+}
118+
119+int LauncherItem::progress() const
120+{
121+ return m_progress;
122+}
123+
124+void LauncherItem::setProgress(int progress)
125+{
126+ if (m_progress != progress) {
127+ m_progress = progress;
128+ Q_EMIT progressChanged(progress);
129+ }
130+}
131+
132+int LauncherItem::count() const
133+{
134+ return m_count;
135+}
136+
137+void LauncherItem::setCount(int count)
138+{
139+ if (m_count != count) {
140+ m_count = count;
141+ Q_EMIT countChanged(count);
142+ }
143+}
144+
145+bool LauncherItem::countVisible() const
146+{
147+ return m_countVisible;
148+}
149+
150+void LauncherItem::setCountVisible(bool countVisible)
151+{
152+ if (m_countVisible != countVisible) {
153+ m_countVisible = countVisible;
154+ Q_EMIT countVisibleChanged(countVisible);
155+ }
156+}
157+
158+bool LauncherItem::focused() const
159+{
160+ return m_focused;
161+}
162+
163+void LauncherItem::setFocused(bool focused)
164+{
165+ if (m_focused != focused) {
166+ m_focused = focused;
167+ Q_EMIT focusedChanged(focused);
168+ }
169+}
170+
171+unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
172+{
173+ return m_quickList;
174+}
plugins/Greeter/Unity/Launcher/launcheritem.hnew file+77
@@ -0,0 +1,77 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Zanetti <michael.zanetti@canonical.com>
18+ */
19+
20+#ifndef LAUNCHERITEM_H
21+#define LAUNCHERITEM_H
22+
23+#include "quicklistmodel.h"
24+
25+#include <unity/shell/launcher/LauncherItemInterface.h>
26+
27+class QuickListModel;
28+
29+using namespace unity::shell::launcher;
30+
31+class LauncherItem: public LauncherItemInterface
32+{
33+ Q_OBJECT
34+public:
35+ LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent = 0);
36+
37+ QString appId() const override;
38+ QString name() const override;
39+ QString icon() const override;
40+ bool pinned() const override;
41+ bool running() const override;
42+ bool recent() const override;
43+ int progress() const override;
44+ int count() const override;
45+ bool countVisible() const override;
46+ bool focused() const override;
47+
48+ unity::shell::launcher::QuickListModelInterface *quickList() const override;
49+
50+private:
51+ void setName(const QString &name);
52+ void setIcon(const QString &icon);
53+ void setPinned(bool pinned);
54+ void setRunning(bool running);
55+ void setRecent(bool recent);
56+ void setProgress(int progress);
57+ void setCount(int count);
58+ void setCountVisible(bool countVisible);
59+ void setFocused(bool focused);
60+
61+private:
62+ QString m_appId;
63+ QString m_name;
64+ QString m_icon;
65+ bool m_pinned;
66+ bool m_running;
67+ bool m_recent;
68+ int m_progress;
69+ int m_count;
70+ bool m_countVisible;
71+ bool m_focused;
72+ QuickListModel *m_quickList;
73+
74+ friend class LauncherModel;
75+};
76+
77+#endif // LAUNCHERITEM_H
plugins/Greeter/Unity/Launcher/launchermodelas.cppnew file+254
@@ -0,0 +1,254 @@
1+/*
2+ * Copyright 2013-2014 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Zanetti <michael.zanetti@canonical.com>
18+ */
19+
20+#include "launchermodelas.h"
21+#include "launcheritem.h"
22+#include "AccountsServiceDBusAdaptor.h"
23+#include <unity/shell/application/ApplicationInfoInterface.h>
24+
25+#include <QDesktopServices>
26+#include <QDebug>
27+#include <QDBusArgument>
28+
29+using namespace unity::shell::application;
30+
31+LauncherModel::LauncherModel(QObject *parent):
32+ LauncherModelInterface(parent),
33+ m_accounts(new AccountsServiceDBusAdaptor(this))
34+{
35+ qDebug() << "Loading AS based launcher model";
36+ connect(m_accounts, &AccountsServiceDBusAdaptor::propertiesChanged, this, &LauncherModel::propertiesChanged);
37+ refresh();
38+}
39+
40+LauncherModel::~LauncherModel()
41+{
42+ while (!m_list.empty()) {
43+ m_list.takeFirst()->deleteLater();
44+ }
45+}
46+
47+int LauncherModel::rowCount(const QModelIndex &parent) const
48+{
49+ Q_UNUSED(parent)
50+ return m_list.count();
51+}
52+
53+QVariant LauncherModel::data(const QModelIndex &index, int role) const
54+{
55+ LauncherItem *item = m_list.at(index.row());
56+ switch(role) {
57+ case RoleAppId:
58+ return item->appId();
59+ case RoleName:
60+ return item->name();
61+ case RoleIcon:
62+ return item->icon();
63+ case RolePinned:
64+ return item->pinned();
65+ case RoleCount:
66+ return item->count();
67+ case RoleCountVisible:
68+ return item->countVisible();
69+ case RoleProgress:
70+ return item->progress();
71+ case RoleFocused:
72+ return item->focused();
73+ }
74+
75+ return QVariant();
76+}
77+
78+unity::shell::launcher::LauncherItemInterface *LauncherModel::get(int index) const
79+{
80+ if (index < 0 || index >= m_list.count()) {
81+ return 0;
82+ }
83+ return m_list.at(index);
84+}
85+
86+void LauncherModel::move(int oldIndex, int newIndex)
87+{
88+ Q_UNUSED(oldIndex)
89+ Q_UNUSED(newIndex)
90+ qWarning() << "This is a read only implementation. Cannot move items.";
91+}
92+
93+void LauncherModel::pin(const QString &appId, int index)
94+{
95+ Q_UNUSED(appId)
96+ Q_UNUSED(index)
97+ qWarning() << "This is a read only implementation. Cannot pin items";
98+}
99+
100+void LauncherModel::requestRemove(const QString &appId)
101+{
102+ Q_UNUSED(appId)
103+ qWarning() << "This is a read only implementation. Cannot remove items";
104+}
105+
106+void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex)
107+{
108+ int index = findApplication(appId);
109+ if (index < 0) {
110+ return;
111+ }
112+
113+ LauncherItem *item = m_list.at(index);
114+ QuickListModel *model = qobject_cast<QuickListModel*>(item->quickList());
115+ if (model) {
116+ QString actionId = model->get(actionIndex).actionId();
117+
118+ // Check if this is one of the launcher actions we handle ourselves
119+ if (actionId == "launch_item") {
120+ QDesktopServices::openUrl(getUrlForAppId(appId));
121+
122+ // Nope, we don't know this action, let the backend forward it to the application
123+ } else {
124+ // TODO: forward quicklist action to app, possibly via m_dbusIface
125+ }
126+ }
127+}
128+
129+void LauncherModel::setUser(const QString &username)
130+{
131+ if (m_user != username) {
132+ m_user = username;
133+ refresh();
134+ }
135+}
136+
137+QString LauncherModel::getUrlForAppId(const QString &appId) const
138+{
139+ // appId is either an appId or a legacy app name. Let's find out which
140+ if (appId.isEmpty()) {
141+ return QString();
142+ }
143+
144+ if (!appId.contains("_")) {
145+ return "application:///" + appId + ".desktop";
146+ }
147+
148+ QStringList parts = appId.split('_');
149+ QString package = parts.value(0);
150+ QString app = parts.value(1, "first-listed-app");
151+ return "appid://" + package + "/" + app + "/current-user-version";
152+}
153+
154+ApplicationManagerInterface *LauncherModel::applicationManager() const
155+{
156+ return nullptr;
157+}
158+
159+void LauncherModel::setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager)
160+{
161+ Q_UNUSED(appManager)
162+ qWarning() << "This plugin syncs all its states from AccountsService. Not using ApplicationManager.";
163+ return;
164+}
165+
166+int LauncherModel::findApplication(const QString &appId)
167+{
168+ for (int i = 0; i < m_list.count(); ++i) {
169+ LauncherItem *item = m_list.at(i);
170+ if (item->appId() == appId) {
171+ return i;
172+ }
173+ }
174+ return -1;
175+}
176+
177+typedef QList<QVariantMap> VariantMapList;
178+void LauncherModel::refresh()
179+{
180+ QList<QVariantMap> items;
181+
182+ if (m_accounts && !m_user.isEmpty()) {
183+ items = m_accounts->getUserProperty<VariantMapList>(m_user, "com.canonical.unity.AccountsService", "launcher-items");
184+ }
185+
186+ // First walk through all the existing items and see if we need to remove something
187+ QList<LauncherItem*> toBeRemoved;
188+
189+ Q_FOREACH (LauncherItem* item, m_list) {
190+ bool found = false;
191+ Q_FOREACH(const QVariant &asItem, items) {
192+ if (asItem.toMap().value("id").toString() == item->appId()) {
193+ found = true;
194+ item->setName(asItem.toMap().value("name").toString());
195+ item->setIcon(asItem.toMap().value("icon").toString());
196+ item->setCount(asItem.toMap().value("count").toInt());
197+ item->setCountVisible(asItem.toMap().value("countVisible").toBool());
198+ int idx = m_list.indexOf(item);
199+ Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleName << RoleIcon);
200+ }
201+ }
202+ if (!found) {
203+ toBeRemoved.append(item);
204+ }
205+ }
206+
207+ Q_FOREACH (LauncherItem* item, toBeRemoved) {
208+ int idx = m_list.indexOf(item);
209+ beginRemoveRows(QModelIndex(), idx, idx);
210+ m_list.takeAt(idx)->deleteLater();
211+ endRemoveRows();
212+ }
213+
214+ // Now walk through list and see if we need to add something
215+ for (int asIndex = 0; asIndex < items.count(); ++asIndex) {
216+ QVariant entry = items.at(asIndex);
217+ qDebug() << "have AS item" << entry.toMap().value("id").toString();
218+ int itemIndex = -1;
219+ for (int i = 0; i < m_list.count(); ++i) {
220+ if (m_list.at(i)->appId() == entry.toMap().value("id").toString()) {
221+ itemIndex = i;
222+ break;
223+ }
224+ }
225+
226+ if (itemIndex == -1) {
227+ // Need to add it. Just add it into the addedIndex to keep same ordering as the list in AS.
228+ LauncherItem *item = new LauncherItem(entry.toMap().value("id").toString(),
229+ entry.toMap().value("name").toString(),
230+ entry.toMap().value("icon").toString(),
231+ this);
232+ item->setPinned(true);
233+ item->setCount(entry.toMap().value("count").toInt());
234+ item->setCountVisible(entry.toMap().value("countVisible").toBool());
235+ beginInsertRows(QModelIndex(), asIndex, asIndex);
236+ m_list.insert(asIndex, item);
237+ endInsertRows();
238+ } else if (itemIndex != asIndex) {
239+ // The item is already there, but it is in a different place than in the settings.
240+ // Move it to the addedIndex
241+ beginMoveRows(QModelIndex(), itemIndex, itemIndex, QModelIndex(), asIndex);
242+ m_list.move(itemIndex, asIndex);
243+ endMoveRows();
244+ }
245+ }
246+}
247+
248+void LauncherModel::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
249+{
250+ if (user != m_user || interface != "com.canonical.unity.AccountsService" || !changed.contains("launcher-items")) {
251+ return;
252+ }
253+ refresh();
254+}
plugins/Greeter/Unity/Launcher/launchermodelas.hnew file+74
@@ -0,0 +1,74 @@
1+/*
2+ * Copyright 2013-2014 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Zanetti <michael.zanetti@canonical.com>
18+ */
19+
20+#ifndef LAUNCHERMODEL_H
21+#define LAUNCHERMODEL_H
22+
23+#include <unity/shell/launcher/LauncherModelInterface.h>
24+#include <unity/shell/application/ApplicationManagerInterface.h>
25+
26+#include <QAbstractListModel>
27+
28+class LauncherItem;
29+class GSettings;
30+class AccountsServiceDBusAdaptor;
31+
32+using namespace unity::shell::launcher;
33+using namespace unity::shell::application;
34+
35+class LauncherModel: public LauncherModelInterface
36+{
37+ Q_OBJECT
38+
39+public:
40+ LauncherModel(QObject *parent = 0);
41+ ~LauncherModel();
42+
43+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
44+
45+ QVariant data(const QModelIndex &index, int role) const;
46+
47+ Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const;
48+ Q_INVOKABLE void move(int oldIndex, int newIndex);
49+ Q_INVOKABLE void pin(const QString &appId, int index = -1);
50+ Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
51+ Q_INVOKABLE void setUser(const QString &username);
52+ Q_INVOKABLE QString getUrlForAppId(const QString &appId) const;
53+
54+ unity::shell::application::ApplicationManagerInterface* applicationManager() const;
55+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager);
56+
57+ int findApplication(const QString &appId);
58+
59+public Q_SLOTS:
60+ void requestRemove(const QString &appId) override;
61+ Q_INVOKABLE void refresh();
62+
63+private Q_SLOTS:
64+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
65+
66+private:
67+ QString m_user;
68+ QList<LauncherItem*> m_list;
69+ AccountsServiceDBusAdaptor *m_accounts;
70+
71+ friend class LauncherModelASTest;
72+};
73+
74+#endif // LAUNCHERMODEL_H
plugins/Greeter/Unity/Launcher/plugin.cppnew file+49
@@ -0,0 +1,49 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Zanetti <michael.zanetti@canonical.com>
18+ */
19+
20+// Qt
21+#include <QtQml/qqml.h>
22+
23+// self
24+#include "plugin.h"
25+
26+// local
27+#include "launchermodelas.h"
28+#include "launcheritem.h"
29+
30+
31+using namespace unity::shell::launcher;
32+
33+static QObject* modelProvider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
34+{
35+ return new LauncherModel();
36+}
37+
38+void UnityLauncherPlugin::registerTypes(const char *uri)
39+{
40+ Q_ASSERT(uri == QLatin1String("Unity.Launcher"));
41+
42+ qmlRegisterUncreatableType<LauncherModelInterface>(uri, 0, 1, "LauncherModelInterface", "Abstract Interface. Cannot be instantiated.");
43+ qmlRegisterUncreatableType<LauncherItemInterface>(uri, 0, 1, "LauncherItemInterface", "Abstract Interface. Cannot be instantiated.");
44+ qmlRegisterUncreatableType<QuickListModelInterface>(uri, 0, 1, "QuickListInterface", "Abstract Interface. Cannot be instantiated.");
45+
46+ qmlRegisterSingletonType<LauncherModel>(uri, 0, 1, "LauncherModel", modelProvider);
47+ qmlRegisterUncreatableType<LauncherItem>(uri, 0, 1, "LauncherItem", "Can't create new Launcher Items in QML. Get them from the LauncherModel.");
48+ qmlRegisterUncreatableType<QuickListModel>(uri, 0, 1, "QuickListModel", "Can't create a QuickListModel in QML. Get them from the LauncherItems.");
49+}
plugins/Greeter/Unity/Launcher/plugin.hnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Zanetti <michael.zanetti@canonical.com>
17+ */
18+
19+#ifndef UNITY_LAUNCHER_PLUGIN_H
20+#define UNITY_LAUNCHER_PLUGIN_H
21+
22+#include <QtQml/QQmlEngine>
23+#include <QtQml/QQmlExtensionPlugin>
24+
25+class UnityLauncherPlugin : public QQmlExtensionPlugin
26+{
27+ Q_OBJECT
28+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29+
30+public:
31+ void registerTypes(const char *uri);
32+};
33+
34+#endif
plugins/Greeter/Unity/Launcher/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Unity.Launcher
2+plugin UnityLauncherAS-qml
3+typeinfo Launcher.qmltypes
plugins/Greeter/Unity/Launcher/quicklistentry.cppnew file+59
@@ -0,0 +1,59 @@
1+/* Copyright (C) 2013 Canonical, Ltd.
2+ *
3+ * Authors:
4+ * Michael Zanetti <michael.zanetti@canonical.com>
5+ *
6+ * This program is free software; you can redistribute it and/or modify
7+ * it under the terms of the GNU General Public License as published by
8+ * the Free Software Foundation; version 3.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License
16+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+#include "quicklistentry.h"
20+
21+QuickListEntry::QuickListEntry()
22+{
23+
24+}
25+
26+QString QuickListEntry::actionId() const
27+{
28+ return m_actionId;
29+}
30+
31+void QuickListEntry::setActionId(const QString &actionId)
32+{
33+ m_actionId = actionId;
34+}
35+
36+QString QuickListEntry::text() const
37+{
38+ return m_text;
39+}
40+
41+void QuickListEntry::setText(const QString &text)
42+{
43+ m_text = text;
44+}
45+
46+QString QuickListEntry::icon() const
47+{
48+ return m_icon;
49+}
50+
51+void QuickListEntry::setIcon(const QString &icon)
52+{
53+ m_icon = icon;
54+}
55+
56+bool QuickListEntry::clickable() const
57+{
58+ return !m_actionId.isEmpty();
59+}
plugins/Greeter/Unity/Launcher/quicklistentry.hnew file+46
@@ -0,0 +1,46 @@
1+/* Copyright (C) 2013 Canonical, Ltd.
2+ *
3+ * Authors:
4+ * Michael Zanetti <michael.zanetti@canonical.com>
5+ *
6+ * This program is free software; you can redistribute it and/or modify
7+ * it under the terms of the GNU General Public License as published by
8+ * the Free Software Foundation; version 3.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License
16+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+#ifndef QUICKLISTENTRY_H
20+#define QUICKLISTENTRY_H
21+
22+#include <QString>
23+
24+class QuickListEntry
25+{
26+public:
27+ QuickListEntry();
28+
29+ QString actionId() const;
30+ void setActionId(const QString &actionId);
31+
32+ QString text() const;
33+ void setText(const QString &text);
34+
35+ QString icon() const;
36+ void setIcon(const QString &icon);
37+
38+ bool clickable() const;
39+
40+private:
41+ QString m_actionId;
42+ QString m_text;
43+ QString m_icon;
44+};
45+
46+#endif // QUICKLISTENTRY
plugins/Greeter/Unity/Launcher/quicklistmodel.cppnew file+73
@@ -0,0 +1,73 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Zanetti <michael.zanetti@canonical.com>
18+ */
19+
20+#include "quicklistmodel.h"
21+
22+QuickListModel::QuickListModel(QObject *parent) :
23+ QuickListModelInterface(parent)
24+{
25+
26+}
27+
28+QuickListModel::~QuickListModel()
29+{
30+
31+}
32+
33+void QuickListModel::appendAction(const QuickListEntry &entry)
34+{
35+ beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
36+ m_list.append(entry);
37+ endInsertRows();
38+}
39+
40+void QuickListModel::updateAction(const QuickListEntry &entry)
41+{
42+ for (int i = 0; i < m_list.count(); ++i) {
43+ if (m_list.at(i).actionId() == entry.actionId()) {
44+ m_list.replace(i, entry);
45+ Q_EMIT dataChanged(index(i), index(i));
46+ return;
47+ }
48+ }
49+}
50+
51+QuickListEntry QuickListModel::get(int index) const
52+{
53+ return m_list.at(index);
54+}
55+
56+int QuickListModel::rowCount(const QModelIndex &index) const
57+{
58+ Q_UNUSED(index)
59+ return m_list.count();
60+}
61+
62+QVariant QuickListModel::data(const QModelIndex &index, int role) const
63+{
64+ switch (role) {
65+ case RoleLabel:
66+ return m_list.at(index.row()).text();
67+ case RoleIcon:
68+ return m_list.at(index.row()).icon();
69+ case RoleClickable:
70+ return m_list.at(index.row()).clickable();
71+ }
72+ return QVariant();
73+}
plugins/Greeter/Unity/Launcher/quicklistmodel.hnew file+58
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Zanetti <michael.zanetti@canonical.com>
18+ */
19+
20+#ifndef QUICKLISTMODEL_H
21+#define QUICKLISTMODEL_H
22+
23+#include "quicklistentry.h"
24+
25+#include <unity/shell/launcher/QuickListModelInterface.h>
26+
27+using namespace unity::shell::launcher;
28+
29+class QuickListModel: public QuickListModelInterface
30+{
31+ Q_OBJECT
32+
33+public:
34+ explicit QuickListModel(QObject *parent = 0);
35+
36+ ~QuickListModel();
37+
38+ void appendAction(const QuickListEntry &entry);
39+
40+ /**
41+ * @brief Update an existing action
42+ * @param entry The new, updated entry
43+ *
44+ * This will only do something if entry.actionId is found in the model.
45+ * To add a new entry, use appendAction().
46+ */
47+ void updateAction(const QuickListEntry &entry);
48+
49+ QuickListEntry get(int index) const;
50+
51+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
52+ QVariant data(const QModelIndex &index, int role) const;
53+
54+private:
55+ QList<QuickListEntry> m_list;
56+};
57+
58+#endif // QUICKLISTMODEL_H
plugins/Unity/Launcher/CMakeLists.txt+1
@@ -21,6 +21,7 @@ set(QMLLAUNCHERPLUGIN_SRC
2121 dbusinterface.cpp
2222 gsettings.cpp
2323 desktopfilehandler.cpp
24+ asadapter.cpp
2425 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
2526 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
2627 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
plugins/Unity/Launcher/asadapter.cppnew file+44
@@ -0,0 +1,44 @@
1+#include "asadapter.h"
2+#include "launcheritem.h"
3+#include "AccountsServiceDBusAdaptor.h"
4+
5+#include <QDebug>
6+
7+ASAdapter::ASAdapter()
8+{
9+ m_accounts = new AccountsServiceDBusAdaptor();
10+ m_user = qgetenv("USER");
11+ if (m_user.isEmpty()) {
12+ qWarning() << "$USER not valid. Account Service integration will not work.";
13+ }
14+}
15+
16+ASAdapter::~ASAdapter()
17+{
18+ m_accounts->deleteLater();
19+}
20+
21+void ASAdapter::syncItems(QList<LauncherItem *> m_list)
22+{
23+ qDebug() << "syncing items to AS" << m_list.count();
24+ if (m_accounts && !m_user.isEmpty()) {
25+ QList<QVariantMap> items;
26+
27+ Q_FOREACH(LauncherItem *item, m_list) {
28+ items << itemToVariant(item);
29+ }
30+
31+ m_accounts->setUserPropertyAsync(m_user, "com.canonical.unity.AccountsService", "launcher-items", QVariant::fromValue(items));
32+ }
33+}
34+
35+QVariantMap ASAdapter::itemToVariant(LauncherItem *item) const
36+{
37+ QVariantMap details;
38+ details.insert("id", item->appId());
39+ details.insert("name", item->name());
40+ details.insert("icon", item->icon());
41+ details.insert("count", item->count());
42+ details.insert("countVisible", item->countVisible());
43+ return details;
44+}
plugins/Unity/Launcher/asadapter.hnew file+30
@@ -0,0 +1,30 @@
1+#ifndef ASADAPTER_H
2+#define ASADAPTER_H
3+
4+#include <QVariantMap>
5+
6+class LauncherItem;
7+class AccountsServiceDBusAdaptor;
8+class QDBusInterface;
9+
10+class ASAdapter
11+{
12+public:
13+ ASAdapter();
14+ ~ASAdapter();
15+
16+ void syncItems(QList<LauncherItem*> m_list);
17+
18+private:
19+ QVariantMap itemToVariant(LauncherItem *item) const;
20+
21+private:
22+ AccountsServiceDBusAdaptor *m_accounts;
23+ QString m_user;
24+
25+ QDBusInterface *m_userInterface;
26+
27+ friend class LauncherModelTest;
28+};
29+
30+#endif
plugins/Unity/Launcher/launchermodel.cpp+13
@@ -22,6 +22,7 @@
2222#include "gsettings.h"
2323#include "desktopfilehandler.h"
2424#include "dbusinterface.h"
25+#include "asadapter.h"
2526
2627#include <unity/shell/application/ApplicationInfoInterface.h>
2728
@@ -34,8 +35,10 @@ LauncherModel::LauncherModel(QObject *parent):
3435 LauncherModelInterface(parent),
3536 m_settings(new GSettings(this)),
3637 m_dbusIface(new DBusInterface(this)),
38+ m_asAdapter(new ASAdapter()),
3739 m_appManager(0)
3840{
41+ qDebug() << "Loading dconf based launcher model";
3942 connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged);
4043 connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged);
4144 connect(m_dbusIface, &DBusInterface::refreshCalled, this, &LauncherModel::refresh);
@@ -50,6 +53,8 @@ LauncherModel::~LauncherModel()
5053 while (!m_list.empty()) {
5154 m_list.takeFirst()->deleteLater();
5255 }
56+
57+ delete m_asAdapter;
5358}
5459
5560int LauncherModel::rowCount(const QModelIndex &parent) const
@@ -271,6 +276,7 @@ void LauncherModel::storeAppList()
271276 }
272277 }
273278 m_settings->setStoredApplications(appIds);
279+ m_asAdapter->syncItems(m_list);
274280}
275281
276282void LauncherModel::unpin(const QString &appId)
@@ -321,6 +327,7 @@ void LauncherModel::countChanged(const QString &appId, int count)
321327 LauncherItem *item = m_list.at(idx);
322328 item->setCount(count);
323329 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
330+ m_asAdapter->syncItems(m_list);
324331 }
325332}
326333
@@ -352,10 +359,12 @@ void LauncherModel::countVisibleChanged(const QString &appId, int countVisible)
352359 Q_EMIT hint();
353360 }
354361 }
362+ m_asAdapter->syncItems(m_list);
355363}
356364
357365void LauncherModel::refresh()
358366{
367+ qDebug() << "refreshing";
359368 // First walk through all the existing items and see if we need to remove something
360369 QList<LauncherItem*> toBeRemoved;
361370 Q_FOREACH (LauncherItem* item, m_list) {
@@ -433,6 +442,8 @@ void LauncherModel::refresh()
433442 if (changed) {
434443 Q_EMIT hint();
435444 }
445+
446+ m_asAdapter->syncItems(m_list);
436447}
437448
438449void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
@@ -467,6 +478,7 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
467478 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
468479 m_list.append(item);
469480 endInsertRows();
481+ m_asAdapter->syncItems(m_list);
470482 }
471483}
472484
@@ -486,6 +498,7 @@ void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
486498 beginRemoveRows(QModelIndex(), appIndex, appIndex);
487499 m_list.takeAt(appIndex)->deleteLater();
488500 endRemoveRows();
501+ m_asAdapter->syncItems(m_list);
489502 }
490503}
491504
plugins/Unity/Launcher/launchermodel.h+2
@@ -28,6 +28,7 @@
2828class LauncherItem;
2929class GSettings;
3030class DBusInterface;
31+class ASAdapter;
3132
3233using namespace unity::shell::launcher;
3334using namespace unity::shell::application;
@@ -79,6 +80,7 @@ private:
7980
8081 GSettings *m_settings;
8182 DBusInterface *m_dbusIface;
83+ ASAdapter *m_asAdapter;
8284
8385 ApplicationManagerInterface *m_appManager;
8486
tests/plugins/CMakeLists.txt+1
@@ -1,4 +1,5 @@
11add_subdirectory(AccountsService)
2+add_subdirectory(Greeter)
23add_subdirectory(LightDM)
34add_subdirectory(Dash)
45add_subdirectory(Ubuntu)
tests/plugins/Greeter/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_subdirectory(Unity)
tests/plugins/Greeter/Unity/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_subdirectory(Launcher)
tests/plugins/Greeter/Unity/Launcher/AccountsServiceDBusAdaptor.cppnew file+51
@@ -0,0 +1,51 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "AccountsServiceDBusAdaptor.h"
20+#include <QDebug>
21+#include <QDBusArgument>
22+#include <QDBusMessage>
23+#include <QDBusMetaType>
24+
25+AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
26+ : QObject(parent)
27+{
28+ qDBusRegisterMetaType<QList<QVariantMap>>();
29+}
30+
31+QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
32+{
33+ Q_UNUSED(user)
34+ Q_UNUSED(interface)
35+ Q_UNUSED(property) // We only fake one property here (launcher-items)
36+
37+ QDBusMessage msg;
38+ QVariant v = QVariant::fromValue(properties);
39+ QDBusVariant dv(v);
40+ QVariant packed = QVariant::fromValue(dv);
41+ msg << packed;
42+
43+ return packed.value<QDBusArgument>().asVariant();
44+}
45+
46+void AccountsServiceDBusAdaptor::simulatePropertyChange(const QString &user, const QString &property, const QVariant &value)
47+{
48+ Q_ASSERT(property == "launcher-items");
49+ properties = value.value<QList<QVariantMap>>();
50+ Q_EMIT propertiesChanged(user, "com.canonical.unity.AccountsService", QStringList() << property);
51+}
tests/plugins/Greeter/Unity/Launcher/AccountsServiceDBusAdaptor.hnew file+56
@@ -0,0 +1,56 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
20+#define UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
21+
22+#include <QMap>
23+#include <QObject>
24+#include <QString>
25+#include <QHash>
26+#include <QDBusArgument>
27+
28+extern QList<QVariantMap> properties;
29+
30+class AccountsServiceDBusAdaptor: public QObject
31+{
32+ Q_OBJECT
33+
34+public:
35+ explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
36+
37+ Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
38+ template <typename T>
39+ inline T getUserProperty(const QString &user, const QString &interface, const QString &property) {
40+ Q_UNUSED(user)
41+ Q_UNUSED(interface)
42+ Q_ASSERT(property == "launcher-items");
43+ T ret = properties;
44+ return ret;
45+ }
46+
47+Q_SIGNALS:
48+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
49+
50+private:
51+ void simulatePropertyChange(const QString &user, const QString &property, const QVariant &value);
52+
53+ friend class LauncherModelASTest;
54+};
55+
56+#endif
tests/plugins/Greeter/Unity/Launcher/CMakeLists.txtnew file+56
@@ -0,0 +1,56 @@
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=5)
2+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
3+
4+include_directories(
5+ ${CMAKE_CURRENT_SOURCE_DIR}
6+ ${CMAKE_CURRENT_BINARY_DIR}
7+ ${CMAKE_SOURCE_DIR}/plugins/Greeter/Unity/Launcher
8+ ${libunity8-private_SOURCE_DIR}
9+ )
10+
11+add_definitions(-DSM_BUSNAME=sessionBus)
12+add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
13+add_definitions(-DLAUNCHER_TESTING)
14+
15+### LauncherModelASTest
16+set(testModelCommand dbus-test-runner --task ${CMAKE_CURRENT_BINARY_DIR}/launchermodelastestExec
17+ --parameter -o --parameter ${CMAKE_BINARY_DIR}/launchermodeltest.xml,xunitxml
18+ --parameter -o --parameter -,txt)
19+add_test(NAME launchermodelastest COMMAND ${testModelCommand})
20+add_custom_target(launchermodelastest ${testModelCommand})
21+add_executable(launchermodelastestExec
22+ launchermodelastest.cpp
23+ AccountsServiceDBusAdaptor.cpp
24+ ${CMAKE_SOURCE_DIR}/plugins/Greeter/Unity/Launcher/launchermodelas.cpp
25+ ${CMAKE_SOURCE_DIR}/plugins/Greeter/Unity/Launcher/launcheritem.cpp
26+ ${CMAKE_SOURCE_DIR}/plugins/Greeter/Unity/Launcher/quicklistmodel.cpp
27+ ${CMAKE_SOURCE_DIR}/plugins/Greeter/Unity/Launcher/quicklistentry.cpp
28+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
29+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
30+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
31+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
32+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
33+ )
34+target_link_libraries(launchermodelastestExec
35+ unity8-private
36+ ${GSETTINGS_QT_LDFLAGS}
37+ )
38+qt5_use_modules(launchermodelastestExec Test Core DBus Gui)
39+
40+# copy .desktop files into build directory for shadow builds
41+file(GLOB DESKTOP_FILES *.desktop)
42+
43+foreach(DESKTOP_FILE ${DESKTOP_FILES})
44+ file(COPY "${DESKTOP_FILE}"
45+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
46+ )
47+endforeach()
48+
49+# copy .svg files into build directory for shadow builds
50+file(GLOB DESKTOP_FILES *.svg)
51+
52+foreach(DESKTOP_FILE ${DESKTOP_FILES})
53+ file(COPY "${DESKTOP_FILE}"
54+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
55+ )
56+endforeach()
tests/plugins/Greeter/Unity/Launcher/launchermodelastest.cppnew file+139
@@ -0,0 +1,139 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Zanetti <michael.zanetti@canonical.com>
18+ */
19+
20+// unity-api
21+#include <unity/shell/launcher/LauncherModelInterface.h>
22+#include <unity/shell/application/ApplicationInfoInterface.h>
23+
24+#include "launcheritem.h"
25+#include "launchermodelas.h"
26+#include "AccountsServiceDBusAdaptor.h"
27+
28+#include <QtTest>
29+
30+QList<QVariantMap> properties;
31+
32+class LauncherModelASTest : public QObject
33+{
34+ Q_OBJECT
35+
36+private:
37+ LauncherModel *launcherModel;
38+
39+private Q_SLOTS:
40+
41+ void init() {
42+ // Prepare some fake list
43+ QList<QVariantMap> list;
44+ QVariantMap item;
45+ item.insert("id", "appId1");
46+ item.insert("name", "Item 1");
47+ item.insert("icon", "fake.svg");
48+ item.insert("count", 0);
49+ item.insert("countVisible", false);
50+ list.append(item);
51+ item["id"] = "appId2";
52+ item["name"] = "Item 2";
53+ list.append(item);
54+ properties = list;
55+ }
56+
57+ bool isInSync(LauncherModel *model) {
58+ // Verify after startup the items are in there
59+ bool inSync = model->rowCount() == properties.count();
60+ for (int i = 0; i < model->rowCount(); i++) {
61+ inSync &= model->get(i)->appId() == properties.at(i).value("id").toString();
62+ inSync &= model->get(i)->name() == properties.at(i).value("name").toString();
63+ inSync &= model->get(i)->icon() == properties.at(i).value("icon").toString();
64+ inSync &= model->get(i)->count() == properties.at(i).value("count").toInt();
65+ inSync &= model->get(i)->countVisible() == properties.at(i).value("countVisible").toBool();
66+ }
67+ return inSync;
68+ }
69+
70+ void testLoadASOnStartup() {
71+ // Load up the model
72+ LauncherModel* model = new LauncherModel(this);
73+
74+ // We didn't set a user yet. model should be empty
75+ QCOMPARE(model->rowCount(), 0);
76+
77+ model->setUser("dummy");
78+
79+ QCOMPARE(isInSync(model), true);
80+ model->deleteLater();
81+ }
82+
83+ void testASChangedUpdatesModel_data() {
84+ QTest::addColumn<QString>("modelUser");
85+ QTest::addColumn<QString>("changedUser");
86+ QTest::addColumn<bool>("inSync");
87+
88+ QTest::newRow("this user changed") << "dummy" << "dummy" << true;
89+ QTest::newRow("other user changed") << "dummy" << "fred" << false;
90+ }
91+
92+ void testASChangedUpdatesModel() {
93+ QFETCH(QString, modelUser);
94+ QFETCH(QString, changedUser);
95+ QFETCH(bool, inSync);
96+
97+ LauncherModel* model = new LauncherModel(this);
98+ model->setUser(modelUser);
99+
100+ int oldCount = properties.count();
101+ QCOMPARE(model->rowCount(), oldCount);
102+
103+ QList<QVariantMap> newList = properties;
104+ QVariantMap newEntry;
105+ newEntry.insert("id", "newappId");
106+ newEntry.insert("name", "New app");
107+ newEntry.insert("icon", "some-icon.svg");
108+ newEntry.insert("count", 0);
109+ newEntry.insert("countVisible", false);
110+ newList.append(newEntry);
111+ model->m_accounts->simulatePropertyChange(changedUser, "launcher-items", QVariant::fromValue(newList));
112+
113+ QCOMPARE(isInSync(model), inSync);
114+
115+ model->deleteLater();
116+ }
117+
118+ void testUpdateCount() {
119+ LauncherModel* model = new LauncherModel(this);
120+ model->setUser("dummy");
121+
122+ QCOMPARE(model->get(0)->countVisible(), false);
123+ QCOMPARE(model->get(0)->count(), 0);
124+
125+ QList<QVariantMap> newList = properties;
126+ QVariantMap entry = newList.at(0);
127+ entry["countVisible"] = true;
128+ entry["count"] = 55;
129+ newList[0] = entry;
130+ model->m_accounts->simulatePropertyChange("dummy", "launcher-items", QVariant::fromValue(newList));
131+
132+ QCOMPARE(isInSync(model), true);
133+
134+ model->deleteLater();
135+ }
136+};
137+
138+QTEST_GUILESS_MAIN(LauncherModelASTest)
139+#include "launchermodelastest.moc"
tests/plugins/Unity/Launcher/AccountsServiceDBusAdaptor.cppnew file+46
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "AccountsServiceDBusAdaptor.h"
20+#include <QDebug>
21+
22+AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
23+ : QObject(parent)
24+{
25+}
26+
27+QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
28+{
29+ Q_UNUSED(user)
30+ Q_UNUSED(interface)
31+ qDebug() << "returning properties" << m_properties.value(property);
32+ return m_properties.value(property);
33+}
34+
35+void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value)
36+{
37+ qDebug() << "setting property" << property << value;
38+ Q_UNUSED(user)
39+ Q_UNUSED(interface)
40+ m_properties[property] = value;
41+}
42+
43+void AccountsServiceDBusAdaptor::setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value)
44+{
45+ setUserProperty(user, interface, property, value);
46+}
tests/plugins/Unity/Launcher/AccountsServiceDBusAdaptor.hnew file+49
@@ -0,0 +1,49 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
20+#define UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
21+
22+#include <QMap>
23+#include <QObject>
24+#include <QString>
25+#include <QHash>
26+
27+class AccountsServiceDBusAdaptor: public QObject
28+{
29+ Q_OBJECT
30+
31+public:
32+ explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
33+
34+ Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
35+ Q_INVOKABLE void setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value);
36+ Q_INVOKABLE void setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value);
37+
38+Q_SIGNALS:
39+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
40+ void maybeChanged(const QString &user); // Standard properties might have changed
41+
42+private:
43+ void simulatePropertyChange(const QString &property, const QVariant &value);
44+
45+private:
46+ QHash<QString, QVariant> m_properties;
47+};
48+
49+#endif
tests/plugins/Unity/Launcher/CMakeLists.txt+2
@@ -23,7 +23,9 @@ add_custom_target(launchermodeltest ${testModelCommand})
2323add_executable(launchermodeltestExec
2424 launchermodeltest.cpp
2525 gsettings.cpp
26+ AccountsServiceDBusAdaptor.cpp
2627 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launchermodel.cpp
28+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/asadapter.cpp
2729 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launcheritem.cpp
2830 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistmodel.cpp
2931 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/dbusinterface.cpp
tests/plugins/Unity/Launcher/launchermodeltest.cpp+64
@@ -25,6 +25,8 @@
2525#include "launchermodel.h"
2626#include "dbusinterface.h"
2727#include "gsettings.h"
28+#include "asadapter.h"
29+#include "AccountsServiceDBusAdaptor.h"
2830
2931#include <QtTest>
3032#include <QDBusInterface>
@@ -129,6 +131,11 @@ private:
129131 LauncherModel *launcherModel;
130132 MockAppManager *appManager;
131133
134+ QList<QVariantMap> getASConfig() {
135+ AccountsServiceDBusAdaptor *as = launcherModel->m_asAdapter->m_accounts;
136+ return as->getUserProperty("", "", "launcher-items").value<QList<QVariantMap>>();
137+ }
138+
132139private Q_SLOTS:
133140
134141 void initTestCase() {
@@ -467,6 +474,63 @@ private Q_SLOTS:
467474 QCOMPARE(launcherModel->get(1)->appId(), QString("abs-icon"));
468475 QCOMPARE(spy.count(), 2);
469476 }
477+
478+ void testAddSyncsToAS() {
479+ // Make sure launcher and AS are in sync when we start the test
480+ QCOMPARE(launcherModel->rowCount(), getASConfig().count());
481+
482+ int oldCount = launcherModel->rowCount();
483+ appManager->addApplication(new MockApp("rel-icon"));
484+ QCOMPARE(launcherModel->rowCount(), oldCount + 1);
485+ QCOMPARE(launcherModel->rowCount(), getASConfig().count());
486+ }
487+
488+ void testRemoveSyncsToAS() {
489+ // Make sure launcher and AS are in sync when we start the test
490+ QCOMPARE(launcherModel->rowCount(), getASConfig().count());
491+
492+ int oldCount = launcherModel->rowCount();
493+ appManager->stopApplication("abs-icon");
494+ QCOMPARE(launcherModel->rowCount(), oldCount - 1);
495+ QCOMPARE(launcherModel->rowCount(), getASConfig().count());
496+ }
497+
498+ void testMoveSyncsToAS() {
499+ // Make sure launcher and AS are in sync when we start the test
500+ QCOMPARE(launcherModel->rowCount(), getASConfig().count());
501+
502+ for (int i = 0; i < launcherModel->rowCount(); i++) {
503+ QString launcherAppId = launcherModel->get(i)->appId();
504+ QString asAppId = getASConfig().at(i).value("id").toString();
505+ QCOMPARE(launcherAppId, asAppId);
506+ }
507+
508+ launcherModel->move(0, 1);
509+
510+ for (int i = 0; i < launcherModel->rowCount(); i++) {
511+ QString launcherAppId = launcherModel->get(i)->appId();
512+ QString asAppId = getASConfig().at(i).value("id").toString();
513+ QCOMPARE(launcherAppId, asAppId);
514+ }
515+ }
516+
517+ void testCountChangeSyncsToAS() {
518+ // Find the index of the abs-icon app
519+ int index = launcherModel->findApplication("abs-icon");
520+
521+ // Make sure it's invisible and 0 at the beginning
522+ QCOMPARE(getASConfig().at(index).value("countVisible").toBool(), false);
523+ QCOMPARE(getASConfig().at(index).value("count").toInt(), 0);
524+
525+ // Change the count of the abs-icon app through D-Bus
526+ QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher/abs_2Dicon", "org.freedesktop.DBus.Properties");
527+ interface.call("Set", "com.canonical.Unity.Launcher.Item", "count", QVariant::fromValue(QDBusVariant(55)));
528+ interface.call("Set", "com.canonical.Unity.Launcher.Item", "countVisible", QVariant::fromValue(QDBusVariant(true)));
529+
530+ // Make sure it changed to visible and 55
531+ QCOMPARE(getASConfig().at(index).value("countVisible").toBool(), true);
532+ QCOMPARE(getASConfig().at(index).value("count").toInt(), 55);
533+ }
470534};
471535
472536QTEST_GUILESS_MAIN(LauncherModelTest)
tests/qmltests/CMakeLists.txt+1−1
@@ -64,7 +64,7 @@ add_qml_test(Greeter MultiGreeter ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DI
6464add_qml_test(Greeter SingleGreeter ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
6565add_qml_test(Greeter Infographics ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
6666add_qml_test(Greeter Clock ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
67−add_qml_test(Launcher Launcher)
67+add_qml_test(Launcher Launcher IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/utils/modules ${CMAKE_BINARY_DIR}/plugins ${CMAKE_BINARY_DIR}/plugins/Greeter/)
6868add_qml_test(Notifications Notifications)
6969add_qml_test(Notifications VisualSnapDecisionsQueue)
7070add_qml_test(Notifications OptionToggle)