on xenial help sign in
Add an AccountService based launcher model to be used with split greeter
5f76e13Michael Zanetti
debian/control+1−1
@@ -27,7 +27,7 @@ Build-Depends: cmake,
27 libqmenumodel-dev (>= 0.2.9),
27 libqmenumodel-dev (>= 0.2.9),
28 libqt5xmlpatterns5-dev,
28 libqt5xmlpatterns5-dev,
29 libsystemsettings-dev,
29 libsystemsettings-dev,
30− libunity-api-dev (>= 7.94),
30+ libunity-api-dev (>= 7.95),
31 libusermetricsoutput1-dev,
31 libusermetricsoutput1-dev,
32 libxcb1-dev,
32 libxcb1-dev,
33 pkg-config,
33 pkg-config,
debian/unity8-private.install+1
@@ -1,6 +1,7 @@
1usr/lib/*/libunity8-private.*
1usr/lib/*/libunity8-private.*
2usr/lib/*/unity8/qml/AccountsService
2usr/lib/*/unity8/qml/AccountsService
3usr/lib/*/unity8/qml/Dash
3usr/lib/*/unity8/qml/Dash
4+usr/lib/*/unity8/qml/Greeter
4usr/lib/*/unity8/qml/LightDM
5usr/lib/*/unity8/qml/LightDM
5usr/lib/*/unity8/qml/Lights
6usr/lib/*/unity8/qml/Lights
6usr/lib/*/unity8/qml/Powerd
7usr/lib/*/unity8/qml/Powerd
plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+9
@@ -57,6 +57,15 @@ void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QStr
57 }
57 }
58}
58}
59
59
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+
60void AccountsServiceDBusAdaptor::propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid)
69void AccountsServiceDBusAdaptor::propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid)
61{
70{
62 // Merge changed and invalidated together
71 // Merge changed and invalidated together
plugins/AccountsService/AccountsServiceDBusAdaptor.h+12
@@ -19,6 +19,7 @@
19#ifndef UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
19#ifndef UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
20#define UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
20#define UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
21
21
22+#include <QDBusArgument>
22#include <QDBusContext>
23#include <QDBusContext>
23#include <QDBusInterface>
24#include <QDBusInterface>
24#include <QMap>
25#include <QMap>
@@ -33,7 +34,18 @@ public:
33 explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
34 explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
34
35
35 Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
36 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+ return qdbus_cast<T>(variant.value<QDBusArgument>());
43+ }
44+ return T();
45+ }
46+
36 Q_INVOKABLE void setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value);
47 Q_INVOKABLE void setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value);
48+ Q_INVOKABLE void setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value);
37
49
38Q_SIGNALS:
50Q_SIGNALS:
39 void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
51 void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
plugins/AccountsService/com.canonical.unity.AccountsService.xml+1−2
@@ -14,8 +14,7 @@
14 <annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/>
14 <annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/>
15 </property>
15 </property>
16
16
17− <!-- Should have been named LauncherItems, sorry folks. -mterry -->
18− <property name="launcher-items" type="aa{sv}" access="readwrite">
17+ <property name="LauncherItems" type="aa{sv}" access="readwrite">
19 <annotation name="org.freedesktop.Accounts.DefaultValue" value="[{'defaults': <true>}]"/>
18 <annotation name="org.freedesktop.Accounts.DefaultValue" value="[{'defaults': <true>}]"/>
20 </property>
19 </property>
21
20
plugins/CMakeLists.txt+1
@@ -12,6 +12,7 @@ macro(add_unity8_plugin PLUGIN VERSION PATH)
12endmacro()
12endmacro()
13
13
14add_subdirectory(AccountsService)
14add_subdirectory(AccountsService)
15+add_subdirectory(Greeter)
15add_subdirectory(LightDM)
16add_subdirectory(LightDM)
16add_subdirectory(Lights)
17add_subdirectory(Lights)
17add_subdirectory(Dash)
18add_subdirectory(Dash)
plugins/Greeter/CMakeLists.txtnew file+6
@@ -0,0 +1,6 @@
1+macro(add_unity8_greeter_plugin PLUGIN VERSION PATH)
2+ export_qmlfiles(${PLUGIN} ${PATH} DESTINATION ${SHELL_INSTALL_QML}/Greeter TARGET_PREFIX Greeter ${ARGN})
3+ export_qmlplugin(${PLUGIN} ${VERSION} ${PATH} DESTINATION ${SHELL_INSTALL_QML}/Greeter TARGET_PREFIX Greeter ${ARGN})
4+endmacro()
5+
6+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=6)
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_greeter_plugin(Unity.Launcher 0.1 Unity/Launcher TARGETS UnityLauncherAS-qml)
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+171
@@ -0,0 +1,171 @@
1+/*
2+ * Copyright 2014-2015 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+
17+#include "launcheritem.h"
18+#include "quicklistmodel.h"
19+
20+#include <libintl.h>
21+
22+LauncherItem::LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent) :
23+ LauncherItemInterface(parent),
24+ m_appId(appId),
25+ m_name(name),
26+ m_icon(icon),
27+ m_pinned(false),
28+ m_running(false),
29+ m_recent(false),
30+ m_progress(-1),
31+ m_count(0),
32+ m_countVisible(false),
33+ m_focused(false),
34+ m_quickList(new QuickListModel(this))
35+{
36+ QuickListEntry nameAction;
37+ nameAction.setActionId("launch_item");
38+ nameAction.setText(m_name);
39+ m_quickList->appendAction(nameAction);
40+}
41+
42+QString LauncherItem::appId() const
43+{
44+ return m_appId;
45+}
46+
47+QString LauncherItem::name() const
48+{
49+ return m_name;
50+}
51+
52+void LauncherItem::setName(const QString &name)
53+{
54+ if (m_name != name) {
55+ m_name = name;
56+ QuickListEntry entry;
57+ entry.setActionId("launch_item");
58+ entry.setText(m_name);
59+ m_quickList->updateAction(entry);
60+ Q_EMIT nameChanged(name);
61+ }
62+}
63+
64+QString LauncherItem::icon() const
65+{
66+ return m_icon;
67+}
68+
69+void LauncherItem::setIcon(const QString &icon)
70+{
71+ if (m_icon != icon) {
72+ m_icon = icon;
73+ Q_EMIT iconChanged(icon);
74+ }
75+}
76+
77+bool LauncherItem::pinned() const
78+{
79+ return m_pinned;
80+}
81+
82+void LauncherItem::setPinned(bool pinned)
83+{
84+ if (m_pinned != pinned) {
85+ m_pinned = pinned;
86+ Q_EMIT pinnedChanged(pinned);
87+ }
88+}
89+
90+bool LauncherItem::running() const
91+{
92+ return m_running;
93+}
94+
95+void LauncherItem::setRunning(bool running)
96+{
97+ if (m_running != running) {
98+ m_running = running;
99+ Q_EMIT runningChanged(running);
100+ }
101+}
102+
103+bool LauncherItem::recent() const
104+{
105+ return m_recent;
106+}
107+
108+void LauncherItem::setRecent(bool recent)
109+{
110+ if (m_recent != recent) {
111+ m_recent = recent;
112+ Q_EMIT recentChanged(recent);
113+ }
114+}
115+
116+int LauncherItem::progress() const
117+{
118+ return m_progress;
119+}
120+
121+void LauncherItem::setProgress(int progress)
122+{
123+ if (m_progress != progress) {
124+ m_progress = progress;
125+ Q_EMIT progressChanged(progress);
126+ }
127+}
128+
129+int LauncherItem::count() const
130+{
131+ return m_count;
132+}
133+
134+void LauncherItem::setCount(int count)
135+{
136+ if (m_count != count) {
137+ m_count = count;
138+ Q_EMIT countChanged(count);
139+ }
140+}
141+
142+bool LauncherItem::countVisible() const
143+{
144+ return m_countVisible;
145+}
146+
147+void LauncherItem::setCountVisible(bool countVisible)
148+{
149+ if (m_countVisible != countVisible) {
150+ m_countVisible = countVisible;
151+ Q_EMIT countVisibleChanged(countVisible);
152+ }
153+}
154+
155+bool LauncherItem::focused() const
156+{
157+ return m_focused;
158+}
159+
160+void LauncherItem::setFocused(bool focused)
161+{
162+ if (m_focused != focused) {
163+ m_focused = focused;
164+ Q_EMIT focusedChanged(focused);
165+ }
166+}
167+
168+unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
169+{
170+ return m_quickList;
171+}
plugins/Greeter/Unity/Launcher/launcheritem.hnew file+74
@@ -0,0 +1,74 @@
1+/*
2+ * Copyright 2014-2015 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+
17+#ifndef LAUNCHERITEM_H
18+#define LAUNCHERITEM_H
19+
20+#include "quicklistmodel.h"
21+
22+#include <unity/shell/launcher/LauncherItemInterface.h>
23+
24+class QuickListModel;
25+
26+using namespace unity::shell::launcher;
27+
28+class LauncherItem: public LauncherItemInterface
29+{
30+ Q_OBJECT
31+public:
32+ LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent = 0);
33+
34+ QString appId() const override;
35+ QString name() const override;
36+ QString icon() const override;
37+ bool pinned() const override;
38+ bool running() const override;
39+ bool recent() const override;
40+ int progress() const override;
41+ int count() const override;
42+ bool countVisible() const override;
43+ bool focused() const override;
44+
45+ unity::shell::launcher::QuickListModelInterface *quickList() const override;
46+
47+private:
48+ void setName(const QString &name);
49+ void setIcon(const QString &icon);
50+ void setPinned(bool pinned);
51+ void setRunning(bool running);
52+ void setRecent(bool recent);
53+ void setProgress(int progress);
54+ void setCount(int count);
55+ void setCountVisible(bool countVisible);
56+ void setFocused(bool focused);
57+
58+private:
59+ QString m_appId;
60+ QString m_name;
61+ QString m_icon;
62+ bool m_pinned;
63+ bool m_running;
64+ bool m_recent;
65+ int m_progress;
66+ int m_count;
67+ bool m_countVisible;
68+ bool m_focused;
69+ QuickListModel *m_quickList;
70+
71+ friend class LauncherModel;
72+};
73+
74+#endif // LAUNCHERITEM_H
plugins/Greeter/Unity/Launcher/launchermodelas.cppnew file+277
@@ -0,0 +1,277 @@
1+/*
2+ * Copyright 2014-2015 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+
17+#include "launchermodelas.h"
18+#include "launcheritem.h"
19+#include "AccountsServiceDBusAdaptor.h"
20+#include <unity/shell/application/ApplicationInfoInterface.h>
21+
22+#include <QDesktopServices>
23+#include <QDebug>
24+#include <QDBusArgument>
25+
26+using namespace unity::shell::application;
27+
28+LauncherModel::LauncherModel(QObject *parent):
29+ LauncherModelInterface(parent),
30+ m_accounts(new AccountsServiceDBusAdaptor(this)),
31+ m_onlyPinned(true)
32+{
33+ connect(m_accounts, &AccountsServiceDBusAdaptor::propertiesChanged, this, &LauncherModel::propertiesChanged);
34+ refresh();
35+}
36+
37+LauncherModel::~LauncherModel()
38+{
39+ while (!m_list.empty()) {
40+ m_list.takeFirst()->deleteLater();
41+ }
42+}
43+
44+int LauncherModel::rowCount(const QModelIndex &parent) const
45+{
46+ Q_UNUSED(parent)
47+ return m_list.count();
48+}
49+
50+QVariant LauncherModel::data(const QModelIndex &index, int role) const
51+{
52+ LauncherItem *item = m_list.at(index.row());
53+ switch(role) {
54+ case RoleAppId:
55+ return item->appId();
56+ case RoleName:
57+ return item->name();
58+ case RoleIcon:
59+ return item->icon();
60+ case RolePinned:
61+ return item->pinned();
62+ case RoleCount:
63+ return item->count();
64+ case RoleCountVisible:
65+ return item->countVisible();
66+ case RoleProgress:
67+ return item->progress();
68+ case RoleFocused:
69+ return item->focused();
70+ }
71+
72+ return QVariant();
73+}
74+
75+unity::shell::launcher::LauncherItemInterface *LauncherModel::get(int index) const
76+{
77+ if (index < 0 || index >= m_list.count()) {
78+ return 0;
79+ }
80+ return m_list.at(index);
81+}
82+
83+void LauncherModel::move(int oldIndex, int newIndex)
84+{
85+ Q_UNUSED(oldIndex)
86+ Q_UNUSED(newIndex)
87+ qWarning() << "This is a read only implementation. Cannot move items.";
88+}
89+
90+void LauncherModel::pin(const QString &appId, int index)
91+{
92+ Q_UNUSED(appId)
93+ Q_UNUSED(index)
94+ qWarning() << "This is a read only implementation. Cannot pin items";
95+}
96+
97+void LauncherModel::requestRemove(const QString &appId)
98+{
99+ Q_UNUSED(appId)
100+ qWarning() << "This is a read only implementation. Cannot remove items";
101+}
102+
103+void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex)
104+{
105+ int index = findApplication(appId);
106+ if (index < 0) {
107+ return;
108+ }
109+
110+ LauncherItem *item = m_list.at(index);
111+ QuickListModel *model = qobject_cast<QuickListModel*>(item->quickList());
112+ if (model) {
113+ QString actionId = model->get(actionIndex).actionId();
114+
115+ // Check if this is one of the launcher actions we handle ourselves
116+ if (actionId == "launch_item") {
117+ QDesktopServices::openUrl(getUrlForAppId(appId));
118+
119+ // Nope, we don't know this action, let the backend forward it to the application
120+ } else {
121+ // TODO: forward quicklist action to app, possibly via m_dbusIface
122+ }
123+ }
124+}
125+
126+void LauncherModel::setUser(const QString &username)
127+{
128+ if (m_user != username) {
129+ m_user = username;
130+ refresh();
131+ }
132+}
133+
134+QString LauncherModel::getUrlForAppId(const QString &appId) const
135+{
136+ // appId is either an appId or a legacy app name. Let's find out which
137+ if (appId.isEmpty()) {
138+ return QString();
139+ }
140+
141+ if (!appId.contains("_")) {
142+ return "application:///" + appId + ".desktop";
143+ }
144+
145+ QStringList parts = appId.split('_');
146+ QString package = parts.value(0);
147+ QString app = parts.value(1, "first-listed-app");
148+ return "appid://" + package + "/" + app + "/current-user-version";
149+}
150+
151+ApplicationManagerInterface *LauncherModel::applicationManager() const
152+{
153+ return nullptr;
154+}
155+
156+void LauncherModel::setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager)
157+{
158+ Q_UNUSED(appManager)
159+ qWarning() << "This plugin syncs all its states from AccountsService. Not using ApplicationManager.";
160+ return;
161+}
162+
163+bool LauncherModel::onlyPinned() const
164+{
165+ return m_onlyPinned;
166+}
167+
168+void LauncherModel::setOnlyPinned(bool onlyPinned)
169+{
170+ if (m_onlyPinned != onlyPinned) {
171+ m_onlyPinned = onlyPinned;
172+ Q_EMIT onlyPinnedChanged();
173+ refresh();
174+ }
175+}
176+
177+int LauncherModel::findApplication(const QString &appId)
178+{
179+ for (int i = 0; i < m_list.count(); ++i) {
180+ LauncherItem *item = m_list.at(i);
181+ if (item->appId() == appId) {
182+ return i;
183+ }
184+ }
185+ return -1;
186+}
187+
188+typedef QList<QVariantMap> VariantMapList;
189+void LauncherModel::refresh()
190+{
191+ QList<QVariantMap> items;
192+
193+ if (m_accounts && !m_user.isEmpty()) {
194+ items = m_accounts->getUserProperty<VariantMapList>(m_user, "com.canonical.unity.AccountsService", "LauncherItems");
195+ }
196+
197+ // First walk through all the existing items and see if we need to remove something
198+ QList<LauncherItem*> toBeRemoved;
199+
200+ Q_FOREACH (LauncherItem* item, m_list) {
201+ bool found = false;
202+ Q_FOREACH(const QVariant &asItem, items) {
203+ if (asItem.toMap().value("id").toString() == item->appId()) {
204+ // Only keep and update it if we either show unpinned or it is pinned
205+ if (!m_onlyPinned || asItem.toMap().value("pinned").toBool()) {
206+ found = true;
207+ item->setName(asItem.toMap().value("name").toString());
208+ item->setIcon(asItem.toMap().value("icon").toString());
209+ item->setCount(asItem.toMap().value("count").toInt());
210+ item->setCountVisible(asItem.toMap().value("countVisible").toBool());
211+ int idx = m_list.indexOf(item);
212+ Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleName << RoleIcon);
213+ }
214+ break;
215+ }
216+ }
217+ if (!found) {
218+ toBeRemoved.append(item);
219+ }
220+ }
221+
222+ Q_FOREACH (LauncherItem* item, toBeRemoved) {
223+ int idx = m_list.indexOf(item);
224+ beginRemoveRows(QModelIndex(), idx, idx);
225+ m_list.takeAt(idx)->deleteLater();
226+ endRemoveRows();
227+ }
228+
229+ // Now walk through list and see if we need to add something
230+ int skipped = 0;
231+ for (int asIndex = 0; asIndex < items.count(); ++asIndex) {
232+ QVariant entry = items.at(asIndex);
233+
234+ if (m_onlyPinned && !entry.toMap().value("pinned").toBool()) {
235+ // Skipping it as we only show pinned and it is not
236+ skipped++;
237+ continue;
238+ }
239+ int newPosition = asIndex - skipped;
240+
241+ int itemIndex = -1;
242+ for (int i = 0; i < m_list.count(); ++i) {
243+ if (m_list.at(i)->appId() == entry.toMap().value("id").toString()) {
244+ itemIndex = i;
245+ break;
246+ }
247+ }
248+
249+ if (itemIndex == -1) {
250+ // Need to add it. Just add it into the addedIndex to keep same ordering as the list in AS.
251+ LauncherItem *item = new LauncherItem(entry.toMap().value("id").toString(),
252+ entry.toMap().value("name").toString(),
253+ entry.toMap().value("icon").toString(),
254+ this);
255+ item->setPinned(true);
256+ item->setCount(entry.toMap().value("count").toInt());
257+ item->setCountVisible(entry.toMap().value("countVisible").toBool());
258+ beginInsertRows(QModelIndex(), newPosition, newPosition);
259+ m_list.insert(newPosition, item);
260+ endInsertRows();
261+ } else if (itemIndex != newPosition) {
262+ // The item is already there, but it is in a different place than in the settings.
263+ // Move it to the addedIndex
264+ beginMoveRows(QModelIndex(), itemIndex, itemIndex, QModelIndex(), newPosition);
265+ m_list.move(itemIndex, newPosition);
266+ endMoveRows();
267+ }
268+ }
269+}
270+
271+void LauncherModel::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
272+{
273+ if (user != m_user || interface != "com.canonical.unity.AccountsService" || !changed.contains("LauncherItems")) {
274+ return;
275+ }
276+ refresh();
277+}
plugins/Greeter/Unity/Launcher/launchermodelas.hnew file+75
@@ -0,0 +1,75 @@
1+/*
2+ * Copyright 2014-2015 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+
17+#ifndef LAUNCHERMODEL_H
18+#define LAUNCHERMODEL_H
19+
20+#include <unity/shell/launcher/LauncherModelInterface.h>
21+#include <unity/shell/application/ApplicationManagerInterface.h>
22+
23+#include <QAbstractListModel>
24+
25+class LauncherItem;
26+class GSettings;
27+class AccountsServiceDBusAdaptor;
28+
29+using namespace unity::shell::launcher;
30+using namespace unity::shell::application;
31+
32+class LauncherModel: public LauncherModelInterface
33+{
34+ Q_OBJECT
35+
36+public:
37+ LauncherModel(QObject *parent = 0);
38+ ~LauncherModel();
39+
40+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
41+
42+ QVariant data(const QModelIndex &index, int role) const;
43+
44+ Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const;
45+ Q_INVOKABLE void move(int oldIndex, int newIndex);
46+ Q_INVOKABLE void pin(const QString &appId, int index = -1);
47+ Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
48+ Q_INVOKABLE void setUser(const QString &username);
49+ Q_INVOKABLE QString getUrlForAppId(const QString &appId) const;
50+
51+ unity::shell::application::ApplicationManagerInterface* applicationManager() const;
52+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager);
53+
54+ bool onlyPinned() const override;
55+ void setOnlyPinned(bool onlyPinned) override;
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+ bool m_onlyPinned;
71+
72+ friend class LauncherModelASTest;
73+};
74+
75+#endif // LAUNCHERMODEL_H
plugins/Greeter/Unity/Launcher/plugin.cppnew file+46
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright 2014-2015 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+
17+// Qt
18+#include <QtQml/qqml.h>
19+
20+// self
21+#include "plugin.h"
22+
23+// local
24+#include "launchermodelas.h"
25+#include "launcheritem.h"
26+
27+
28+using namespace unity::shell::launcher;
29+
30+static QObject* modelProvider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
31+{
32+ return new LauncherModel();
33+}
34+
35+void UnityLauncherPlugin::registerTypes(const char *uri)
36+{
37+ Q_ASSERT(uri == QLatin1String("Unity.Launcher"));
38+
39+ qmlRegisterUncreatableType<LauncherModelInterface>(uri, 0, 1, "LauncherModelInterface", "Abstract Interface. Cannot be instantiated.");
40+ qmlRegisterUncreatableType<LauncherItemInterface>(uri, 0, 1, "LauncherItemInterface", "Abstract Interface. Cannot be instantiated.");
41+ qmlRegisterUncreatableType<QuickListModelInterface>(uri, 0, 1, "QuickListInterface", "Abstract Interface. Cannot be instantiated.");
42+
43+ qmlRegisterSingletonType<LauncherModel>(uri, 0, 1, "LauncherModel", modelProvider);
44+ qmlRegisterUncreatableType<LauncherItem>(uri, 0, 1, "LauncherItem", "Can't create new Launcher Items in QML. Get them from the LauncherModel.");
45+ qmlRegisterUncreatableType<QuickListModel>(uri, 0, 1, "QuickListModel", "Can't create a QuickListModel in QML. Get them from the LauncherItems.");
46+}
plugins/Greeter/Unity/Launcher/plugin.hnew file+32
@@ -0,0 +1,32 @@
1+/*
2+ * Copyright (C) 2014-2015 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+
17+#ifndef UNITY_LAUNCHER_PLUGIN_H
18+#define UNITY_LAUNCHER_PLUGIN_H
19+
20+#include <QtQml/QQmlEngine>
21+#include <QtQml/QQmlExtensionPlugin>
22+
23+class UnityLauncherPlugin : public QQmlExtensionPlugin
24+{
25+ Q_OBJECT
26+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27+
28+public:
29+ void registerTypes(const char *uri);
30+};
31+
32+#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+56
@@ -0,0 +1,56 @@
1+/* Copyright (C) 2014-2015 Canonical, Ltd.
2+ *
3+ * This program is free software; you can redistribute it and/or modify
4+ * it under the terms of the GNU General Public License as published by
5+ * the Free Software Foundation; version 3.
6+ *
7+ * This program is distributed in the hope that it will be useful,
8+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+ * GNU General Public License for more details.
11+ *
12+ * You should have received a copy of the GNU General Public License
13+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
14+ */
15+
16+#include "quicklistentry.h"
17+
18+QuickListEntry::QuickListEntry()
19+{
20+
21+}
22+
23+QString QuickListEntry::actionId() const
24+{
25+ return m_actionId;
26+}
27+
28+void QuickListEntry::setActionId(const QString &actionId)
29+{
30+ m_actionId = actionId;
31+}
32+
33+QString QuickListEntry::text() const
34+{
35+ return m_text;
36+}
37+
38+void QuickListEntry::setText(const QString &text)
39+{
40+ m_text = text;
41+}
42+
43+QString QuickListEntry::icon() const
44+{
45+ return m_icon;
46+}
47+
48+void QuickListEntry::setIcon(const QString &icon)
49+{
50+ m_icon = icon;
51+}
52+
53+bool QuickListEntry::clickable() const
54+{
55+ return !m_actionId.isEmpty();
56+}
plugins/Greeter/Unity/Launcher/quicklistentry.hnew file+43
@@ -0,0 +1,43 @@
1+/* Copyright (C) 2014-2015 Canonical, Ltd.
2+ *
3+ * This program is free software; you can redistribute it and/or modify
4+ * it under the terms of the GNU General Public License as published by
5+ * the Free Software Foundation; version 3.
6+ *
7+ * This program is distributed in the hope that it will be useful,
8+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+ * GNU General Public License for more details.
11+ *
12+ * You should have received a copy of the GNU General Public License
13+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
14+ */
15+
16+#ifndef QUICKLISTENTRY_H
17+#define QUICKLISTENTRY_H
18+
19+#include <QString>
20+
21+class QuickListEntry
22+{
23+public:
24+ QuickListEntry();
25+
26+ QString actionId() const;
27+ void setActionId(const QString &actionId);
28+
29+ QString text() const;
30+ void setText(const QString &text);
31+
32+ QString icon() const;
33+ void setIcon(const QString &icon);
34+
35+ bool clickable() const;
36+
37+private:
38+ QString m_actionId;
39+ QString m_text;
40+ QString m_icon;
41+};
42+
43+#endif // QUICKLISTENTRY
plugins/Greeter/Unity/Launcher/quicklistmodel.cppnew file+70
@@ -0,0 +1,70 @@
1+/*
2+ * Copyright 2014-2015 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+
17+#include "quicklistmodel.h"
18+
19+QuickListModel::QuickListModel(QObject *parent) :
20+ QuickListModelInterface(parent)
21+{
22+
23+}
24+
25+QuickListModel::~QuickListModel()
26+{
27+
28+}
29+
30+void QuickListModel::appendAction(const QuickListEntry &entry)
31+{
32+ beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
33+ m_list.append(entry);
34+ endInsertRows();
35+}
36+
37+void QuickListModel::updateAction(const QuickListEntry &entry)
38+{
39+ for (int i = 0; i < m_list.count(); ++i) {
40+ if (m_list.at(i).actionId() == entry.actionId()) {
41+ m_list.replace(i, entry);
42+ Q_EMIT dataChanged(index(i), index(i));
43+ return;
44+ }
45+ }
46+}
47+
48+QuickListEntry QuickListModel::get(int index) const
49+{
50+ return m_list.at(index);
51+}
52+
53+int QuickListModel::rowCount(const QModelIndex &index) const
54+{
55+ Q_UNUSED(index)
56+ return m_list.count();
57+}
58+
59+QVariant QuickListModel::data(const QModelIndex &index, int role) const
60+{
61+ switch (role) {
62+ case RoleLabel:
63+ return m_list.at(index.row()).text();
64+ case RoleIcon:
65+ return m_list.at(index.row()).icon();
66+ case RoleClickable:
67+ return m_list.at(index.row()).clickable();
68+ }
69+ return QVariant();
70+}
plugins/Greeter/Unity/Launcher/quicklistmodel.hnew file+55
@@ -0,0 +1,55 @@
1+/*
2+ * Copyright 2014-2015 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+
17+#ifndef QUICKLISTMODEL_H
18+#define QUICKLISTMODEL_H
19+
20+#include "quicklistentry.h"
21+
22+#include <unity/shell/launcher/QuickListModelInterface.h>
23+
24+using namespace unity::shell::launcher;
25+
26+class QuickListModel: public QuickListModelInterface
27+{
28+ Q_OBJECT
29+
30+public:
31+ explicit QuickListModel(QObject *parent = 0);
32+
33+ ~QuickListModel();
34+
35+ void appendAction(const QuickListEntry &entry);
36+
37+ /**
38+ * @brief Update an existing action
39+ * @param entry The new, updated entry
40+ *
41+ * This will only do something if entry.actionId is found in the model.
42+ * To add a new entry, use appendAction().
43+ */
44+ void updateAction(const QuickListEntry &entry);
45+
46+ QuickListEntry get(int index) const;
47+
48+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
49+ QVariant data(const QModelIndex &index, int role) const;
50+
51+private:
52+ QList<QuickListEntry> m_list;
53+};
54+
55+#endif // QUICKLISTMODEL_H
plugins/Unity/Launcher/CMakeLists.txt+2−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=5)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
4
4
@@ -20,6 +20,7 @@ set(QMLLAUNCHERPLUGIN_SRC
20 dbusinterface.cpp
20 dbusinterface.cpp
21 gsettings.cpp
21 gsettings.cpp
22 desktopfilehandler.cpp
22 desktopfilehandler.cpp
23+ asadapter.cpp
23 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
24 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
24 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
25 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
25 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
26 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
plugins/Unity/Launcher/asadapter.cppnew file+60
@@ -0,0 +1,60 @@
1+/*
2+ * Copyright 2014-2015 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+
17+#include "asadapter.h"
18+#include "launcheritem.h"
19+#include "AccountsServiceDBusAdaptor.h"
20+
21+#include <QDebug>
22+
23+ASAdapter::ASAdapter()
24+{
25+ m_accounts = new AccountsServiceDBusAdaptor();
26+ m_user = qgetenv("USER");
27+ if (m_user.isEmpty()) {
28+ qWarning() << "$USER not valid. Account Service integration will not work.";
29+ }
30+}
31+
32+ASAdapter::~ASAdapter()
33+{
34+ m_accounts->deleteLater();
35+}
36+
37+void ASAdapter::syncItems(QList<LauncherItem *> m_list)
38+{
39+ if (m_accounts && !m_user.isEmpty()) {
40+ QList<QVariantMap> items;
41+
42+ Q_FOREACH(LauncherItem *item, m_list) {
43+ items << itemToVariant(item);
44+ }
45+
46+ m_accounts->setUserPropertyAsync(m_user, "com.canonical.unity.AccountsService", "LauncherItems", QVariant::fromValue(items));
47+ }
48+}
49+
50+QVariantMap ASAdapter::itemToVariant(LauncherItem *item) const
51+{
52+ QVariantMap details;
53+ details.insert("id", item->appId());
54+ details.insert("name", item->name());
55+ details.insert("icon", item->icon());
56+ details.insert("count", item->count());
57+ details.insert("countVisible", item->countVisible());
58+ details.insert("pinned", item->pinned());
59+ return details;
60+}
plugins/Unity/Launcher/asadapter.hnew file+46
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright 2014-2015 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+
17+#ifndef ASADAPTER_H
18+#define ASADAPTER_H
19+
20+#include <QVariantMap>
21+
22+class LauncherItem;
23+class AccountsServiceDBusAdaptor;
24+class QDBusInterface;
25+
26+class ASAdapter
27+{
28+public:
29+ ASAdapter();
30+ ~ASAdapter();
31+
32+ void syncItems(QList<LauncherItem*> m_list);
33+
34+private:
35+ QVariantMap itemToVariant(LauncherItem *item) const;
36+
37+private:
38+ AccountsServiceDBusAdaptor *m_accounts;
39+ QString m_user;
40+
41+ QDBusInterface *m_userInterface;
42+
43+ friend class LauncherModelTest;
44+};
45+
46+#endif
plugins/Unity/Launcher/launchermodel.cpp+20
@@ -22,6 +22,7 @@
22#include "gsettings.h"
22#include "gsettings.h"
23#include "desktopfilehandler.h"
23#include "desktopfilehandler.h"
24#include "dbusinterface.h"
24#include "dbusinterface.h"
25+#include "asadapter.h"
25
26
26#include <unity/shell/application/ApplicationInfoInterface.h>
27#include <unity/shell/application/ApplicationInfoInterface.h>
27
28
@@ -34,6 +35,7 @@ LauncherModel::LauncherModel(QObject *parent):
34 LauncherModelInterface(parent),
35 LauncherModelInterface(parent),
35 m_settings(new GSettings(this)),
36 m_settings(new GSettings(this)),
36 m_dbusIface(new DBusInterface(this)),
37 m_dbusIface(new DBusInterface(this)),
38+ m_asAdapter(new ASAdapter()),
37 m_appManager(0)
39 m_appManager(0)
38{
40{
39 connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged);
41 connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged);
@@ -50,6 +52,8 @@ LauncherModel::~LauncherModel()
50 while (!m_list.empty()) {
52 while (!m_list.empty()) {
51 m_list.takeFirst()->deleteLater();
53 m_list.takeFirst()->deleteLater();
52 }
54 }
55+
56+ delete m_asAdapter;
53}
57}
54
58
55int LauncherModel::rowCount(const QModelIndex &parent) const
59int LauncherModel::rowCount(const QModelIndex &parent) const
@@ -261,6 +265,15 @@ void LauncherModel::setApplicationManager(unity::shell::application::Application
261 }
265 }
262}
266}
263
267
268+bool LauncherModel::onlyPinned() const
269+{
270+ return false;
271+}
272+
273+void LauncherModel::setOnlyPinned(bool onlyPinned) {
274+ Q_UNUSED(onlyPinned);
275+ qWarning() << "This launcher implementation does not support showing only pinned apps";
276+}
264
277
265void LauncherModel::storeAppList()
278void LauncherModel::storeAppList()
266{
279{
@@ -271,6 +284,7 @@ void LauncherModel::storeAppList()
271 }
284 }
272 }
285 }
273 m_settings->setStoredApplications(appIds);
286 m_settings->setStoredApplications(appIds);
287+ m_asAdapter->syncItems(m_list);
274}
288}
275
289
276void LauncherModel::unpin(const QString &appId)
290void LauncherModel::unpin(const QString &appId)
@@ -321,6 +335,7 @@ void LauncherModel::countChanged(const QString &appId, int count)
321 LauncherItem *item = m_list.at(idx);
335 LauncherItem *item = m_list.at(idx);
322 item->setCount(count);
336 item->setCount(count);
323 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
337 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
338+ m_asAdapter->syncItems(m_list);
324 }
339 }
325}
340}
326
341
@@ -352,6 +367,7 @@ void LauncherModel::countVisibleChanged(const QString &appId, int countVisible)
352 Q_EMIT hint();
367 Q_EMIT hint();
353 }
368 }
354 }
369 }
370+ m_asAdapter->syncItems(m_list);
355}
371}
356
372
357void LauncherModel::refresh()
373void LauncherModel::refresh()
@@ -433,6 +449,8 @@ void LauncherModel::refresh()
433 if (changed) {
449 if (changed) {
434 Q_EMIT hint();
450 Q_EMIT hint();
435 }
451 }
452+
453+ m_asAdapter->syncItems(m_list);
436}
454}
437
455
438void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
456void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
@@ -467,6 +485,7 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
467 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
485 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
468 m_list.append(item);
486 m_list.append(item);
469 endInsertRows();
487 endInsertRows();
488+ m_asAdapter->syncItems(m_list);
470 }
489 }
471}
490}
472
491
@@ -486,6 +505,7 @@ void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
486 beginRemoveRows(QModelIndex(), appIndex, appIndex);
505 beginRemoveRows(QModelIndex(), appIndex, appIndex);
487 m_list.takeAt(appIndex)->deleteLater();
506 m_list.takeAt(appIndex)->deleteLater();
488 endRemoveRows();
507 endRemoveRows();
508+ m_asAdapter->syncItems(m_list);
489 }
509 }
490}
510}
491
511
plugins/Unity/Launcher/launchermodel.h+5
@@ -28,6 +28,7 @@
28class LauncherItem;
28class LauncherItem;
29class GSettings;
29class GSettings;
30class DBusInterface;
30class DBusInterface;
31+class ASAdapter;
31
32
32using namespace unity::shell::launcher;
33using namespace unity::shell::launcher;
33using namespace unity::shell::application;
34using namespace unity::shell::application;
@@ -54,6 +55,9 @@ public:
54 unity::shell::application::ApplicationManagerInterface* applicationManager() const;
55 unity::shell::application::ApplicationManagerInterface* applicationManager() const;
55 void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager);
56 void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager);
56
57
58+ bool onlyPinned() const override;
59+ void setOnlyPinned(bool onlyPinned) override;
60+
57 int findApplication(const QString &appId);
61 int findApplication(const QString &appId);
58
62
59public Q_SLOTS:
63public Q_SLOTS:
@@ -79,6 +83,7 @@ private:
79
83
80 GSettings *m_settings;
84 GSettings *m_settings;
81 DBusInterface *m_dbusIface;
85 DBusInterface *m_dbusIface;
86+ ASAdapter *m_asAdapter;
82
87
83 ApplicationManagerInterface *m_appManager;
88 ApplicationManagerInterface *m_appManager;
84
89
tests/mocks/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=5)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
2
2
3include_directories(
3include_directories(
4 ${CMAKE_CURRENT_SOURCE_DIR}
4 ${CMAKE_CURRENT_SOURCE_DIR}
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+10
@@ -209,6 +209,16 @@ void MockLauncherModel::setApplicationManager(unity::shell::application::Applica
209 Q_UNUSED(applicationManager)
209 Q_UNUSED(applicationManager)
210}
210}
211
211
212+bool MockLauncherModel::onlyPinned() const
213+{
214+ return false;
215+}
216+
217+void MockLauncherModel::setOnlyPinned(bool onlyPinned)
218+{
219+ Q_UNUSED(onlyPinned)
220+}
221+
212void MockLauncherModel::emitHint()
222void MockLauncherModel::emitHint()
213{
223{
214 Q_EMIT hint();
224 Q_EMIT hint();
tests/mocks/Unity/Launcher/MockLauncherModel.h+3
@@ -49,6 +49,9 @@ public:
49 unity::shell::application::ApplicationManagerInterface *applicationManager() const;
49 unity::shell::application::ApplicationManagerInterface *applicationManager() const;
50 void setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager);
50 void setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager);
51
51
52+ bool onlyPinned() const override;
53+ void setOnlyPinned(bool onlyPinned) override;
54+
52 // For testing
55 // For testing
53 Q_INVOKABLE void emitHint();
56 Q_INVOKABLE void emitHint();
54
57
tests/plugins/CMakeLists.txt+1
@@ -1,4 +1,5 @@
1add_subdirectory(AccountsService)
1add_subdirectory(AccountsService)
2+add_subdirectory(Greeter)
2add_subdirectory(LightDM)
3add_subdirectory(LightDM)
3add_subdirectory(Dash)
4add_subdirectory(Dash)
4add_subdirectory(Ubuntu)
5add_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+48
@@ -0,0 +1,48 @@
1+/*
2+ * Copyright (C) 2014-2015 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+
17+#include "AccountsServiceDBusAdaptor.h"
18+#include <QDebug>
19+#include <QDBusArgument>
20+#include <QDBusMessage>
21+#include <QDBusMetaType>
22+
23+AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
24+ : QObject(parent)
25+{
26+ qDBusRegisterMetaType<QList<QVariantMap>>();
27+}
28+
29+QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
30+{
31+ Q_UNUSED(interface)
32+ Q_UNUSED(property) // We only fake one property here (LauncherItems)
33+
34+ QDBusMessage msg;
35+ QVariant v = QVariant::fromValue(mockProperties.value(user));
36+ QDBusVariant dv(v);
37+ QVariant packed = QVariant::fromValue(dv);
38+ msg << packed;
39+
40+ return packed.value<QDBusArgument>().asVariant();
41+}
42+
43+void AccountsServiceDBusAdaptor::simulatePropertyChange(const QString &user, const QString &property, const QVariant &value)
44+{
45+ Q_ASSERT(property == "LauncherItems");
46+ mockProperties[user] = value.value<QList<QVariantMap>>();
47+ Q_EMIT propertiesChanged(user, "com.canonical.unity.AccountsService", QStringList() << property);
48+}
tests/plugins/Greeter/Unity/Launcher/AccountsServiceDBusAdaptor.hnew file+53
@@ -0,0 +1,53 @@
1+/*
2+ * Copyright (C) 2014-2015 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+
17+#ifndef UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
18+#define UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
19+
20+#include <QMap>
21+#include <QObject>
22+#include <QString>
23+#include <QHash>
24+#include <QDBusArgument>
25+
26+extern QHash<QString, QList<QVariantMap>> mockProperties;
27+
28+class AccountsServiceDBusAdaptor: public QObject
29+{
30+ Q_OBJECT
31+
32+public:
33+ explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
34+
35+ Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
36+ template <typename T>
37+ inline T getUserProperty(const QString &user, const QString &interface, const QString &property) {
38+ Q_UNUSED(interface)
39+ Q_ASSERT(property == "LauncherItems");
40+ T ret = mockProperties[user];
41+ return ret;
42+ }
43+
44+Q_SIGNALS:
45+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
46+
47+private:
48+ void simulatePropertyChange(const QString &user, const QString &property, const QVariant &value);
49+
50+ friend class LauncherModelASTest;
51+};
52+
53+#endif
tests/plugins/Greeter/Unity/Launcher/CMakeLists.txtnew file+56
@@ -0,0 +1,56 @@
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
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+169
@@ -0,0 +1,169 @@
1+/*
2+ * Copyright 2014-2015 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+
17+// unity-api
18+#include <unity/shell/launcher/LauncherModelInterface.h>
19+#include <unity/shell/application/ApplicationInfoInterface.h>
20+
21+#include "launcheritem.h"
22+#include "launchermodelas.h"
23+#include "AccountsServiceDBusAdaptor.h"
24+
25+#include <QtTest>
26+
27+QHash<QString, QList<QVariantMap>> mockProperties;
28+
29+class LauncherModelASTest : public QObject
30+{
31+ Q_OBJECT
32+
33+private:
34+ LauncherModel *launcherModel;
35+
36+private Q_SLOTS:
37+
38+ void init() {
39+ // Prepare some fake list
40+ QList<QVariantMap> list;
41+ QVariantMap item;
42+ item.insert("id", "appId1");
43+ item.insert("name", "Item 1");
44+ item.insert("icon", "fake.svg");
45+ item.insert("count", 0);
46+ item.insert("countVisible", false);
47+ item.insert("pinned", true);
48+ list.append(item);
49+ item["id"] = "appId2";
50+ item["name"] = "Item 2";
51+ list.append(item);
52+ mockProperties["user1"] = list;
53+ }
54+
55+ bool isInSync(LauncherModel *model, const QList<QVariantMap> &properties) {
56+ QList<QVariantMap> list;
57+ // Strip unpinned if onlyPinned is set
58+ Q_FOREACH (const QVariantMap &map, properties) {
59+ if (!model->onlyPinned() || map.value("pinned").toBool()) {
60+ list << map;
61+ }
62+ }
63+
64+ bool inSync = model->rowCount() == list.count();
65+ for (int i = 0; inSync && i < model->rowCount(); i++) {
66+ inSync &= model->get(i)->appId() == list.at(i).value("id").toString();
67+ inSync &= model->get(i)->name() == list.at(i).value("name").toString();
68+ inSync &= model->get(i)->icon() == list.at(i).value("icon").toString();
69+ inSync &= model->get(i)->count() == list.at(i).value("count").toInt();
70+ inSync &= model->get(i)->countVisible() == list.at(i).value("countVisible").toBool();
71+ }
72+ return inSync;
73+ }
74+
75+ void testLoadASOnStartup() {
76+ // Load up the model
77+ LauncherModel* model = new LauncherModel(this);
78+
79+ // We didn't set a user yet. model should be empty
80+ QCOMPARE(model->rowCount(), 0);
81+
82+ model->setUser("user1");
83+
84+ QCOMPARE(isInSync(model, mockProperties["user1"]), true);
85+ model->deleteLater();
86+ }
87+
88+ void testASChangedUpdatesModel_data() {
89+ QTest::addColumn<QString>("modelUser");
90+ QTest::addColumn<QString>("changedUser");
91+ QTest::addColumn<bool>("inSync");
92+
93+ QTest::newRow("this user changed") << "user1" << "user1" << true;
94+ QTest::newRow("other user changed") << "user1" << "user2" << false;
95+ }
96+
97+ void testASChangedUpdatesModel() {
98+ QFETCH(QString, modelUser);
99+ QFETCH(QString, changedUser);
100+ QFETCH(bool, inSync);
101+
102+ LauncherModel* model = new LauncherModel(this);
103+ model->setUser(modelUser);
104+
105+ int oldCount = mockProperties[modelUser].count();
106+ QCOMPARE(model->rowCount(), oldCount);
107+
108+ QList<QVariantMap> newList;
109+ QVariantMap newEntry;
110+ newEntry.insert("id", "newappId");
111+ newEntry.insert("name", "New app");
112+ newEntry.insert("icon", "some-icon.svg");
113+ newEntry.insert("count", 0);
114+ newEntry.insert("countVisible", false);
115+ newEntry.insert("pinned", true);
116+ newList.append(newEntry);
117+ model->m_accounts->simulatePropertyChange(changedUser, "LauncherItems", QVariant::fromValue(newList));
118+
119+ QCOMPARE(isInSync(model, mockProperties[modelUser]), true);
120+ QCOMPARE(isInSync(model, mockProperties[changedUser]), inSync);
121+
122+ model->deleteLater();
123+ }
124+
125+ void testUpdateCount() {
126+ LauncherModel* model = new LauncherModel(this);
127+ model->setUser("user1");
128+
129+ QCOMPARE(model->get(0)->countVisible(), false);
130+ QCOMPARE(model->get(0)->count(), 0);
131+
132+ QList<QVariantMap> newList = mockProperties["user1"];
133+ QVariantMap entry = newList.at(0);
134+ entry["countVisible"] = true;
135+ entry["count"] = 55;
136+ newList[0] = entry;
137+ model->m_accounts->simulatePropertyChange("user1", "LauncherItems", QVariant::fromValue(newList));
138+
139+ QCOMPARE(isInSync(model, mockProperties["user1"]), true);
140+
141+ model->deleteLater();
142+ }
143+
144+ void testOnlyPinned() {
145+ LauncherModel *model = new LauncherModel(this);
146+ model->setUser("user1");
147+ model->setOnlyPinned(true);
148+
149+ QCOMPARE(isInSync(model, mockProperties["user1"]), true);
150+
151+ // Let's unpin one item
152+ QList<QVariantMap> newList = mockProperties["user1"];
153+ QVariantMap entry = newList.at(0);
154+ entry["pinned"] = false;
155+ newList[0] = entry;
156+ model->m_accounts->simulatePropertyChange("user1", "LauncherItems", QVariant::fromValue(newList));
157+ QCOMPARE(isInSync(model, mockProperties["user1"]), true);
158+
159+ // Now toggle onlyPinned and make sure the model keeps up
160+ model->setOnlyPinned(false);
161+ QCOMPARE(isInSync(model, mockProperties["user1"]), true);
162+
163+ model->setOnlyPinned(true);
164+ QCOMPARE(isInSync(model, mockProperties["user1"]), true);
165+ }
166+};
167+
168+QTEST_GUILESS_MAIN(LauncherModelASTest)
169+#include "launchermodelastest.moc"
tests/plugins/Unity/Launcher/AccountsServiceDBusAdaptor.cppnew file+42
@@ -0,0 +1,42 @@
1+/*
2+ * Copyright (C) 2014-2015 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+
17+#include "AccountsServiceDBusAdaptor.h"
18+#include <QDebug>
19+
20+AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
21+ : QObject(parent)
22+{
23+}
24+
25+QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
26+{
27+ Q_UNUSED(user)
28+ Q_UNUSED(interface)
29+ return m_properties.value(property);
30+}
31+
32+void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value)
33+{
34+ Q_UNUSED(user)
35+ Q_UNUSED(interface)
36+ m_properties[property] = value;
37+}
38+
39+void AccountsServiceDBusAdaptor::setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value)
40+{
41+ setUserProperty(user, interface, property, value);
42+}
tests/plugins/Unity/Launcher/AccountsServiceDBusAdaptor.hnew file+47
@@ -0,0 +1,47 @@
1+/*
2+ * Copyright (C) 2014-2015 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+
17+#ifndef UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
18+#define UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
19+
20+#include <QMap>
21+#include <QObject>
22+#include <QString>
23+#include <QHash>
24+
25+class AccountsServiceDBusAdaptor: public QObject
26+{
27+ Q_OBJECT
28+
29+public:
30+ explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
31+
32+ Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
33+ Q_INVOKABLE void setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value);
34+ Q_INVOKABLE void setUserPropertyAsync(const QString &user, const QString &interface, const QString &property, const QVariant &value);
35+
36+Q_SIGNALS:
37+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
38+ void maybeChanged(const QString &user); // Standard properties might have changed
39+
40+private:
41+ void simulatePropertyChange(const QString &property, const QVariant &value);
42+
43+private:
44+ QHash<QString, QVariant> m_properties;
45+};
46+
47+#endif
tests/plugins/Unity/Launcher/CMakeLists.txt+3−1
@@ -1,5 +1,5 @@
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=5)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
3pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
3pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=5)
4
4
5include_directories(
5include_directories(
@@ -23,7 +23,9 @@ add_custom_target(launchermodeltest ${testModelCommand})
23add_executable(launchermodeltestExec
23add_executable(launchermodeltestExec
24 launchermodeltest.cpp
24 launchermodeltest.cpp
25 gsettings.cpp
25 gsettings.cpp
26+ AccountsServiceDBusAdaptor.cpp
26 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launchermodel.cpp
27 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launchermodel.cpp
28+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/asadapter.cpp
27 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launcheritem.cpp
29 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launcheritem.cpp
28 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistmodel.cpp
30 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistmodel.cpp
29 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/dbusinterface.cpp
31 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/dbusinterface.cpp
tests/plugins/Unity/Launcher/launchermodeltest.cpp+65−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 2013-2014 Canonical Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -25,6 +25,8 @@
25#include "launchermodel.h"
25#include "launchermodel.h"
26#include "dbusinterface.h"
26#include "dbusinterface.h"
27#include "gsettings.h"
27#include "gsettings.h"
28+#include "asadapter.h"
29+#include "AccountsServiceDBusAdaptor.h"
28
30
29#include <QtTest>
31#include <QtTest>
30#include <QDBusInterface>
32#include <QDBusInterface>
@@ -129,6 +131,11 @@ private:
129 LauncherModel *launcherModel;
131 LauncherModel *launcherModel;
130 MockAppManager *appManager;
132 MockAppManager *appManager;
131
133
134+ QList<QVariantMap> getASConfig() {
135+ AccountsServiceDBusAdaptor *as = launcherModel->m_asAdapter->m_accounts;
136+ return as->getUserProperty("", "", "LauncherItems").value<QList<QVariantMap>>();
137+ }
138+
132private Q_SLOTS:
139private Q_SLOTS:
133
140
134 void initTestCase() {
141 void initTestCase() {
@@ -467,6 +474,63 @@ private Q_SLOTS:
467 QCOMPARE(launcherModel->get(1)->appId(), QString("abs-icon"));
474 QCOMPARE(launcherModel->get(1)->appId(), QString("abs-icon"));
468 QCOMPARE(spy.count(), 2);
475 QCOMPARE(spy.count(), 2);
469 }
476 }
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+ }
470};
534};
471
535
472QTEST_GUILESS_MAIN(LauncherModelTest)
536QTEST_GUILESS_MAIN(LauncherModelTest)