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