Merge lp:~lukas-kde/unity8/closeAppsFromQuicklist into lp:unity8
- closeAppsFromQuicklist
- Merge into trunk
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 | ||||
Related bugs: |
|
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
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
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.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
In qml/Launcher/
"""
- __foregroundColor: "black"
+ __foregroundColor: Theme.palette.
"""
"Theme" is deprecated. Please use the context variable "theme" instead. We have tons of warnings on this already. See https:/
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.
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: launchermodelte
> 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).
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1811
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
Some inline comments.
Lukáš Tinkl (lukas-kde) wrote : | # |
> Some inline comments.
Should be fixed by r. 1812
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1813
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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.
Lukáš Tinkl (lukas-kde) wrote : | # |
Ack, will fix
Michael Zanetti (mzanetti) wrote : | # |
http://
Font is white on white, also I'm missing the close entry.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1814
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1815
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1823
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Text conflict in qml/Launcher/
1 conflicts encountered.
- 1824. By Lukáš Tinkl
-
merge and fix conflict
Albert Astals Cid (aacid) : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1824
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
Looks ok and works, except the dbusinterface changes are not needed. Please drop them.
- 1825. By Lukáš Tinkl
-
drop dbusinterface changes
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1825
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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
- 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
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' |
1298 | Binary 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' |
1311 | Binary 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 |
PASSED: Continuous integration, rev:1810 jenkins. qa.ubuntu. com/job/ unity8- ci/5803/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- wily-touch/ 94 jenkins. qa.ubuntu. com/job/ unity8- wily-amd64- ci/81 jenkins. qa.ubuntu. com/job/ unity8- wily-i386- ci/81 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- wily-mako/ 72 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- wily-armhf/ 94 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- wily-armhf/ 94/artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 21099
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/5803/ rebuild
http://