Merge lp:~lukas-kde/unity8/closeAppsFromQuicklist into lp:unity8

Proposed by Lukáš Tinkl
Status: Superseded
Proposed branch: lp:~lukas-kde/unity8/closeAppsFromQuicklist
Merge into: lp:unity8
Prerequisite: lp:~lukas-kde/unity8/highdpi-mousetouchadaptor
Diff against target: 2092 lines (+824/-123)
41 files modified
debian/control (+3/-3)
plugins/Greeter/Unity/Launcher/CMakeLists.txt (+1/-1)
plugins/Greeter/Unity/Launcher/launcheritem.cpp (+14/-0)
plugins/Greeter/Unity/Launcher/launcheritem.h (+4/-0)
plugins/Greeter/Unity/Launcher/launchermodelas.cpp (+28/-12)
plugins/Greeter/Unity/Launcher/launchermodelas.h (+1/-0)
plugins/Unity/Launcher/CMakeLists.txt (+1/-1)
plugins/Unity/Launcher/asadapter.cpp (+4/-2)
plugins/Unity/Launcher/asadapter.h (+1/-4)
plugins/Unity/Launcher/dbusinterface.cpp (+39/-13)
plugins/Unity/Launcher/dbusinterface.h (+2/-0)
plugins/Unity/Launcher/gsettings.cpp (+1/-1)
plugins/Unity/Launcher/launcheritem.cpp (+33/-0)
plugins/Unity/Launcher/launcheritem.h (+4/-0)
plugins/Unity/Launcher/launchermodel.cpp (+77/-24)
plugins/Unity/Launcher/launchermodel.h (+2/-0)
plugins/Unity/Launcher/quicklistentry.cpp (+6/-2)
plugins/Unity/Launcher/quicklistentry.h (+3/-1)
plugins/Unity/Launcher/quicklistmodel.cpp (+12/-1)
plugins/Unity/Launcher/quicklistmodel.h (+3/-1)
qml/Launcher/LauncherDelegate.qml (+101/-15)
qml/Launcher/LauncherPanel.qml (+93/-14)
qml/Launcher/graphics/progressbar-fill@30.sci (+0/-5)
qml/Launcher/graphics/progressbar-trough@30.sci (+0/-5)
tests/mocks/Unity/Launcher/CMakeLists.txt (+1/-1)
tests/mocks/Unity/Launcher/MockLauncherItem.cpp (+22/-0)
tests/mocks/Unity/Launcher/MockLauncherItem.h (+4/-0)
tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+54/-1)
tests/mocks/Unity/Launcher/MockLauncherModel.h (+4/-0)
tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt (+1/-1)
tests/plugins/Greeter/Unity/Launcher/launchermodelastest.cpp (+3/-0)
tests/plugins/Unity/Launcher/CMakeLists.txt (+1/-1)
tests/plugins/Unity/Launcher/launchermodeltest.cpp (+64/-7)
tests/qmltests/Launcher/tst_Launcher.qml (+210/-7)
tests/scripts/README (+9/-0)
tests/scripts/alert-launcher-icon.sh (+3/-0)
tests/scripts/get-progress.sh (+3/-0)
tests/scripts/list-launcher-icons.sh (+3/-0)
tests/scripts/set-count-visible.sh (+3/-0)
tests/scripts/set-count.sh (+3/-0)
tests/scripts/set-progress.sh (+3/-0)
To merge this branch: bzr merge lp:~lukas-kde/unity8/closeAppsFromQuicklist
Reviewer Review Type Date Requested Status
Michael Zanetti (community) Approve
PS Jenkins bot (community) continuous-integration Needs Fixing
Albert Astals Cid (community) tags clean & merges fine Abstain
Daniel d'Andrada Pending
Review via email: mp+262353@code.launchpad.net

This proposal supersedes a proposal from 2015-06-10.

This proposal has been superseded by a proposal from 2015-07-23.

Commit message

launcher parity: close apps from quicklist

Description of the change

launcher parity: close apps from quicklist

- adds a Quit item to the launcher quicklist
- partially reverts the visual appearance to the old design of popup menus
- invokes the popup menu also on the right mouse click

 * Are there any related MPs required for this MP to build/function as expected? Please list.

No

 * Did you perform an exploratory manual test run of your code change and any related functionality?

Yes

 * 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?

N/A

 * If you changed the UI, has there been a design review?

No (however, there is a revert to the old design)

 * Did you have a look at the warnings when running tests? Can they be reduced?

Yes

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

I see you have lp:~lukas-kde/unity8/highdpi-mousetouchadaptor in this branch. Either remove those changes or make lp:~lukas-kde/unity8/highdpi-mousetouchadaptor a prerequisite.

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

In qml/Launcher/LauncherPanel.qml

"""
- __foregroundColor: "black"
+ __foregroundColor: Theme.palette.selected.backgroundText
"""

"Theme" is deprecated. Please use the context variable "theme" instead. We have tons of warnings on this already. See https://code.launchpad.net/~dandrader/unity8/deprecatedTheme/+merge/262216

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

I would like to see a qml test launches an app and then closes it using this "quit" quick list menu entry.

I should also be able to manually test this feature or try it out (eg, via "make tryShell"), without having to flash a device for that.

review: Needs Fixing
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

> I would like to see a qml test launches an app and then closes it using this
> "quit" quick list menu entry.

There is already a test for this, albeit not a QML one: launchermodeltest.cp, void testQuitMenuItem()

> I should also be able to manually test this feature or try it out (eg, via
> "make tryShell"), without having to flash a device for that.

Right, I'll see what I can do with that but I'd prefer doing that in a separate MP; it goes a bit beyond the scope of this review, none of the current quick list actions are testable from QML yet (Pin/Unpin etc).

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

Some inline comments.

review: Needs Fixing
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

> Some inline comments.

Should be fixed by r. 1812

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

Hmm... testing it, the quicklist visuals seem to be the expected ones any more. Sorry if I gave bad advice on reverting the complete commit. We should only revert the positioning to what it was before, but not the coloring. Also the arrow points to the wrong direction. It should point from the menu box towards the clicked launcher item, not the other way round.

review: Needs Fixing
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Ack, will fix

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

http://i.imgur.com/bGXaemm.png

Font is white on white, also I'm missing the close entry.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in qml/Launcher/LauncherPanel.qml
1 conflicts encountered.

review: Needs Fixing
1824. By Lukáš Tinkl

merge and fix conflict

Revision history for this message
Albert Astals Cid (aacid) :
review: Abstain (tags clean & merges fine)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

Looks ok and works, except the dbusinterface changes are not needed. Please drop them.

review: Needs Fixing
1825. By Lukáš Tinkl

drop dbusinterface changes

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?

yes

 * Did CI run pass? If not, please explain why.

as much as it can, yes

 * Did you make sure that the branch does not contain spurious tags?

yes

review: Approve
1826. By Lukáš Tinkl

rebase on top of lp:~macslow/unity8/use-set-progress-api

1827. By Lukáš Tinkl

re-merge again on top of use-set-progress-api to fix failing QML tests

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2015-07-09 20:22:36 +0000
3+++ debian/control 2015-07-23 14:15:26 +0000
4@@ -30,7 +30,7 @@
5 libqt5xmlpatterns5-dev,
6 libsystemsettings-dev,
7 libudev-dev,
8- libunity-api-dev (>= 7.97),
9+ libunity-api-dev (>= 7.98),
10 libusermetricsoutput1-dev,
11 libxcb1-dev,
12 pkg-config,
13@@ -101,7 +101,7 @@
14 qtdeclarative5-ubuntu-telephony0.1,
15 qtdeclarative5-ubuntu-web-plugin,
16 ubuntu-system-settings,
17- unity-launcher-impl-4,
18+ unity-launcher-impl-7,
19 unity8-common (= ${source:Version}),
20 unity8-private (= ${binary:Version}),
21 unity8-private | unity-launcher-impl,
22@@ -191,7 +191,7 @@
23 ${misc:Depends},
24 ${shlibs:Depends},
25 Provides: unity-launcher-impl,
26- unity-launcher-impl-4,
27+ unity-launcher-impl-7,
28 Description: Unity 8 private libs
29 The Unity 8 shell is the primary user interface for Ubuntu devices.
30 .
31
32=== modified file 'plugins/Greeter/Unity/Launcher/CMakeLists.txt'
33--- plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-04-24 09:53:37 +0000
34+++ plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-07-23 14:15:26 +0000
35@@ -1,4 +1,4 @@
36-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
37+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
38 pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
39 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
40
41
42=== modified file 'plugins/Greeter/Unity/Launcher/launcheritem.cpp'
43--- plugins/Greeter/Unity/Launcher/launcheritem.cpp 2015-02-11 14:02:24 +0000
44+++ plugins/Greeter/Unity/Launcher/launcheritem.cpp 2015-07-23 14:15:26 +0000
45@@ -31,6 +31,7 @@
46 m_count(0),
47 m_countVisible(false),
48 m_focused(false),
49+ m_alerting(false),
50 m_quickList(new QuickListModel(this))
51 {
52 QuickListEntry nameAction;
53@@ -165,6 +166,19 @@
54 }
55 }
56
57+bool LauncherItem::alerting() const
58+{
59+ return m_alerting;
60+}
61+
62+void LauncherItem::setAlerting(bool alerting)
63+{
64+ if (m_alerting != alerting) {
65+ m_alerting = alerting;
66+ Q_EMIT alertingChanged(alerting);
67+ }
68+}
69+
70 unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
71 {
72 return m_quickList;
73
74=== modified file 'plugins/Greeter/Unity/Launcher/launcheritem.h'
75--- plugins/Greeter/Unity/Launcher/launcheritem.h 2015-02-11 14:02:24 +0000
76+++ plugins/Greeter/Unity/Launcher/launcheritem.h 2015-07-23 14:15:26 +0000
77@@ -41,6 +41,7 @@
78 int count() const override;
79 bool countVisible() const override;
80 bool focused() const override;
81+ bool alerting() const override;
82
83 unity::shell::launcher::QuickListModelInterface *quickList() const override;
84
85@@ -54,6 +55,8 @@
86 void setCount(int count);
87 void setCountVisible(bool countVisible);
88 void setFocused(bool focused);
89+ void setAlerting(bool alerting);
90+
91
92 private:
93 QString m_appId;
94@@ -66,6 +69,7 @@
95 int m_count;
96 bool m_countVisible;
97 bool m_focused;
98+ bool m_alerting;
99 QuickListModel *m_quickList;
100
101 friend class LauncherModel;
102
103=== modified file 'plugins/Greeter/Unity/Launcher/launchermodelas.cpp'
104--- plugins/Greeter/Unity/Launcher/launchermodelas.cpp 2015-02-11 14:02:24 +0000
105+++ plugins/Greeter/Unity/Launcher/launchermodelas.cpp 2015-07-23 14:15:26 +0000
106@@ -67,11 +67,20 @@
107 return item->progress();
108 case RoleFocused:
109 return item->focused();
110+ case RoleRunning:
111+ return item->running();
112 }
113
114 return QVariant();
115 }
116
117+void LauncherModel::setAlerting(const QString &appId, bool alerting)
118+{
119+ Q_UNUSED(appId)
120+ Q_UNUSED(alerting)
121+ qWarning() << "This is a read only implementation. Cannot set alert-state of items.";
122+}
123+
124 unity::shell::launcher::LauncherItemInterface *LauncherModel::get(int index) const
125 {
126 if (index < 0 || index >= m_list.count()) {
127@@ -200,16 +209,20 @@
128 Q_FOREACH (LauncherItem* item, m_list) {
129 bool found = false;
130 Q_FOREACH(const QVariant &asItem, items) {
131- if (asItem.toMap().value("id").toString() == item->appId()) {
132+ QVariantMap cachedMap = asItem.toMap();
133+ if (cachedMap.value("id").toString() == item->appId()) {
134 // Only keep and update it if we either show unpinned or it is pinned
135- if (!m_onlyPinned || asItem.toMap().value("pinned").toBool()) {
136+ if (!m_onlyPinned || cachedMap.value("pinned").toBool()) {
137 found = true;
138- item->setName(asItem.toMap().value("name").toString());
139- item->setIcon(asItem.toMap().value("icon").toString());
140- item->setCount(asItem.toMap().value("count").toInt());
141- item->setCountVisible(asItem.toMap().value("countVisible").toBool());
142+ item->setName(cachedMap.value("name").toString());
143+ item->setIcon(cachedMap.value("icon").toString());
144+ item->setCount(cachedMap.value("count").toInt());
145+ item->setCountVisible(cachedMap.value("countVisible").toBool());
146+ item->setProgress(cachedMap.value("progress").toInt());
147+ item->setRunning(cachedMap.value("running").toBool());
148+
149 int idx = m_list.indexOf(item);
150- Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleName << RoleIcon);
151+ Q_EMIT dataChanged(index(idx), index(idx), {RoleName, RoleIcon, RoleCount, RoleCountVisible, RoleRunning, RoleProgress});
152 }
153 break;
154 }
155@@ -247,14 +260,17 @@
156 }
157
158 if (itemIndex == -1) {
159+ QVariantMap cachedMap = entry.toMap();
160 // Need to add it. Just add it into the addedIndex to keep same ordering as the list in AS.
161- LauncherItem *item = new LauncherItem(entry.toMap().value("id").toString(),
162- entry.toMap().value("name").toString(),
163- entry.toMap().value("icon").toString(),
164+ LauncherItem *item = new LauncherItem(cachedMap.value("id").toString(),
165+ cachedMap.value("name").toString(),
166+ cachedMap.value("icon").toString(),
167 this);
168 item->setPinned(true);
169- item->setCount(entry.toMap().value("count").toInt());
170- item->setCountVisible(entry.toMap().value("countVisible").toBool());
171+ item->setCount(cachedMap.value("count").toInt());
172+ item->setCountVisible(cachedMap.value("countVisible").toBool());
173+ item->setProgress(cachedMap.value("progress").toInt());
174+ item->setRunning(cachedMap.value("running").toBool());
175 beginInsertRows(QModelIndex(), newPosition, newPosition);
176 m_list.insert(newPosition, item);
177 endInsertRows();
178
179=== modified file 'plugins/Greeter/Unity/Launcher/launchermodelas.h'
180--- plugins/Greeter/Unity/Launcher/launchermodelas.h 2015-04-30 09:31:51 +0000
181+++ plugins/Greeter/Unity/Launcher/launchermodelas.h 2015-07-23 14:15:26 +0000
182@@ -41,6 +41,7 @@
183
184 QVariant data(const QModelIndex &index, int role) const override;
185
186+ Q_INVOKABLE void setAlerting(const QString &appId, bool alerting) override;
187 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const override;
188 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
189 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
190
191=== modified file 'plugins/Unity/Launcher/CMakeLists.txt'
192--- plugins/Unity/Launcher/CMakeLists.txt 2015-04-24 09:53:37 +0000
193+++ plugins/Unity/Launcher/CMakeLists.txt 2015-07-23 14:15:26 +0000
194@@ -1,4 +1,4 @@
195-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
196+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
197 pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
198 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
199
200
201=== modified file 'plugins/Unity/Launcher/asadapter.cpp'
202--- plugins/Unity/Launcher/asadapter.cpp 2015-02-11 14:13:26 +0000
203+++ plugins/Unity/Launcher/asadapter.cpp 2015-07-23 14:15:26 +0000
204@@ -34,12 +34,12 @@
205 m_accounts->deleteLater();
206 }
207
208-void ASAdapter::syncItems(QList<LauncherItem *> m_list)
209+void ASAdapter::syncItems(const QList<LauncherItem*> &list)
210 {
211 if (m_accounts && !m_user.isEmpty()) {
212 QList<QVariantMap> items;
213
214- Q_FOREACH(LauncherItem *item, m_list) {
215+ Q_FOREACH(LauncherItem *item, list) {
216 items << itemToVariant(item);
217 }
218
219@@ -56,5 +56,7 @@
220 details.insert("count", item->count());
221 details.insert("countVisible", item->countVisible());
222 details.insert("pinned", item->pinned());
223+ details.insert("running", item->running());
224+ details.insert("progress", item->progress());
225 return details;
226 }
227
228=== modified file 'plugins/Unity/Launcher/asadapter.h'
229--- plugins/Unity/Launcher/asadapter.h 2015-02-11 14:13:26 +0000
230+++ plugins/Unity/Launcher/asadapter.h 2015-07-23 14:15:26 +0000
231@@ -21,7 +21,6 @@
232
233 class LauncherItem;
234 class AccountsServiceDBusAdaptor;
235-class QDBusInterface;
236
237 class ASAdapter
238 {
239@@ -29,7 +28,7 @@
240 ASAdapter();
241 ~ASAdapter();
242
243- void syncItems(QList<LauncherItem*> m_list);
244+ void syncItems(const QList<LauncherItem*> &list);
245
246 private:
247 QVariantMap itemToVariant(LauncherItem *item) const;
248@@ -38,8 +37,6 @@
249 AccountsServiceDBusAdaptor *m_accounts;
250 QString m_user;
251
252- QDBusInterface *m_userInterface;
253-
254 friend class LauncherModelTest;
255 };
256
257
258=== modified file 'plugins/Unity/Launcher/dbusinterface.cpp'
259--- plugins/Unity/Launcher/dbusinterface.cpp 2015-06-11 23:45:12 +0000
260+++ plugins/Unity/Launcher/dbusinterface.cpp 2015-07-23 14:15:26 +0000
261@@ -62,6 +62,8 @@
262 "<interface name=\"com.canonical.Unity.Launcher.Item\">"
263 "<property name=\"count\" type=\"i\" access=\"readwrite\" />"
264 "<property name=\"countVisible\" type=\"b\" access=\"readwrite\" />"
265+ "<property name=\"progress\" type=\"i\" access=\"readwrite\" />"
266+ "<method name=\"Alert\" />"
267 "</interface>";
268 return nodeiface;
269 }
270@@ -122,6 +124,20 @@
271 return false;
272 }
273
274+ /* Break down the path to just the app id */
275+ bool validpath = true;
276+ QString pathtemp = message.path();
277+ if (!pathtemp.startsWith("/com/canonical/Unity/Launcher/")) {
278+ validpath = false;
279+ }
280+ pathtemp.remove("/com/canonical/Unity/Launcher/");
281+ if (pathtemp.indexOf('/') >= 0) {
282+ validpath = false;
283+ }
284+
285+ /* Find ourselves an appid */
286+ QString appid = decodeAppId(pathtemp);
287+
288 // First handle methods of the Launcher interface
289 if (message.interface() == "com.canonical.Unity.Launcher") {
290 if (message.member() == "Refresh") {
291@@ -129,6 +145,13 @@
292 Q_EMIT refreshCalled();
293 return connection.send(reply);
294 }
295+ } else if (message.interface() == "com.canonical.Unity.Launcher.Item") {
296+ // Handle methods of the Launcher-Item interface
297+ if (message.member() == "Alert" && validpath) {
298+ QDBusMessage reply = message.createReply();
299+ Q_EMIT alertCalled(appid);
300+ return connection.send(reply);
301+ }
302 }
303
304 // Now handle dynamic properties (for launcher emblems)
305@@ -140,50 +163,53 @@
306 return false;
307 }
308
309- /* Break down the path to just the app id */
310- QString pathtemp = message.path();
311- if (!pathtemp.startsWith("/com/canonical/Unity/Launcher/")) {
312- return false;
313- }
314- pathtemp.remove("/com/canonical/Unity/Launcher/");
315- if (pathtemp.indexOf('/') >= 0) {
316+ if (!validpath) {
317 return false;
318 }
319
320- /* Find ourselves an appid */
321- QString appid = decodeAppId(pathtemp);
322 int index = m_launcherModel->findApplication(appid);
323 LauncherItem *item = static_cast<LauncherItem*>(m_launcherModel->get(index));
324
325 QVariantList retval;
326 if (message.member() == "Get") {
327+ QString cachedString = message.arguments()[1].toString();
328 if (!item) {
329 return false;
330 }
331- if (message.arguments()[1].toString() == "count") {
332+ if (cachedString == "count") {
333 retval.append(QVariant::fromValue(QDBusVariant(item->count())));
334- } else if (message.arguments()[1].toString() == "countVisible") {
335+ } else if (cachedString == "countVisible") {
336 retval.append(QVariant::fromValue(QDBusVariant(item->countVisible())));
337+ } else if (cachedString == "progress") {
338+ retval.append(QVariant::fromValue(QDBusVariant(item->progress())));
339 }
340 } else if (message.member() == "Set") {
341- if (message.arguments()[1].toString() == "count") {
342+ QString cachedString = message.arguments()[1].toString();
343+ if (cachedString == "count") {
344 int newCount = message.arguments()[2].value<QDBusVariant>().variant().toInt();
345 if (!item || newCount != item->count()) {
346 Q_EMIT countChanged(appid, newCount);
347 notifyPropertyChanged("com.canonical.Unity.Launcher.Item", encodeAppId(appid), "count", QVariant(newCount));
348 }
349- } else if (message.arguments()[1].toString() == "countVisible") {
350+ } else if (cachedString == "countVisible") {
351 bool newVisible = message.arguments()[2].value<QDBusVariant>().variant().toBool();
352 if (!item || newVisible != item->countVisible()) {
353 Q_EMIT countVisibleChanged(appid, newVisible);
354 notifyPropertyChanged("com.canonical.Unity.Launcher.Item", encodeAppId(appid), "countVisible", newVisible);
355 }
356+ } else if (cachedString == "progress") {
357+ int newProgress = message.arguments()[2].value<QDBusVariant>().variant().toInt();
358+ if (!item || newProgress != item->progress()) {
359+ Q_EMIT progressChanged(appid, newProgress);
360+ notifyPropertyChanged("com.canonical.Unity.Launcher.Item", encodeAppId(appid), "progress", QVariant(newProgress));
361+ }
362 }
363 } else if (message.member() == "GetAll") {
364 if (item) {
365 QVariantMap all;
366 all.insert("count", item->count());
367 all.insert("countVisible", item->countVisible());
368+ all.insert("progress", item->progress());
369 retval.append(all);
370 }
371 } else {
372
373=== modified file 'plugins/Unity/Launcher/dbusinterface.h'
374--- plugins/Unity/Launcher/dbusinterface.h 2015-06-11 23:45:12 +0000
375+++ plugins/Unity/Launcher/dbusinterface.h 2015-07-23 14:15:26 +0000
376@@ -36,7 +36,9 @@
377 Q_SIGNALS:
378 void countChanged(const QString &appId, int count);
379 void countVisibleChanged(const QString &appId, bool countVisible);
380+ void progressChanged(const QString &appId, int progress);
381 void refreshCalled();
382+ void alertCalled(const QString &appId);
383
384 private:
385 static QString decodeAppId(const QString& path);
386
387=== modified file 'plugins/Unity/Launcher/gsettings.cpp'
388--- plugins/Unity/Launcher/gsettings.cpp 2015-03-04 08:54:12 +0000
389+++ plugins/Unity/Launcher/gsettings.cpp 2015-07-23 14:15:26 +0000
390@@ -68,7 +68,7 @@
391 void GSettings::onSettingsChanged(const QString &key)
392 {
393 if (key == "items") {
394- QStringList cachedItems = m_gSettings->get("items").toStringList();
395+ const QStringList cachedItems = m_gSettings->get("items").toStringList();
396 if (m_cachedItems != cachedItems) {
397 m_cachedItems = cachedItems;
398 Q_EMIT changed();
399
400=== modified file 'plugins/Unity/Launcher/launcheritem.cpp'
401--- plugins/Unity/Launcher/launcheritem.cpp 2014-11-19 17:43:09 +0000
402+++ plugins/Unity/Launcher/launcheritem.cpp 2015-07-23 14:15:26 +0000
403@@ -34,16 +34,22 @@
404 m_count(0),
405 m_countVisible(false),
406 m_focused(false),
407+ m_alerting(false),
408 m_quickList(new QuickListModel(this))
409 {
410 QuickListEntry nameAction;
411 nameAction.setActionId("launch_item");
412 nameAction.setText(m_name);
413 m_quickList->appendAction(nameAction);
414+
415 QuickListEntry pinningAction;
416 pinningAction.setActionId("pin_item");
417 pinningAction.setText(gettext("Pin shortcut"));
418 m_quickList->appendAction(pinningAction);
419+
420+ m_quitAction.setActionId("stop_item");
421+ m_quitAction.setIcon("application-exit");
422+ m_quitAction.setText(gettext("Quit"));
423 }
424
425 QString LauncherItem::appId() const
426@@ -110,6 +116,11 @@
427 {
428 if (m_running != running) {
429 m_running = running;
430+ if (m_running) { // add the quit action
431+ m_quickList->appendAction(m_quitAction);
432+ } else { // remove the quit action
433+ m_quickList->removeAction(m_quitAction);
434+ }
435 Q_EMIT runningChanged(running);
436 }
437 }
438@@ -150,6 +161,9 @@
439 if (m_count != count) {
440 m_count = count;
441 Q_EMIT countChanged(count);
442+ if (m_countVisible) {
443+ setAlerting(true);
444+ }
445 }
446 }
447
448@@ -163,6 +177,9 @@
449 if (m_countVisible != countVisible) {
450 m_countVisible = countVisible;
451 Q_EMIT countVisibleChanged(countVisible);
452+ if (countVisible) {
453+ setAlerting(true);
454+ }
455 }
456 }
457
458@@ -175,10 +192,26 @@
459 {
460 if (m_focused != focused) {
461 m_focused = focused;
462+ if (focused) {
463+ setAlerting(false);
464+ }
465 Q_EMIT focusedChanged(focused);
466 }
467 }
468
469+bool LauncherItem::alerting() const
470+{
471+ return m_alerting;
472+}
473+
474+void LauncherItem::setAlerting(bool alerting)
475+{
476+ if (m_alerting != alerting) {
477+ m_alerting = alerting;
478+ Q_EMIT alertingChanged(alerting);
479+ }
480+}
481+
482 unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
483 {
484 return m_quickList;
485
486=== modified file 'plugins/Unity/Launcher/launcheritem.h'
487--- plugins/Unity/Launcher/launcheritem.h 2014-09-02 18:22:37 +0000
488+++ plugins/Unity/Launcher/launcheritem.h 2015-07-23 14:15:26 +0000
489@@ -44,6 +44,7 @@
490 int count() const override;
491 bool countVisible() const override;
492 bool focused() const override;
493+ bool alerting() const override;
494
495 unity::shell::launcher::QuickListModelInterface *quickList() const override;
496
497@@ -57,6 +58,7 @@
498 void setCount(int count);
499 void setCountVisible(bool countVisible);
500 void setFocused(bool focused);
501+ void setAlerting(bool alerting);
502
503 private:
504 QString m_appId;
505@@ -69,7 +71,9 @@
506 int m_count;
507 bool m_countVisible;
508 bool m_focused;
509+ bool m_alerting;
510 QuickListModel *m_quickList;
511+ QuickListEntry m_quitAction;
512
513 friend class LauncherModel;
514 };
515
516=== modified file 'plugins/Unity/Launcher/launchermodel.cpp'
517--- plugins/Unity/Launcher/launchermodel.cpp 2015-03-30 17:36:42 +0000
518+++ plugins/Unity/Launcher/launchermodel.cpp 2015-07-23 14:15:26 +0000
519@@ -36,11 +36,13 @@
520 m_settings(new GSettings(this)),
521 m_dbusIface(new DBusInterface(this)),
522 m_asAdapter(new ASAdapter()),
523- m_appManager(0)
524+ m_appManager(nullptr)
525 {
526 connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged);
527 connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged);
528+ connect(m_dbusIface, &DBusInterface::progressChanged, this, &LauncherModel::progressChanged);
529 connect(m_dbusIface, &DBusInterface::refreshCalled, this, &LauncherModel::refresh);
530+ connect(m_dbusIface, &DBusInterface::alertCalled, this, &LauncherModel::alert);
531
532 connect(m_settings, &GSettings::changed, this, &LauncherModel::refresh);
533
534@@ -82,11 +84,30 @@
535 return item->progress();
536 case RoleFocused:
537 return item->focused();
538+ case RoleAlerting:
539+ return item->alerting();
540+ case RoleRunning:
541+ return item->running();
542+ default:
543+ qWarning() << Q_FUNC_INFO << "missing role, implement me";
544+ return QVariant();
545 }
546
547 return QVariant();
548 }
549
550+void LauncherModel::setAlerting(const QString &appId, bool alerting) {
551+ int index = findApplication(appId);
552+ if (index >= 0) {
553+ QModelIndex modelIndex = this->index(index);
554+ LauncherItem *item = m_list.at(index);
555+ if (!item->focused()) {
556+ item->setAlerting(alerting);
557+ Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RoleAlerting);
558+ }
559+ }
560+}
561+
562 unity::shell::launcher::LauncherItemInterface *LauncherModel::get(int index) const
563 {
564 if (index < 0 || index >= m_list.count()) {
565@@ -134,7 +155,7 @@
566 if (index == -1 || index == currentIndex) {
567 m_list.at(currentIndex)->setPinned(true);
568 QModelIndex modelIndex = this->index(currentIndex);
569- Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RolePinned);
570+ Q_EMIT dataChanged(modelIndex, modelIndex, {RolePinned});
571 } else {
572 move(currentIndex, index);
573 // move() will store the list to the backend itself, so just exit at this point.
574@@ -147,7 +168,7 @@
575
576 DesktopFileHandler desktopFile(appId);
577 if (!desktopFile.isValid()) {
578- qWarning() << "Can't pin this application, there is no .destkop file available.";
579+ qWarning() << "Can't pin this application, there is no .desktop file available.";
580 return;
581 }
582
583@@ -172,7 +193,7 @@
584
585 void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex)
586 {
587- int index = findApplication(appId);
588+ const int index = findApplication(appId);
589 if (index < 0) {
590 return;
591 }
592@@ -180,7 +201,7 @@
593 LauncherItem *item = m_list.at(index);
594 QuickListModel *model = qobject_cast<QuickListModel*>(item->quickList());
595 if (model) {
596- QString actionId = model->get(actionIndex).actionId();
597+ const QString actionId = model->get(actionIndex).actionId();
598
599 // Check if this is one of the launcher actions we handle ourselves
600 if (actionId == "pin_item") {
601@@ -191,7 +212,10 @@
602 }
603 } else if (actionId == "launch_item") {
604 QDesktopServices::openUrl(getUrlForAppId(appId));
605-
606+ } else if (actionId == "stop_item") { // Quit
607+ if (m_appManager) {
608+ m_appManager->stopApplication(appId);
609+ }
610 // Nope, we don't know this action, let the backend forward it to the application
611 } else {
612 // TODO: forward quicklist action to app, possibly via m_dbusIface
613@@ -289,7 +313,7 @@
614
615 void LauncherModel::unpin(const QString &appId)
616 {
617- int index = findApplication(appId);
618+ const int index = findApplication(appId);
619 if (index < 0) {
620 return;
621 }
622@@ -298,7 +322,7 @@
623 if (m_list.at(index)->pinned()) {
624 m_list.at(index)->setPinned(false);
625 QModelIndex modelIndex = this->index(index);
626- Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RolePinned);
627+ Q_EMIT dataChanged(modelIndex, modelIndex, {RolePinned});
628 }
629 } else {
630 beginRemoveRows(QModelIndex(), index, index);
631@@ -320,22 +344,25 @@
632
633 void LauncherModel::progressChanged(const QString &appId, int progress)
634 {
635- int idx = findApplication(appId);
636+ const int idx = findApplication(appId);
637 if (idx >= 0) {
638 LauncherItem *item = m_list.at(idx);
639 item->setProgress(progress);
640- Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleProgress);
641+ Q_EMIT dataChanged(index(idx), index(idx), {RoleProgress});
642 }
643 }
644
645 void LauncherModel::countChanged(const QString &appId, int count)
646 {
647- int idx = findApplication(appId);
648+ const int idx = findApplication(appId);
649 if (idx >= 0) {
650 LauncherItem *item = m_list.at(idx);
651 item->setCount(count);
652- Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
653+ if (item->countVisible()) {
654+ setAlerting(item->appId(), true);
655+ }
656 m_asAdapter->syncItems(m_list);
657+ Q_EMIT dataChanged(index(idx), index(idx), {RoleCount});
658 }
659 }
660
661@@ -345,7 +372,10 @@
662 if (idx >= 0) {
663 LauncherItem *item = m_list.at(idx);
664 item->setCountVisible(countVisible);
665- Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCountVisible);
666+ if (countVisible) {
667+ setAlerting(item->appId(), true);
668+ }
669+ Q_EMIT dataChanged(index(idx), index(idx), {RoleCountVisible});
670
671 // If countVisible goes to false, and the item is neither pinned nor recent we can drop it
672 if (!countVisible && !item->pinned() && !item->recent()) {
673@@ -387,7 +417,8 @@
674 item->setName(desktopFile.displayName());
675 item->setIcon(desktopFile.icon());
676 item->setPinned(item->pinned()); // update pinned text if needed
677- Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleName << RoleIcon);
678+ item->setRunning(item->running());
679+ Q_EMIT dataChanged(index(idx), index(idx), {RoleName, RoleIcon, RoleRunning});
680 }
681 }
682
683@@ -405,7 +436,7 @@
684
685 // Now walk through settings and see if we need to add something
686 for (int settingsIndex = 0; settingsIndex < m_settings->storedApplications().count(); ++settingsIndex) {
687- QString entry = m_settings->storedApplications().at(settingsIndex);
688+ const QString entry = m_settings->storedApplications().at(settingsIndex);
689 int itemIndex = -1;
690 for (int i = 0; i < m_list.count(); ++i) {
691 if (m_list.at(i)->appId() == entry) {
692@@ -453,6 +484,16 @@
693 m_asAdapter->syncItems(m_list);
694 }
695
696+void LauncherModel::alert(const QString &appId)
697+{
698+ int idx = findApplication(appId);
699+ if (idx >= 0) {
700+ LauncherItem *item = m_list.at(idx);
701+ setAlerting(item->appId(), true);
702+ Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleAlerting);
703+ }
704+}
705+
706 void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
707 {
708 Q_UNUSED(parent);
709@@ -468,25 +509,27 @@
710 return;
711 }
712
713- int itemIndex = findApplication(app->appId());
714+ const int itemIndex = findApplication(app->appId());
715 if (itemIndex != -1) {
716 LauncherItem *item = m_list.at(itemIndex);
717 if (!item->recent()) {
718 item->setRecent(true);
719- m_asAdapter->syncItems(m_list);
720- Q_EMIT dataChanged(index(itemIndex), index(itemIndex), QVector<int>() << RoleRecent);
721+ Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent});
722 }
723- // Shall we paint some running/recent app highlight? If yes, do it here.
724+ item->setRunning(true);
725+ // TODO Shall we paint some running/recent app highlight? If yes, do it here.
726 } else {
727 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
728 item->setRecent(true);
729+ item->setRunning(true);
730 item->setFocused(app->focused());
731
732 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
733 m_list.append(item);
734 endInsertRows();
735- m_asAdapter->syncItems(m_list);
736 }
737+ m_asAdapter->syncItems(m_list);
738+ Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRunning});
739 }
740
741 void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
742@@ -501,25 +544,35 @@
743 }
744 }
745
746- if (appIndex > -1 && !m_list.at(appIndex)->pinned()) {
747+ if (appIndex < 0) {
748+ qWarning() << Q_FUNC_INFO << "appIndex not found";
749+ return;
750+ }
751+
752+ LauncherItem * item = m_list.at(appIndex);
753+ item->setRunning(false);
754+
755+ if (!item->pinned()) {
756 beginRemoveRows(QModelIndex(), appIndex, appIndex);
757 m_list.takeAt(appIndex)->deleteLater();
758 endRemoveRows();
759 m_asAdapter->syncItems(m_list);
760+ Q_EMIT dataChanged(index(appIndex), index(appIndex), {RolePinned});
761 }
762+ Q_EMIT dataChanged(index(appIndex), index(appIndex), {RoleRunning});
763 }
764
765 void LauncherModel::focusedAppIdChanged()
766 {
767- QString appId = m_appManager->focusedApplicationId();
768+ const QString appId = m_appManager->focusedApplicationId();
769 for (int i = 0; i < m_list.count(); ++i) {
770 LauncherItem *item = m_list.at(i);
771 if (!item->focused() && item->appId() == appId) {
772 item->setFocused(true);
773- Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
774+ Q_EMIT dataChanged(index(i), index(i), {RoleFocused});
775 } else if (item->focused() && item->appId() != appId) {
776 item->setFocused(false);
777- Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
778+ Q_EMIT dataChanged(index(i), index(i), {RoleFocused});
779 }
780 }
781 }
782
783=== modified file 'plugins/Unity/Launcher/launchermodel.h'
784--- plugins/Unity/Launcher/launchermodel.h 2015-04-30 09:31:51 +0000
785+++ plugins/Unity/Launcher/launchermodel.h 2015-07-23 14:15:26 +0000
786@@ -45,6 +45,7 @@
787
788 QVariant data(const QModelIndex &index, int role) const override;
789
790+ Q_INVOKABLE void setAlerting(const QString &appId, bool alerting) override;
791 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const override;
792 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
793 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
794@@ -63,6 +64,7 @@
795 public Q_SLOTS:
796 void requestRemove(const QString &appId) override;
797 Q_INVOKABLE void refresh();
798+ Q_INVOKABLE void alert(const QString &appId);
799
800 private:
801 void storeAppList();
802
803=== modified file 'plugins/Unity/Launcher/quicklistentry.cpp'
804--- plugins/Unity/Launcher/quicklistentry.cpp 2014-08-26 11:34:22 +0000
805+++ plugins/Unity/Launcher/quicklistentry.cpp 2015-07-23 14:15:26 +0000
806@@ -1,4 +1,4 @@
807-/* Copyright (C) 2013 Canonical, Ltd.
808+/* Copyright (C) 2013, 2015 Canonical, Ltd.
809 *
810 * Authors:
811 * Michael Zanetti <michael.zanetti@canonical.com>
812@@ -20,7 +20,6 @@
813
814 QuickListEntry::QuickListEntry()
815 {
816-
817 }
818
819 QString QuickListEntry::actionId() const
820@@ -57,3 +56,8 @@
821 {
822 return !m_actionId.isEmpty();
823 }
824+
825+bool QuickListEntry::operator==(const QuickListEntry &other)
826+{
827+ return !other.actionId().isEmpty() && other.actionId() == m_actionId;
828+}
829
830=== modified file 'plugins/Unity/Launcher/quicklistentry.h'
831--- plugins/Unity/Launcher/quicklistentry.h 2014-08-26 11:34:22 +0000
832+++ plugins/Unity/Launcher/quicklistentry.h 2015-07-23 14:15:26 +0000
833@@ -1,4 +1,4 @@
834-/* Copyright (C) 2013 Canonical, Ltd.
835+/* Copyright (C) 2013, 2015 Canonical, Ltd.
836 *
837 * Authors:
838 * Michael Zanetti <michael.zanetti@canonical.com>
839@@ -37,6 +37,8 @@
840
841 bool clickable() const;
842
843+ bool operator==(const QuickListEntry & other);
844+
845 private:
846 QString m_actionId;
847 QString m_text;
848
849=== modified file 'plugins/Unity/Launcher/quicklistmodel.cpp'
850--- plugins/Unity/Launcher/quicklistmodel.cpp 2013-10-02 11:00:53 +0000
851+++ plugins/Unity/Launcher/quicklistmodel.cpp 2015-07-23 14:15:26 +0000
852@@ -1,5 +1,5 @@
853 /*
854- * Copyright 2013 Canonical Ltd.
855+ * Copyright 2013, 2015 Canonical Ltd.
856 *
857 * This program is free software; you can redistribute it and/or modify
858 * it under the terms of the GNU Lesser General Public License as published by
859@@ -48,6 +48,17 @@
860 }
861 }
862
863+void QuickListModel::removeAction(const QuickListEntry &entry)
864+{
865+ const int start = m_list.indexOf(entry);
866+ if (start > -1) {
867+ beginRemoveRows(QModelIndex(), start, start);
868+ m_list.removeOne(entry);
869+ Q_EMIT dataChanged(index(start), index(start));
870+ endRemoveRows();
871+ }
872+}
873+
874 QuickListEntry QuickListModel::get(int index) const
875 {
876 return m_list.at(index);
877
878=== modified file 'plugins/Unity/Launcher/quicklistmodel.h'
879--- plugins/Unity/Launcher/quicklistmodel.h 2015-04-30 09:31:51 +0000
880+++ plugins/Unity/Launcher/quicklistmodel.h 2015-07-23 14:15:26 +0000
881@@ -1,5 +1,5 @@
882 /*
883- * Copyright 2013 Canonical Ltd.
884+ * Copyright 201, 2015 Canonical Ltd.
885 *
886 * This program is free software; you can redistribute it and/or modify
887 * it under the terms of the GNU Lesser General Public License as published by
888@@ -46,6 +46,8 @@
889 */
890 void updateAction(const QuickListEntry &entry);
891
892+ void removeAction(const QuickListEntry &entry);
893+
894 QuickListEntry get(int index) const;
895
896 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
897
898=== modified file 'qml/Launcher/LauncherDelegate.qml'
899--- qml/Launcher/LauncherDelegate.qml 2014-10-14 12:28:07 +0000
900+++ qml/Launcher/LauncherDelegate.qml 2015-07-23 14:15:26 +0000
901@@ -15,7 +15,7 @@
902 */
903
904 import QtQuick 2.0
905-import Ubuntu.Components 0.1
906+import Ubuntu.Components 1.1
907
908 Item {
909 id: root
910@@ -27,6 +27,8 @@
911 property bool itemFocused: false
912 property real maxAngle: 0
913 property bool inverted: false
914+ property bool alerting: false
915+ readonly property alias wiggling: wiggleAnim.running
916
917 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
918 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
919@@ -39,6 +41,82 @@
920 property real offset: 0
921 property real itemOpacity: 1
922 property real brightness: 0
923+ property double maxWiggleAngle: 5.0
924+
925+ QtObject {
926+ id: priv
927+
928+ readonly property int wiggleDuration: UbuntuAnimation.SnapDuration
929+ property real wiggleAngle: 0
930+ }
931+
932+ SequentialAnimation {
933+ id: wiggleAnim
934+
935+ running: alerting
936+ loops: 1
937+ alwaysRunToEnd: true
938+
939+ NumberAnimation {
940+ target: priv
941+ property: "wiggleAngle"
942+ from: 0
943+ to: maxWiggleAngle
944+ duration: priv.wiggleDuration
945+ easing.type: Easing.InQuad
946+ }
947+
948+ NumberAnimation {
949+ target: priv
950+ property: "wiggleAngle"
951+ from: maxWiggleAngle
952+ to: -maxWiggleAngle
953+ duration: priv.wiggleDuration
954+ easing.type: Easing.InOutQuad
955+ }
956+
957+ NumberAnimation {
958+ target: priv
959+ property: "wiggleAngle"
960+ from: -maxWiggleAngle
961+ to: maxWiggleAngle
962+ duration: priv.wiggleDuration
963+ easing.type: Easing.InOutQuad
964+ }
965+
966+ NumberAnimation {
967+ target: priv
968+ property: "wiggleAngle"
969+ from: maxWiggleAngle
970+ to: -maxWiggleAngle
971+ duration: priv.wiggleDuration
972+ easing.type: Easing.InOutQuad
973+ }
974+
975+ NumberAnimation {
976+ target: priv
977+ property: "wiggleAngle"
978+ from: -maxWiggleAngle
979+ to: maxWiggleAngle
980+ duration: priv.wiggleDuration
981+ easing.type: Easing.InOutQuad
982+ }
983+
984+ NumberAnimation {
985+ target: priv
986+ property: "wiggleAngle"
987+ from: maxWiggleAngle
988+ to: 0
989+ duration: priv.wiggleDuration
990+ easing.type: Easing.OutQuad
991+ }
992+
993+ UbuntuNumberAnimation {
994+ target: root
995+ property: "alerting"
996+ to: 0
997+ }
998+ }
999
1000 Item {
1001 id: iconItem
1002@@ -75,7 +153,7 @@
1003 objectName: "countEmblem"
1004 anchors {
1005 right: parent.right
1006- top: parent.top
1007+ bottom: parent.bottom
1008 margins: units.dp(3)
1009 }
1010 width: Math.min(root.itemWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1)))
1011@@ -100,23 +178,21 @@
1012 }
1013 }
1014
1015- BorderImage {
1016+ UbuntuShape {
1017 id: progressOverlay
1018 objectName: "progressOverlay"
1019+
1020 anchors {
1021 left: iconItem.left
1022 right: iconItem.right
1023- bottom: iconItem.bottom
1024- leftMargin: units.gu(1)
1025- rightMargin: units.gu(1)
1026- bottomMargin: units.gu(1)
1027+ verticalCenter: parent.verticalCenter
1028+ leftMargin: units.gu(1.5)
1029+ rightMargin: units.gu(1.5)
1030 }
1031- height: units.gu(1.5)
1032+ height: units.gu(1)
1033 visible: root.progress > -1
1034- source: "graphics/progressbar-trough.sci"
1035-
1036- // For fill calculation we need to remove the 2 units of border defined in .sci file
1037- property int adjustedWidth: width - units.gu(2)
1038+ color: UbuntuColors.darkGrey
1039+ borderSource: "none"
1040
1041 Item {
1042 anchors {
1043@@ -124,20 +200,22 @@
1044 top: parent.top
1045 bottom: parent.bottom
1046 }
1047- width: Math.min(100, root.progress) / 100 * parent.adjustedWidth + units.gu(1)
1048+ width: Math.min(100, root.progress) / 100 * parent.width
1049 clip: true
1050
1051- BorderImage {
1052+ UbuntuShape {
1053 anchors {
1054 left: parent.left
1055 top: parent.top
1056 bottom: parent.bottom
1057 }
1058+ color: "white"
1059+ borderSource: "none"
1060 width: progressOverlay.width
1061- source: "graphics/progressbar-fill.sci"
1062 }
1063 }
1064 }
1065+
1066 Image {
1067 objectName: "focusedHighlight"
1068 anchors {
1069@@ -167,6 +245,14 @@
1070 }
1071
1072 transform: [
1073+ // The rotation about the icon's center/z-axis for the wiggle
1074+ // needs to happen here too, because there's no other way to
1075+ // align the wiggle with the icon-folding otherwise
1076+ Rotation {
1077+ axis { x: 0; y: 0; z: 1 }
1078+ origin { x: iconItem.width / 2; y: iconItem.height / 2; z: 0 }
1079+ angle: priv.wiggleAngle
1080+ },
1081 // Rotating 3 times at top/bottom because that increases the perspective.
1082 // This is a hack, but as QML does not support real 3D coordinates
1083 // getting a higher perspective can only be done by a hack. This is the most
1084
1085=== modified file 'qml/Launcher/LauncherPanel.qml'
1086--- qml/Launcher/LauncherPanel.qml 2015-07-01 11:39:49 +0000
1087+++ qml/Launcher/LauncherPanel.qml 2015-07-23 14:15:26 +0000
1088@@ -15,7 +15,7 @@
1089 */
1090
1091 import QtQuick 2.3
1092-import Ubuntu.Components 1.1
1093+import Ubuntu.Components 1.2
1094 import Ubuntu.Components.ListItems 1.0 as ListItems
1095 import Unity.Launcher 0.1
1096 import Ubuntu.Components.Popups 0.1
1097@@ -86,6 +86,7 @@
1098 height: parent.height - dashItem.height - parent.spacing*2
1099
1100 Item {
1101+ id: launcherListViewItem
1102 anchors.fill: parent
1103 clip: true
1104
1105@@ -109,12 +110,21 @@
1106 preferredHighlightBegin: (height - itemHeight) / 2
1107 preferredHighlightEnd: (height + itemHeight) / 2
1108
1109+ // for the single peeking icon, when alert-state is set on delegate
1110+ property int peekingIndex: -1
1111+
1112 // The size of the area the ListView is extended to make sure items are not
1113 // destroyed when dragging them outside the list. This needs to be at least
1114 // itemHeight to prevent folded items from disappearing and DragArea limits
1115 // need to be smaller than this size to avoid breakage.
1116 property int extensionSize: 0
1117
1118+ // These properties are needed to facilitate implicitly unfolding the
1119+ // launcher to the peeking icon, if it is not already fully flat
1120+ // and in view for the user
1121+ property real moveToIndexYFrom
1122+ property real moveToIndexYTo
1123+
1124 // Setting extensionSize after the list has been populated because it has
1125 // the potential to mess up with the intial positioning in combination
1126 // with snapping to the center of the list. This catches all the cases
1127@@ -128,6 +138,14 @@
1128 flick(0, clickFlickSpeed)
1129 }
1130
1131+ UbuntuNumberAnimation {
1132+ id: moveToIndexAnimation
1133+ target: launcherListView
1134+ property: "contentY"
1135+ from: launcherListView.moveToIndexYFrom
1136+ to: launcherListView.moveToIndexYTo
1137+ }
1138+
1139 // The height of the area where icons start getting folded
1140 property int foldingStartHeight: units.gu(6.5)
1141 // The height of the area where the items reach the final folding angle
1142@@ -180,10 +198,63 @@
1143 progress: model.progress
1144 itemFocused: model.focused
1145 inverted: root.inverted
1146+ alerting: model.alerting
1147 z: -Math.abs(offset)
1148 maxAngle: 55
1149 property bool dragging: false
1150
1151+ SequentialAnimation {
1152+ id: peekingAnimation
1153+
1154+ // revealing
1155+ PropertyAction { target: root; property: "visible"; value: (launcher.visibleWidth === 0) ? 1 : 0 }
1156+ PropertyAction { target: launcherListViewItem; property: "clip"; value: 0 }
1157+
1158+ UbuntuNumberAnimation {
1159+ target: launcherDelegate
1160+ alwaysRunToEnd: true
1161+ loops: 1
1162+ properties: "x"
1163+ to: (units.gu(.5) + launcherListView.width * .5) * (root.inverted ? -1 : 1)
1164+ duration: UbuntuAnimation.BriskDuration
1165+ }
1166+
1167+ // hiding
1168+ UbuntuNumberAnimation {
1169+ target: launcherDelegate
1170+ alwaysRunToEnd: true
1171+ loops: 1
1172+ properties: "x"
1173+ to: 0
1174+ duration: UbuntuAnimation.BriskDuration
1175+ }
1176+
1177+ PropertyAction { target: launcherListViewItem; property: "clip"; value: 1 }
1178+ PropertyAction { target: root; property: "visible"; value: (launcher.visibleWidth === 0) ? 0 : 1 }
1179+ }
1180+
1181+ onAlertingChanged: {
1182+ if(alerting) {
1183+ if (!dragging && (launcherListView.peekingIndex === -1 || launcher.visibleWidth > 0)) {
1184+ launcherListView.moveToIndexYFrom = launcherListView.contentY
1185+ launcherListView.positionViewAtIndex(index, ListView.Center)
1186+ launcherListView.moveToIndexYTo = launcherListView.contentY
1187+ moveToIndexAnimation.start()
1188+ if (!dragging && launcher.state !== "visible") {
1189+ peekingAnimation.start()
1190+ }
1191+ }
1192+
1193+ if (launcherListView.peekingIndex === -1) {
1194+ launcherListView.peekingIndex = index
1195+ }
1196+ } else {
1197+ if (launcherListView.peekingIndex === index) {
1198+ launcherListView.peekingIndex = -1
1199+ }
1200+ }
1201+ }
1202+
1203 ThinDivider {
1204 id: dropIndicator
1205 objectName: "dropIndicator"
1206@@ -286,6 +357,7 @@
1207 MouseArea {
1208 id: dndArea
1209 objectName: "dndArea"
1210+ acceptedButtons: Qt.LeftButton | Qt.RightButton
1211 anchors {
1212 fill: parent
1213 topMargin: launcherListView.topMargin
1214@@ -297,7 +369,7 @@
1215 property int draggedIndex: -1
1216 property var selectedItem
1217 property bool preDragging: false
1218- property bool dragging: selectedItem !== undefined && selectedItem !== null && selectedItem.dragging
1219+ property bool dragging: !!selectedItem && selectedItem.dragging
1220 property bool postDragging: false
1221 property int startX
1222 property int startY
1223@@ -315,6 +387,15 @@
1224 return;
1225 }
1226
1227+ if (mouse.button & Qt.RightButton) { // context menu
1228+ // Opening QuickList
1229+ quickList.item = clickedItem;
1230+ quickList.model = launcherListView.model.get(index).quickList;
1231+ quickList.appId = launcherListView.model.get(index).appId;
1232+ quickList.state = "open";
1233+ return
1234+ }
1235+
1236 // First/last item do the scrolling at more than 12 degrees
1237 if (index == 0 || index == launcherListView.count - 1) {
1238 if (clickedItem.angle > 12) {
1239@@ -508,7 +589,7 @@
1240 id: quickListShape
1241 objectName: "quickListShape"
1242 anchors.fill: quickList
1243- opacity: quickList.state === "open" ? 0.96 : 0
1244+ opacity: quickList.state === "open" ? 0.8 : 0
1245 visible: opacity > 0
1246 rotation: root.rotation
1247
1248@@ -520,15 +601,15 @@
1249
1250 Image {
1251 anchors {
1252- left: parent.left
1253- leftMargin: quickList.item ? (quickList.item.width - units.gu(1)) / 2 - width / 2 : 0
1254+ right: parent.left
1255+ rightMargin: -units.dp(4)
1256 verticalCenter: parent.verticalCenter
1257- verticalCenterOffset: (parent.height / 2 + units.dp(3)) * (quickList.offset > 0 ? 1 : -1) * (root.inverted ? 1 : -1)
1258+ verticalCenterOffset: -quickList.offset * (root.inverted ? -1 : 1)
1259 }
1260 height: units.gu(1)
1261 width: units.gu(2)
1262 source: "graphics/quicklist_tooltip.png"
1263- rotation: (quickList.offset > 0 ? 0 : 180) + (root.inverted ? 0 : 180)
1264+ rotation: 90
1265 }
1266
1267 InverseMouseArea {
1268@@ -551,11 +632,11 @@
1269 height: quickListColumn.height
1270 visible: quickListShape.visible
1271 anchors {
1272- left: root.inverted ? undefined : parent.left
1273- right: root.inverted ? parent.right : undefined
1274+ left: root.inverted ? undefined : parent.right
1275+ right: root.inverted ? parent.left : undefined
1276 margins: units.gu(1)
1277 }
1278- y: itemCenter + offset
1279+ y: itemCenter - (height / 2) + offset
1280 rotation: root.rotation
1281
1282 property var model
1283@@ -564,10 +645,8 @@
1284
1285 // internal
1286 property int itemCenter: item ? root.mapFromItem(quickList.item).y + (item.height / 2) : units.gu(1)
1287- property int offset: item ? itemCenter + (item.height/2) + height + units.gu(1) > parent.height ?
1288- -(item.height/2) - height - units.gu(.5) :
1289- (item.height/2) + units.gu(.5) :
1290- 0
1291+ property int offset: itemCenter + (height/2) + units.gu(1) > parent.height ? -itemCenter - (height/2) - units.gu(1) + parent.height :
1292+ itemCenter - (height/2) < units.gu(1) ? (height/2) - itemCenter + units.gu(1) : 0
1293
1294 Column {
1295 id: quickListColumn
1296
1297=== removed file 'qml/Launcher/graphics/progressbar-fill@30.png'
1298Binary files qml/Launcher/graphics/progressbar-fill@30.png 2013-08-19 19:34:03 +0000 and qml/Launcher/graphics/progressbar-fill@30.png 1970-01-01 00:00:00 +0000 differ
1299=== removed file 'qml/Launcher/graphics/progressbar-fill@30.sci'
1300--- qml/Launcher/graphics/progressbar-fill@30.sci 2013-08-19 19:34:03 +0000
1301+++ qml/Launcher/graphics/progressbar-fill@30.sci 1970-01-01 00:00:00 +0000
1302@@ -1,5 +0,0 @@
1303-border.left: 36
1304-border.top: 16
1305-border.bottom: 28
1306-border.right: 36
1307-source: progressbar-fill@30.png
1308\ No newline at end of file
1309
1310=== removed file 'qml/Launcher/graphics/progressbar-trough@30.png'
1311Binary files qml/Launcher/graphics/progressbar-trough@30.png 2013-08-19 19:34:03 +0000 and qml/Launcher/graphics/progressbar-trough@30.png 1970-01-01 00:00:00 +0000 differ
1312=== removed file 'qml/Launcher/graphics/progressbar-trough@30.sci'
1313--- qml/Launcher/graphics/progressbar-trough@30.sci 2013-08-19 19:34:03 +0000
1314+++ qml/Launcher/graphics/progressbar-trough@30.sci 1970-01-01 00:00:00 +0000
1315@@ -1,5 +0,0 @@
1316-border.left: 36
1317-border.top: 16
1318-border.bottom: 26
1319-border.right: 36
1320-source: progressbar-trough@30.png
1321\ No newline at end of file
1322
1323=== modified file 'tests/mocks/Unity/Launcher/CMakeLists.txt'
1324--- tests/mocks/Unity/Launcher/CMakeLists.txt 2015-04-13 09:33:28 +0000
1325+++ tests/mocks/Unity/Launcher/CMakeLists.txt 2015-07-23 14:15:26 +0000
1326@@ -1,4 +1,4 @@
1327-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
1328+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
1329
1330 include_directories(
1331 ${CMAKE_CURRENT_SOURCE_DIR}
1332
1333=== modified file 'tests/mocks/Unity/Launcher/MockLauncherItem.cpp'
1334--- tests/mocks/Unity/Launcher/MockLauncherItem.cpp 2014-09-03 13:30:52 +0000
1335+++ tests/mocks/Unity/Launcher/MockLauncherItem.cpp 2015-07-23 14:15:26 +0000
1336@@ -37,9 +37,13 @@
1337 m_count(0),
1338 m_countVisible(false),
1339 m_focused(false),
1340+ m_alerting(false),
1341 m_quickList(new MockQuickListModel(this))
1342 {
1343+}
1344
1345+MockLauncherItem::~MockLauncherItem()
1346+{
1347 }
1348
1349 QString MockLauncherItem::appId() const
1350@@ -129,6 +133,9 @@
1351 {
1352 m_count = count;
1353 Q_EMIT countChanged(count);
1354+ if (m_countVisible) {
1355+ setAlerting(true);
1356+ }
1357 }
1358 }
1359
1360@@ -142,6 +149,9 @@
1361 if (m_countVisible != countVisible) {
1362 m_countVisible = countVisible;
1363 Q_EMIT countVisibleChanged(countVisible);
1364+ if (countVisible) {
1365+ setAlerting(true);
1366+ }
1367 }
1368 }
1369
1370@@ -159,6 +169,18 @@
1371 }
1372 }
1373
1374+bool MockLauncherItem::alerting() const
1375+{
1376+ return m_alerting;
1377+}
1378+
1379+void MockLauncherItem::setAlerting(bool alerting)
1380+{
1381+ if (m_alerting != alerting) {
1382+ m_alerting = alerting;
1383+ Q_EMIT alertingChanged(alerting);
1384+ }
1385+}
1386
1387 unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
1388 {
1389
1390=== modified file 'tests/mocks/Unity/Launcher/MockLauncherItem.h'
1391--- tests/mocks/Unity/Launcher/MockLauncherItem.h 2015-04-30 09:31:51 +0000
1392+++ tests/mocks/Unity/Launcher/MockLauncherItem.h 2015-07-23 14:15:26 +0000
1393@@ -31,6 +31,7 @@
1394 Q_OBJECT
1395 public:
1396 MockLauncherItem(const QString &appId, const QString& desktopFile, const QString& name, const QString& icon, QObject* parent = 0);
1397+ ~MockLauncherItem();
1398
1399 QString appId() const override;
1400 QString desktopFile() const;
1401@@ -44,6 +45,7 @@
1402 int count() const override;
1403 bool countVisible() const override;
1404 bool focused() const override;
1405+ bool alerting() const override;
1406
1407 unity::shell::launcher::QuickListModelInterface *quickList() const override;
1408
1409@@ -55,6 +57,7 @@
1410 void setCount(int count);
1411 void setCountVisible(bool countVisible);
1412 void setFocused(bool focused);
1413+ void setAlerting(bool alerting);
1414
1415 QString m_appId;
1416 QString m_desktopFile;
1417@@ -67,6 +70,7 @@
1418 int m_count;
1419 bool m_countVisible;
1420 bool m_focused;
1421+ bool m_alerting;
1422 MockQuickListModel *m_quickList;
1423
1424 friend class MockLauncherModel;
1425
1426=== modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.cpp'
1427--- tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-03-06 04:44:11 +0000
1428+++ tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-07-23 14:15:26 +0000
1429@@ -34,6 +34,7 @@
1430 item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
1431 item->setProgress(50);
1432 item->setCountVisible(true);
1433+ item->setAlerting(false);
1434 m_list.append(item);
1435 item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
1436 m_list.append(item);
1437@@ -43,25 +44,31 @@
1438 item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this);
1439 item->setCount(1);
1440 item->setCountVisible(true);
1441+ item->setRunning(true);
1442+ item->setAlerting(false);
1443 m_list.append(item);
1444 item = new MockLauncherItem("twitter-webapp", "/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter", this);
1445 item->setCount(12);
1446 item->setCountVisible(true);
1447+ item->setAlerting(false);
1448 item->setPinned(true);
1449 m_list.append(item);
1450 item = new MockLauncherItem("gmail-webapp", "/usr/share/applications/gmail-webapp.desktop", "GMail", "gmail", this);
1451 item->setCount(123);
1452 item->setCountVisible(true);
1453+ item->setAlerting(false);
1454 m_list.append(item);
1455 item = new MockLauncherItem("ubuntu-weather-app", "/usr/share/applications/ubuntu-weather-app.desktop", "Weather", "weather", this);
1456 item->setCount(1234567890);
1457 item->setCountVisible(true);
1458+ item->setAlerting(false);
1459 item->setPinned(true);
1460 m_list.append(item);
1461 item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
1462 item->setProgress(50);
1463 item->setCount(5);
1464 item->setCountVisible(true);
1465+ item->setAlerting(false);
1466 item->setFocused(true);
1467 item->setPinned(true);
1468 m_list.append(item);
1469@@ -105,6 +112,8 @@
1470 return item->countVisible();
1471 case RoleFocused:
1472 return item->focused();
1473+ case RoleAlerting:
1474+ return item->alerting();
1475 }
1476
1477 return QVariant();
1478@@ -119,6 +128,18 @@
1479 return m_list.at(index);
1480 }
1481
1482+void MockLauncherModel::setAlerting(const QString &appId, bool alerting) {
1483+ int index = findApp(appId);
1484+ if (index >= 0) {
1485+ QModelIndex modelIndex = this->index(index);
1486+ MockLauncherItem *item = m_list.at(index);
1487+ if (!item->focused()) {
1488+ item->setAlerting(alerting);
1489+ Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RoleAlerting);
1490+ }
1491+ }
1492+}
1493+
1494 void MockLauncherModel::move(int oldIndex, int newIndex)
1495 {
1496 // Make sure its not moved outside the lists
1497@@ -174,7 +195,9 @@
1498 int index = findApp(appId);
1499 if (index >= 0) {
1500 beginRemoveRows(QModelIndex(), index, 0);
1501- m_list.takeAt(index)->deleteLater();
1502+ MockLauncherItem * item = m_list.takeAt(index);
1503+ item->setRunning(false);
1504+ item->deleteLater();
1505 endRemoveRows();
1506 }
1507 }
1508@@ -195,6 +218,16 @@
1509 return -1;
1510 }
1511
1512+void MockLauncherModel::setProgress(const QString &appId, int progress)
1513+{
1514+ int index = findApp(appId);
1515+ if (index >= 0) {
1516+ m_list.at(index)->setProgress(progress);
1517+ QModelIndex modelIndex = this->index(index);
1518+ Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RoleProgress);
1519+ }
1520+}
1521+
1522 void MockLauncherModel::setUser(const QString &username)
1523 {
1524 Q_UNUSED(username)
1525@@ -226,6 +259,26 @@
1526 Q_EMIT hint();
1527 }
1528
1529+void MockLauncherModel::setCount(const QString &appId, int count)
1530+{
1531+ int index = findApp(appId);
1532+ if (index >= 0) {
1533+ m_list.at(index)->setCount(count);
1534+ QModelIndex modelIndex = this->index(index);
1535+ Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RoleCount);
1536+ }
1537+}
1538+
1539+void MockLauncherModel::setCountVisible(const QString &appId, bool countVisible)
1540+{
1541+ int index = findApp(appId);
1542+ if (index >= 0) {
1543+ m_list.at(index)->setCountVisible(countVisible);
1544+ QModelIndex modelIndex = this->index(index);
1545+ Q_EMIT dataChanged(modelIndex, modelIndex);
1546+ }
1547+}
1548+
1549 unity::shell::application::ApplicationManagerInterface *MockLauncherModel::applicationManager() const
1550 {
1551 return nullptr;
1552
1553=== modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.h'
1554--- tests/mocks/Unity/Launcher/MockLauncherModel.h 2015-04-30 09:31:51 +0000
1555+++ tests/mocks/Unity/Launcher/MockLauncherModel.h 2015-07-23 14:15:26 +0000
1556@@ -38,6 +38,7 @@
1557
1558 QVariant data(const QModelIndex& index, int role) const override;
1559
1560+ Q_INVOKABLE void setAlerting(const QString &appId, bool alerting) override;
1561 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface *get(int index) const override;
1562 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
1563 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
1564@@ -54,6 +55,9 @@
1565
1566 // For testing
1567 Q_INVOKABLE void emitHint();
1568+ Q_INVOKABLE void setProgress(const QString &appId, int progress);
1569+ Q_INVOKABLE void setCount(const QString &appId, int count);
1570+ Q_INVOKABLE void setCountVisible(const QString &appId, bool countVisible);
1571
1572 Q_SIGNALS:
1573 void quickListTriggered(const QString &appId, int index);
1574
1575=== modified file 'tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt'
1576--- tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-06-17 12:14:27 +0000
1577+++ tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-07-23 14:15:26 +0000
1578@@ -1,4 +1,4 @@
1579-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
1580+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
1581 pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
1582
1583 include_directories(
1584
1585=== modified file 'tests/plugins/Greeter/Unity/Launcher/launchermodelastest.cpp'
1586--- tests/plugins/Greeter/Unity/Launcher/launchermodelastest.cpp 2015-02-11 14:11:26 +0000
1587+++ tests/plugins/Greeter/Unity/Launcher/launchermodelastest.cpp 2015-07-23 14:15:26 +0000
1588@@ -43,6 +43,7 @@
1589 item.insert("name", "Item 1");
1590 item.insert("icon", "fake.svg");
1591 item.insert("count", 0);
1592+ item.insert("progress", 0);
1593 item.insert("countVisible", false);
1594 item.insert("pinned", true);
1595 list.append(item);
1596@@ -67,6 +68,7 @@
1597 inSync &= model->get(i)->name() == list.at(i).value("name").toString();
1598 inSync &= model->get(i)->icon() == list.at(i).value("icon").toString();
1599 inSync &= model->get(i)->count() == list.at(i).value("count").toInt();
1600+ inSync &= model->get(i)->progress() == list.at(i).value("progress").toInt();
1601 inSync &= model->get(i)->countVisible() == list.at(i).value("countVisible").toBool();
1602 }
1603 return inSync;
1604@@ -111,6 +113,7 @@
1605 newEntry.insert("name", "New app");
1606 newEntry.insert("icon", "some-icon.svg");
1607 newEntry.insert("count", 0);
1608+ newEntry.insert("progress", 42);
1609 newEntry.insert("countVisible", false);
1610 newEntry.insert("pinned", true);
1611 newList.append(newEntry);
1612
1613=== modified file 'tests/plugins/Unity/Launcher/CMakeLists.txt'
1614--- tests/plugins/Unity/Launcher/CMakeLists.txt 2015-06-17 12:14:27 +0000
1615+++ tests/plugins/Unity/Launcher/CMakeLists.txt 2015-07-23 14:15:26 +0000
1616@@ -1,5 +1,5 @@
1617 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
1618-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
1619+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
1620
1621 include_directories(
1622 ${CMAKE_CURRENT_SOURCE_DIR}
1623
1624=== modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp'
1625--- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-06-12 16:07:43 +0000
1626+++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-07-23 14:15:26 +0000
1627@@ -68,6 +68,7 @@
1628 Q_OBJECT
1629 public:
1630 MockAppManager(QObject *parent = 0): ApplicationManagerInterface(parent) {}
1631+ ~MockAppManager() {}
1632 int rowCount(const QModelIndex &) const override { return m_list.count(); }
1633 QVariant data(const QModelIndex &, int ) const override { return QVariant(); }
1634 QString focusedApplicationId() const override {
1635@@ -325,6 +326,46 @@
1636 QCOMPARE(launcherModel->get(0)->appId(), QLatin1String("abs-icon"));
1637 }
1638
1639+ void testQuitMenuItem() {
1640+ // we have 2 apps running, both should have the Quit action in its quick list
1641+ QCOMPARE(launcherModel->rowCount(), 2);
1642+
1643+ // stop the second one keeping it pinned so that it doesn't go away
1644+ launcherModel->pin("no-icon");
1645+ appManager->stopApplication("no-icon");
1646+
1647+ // find the first Quit item, should be there
1648+ QuickListModel *model = qobject_cast<QuickListModel*>(launcherModel->get(0)->quickList());
1649+ int quitActionIndex = -1;
1650+ for (int i = 0; i < model->rowCount(); ++i) {
1651+ if (model->get(i).actionId() == "stop_item") {
1652+ quitActionIndex = i;
1653+ break;
1654+ }
1655+ }
1656+ QVERIFY(quitActionIndex >= 0);
1657+
1658+ // find the second Quit item, should NOT be there, the app is stopped
1659+ QuickListModel *model2 = qobject_cast<QuickListModel*>(launcherModel->get(1)->quickList());
1660+ int quitActionIndex2 = -1;
1661+ for (int i = 0; i < model2->rowCount(); ++i) {
1662+ if (model2->get(i).actionId() == "stop_item") {
1663+ quitActionIndex2 = i;
1664+ break;
1665+ }
1666+ }
1667+ QVERIFY(quitActionIndex2 == -1);
1668+
1669+ // trigger the first quit item quicklist action
1670+ launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), quitActionIndex);
1671+ // first app should be gone...
1672+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
1673+ // ... the second app (now at index 0) should still be there, pinned and stopped
1674+ QCOMPARE(launcherModel->get(0)->appId(), QStringLiteral("no-icon"));
1675+ QCOMPARE(launcherModel->get(0)->pinned(), true);
1676+ QCOMPARE(launcherModel->get(0)->running(), false);
1677+ }
1678+
1679 void testGetUrlForAppId() {
1680 QCOMPARE(launcherModel->getUrlForAppId(QString()), QString());
1681 QCOMPARE(launcherModel->getUrlForAppId(""), QString());
1682@@ -368,11 +409,18 @@
1683 }
1684
1685 void testCountEmblems() {
1686+ QSignalSpy spy(launcherModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)));
1687+
1688 // Call GetAll on abs-icon
1689 QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher/abs_2Dicon", "org.freedesktop.DBus.Properties");
1690 QDBusReply<QVariantMap> reply = interface.call("GetAll");
1691 QVariantMap map = reply.value();
1692
1693+ // Check that the alerting-status is still false, and the item on the upper side of the API
1694+ int index = launcherModel->findApplication("abs-icon");
1695+ QCOMPARE(index >= 0, true);
1696+ QVERIFY(launcherModel->get(index)->alerting() == false);
1697+
1698 // Make sure GetAll returns a map with count and countVisible props
1699 QCOMPARE(map.contains("count"), true);
1700 QCOMPARE(map.contains("countVisible"), true);
1701@@ -393,13 +441,8 @@
1702 QCOMPARE(map.value("count").toInt(), 55);
1703 QCOMPARE(map.value("countVisible").toBool(), true);
1704
1705- // Now the item on the upper side of the API
1706- int index = launcherModel->findApplication("abs-icon");
1707- QCOMPARE(index >= 0, true);
1708-
1709- // And make sure values have changed there as well
1710- QCOMPARE(launcherModel->get(index)->countVisible(), true);
1711- QCOMPARE(launcherModel->get(index)->count(), 55);
1712+ // Finally check, that the change to "count" implicitly also set the alerting-state to true
1713+ QVERIFY(launcherModel->get(index)->alerting() == true);
1714 }
1715
1716 void testCountEmblemAddsRemovesItem_data() {
1717@@ -459,6 +502,20 @@
1718 QCOMPARE(index == -1, !isRunning && !isPinned && !startWhenVisible);
1719 }
1720
1721+ void testAlert() {
1722+ // Check that the alerting-status is still false
1723+ int index = launcherModel->findApplication("abs-icon");
1724+ QCOMPARE(index >= 0, true);
1725+ QVERIFY(launcherModel->get(index)->alerting() == false);
1726+
1727+ // Call Alert() on "abs-icon"
1728+ QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher/abs_2Dicon", "com.canonical.Unity.Launcher.Item");
1729+ interface.call("Alert");
1730+
1731+ // Check that the alerting-status is now true
1732+ QVERIFY(launcherModel->get(index)->alerting() == true);
1733+ }
1734+
1735 void testRefreshAfterDeletedDesktopFiles_data() {
1736 QTest::addColumn<bool>("deleted");
1737 QTest::newRow("have .desktop files") << false;
1738
1739=== modified file 'tests/qmltests/Launcher/tst_Launcher.qml'
1740--- tests/qmltests/Launcher/tst_Launcher.qml 2015-04-24 09:53:37 +0000
1741+++ tests/qmltests/Launcher/tst_Launcher.qml 2015-07-23 14:15:26 +0000
1742@@ -93,6 +93,57 @@
1743 onClicked: launcherLoader.item.inverted = !launcherLoader.item.inverted
1744 Layout.fillWidth: true
1745 }
1746+
1747+ Row {
1748+ spacing: units.gu(1)
1749+
1750+ Button {
1751+ text: "35% bar"
1752+ onClicked: LauncherModel.setProgress(LauncherModel.get(parseInt(appIdEntryBar.displayText)).appId, 35)
1753+ Layout.fillWidth: true
1754+ }
1755+
1756+ TextArea {
1757+ id: appIdEntryBar
1758+ anchors.verticalCenter: parent.verticalCenter
1759+ width: units.gu(4)
1760+ height: units.gu(4)
1761+ autoSize: true
1762+ text: "2"
1763+ maximumLineCount: 1
1764+ }
1765+
1766+ Button {
1767+ text: "no bar"
1768+ onClicked: LauncherModel.setProgress(LauncherModel.get(parseInt(appIdEntryBar.displayText)).appId, -1)
1769+ Layout.fillWidth: true
1770+ }
1771+ }
1772+
1773+ Row {
1774+ spacing: units.gu(1)
1775+
1776+ Button {
1777+ text: "set alert"
1778+ onClicked: LauncherModel.setAlerting(LauncherModel.get(parseInt(appIdEntryAlert.displayText)).appId, true)
1779+ }
1780+
1781+ TextArea {
1782+ id: appIdEntryAlert
1783+ anchors.verticalCenter: parent.verticalCenter
1784+ width: units.gu(5)
1785+ height: units.gu(4)
1786+ autoSize: true
1787+ text: "2"
1788+ maximumLineCount: 1
1789+ Layout.fillWidth: true
1790+ }
1791+
1792+ Button {
1793+ text: "unset alert"
1794+ onClicked: LauncherModel.setAlerting(LauncherModel.get(parseInt(appIdEntryAlert.displayText)).appId, false)
1795+ }
1796+ }
1797 }
1798
1799 SignalSpy {
1800@@ -146,7 +197,7 @@
1801 startX+units.gu(8), startY);
1802
1803 var panel = findChild(launcher, "launcherPanel");
1804- verify(panel != undefined);
1805+ verify(!!panel);
1806
1807 // wait until it gets fully extended
1808 tryCompare(panel, "x", 0);
1809@@ -157,7 +208,7 @@
1810 mouseMove(root, 1, root.height / 2);
1811
1812 var panel = findChild(launcher, "launcherPanel");
1813- verify(panel != undefined);
1814+ verify(!!panel);
1815
1816 // wait until it gets fully extended
1817 tryCompare(panel, "x", 0);
1818@@ -169,6 +220,16 @@
1819 tryCompare(panel, "x", -panel.width, 1000);
1820 }
1821
1822+ function waitForWiggleToStart(appIcon) {
1823+ verify(appIcon != undefined)
1824+ tryCompare(appIcon, "wiggling", true, 1000, "wiggle-anim should not be in stopped state")
1825+ }
1826+
1827+ function waitForWiggleToStop(appIcon) {
1828+ verify(appIcon != undefined)
1829+ tryCompare(appIcon, "wiggling", false, 1000, "wiggle-anim should not be in running state")
1830+ }
1831+
1832 function positionLauncherListAtBeginning() {
1833 var listView = testCase.findChild(launcherLoader.item, "launcherListView");
1834 listView.contentY = -listView.topMargin;
1835@@ -187,7 +248,7 @@
1836 waitUntilLauncherDisappears();
1837
1838 var panel = findChild(launcher, "launcherPanel")
1839- verify(panel != undefined)
1840+ verify(!!panel)
1841
1842 // it starts out hidden just left of the left launcher edge
1843 compare(panel.x, -panel.width)
1844@@ -225,7 +286,7 @@
1845
1846 var appIcon = findChild(launcher, "launcherDelegate0");
1847
1848- verify(appIcon != undefined);
1849+ verify(!!appIcon);
1850
1851 if (data.mouse) {
1852 mouseClick(appIcon);
1853@@ -248,7 +309,7 @@
1854 dragLauncherIntoView()
1855
1856 var dashIcon = findChild(launcher, "dashItem")
1857- verify(dashIcon != undefined)
1858+ verify(!!dashIcon)
1859
1860 mouseClick(dashIcon)
1861
1862@@ -538,7 +599,7 @@
1863
1864 // Doing longpress
1865 mousePress(draggedItem);
1866- tryCompare(quickListShape, "opacity", 0.96);
1867+ tryCompare(quickListShape, "opacity", 0.8);
1868 mouseRelease(draggedItem);
1869
1870 verify(quickList.y >= units.gu(1));
1871@@ -623,9 +684,31 @@
1872 tryCompare(quickList, "state", "");
1873 }
1874
1875+ function test_quickListMenuOnRMB() {
1876+ dragLauncherIntoView();
1877+ var clickedItem = findChild(launcher, "launcherDelegate5")
1878+ var quickList = findChild(launcher, "quickList")
1879+ var quickListShape = findChild(launcher, "quickListShape")
1880+ var dndArea = findChild(launcher, "dndArea");
1881+
1882+ // Initial state
1883+ tryCompare(quickListShape, "visible", false)
1884+
1885+ // Doing RMB click
1886+ mouseClick(clickedItem, clickedItem.width / 2, clickedItem.height / 2, Qt.RightButton)
1887+ tryCompare(quickListShape, "visible", true)
1888+ verify(quickList, "state", "open")
1889+ verify(dndArea, "dragging", false)
1890+
1891+ // Click somewhere in the empty space to dismiss the quicklist
1892+ mouseClick(launcher, launcher.width - units.gu(1), units.gu(1));
1893+ tryCompare(quickListShape, "visible", false);
1894+ verify(quickList, "state", "")
1895+ }
1896+
1897 function test_revealByHover() {
1898 var panel = findChild(launcher, "launcherPanel");
1899- verify(panel != undefined);
1900+ verify(!!panel);
1901
1902 revealByHover();
1903 tryCompare(launcher, "state", "visibleTemporary");
1904@@ -636,5 +719,125 @@
1905 tryCompare(launcher, "state", "", 1000, "Launcher didn't hide after moving mouse away from it");
1906 waitUntilLauncherDisappears();
1907 }
1908+
1909+ function test_progressChangeViaModel() {
1910+ dragLauncherIntoView();
1911+ var item = findChild(launcher, "launcherDelegate0")
1912+ verify(item != undefined)
1913+ LauncherModel.setProgress(LauncherModel.get(0).appId, -1)
1914+ compare(findChild(item, "progressOverlay").visible, false)
1915+ LauncherModel.setProgress(LauncherModel.get(0).appId, 20)
1916+ compare(findChild(item, "progressOverlay").visible, true)
1917+ LauncherModel.setProgress(LauncherModel.get(0).appId, 0)
1918+ }
1919+
1920+ function test_alertPeekingIcon() {
1921+ var listView = findChild(launcher, "launcherListView")
1922+ verify(listView != undefined)
1923+ LauncherModel.setAlerting(LauncherModel.get(5).appId, true)
1924+ tryCompare(listView, "peekingIndex", 5, 1000, "Wrong appId set as peeking-index")
1925+ LauncherModel.setAlerting(LauncherModel.get(5).appId, false)
1926+ tryCompare(listView, "peekingIndex", -1, 1000, "peeking-index should be -1")
1927+ }
1928+
1929+ function test_alertHidingIcon() {
1930+ var listView = findChild(launcher, "launcherListView")
1931+ verify(listView != undefined)
1932+ var appIcon6 = findChild(launcher, "launcherDelegate6")
1933+ verify(appIcon6 != undefined)
1934+ LauncherModel.setAlerting(LauncherModel.get(6).appId, true)
1935+ waitForWiggleToStart(appIcon6)
1936+ LauncherModel.setAlerting(LauncherModel.get(6).appId, false)
1937+ waitForWiggleToStop(appIcon6)
1938+ tryCompare(appIcon6, "x", 0, 1000, "x-value of appId #6 should not be non-zero")
1939+ waitForRendering(listView)
1940+ }
1941+
1942+ function test_alertIgnoreFocusedApp() {
1943+ LauncherModel.setAlerting(LauncherModel.get(0).appId, true)
1944+ compare(LauncherModel.get(0).alerting, false, "Focused app should not have the alert-state set")
1945+ }
1946+
1947+ function test_alertOnlyOnePeekingIcon() {
1948+ var listView = findChild(launcher, "launcherListView")
1949+ verify(listView != undefined)
1950+ LauncherModel.setAlerting(LauncherModel.get(3).appId, true)
1951+ LauncherModel.setAlerting(LauncherModel.get(1).appId, true)
1952+ LauncherModel.setAlerting(LauncherModel.get(5).appId, true)
1953+ tryCompare(listView, "peekingIndex", 3, 1000, "Wrong appId set as peeking-index")
1954+ LauncherModel.setAlerting(LauncherModel.get(1).appId, false)
1955+ LauncherModel.setAlerting(LauncherModel.get(3).appId, false)
1956+ LauncherModel.setAlerting(LauncherModel.get(5).appId, false)
1957+ tryCompare(listView, "peekingIndex", -1, 1000, "peeking-index should be -1")
1958+ waitForRendering(listView)
1959+ }
1960+
1961+ function test_alertMultipleApps() {
1962+ LauncherModel.setAlerting(LauncherModel.get(1).appId, true)
1963+ LauncherModel.setAlerting(LauncherModel.get(3).appId, true)
1964+ LauncherModel.setAlerting(LauncherModel.get(5).appId, true)
1965+ LauncherModel.setAlerting(LauncherModel.get(7).appId, true)
1966+ compare(LauncherModel.get(1).alerting, true, "Alert-state of appId #1 should not be false")
1967+ compare(LauncherModel.get(3).alerting, true, "Alert-state of appId #3 should not be false")
1968+ compare(LauncherModel.get(5).alerting, true, "Alert-state of appId #5 should not be false")
1969+ compare(LauncherModel.get(7).alerting, true, "Alert-state of appId #7 should not be false")
1970+ LauncherModel.setAlerting(LauncherModel.get(1).appId, false)
1971+ LauncherModel.setAlerting(LauncherModel.get(3).appId, false)
1972+ LauncherModel.setAlerting(LauncherModel.get(5).appId, false)
1973+ LauncherModel.setAlerting(LauncherModel.get(7).appId, false)
1974+ compare(LauncherModel.get(1).alerting, false, "Alert-state of appId #1 should not be true")
1975+ compare(LauncherModel.get(3).alerting, false, "Alert-state of appId #1 should not be true")
1976+ compare(LauncherModel.get(5).alerting, false, "Alert-state of appId #1 should not be true")
1977+ compare(LauncherModel.get(7).alerting, false, "Alert-state of appId #1 should not be true")
1978+ }
1979+
1980+ function test_alertMoveIconIntoView() {
1981+ dragLauncherIntoView();
1982+ var appIcon1 = findChild(launcher, "launcherDelegate1");
1983+ var appIcon7 = findChild(launcher, "launcherDelegate7");
1984+ LauncherModel.setAlerting(LauncherModel.get(1).appId, true)
1985+ tryCompare(appIcon1, "angle", 0, 1000, "angle of appId #1 should not be non-zero")
1986+ waitForWiggleToStart(appIcon1)
1987+ LauncherModel.setAlerting(LauncherModel.get(7).appId, true)
1988+ tryCompare(appIcon7, "angle", 0, 1000, "angle of appId #7 should not be non-zero")
1989+ waitForWiggleToStart(appIcon7)
1990+ LauncherModel.setAlerting(LauncherModel.get(1).appId, false)
1991+ waitForWiggleToStop(appIcon1)
1992+ LauncherModel.setAlerting(LauncherModel.get(7).appId, false)
1993+ waitForWiggleToStop(appIcon7)
1994+ }
1995+
1996+ function test_alertWigglePeekDrag() {
1997+ var appIcon5 = findChild(launcher, "launcherDelegate5");
1998+ var listView = findChild(launcher, "launcherListView")
1999+ verify(listView != undefined)
2000+ LauncherModel.setAlerting(LauncherModel.get(5).appId, true)
2001+ tryCompare(listView, "peekingIndex", 5, 1000, "Wrong appId set as peeking-index")
2002+ waitForWiggleToStart(appIcon5)
2003+ tryCompare(appIcon5, "wiggling", true, 1000, "appId #6 should not be still")
2004+ dragLauncherIntoView();
2005+ tryCompare(listView, "peekingIndex", -1, 1000, "peeking-index should be -1")
2006+ LauncherModel.setAlerting(LauncherModel.get(5).appId, false)
2007+ waitForWiggleToStop(appIcon5)
2008+ tryCompare(appIcon5, "wiggling", false, 1000, "appId #1 should not be wiggling")
2009+ }
2010+
2011+ function test_alertViaCountAndCountVisible() {
2012+ dragLauncherIntoView();
2013+ var appIcon1 = findChild(launcher, "launcherDelegate1")
2014+ var oldCount = LauncherModel.get(1).count
2015+ LauncherModel.setCount(LauncherModel.get(1).appId, 42)
2016+ tryCompare(appIcon1, "wiggling", false, 1000, "appId #1 should be still")
2017+ LauncherModel.setCountVisible(LauncherModel.get(1).appId, 1)
2018+ tryCompare(appIcon1, "wiggling", true, 1000, "appId #1 should not be still")
2019+ LauncherModel.setAlerting(LauncherModel.get(1).appId, false)
2020+ waitForWiggleToStop(appIcon1)
2021+ LauncherModel.setCount(LauncherModel.get(1).appId, 4711)
2022+ tryCompare(appIcon1, "wiggling", true, 1000, "appId #1 should not be still")
2023+ LauncherModel.setAlerting(LauncherModel.get(1).appId, false)
2024+ waitForWiggleToStop(appIcon1)
2025+ LauncherModel.setCountVisible(LauncherModel.get(1).appId, 0)
2026+ LauncherModel.setCount(LauncherModel.get(1).appId, oldCount)
2027+ }
2028 }
2029 }
2030
2031=== added directory 'tests/scripts'
2032=== added file 'tests/scripts/README'
2033--- tests/scripts/README 1970-01-01 00:00:00 +0000
2034+++ tests/scripts/README 2015-07-23 14:15:26 +0000
2035@@ -0,0 +1,9 @@
2036+This directory holds a few handy shell-scripts to simplify runtime-testing of DBus-APIs (requires qdbus-qt5 to be installed).
2037+
2038+launcher-icon related:
2039+ * list-launcher-icons.sh - get all icons of unity8-launcher
2040+ * alert-launcher-icon.sh - trigger alert/wiggle of unfocused launcher-icon
2041+ * get-progress.sh - get progress-value of a launcher-icon
2042+ * set-progress.sh - set progress-value of a launcher-icon
2043+ * set-count.sh - set the count of a launcher-icon
2044+ * set-count-visible.sh - set the count-visible flag of a launcher-icon
2045
2046=== added file 'tests/scripts/alert-launcher-icon.sh'
2047--- tests/scripts/alert-launcher-icon.sh 1970-01-01 00:00:00 +0000
2048+++ tests/scripts/alert-launcher-icon.sh 2015-07-23 14:15:26 +0000
2049@@ -0,0 +1,3 @@
2050+#!/bin/sh
2051+
2052+qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 com.canonical.Unity.Launcher.Item.Alert
2053
2054=== added file 'tests/scripts/get-progress.sh'
2055--- tests/scripts/get-progress.sh 1970-01-01 00:00:00 +0000
2056+++ tests/scripts/get-progress.sh 2015-07-23 14:15:26 +0000
2057@@ -0,0 +1,3 @@
2058+#!/bin/sh
2059+
2060+qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Get com.canonical.Unity.Launcher.Item progress
2061
2062=== added file 'tests/scripts/list-launcher-icons.sh'
2063--- tests/scripts/list-launcher-icons.sh 1970-01-01 00:00:00 +0000
2064+++ tests/scripts/list-launcher-icons.sh 2015-07-23 14:15:26 +0000
2065@@ -0,0 +1,3 @@
2066+#!/bin/sh
2067+
2068+qdbus com.canonical.Unity | grep Launcher | cut -f6 -d/
2069
2070=== added file 'tests/scripts/set-count-visible.sh'
2071--- tests/scripts/set-count-visible.sh 1970-01-01 00:00:00 +0000
2072+++ tests/scripts/set-count-visible.sh 2015-07-23 14:15:26 +0000
2073@@ -0,0 +1,3 @@
2074+#!/bin/sh
2075+
2076+qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Set com.canonical.Unity.Launcher.Item countVisible $2
2077
2078=== added file 'tests/scripts/set-count.sh'
2079--- tests/scripts/set-count.sh 1970-01-01 00:00:00 +0000
2080+++ tests/scripts/set-count.sh 2015-07-23 14:15:26 +0000
2081@@ -0,0 +1,3 @@
2082+#!/bin/sh
2083+
2084+qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Set com.canonical.Unity.Launcher.Item count $2
2085
2086=== added file 'tests/scripts/set-progress.sh'
2087--- tests/scripts/set-progress.sh 1970-01-01 00:00:00 +0000
2088+++ tests/scripts/set-progress.sh 2015-07-23 14:15:26 +0000
2089@@ -0,0 +1,3 @@
2090+#!/bin/sh
2091+
2092+qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 org.freedesktop.DBus.Properties.Set com.canonical.Unity.Launcher.Item progress $2

Subscribers

People subscribed via source and target branches