Merge lp:~dandrader/unity/phablet_close_apps_from_dash into lp:unity/phablet
- phablet_close_apps_from_dash
- Merge into phablet
Status: | Merged |
---|---|
Approved by: | Daniel d'Andrada |
Approved revision: | no longer in the source branch. |
Merged at revision: | 619 |
Proposed branch: | lp:~dandrader/unity/phablet_close_apps_from_dash |
Merge into: | lp:unity/phablet |
Diff against target: |
654 lines (+458/-11) 13 files modified
Components/ApplicationManagerWrapper.qml (+4/-0) Components/ResponsiveFlowView.qml (+1/-0) Dash/Apps/CloseIcon.qml (+62/-0) Dash/Apps/RunningApplicationTile.qml (+41/-3) Dash/Apps/RunningApplicationsGrid.qml (+30/-1) Dash/DashApps.qml (+15/-0) tests/mocks/Ubuntu/Application/ApplicationListModel.cpp (+62/-0) tests/mocks/Ubuntu/Application/ApplicationListModel.h (+16/-4) tests/mocks/Ubuntu/Application/ApplicationManager.cpp (+19/-0) tests/mocks/Ubuntu/Application/ApplicationManager.h (+1/-1) tests/mocks/Ubuntu/Application/plugin.cpp (+1/-2) tests/qmltests/CMakeLists.txt (+1/-0) tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml (+205/-0) |
To merge this branch: | bzr merge lp:~dandrader/unity/phablet_close_apps_from_dash |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Albert Astals Cid (community) | Approve | ||
Review via email: mp+159845@code.launchpad.net |
Commit message
Close applications using their thumbnails on the Dash
Long-press on a application thumbnail to bring up the close mode
(close icon decorations will pop up). Then tap on the thumbnail
of the application you want to close to close it.
You can dismiss the close/termination mode in two ways:
1 - by long-pressing one of the app thumbnails
2 - by sliding horizontally to another dash.
As there's no design for this feature yet I didn't to go any further/deeper
on it.
Description of the change
Close applications using their thumbnails on the Dash
Long-press on a application thumbnail to bring up the close mode (close icon decorations will pop up). Then tap on the thumbnail of the application you want to close to close it.
You can dismiss the close/termination mode in two ways:
1 - by long-pressing one of the app thumbnails
2 - by sliding horizontally to another dash.
As there's no design for this feature yet I didn't to go any further/deeper on it.
PS Jenkins bot (ps-jenkins) wrote : | # |
Albert Astals Cid (aacid) wrote : | # |
As discussed in IRC it'd be good to have a way to remove the 800 and make sure that the termination properties are disabled until the pressAndHold signal is triggered, suggested to use a signalspy and the tryCompareFunction thing
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:618
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:619
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Dash/Apps/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:620
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Text conflict in tests/qmltests/
Daniel d'Andrada (dandrader) wrote : | # |
All fixed.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:627
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'Components/ApplicationManagerWrapper.qml' |
2 | --- Components/ApplicationManagerWrapper.qml 2013-04-09 12:03:53 +0000 |
3 | +++ Components/ApplicationManagerWrapper.qml 2013-04-22 15:40:50 +0000 |
4 | @@ -54,6 +54,10 @@ |
5 | } |
6 | } |
7 | |
8 | + function stopProcess(application) { |
9 | + ApplicationManager.stopProcess(application) |
10 | + } |
11 | + |
12 | function focusApplication(application) { |
13 | if (application == null || application == undefined) { |
14 | return; |
15 | |
16 | === modified file 'Components/ResponsiveFlowView.qml' |
17 | --- Components/ResponsiveFlowView.qml 2013-04-09 15:52:21 +0000 |
18 | +++ Components/ResponsiveFlowView.qml 2013-04-22 15:40:50 +0000 |
19 | @@ -32,6 +32,7 @@ |
20 | property alias delegate: repeater1.delegate |
21 | readonly property int cellWidth: referenceDelegateWidth + horizontalSpacing |
22 | readonly property int cellHeight: referenceDelegateWidth + verticalSpacing |
23 | + property alias move: flow.move |
24 | |
25 | height: flow.height + flow.anchors.topMargin |
26 | |
27 | |
28 | === added file 'Dash/Apps/CloseIcon.qml' |
29 | --- Dash/Apps/CloseIcon.qml 1970-01-01 00:00:00 +0000 |
30 | +++ Dash/Apps/CloseIcon.qml 2013-04-22 15:40:50 +0000 |
31 | @@ -0,0 +1,62 @@ |
32 | +/* |
33 | + * Copyright (C) 2013 Canonical, Ltd. |
34 | + * |
35 | + * This program is free software; you can redistribute it and/or modify |
36 | + * it under the terms of the GNU General Public License as published by |
37 | + * the Free Software Foundation; version 3. |
38 | + * |
39 | + * This program is distributed in the hope that it will be useful, |
40 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
41 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
42 | + * GNU General Public License for more details. |
43 | + * |
44 | + * You should have received a copy of the GNU General Public License |
45 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
46 | + */ |
47 | + |
48 | +import QtQuick 2.0 |
49 | + |
50 | +Item { |
51 | + id: root |
52 | + |
53 | + Image { |
54 | + id: closeIcon |
55 | + anchors.centerIn: parent |
56 | + source: "graphics/close_btn.png" |
57 | + |
58 | + state: (root.enabled) ? "shown" : "hidden" |
59 | + |
60 | + states: [ |
61 | + State { |
62 | + name: "shown" |
63 | + PropertyChanges { |
64 | + target: closeIcon |
65 | + height: root.height |
66 | + width: root.width |
67 | + } |
68 | + }, |
69 | + State { |
70 | + name: "hidden" |
71 | + PropertyChanges { |
72 | + target: closeIcon |
73 | + height: 0 |
74 | + width: 0 |
75 | + } |
76 | + } |
77 | + |
78 | + ] |
79 | + transitions: [ |
80 | + Transition { |
81 | + to: "shown" |
82 | + NumberAnimation { |
83 | + properties: "width, height"; duration: 300 |
84 | + easing { type: Easing.OutBack; overshoot: 5 } |
85 | + } |
86 | + }, |
87 | + Transition { |
88 | + to: "hidden" |
89 | + NumberAnimation { properties: "width, height"; duration: 250; } |
90 | + } |
91 | + ] |
92 | + } |
93 | +} |
94 | |
95 | === modified file 'Dash/Apps/RunningApplicationTile.qml' |
96 | --- Dash/Apps/RunningApplicationTile.qml 2013-02-26 13:51:48 +0000 |
97 | +++ Dash/Apps/RunningApplicationTile.qml 2013-04-22 15:40:50 +0000 |
98 | @@ -26,11 +26,32 @@ |
99 | property var application |
100 | property bool __sideStageEnabled: shell.applicationManager.sideStageEnabled |
101 | |
102 | - height: childrenRect.height |
103 | + signal requestedApplicationActivation(var application) |
104 | + signal requestedApplicationTermination(var application) |
105 | + signal requestedActivationMode() |
106 | + signal requestedTerminationMode() |
107 | + |
108 | + // Was: childrenRect.height |
109 | + // To avoid "binding loop" warning |
110 | + height: shapedApplicationImage.height + labelContainer.height |
111 | + |
112 | width: shapedApplicationImage.width |
113 | |
114 | + property bool terminationModeEnabled: false |
115 | + |
116 | onClicked: { |
117 | - shell.activateApplication(application.desktopFile) |
118 | + if (terminationModeEnabled) |
119 | + requestedApplicationTermination(application) |
120 | + else |
121 | + requestedApplicationActivation(application) |
122 | + } |
123 | + |
124 | + onPressAndHold: { |
125 | + if (terminationModeEnabled) { |
126 | + requestedActivationMode() |
127 | + } else { |
128 | + requestedTerminationMode() |
129 | + } |
130 | } |
131 | |
132 | function updateScreenshotFromCache() { |
133 | @@ -44,7 +65,11 @@ |
134 | top: parent.top |
135 | horizontalCenter: parent.horizontalCenter |
136 | } |
137 | - width: (application.stage === ApplicationsModel.MainStage && __sideStageEnabled) ? units.gu(22) : units.gu(11) |
138 | + |
139 | + // FIXME: width and height should be defined according to the |
140 | + // application window's aspect ratio. |
141 | + width: (application.stage === ApplicationsModel.MainStage && __sideStageEnabled) ? |
142 | + units.gu(22) : units.gu(11) |
143 | height: (__sideStageEnabled) ? units.gu(22) : units.gu(19) |
144 | radius: "medium" |
145 | image: applicationImage |
146 | @@ -98,4 +123,17 @@ |
147 | horizontalAlignment: Text.AlignHCenter |
148 | } |
149 | } |
150 | + |
151 | + CloseIcon { |
152 | + anchors { |
153 | + right: shapedApplicationImage.right |
154 | + rightMargin: -units.gu(1) |
155 | + top: parent.top |
156 | + topMargin: -units.gu(1) |
157 | + } |
158 | + height: units.gu(6) |
159 | + width: units.gu(6) |
160 | + id: closeIcon |
161 | + enabled: root.terminationModeEnabled |
162 | + } |
163 | } |
164 | |
165 | === modified file 'Dash/Apps/RunningApplicationsGrid.qml' |
166 | --- Dash/Apps/RunningApplicationsGrid.qml 2013-04-18 13:04:23 +0000 |
167 | +++ Dash/Apps/RunningApplicationsGrid.qml 2013-04-22 15:40:50 +0000 |
168 | @@ -30,6 +30,16 @@ |
169 | |
170 | Behavior on height { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } |
171 | |
172 | + property bool canEnableTerminationMode: true |
173 | + |
174 | + onCanEnableTerminationModeChanged: { |
175 | + if (!canEnableTerminationMode) |
176 | + terminationModeEnabled = false |
177 | + } |
178 | + |
179 | + // when false, it means it's on activation mode |
180 | + property bool terminationModeEnabled: false |
181 | + |
182 | maximumNumberOfColumns: 10 |
183 | minimumHorizontalSpacing: units.gu(2) |
184 | referenceDelegateWidth: units.gu(11) |
185 | @@ -41,15 +51,34 @@ |
186 | |
187 | RunningApplicationTile { |
188 | id: runningAppTile |
189 | + objectName: "runningAppTile " + model.application.name |
190 | anchors { |
191 | top: parent.top |
192 | horizontalCenter: parent.horizontalCenter |
193 | } |
194 | application: model.application |
195 | + onRequestedActivationMode: { root.terminationModeEnabled = false } |
196 | + onRequestedTerminationMode: { |
197 | + if (canEnableTerminationMode) |
198 | + root.terminationModeEnabled = true |
199 | + } |
200 | + onRequestedApplicationTermination: { |
201 | + shell.applicationManager.stopProcess(application) |
202 | + } |
203 | + onRequestedApplicationActivation: { |
204 | + shell.activateApplication(application.desktopFile) |
205 | + } |
206 | + |
207 | + terminationModeEnabled: root.terminationModeEnabled |
208 | + |
209 | Component.onCompleted: { |
210 | root.updateScreenshots.connect(updateScreenshotFromCache); |
211 | } |
212 | - //FIXME: add animation on item removal |
213 | } |
214 | } |
215 | + |
216 | + move: Transition { |
217 | + NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutCubic } |
218 | + } |
219 | } |
220 | + |
221 | |
222 | === added directory 'Dash/Apps/graphics' |
223 | === added file 'Dash/Apps/graphics/close_btn@9.png' |
224 | Binary files Dash/Apps/graphics/close_btn@9.png 1970-01-01 00:00:00 +0000 and Dash/Apps/graphics/close_btn@9.png 2013-04-22 15:40:50 +0000 differ |
225 | === modified file 'Dash/DashApps.qml' |
226 | --- Dash/DashApps.qml 2013-04-19 16:50:39 +0000 |
227 | +++ Dash/DashApps.qml 2013-04-22 15:40:50 +0000 |
228 | @@ -129,12 +129,27 @@ |
229 | if (modelName == "RunningApplicationsModel") { |
230 | item.firstModel = mainStageApplicationsModel |
231 | item.secondModel = sideStageApplicationModel |
232 | + item.canEnableTerminationMode = |
233 | + Qt.binding(function() { return isCurrent; }) |
234 | } else { |
235 | item.model = categoryModels[modelName] |
236 | } |
237 | } |
238 | asynchronous: true |
239 | } |
240 | + |
241 | + ListView.onRemove: SequentialAnimation { |
242 | + PropertyAction { |
243 | + target: container; property: "ListView.delayRemove"; value: true |
244 | + } |
245 | + NumberAnimation { |
246 | + target: container; property: "height"; to: 0; |
247 | + duration: 250; easing.type: Easing.InOutQuad |
248 | + } |
249 | + PropertyAction { |
250 | + target: container; property: "ListView.delayRemove"; value: false |
251 | + } |
252 | + } |
253 | } |
254 | |
255 | sectionProperty: "category" |
256 | |
257 | === modified file 'tests/mocks/Ubuntu/Application/ApplicationListModel.cpp' |
258 | --- tests/mocks/Ubuntu/Application/ApplicationListModel.cpp 2013-04-18 12:47:12 +0000 |
259 | +++ tests/mocks/Ubuntu/Application/ApplicationListModel.cpp 2013-04-22 15:40:50 +0000 |
260 | @@ -80,3 +80,65 @@ |
261 | Q_EMIT countChanged(); |
262 | } |
263 | } |
264 | + |
265 | +bool ApplicationListModel::contains(Application* application) const { |
266 | + return m_applications.contains(application); |
267 | +} |
268 | + |
269 | +void ApplicationListModel::clear() |
270 | +{ |
271 | + beginRemoveRows(QModelIndex(), 0, m_applications.size()-1); |
272 | + m_applications.clear(); |
273 | + endRemoveRows(); |
274 | + Q_EMIT countChanged(); |
275 | +} |
276 | + |
277 | +QQmlListProperty<Application> ApplicationListModel::applications() |
278 | +{ |
279 | + return QQmlListProperty<Application>(this, 0, |
280 | + &ApplicationListModel::appendApplication, |
281 | + &ApplicationListModel::countApplications, |
282 | + &ApplicationListModel::atApplication, |
283 | + &ApplicationListModel::clearApplications); |
284 | +} |
285 | + |
286 | +void ApplicationListModel::appendApplication(QQmlListProperty<Application> *list, |
287 | + Application *application) |
288 | +{ |
289 | + ApplicationListModel *self = qobject_cast<ApplicationListModel *>(list->object); |
290 | + if (self) { |
291 | + application->setParent(self); |
292 | + self->add(application); |
293 | + } |
294 | +} |
295 | + |
296 | +int ApplicationListModel::countApplications(QQmlListProperty<Application> *list) |
297 | +{ |
298 | + ApplicationListModel *self = qobject_cast<ApplicationListModel *>(list->object); |
299 | + if (self) { |
300 | + return self->m_applications.size(); |
301 | + } else { |
302 | + return 0; |
303 | + } |
304 | +} |
305 | + |
306 | +Application* ApplicationListModel::atApplication(QQmlListProperty<Application> *list, |
307 | + int index) |
308 | +{ |
309 | + ApplicationListModel *self = qobject_cast<ApplicationListModel *>(list->object); |
310 | + if (!self) { return 0; } |
311 | + |
312 | + if (index >= 0 && index < self->m_applications.size()) { |
313 | + return self->m_applications.at(index); |
314 | + } else { |
315 | + return 0; |
316 | + } |
317 | +} |
318 | + |
319 | +void ApplicationListModel::clearApplications(QQmlListProperty<Application> *list) |
320 | +{ |
321 | + ApplicationListModel *self = qobject_cast<ApplicationListModel *>(list->object); |
322 | + if (self) { |
323 | + self->clear(); |
324 | + } |
325 | +} |
326 | |
327 | === modified file 'tests/mocks/Ubuntu/Application/ApplicationListModel.h' |
328 | --- tests/mocks/Ubuntu/Application/ApplicationListModel.h 2013-04-18 12:47:12 +0000 |
329 | +++ tests/mocks/Ubuntu/Application/ApplicationListModel.h 2013-04-22 15:40:50 +0000 |
330 | @@ -18,14 +18,17 @@ |
331 | #define APPLICATION_LIST_MODEL_H |
332 | |
333 | #include <QAbstractListModel> |
334 | +#include <QQmlListProperty> |
335 | +#include "Application.h" |
336 | |
337 | -class Application; |
338 | class ApplicationManager; |
339 | |
340 | class ApplicationListModel : public QAbstractListModel { |
341 | Q_OBJECT |
342 | |
343 | Q_PROPERTY(int count READ rowCount NOTIFY countChanged) |
344 | + Q_PROPERTY(QQmlListProperty<Application> applications READ applications) |
345 | + Q_CLASSINFO("DefaultProperty", "applications") |
346 | |
347 | public: |
348 | explicit ApplicationListModel(QObject* parent = 0); |
349 | @@ -38,15 +41,24 @@ |
350 | Q_INVOKABLE QVariant get(int index) const; |
351 | Q_INVOKABLE void move(int from, int to); |
352 | |
353 | + QQmlListProperty<Application> applications(); |
354 | + |
355 | + Q_INVOKABLE void add(Application* application); |
356 | + Q_INVOKABLE void remove(Application* application); |
357 | + Q_INVOKABLE bool contains(Application* application) const; |
358 | + Q_INVOKABLE void clear(); |
359 | + |
360 | Q_SIGNALS: |
361 | void countChanged(); |
362 | |
363 | private: |
364 | Q_DISABLE_COPY(ApplicationListModel) |
365 | |
366 | - void add(Application* application); |
367 | - void remove(Application* application); |
368 | - bool contains(Application* application) const { return m_applications.contains(application); } |
369 | + static void appendApplication(QQmlListProperty<Application> *list, |
370 | + Application *application); |
371 | + static int countApplications(QQmlListProperty<Application> *list); |
372 | + static Application* atApplication(QQmlListProperty<Application> *list, int index); |
373 | + static void clearApplications(QQmlListProperty<Application> *list); |
374 | |
375 | QHash<int,QByteArray> m_roleNames; |
376 | QList<Application*> m_applications; |
377 | |
378 | === modified file 'tests/mocks/Ubuntu/Application/ApplicationManager.cpp' |
379 | --- tests/mocks/Ubuntu/Application/ApplicationManager.cpp 2013-04-18 13:06:18 +0000 |
380 | +++ tests/mocks/Ubuntu/Application/ApplicationManager.cpp 2013-04-22 15:40:50 +0000 |
381 | @@ -120,6 +120,25 @@ |
382 | return application; |
383 | } |
384 | |
385 | +void ApplicationManager::stopProcess(Application* application) |
386 | +{ |
387 | + if (m_mainStageApplications->contains(application)) { |
388 | + m_mainStageApplications->remove(application); |
389 | + |
390 | + if (m_mainStageFocusedApplication == application) { |
391 | + m_mainStageFocusedApplication = 0; |
392 | + Q_EMIT mainStageFocusedApplicationChanged(); |
393 | + } |
394 | + } else if (m_sideStageApplications->contains(application)){ |
395 | + m_sideStageApplications->remove(application); |
396 | + |
397 | + if (m_sideStageFocusedApplication == application) { |
398 | + m_sideStageFocusedApplication = 0; |
399 | + Q_EMIT sideStageFocusedApplicationChanged(); |
400 | + } |
401 | + } |
402 | +} |
403 | + |
404 | void ApplicationManager::focusApplication(int handle) |
405 | { |
406 | for (int i = 0; i < m_mainStageApplications->m_applications.count(); ++i) { |
407 | |
408 | === modified file 'tests/mocks/Ubuntu/Application/ApplicationManager.h' |
409 | --- tests/mocks/Ubuntu/Application/ApplicationManager.h 2013-04-18 13:06:18 +0000 |
410 | +++ tests/mocks/Ubuntu/Application/ApplicationManager.h 2013-04-22 15:40:50 +0000 |
411 | @@ -85,7 +85,7 @@ |
412 | Q_INVOKABLE Application* startProcess(QString desktopFile, |
413 | ExecFlags flags, |
414 | QStringList arguments = QStringList()); |
415 | - Q_INVOKABLE void stopProcess(Application* /*application*/) {} |
416 | + Q_INVOKABLE void stopProcess(Application* application); |
417 | Q_INVOKABLE void startWatcher() {} |
418 | |
419 | Q_SIGNALS: |
420 | |
421 | === modified file 'tests/mocks/Ubuntu/Application/plugin.cpp' |
422 | --- tests/mocks/Ubuntu/Application/plugin.cpp 2013-04-12 14:41:56 +0000 |
423 | +++ tests/mocks/Ubuntu/Application/plugin.cpp 2013-04-22 15:40:50 +0000 |
424 | @@ -34,6 +34,5 @@ |
425 | uri, 0, 1, "ApplicationManager", applicationManagerSingleton); |
426 | qmlRegisterType<Application>(uri, 0, 1, "Application"); |
427 | qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage"); |
428 | - qmlRegisterUncreatableType<ApplicationListModel>( |
429 | - uri, 0, 1, "ApplicationListModel", "ApplicationListModel can't be instantiated"); |
430 | + qmlRegisterType<ApplicationListModel>(uri, 0, 1, "ApplicationListModel"); |
431 | } |
432 | |
433 | === modified file 'tests/qmltests/CMakeLists.txt' |
434 | --- tests/qmltests/CMakeLists.txt 2013-04-22 09:57:23 +0000 |
435 | +++ tests/qmltests/CMakeLists.txt 2013-04-22 15:40:50 +0000 |
436 | @@ -44,6 +44,7 @@ |
437 | add_qml_test(Dash DashPreview) |
438 | add_qml_test(Dash PeoplePreview) |
439 | add_qml_test(Dash FilterGrids IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_SOURCE_DIR}/plugins) |
440 | +add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks) |
441 | add_qml_test(Greeter Greeter) |
442 | add_qml_test(Hud Hud) |
443 | add_qml_test(Launcher Launcher) |
444 | |
445 | === added directory 'tests/qmltests/Dash/Apps' |
446 | === added file 'tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml' |
447 | --- tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml 1970-01-01 00:00:00 +0000 |
448 | +++ tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml 2013-04-22 15:40:50 +0000 |
449 | @@ -0,0 +1,205 @@ |
450 | +/* |
451 | + * Copyright 2013 Canonical Ltd. |
452 | + * |
453 | + * This program is free software; you can redistribute it and/or modify |
454 | + * it under the terms of the GNU General Public License as published by |
455 | + * the Free Software Foundation; version 3. |
456 | + * |
457 | + * This program is distributed in the hope that it will be useful, |
458 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
459 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
460 | + * GNU General Public License for more details. |
461 | + * |
462 | + * You should have received a copy of the GNU General Public License |
463 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
464 | + */ |
465 | + |
466 | +import QtQuick 2.0 |
467 | +import QtTest 1.0 |
468 | +import Ubuntu.Application 0.1 |
469 | +import "../../../../Dash/Apps" |
470 | +import "../../../../Applications/applications.js" as ApplicationsModel |
471 | +import Unity.Test 0.1 as UT |
472 | + |
473 | +Item { |
474 | + width: units.gu(50) |
475 | + height: units.gu(40) |
476 | + |
477 | + QtObject { |
478 | + id: fakeApplicationManager |
479 | + |
480 | + property bool sideStageEnabled: false |
481 | + |
482 | + function stopProcess(application) { |
483 | + fakeRunningAppsModel.remove(application) |
484 | + } |
485 | + } |
486 | + |
487 | + QtObject { |
488 | + id: shell |
489 | + property bool dashShown: true |
490 | + property bool stageScreenshotsReady: false |
491 | + property var applicationManager: fakeApplicationManager |
492 | + |
493 | + function activateApplication(desktopFile) { |
494 | + } |
495 | + } |
496 | + |
497 | + ApplicationListModel { id: fakeRunningAppsModel } |
498 | + |
499 | + Application { |
500 | + id: phoneApp |
501 | + name: "Phone" |
502 | + icon: "phone-app" |
503 | + exec: "/usr/bin/phone-app" |
504 | + stage: ApplicationsModel.MainStage |
505 | + desktopFile: "phone.desktop" |
506 | + imageQml: "import QtQuick 2.0\n" + |
507 | + "Rectangle { \n" + |
508 | + " anchors.fill:parent \n" + |
509 | + " color:'darkgreen' \n" + |
510 | + " Text { anchors.centerIn: parent; text: 'PHONE' } \n" + |
511 | + "}" |
512 | + } |
513 | + |
514 | + Application { |
515 | + id: calendarApp |
516 | + name: "Calendar" |
517 | + icon: "calendar-app" |
518 | + exec: "/usr/bin/calendar-app" |
519 | + stage: ApplicationsModel.MainStage |
520 | + desktopFile: "calendar.desktop" |
521 | + imageQml: "import QtQuick 2.0\n" + |
522 | + "Rectangle { \n" + |
523 | + " anchors.fill:parent \n" + |
524 | + " color:'darkblue' \n" + |
525 | + " Text { anchors.centerIn: parent; text: 'CALENDAR'\n" + |
526 | + " color:'white'} \n" + |
527 | + "}" |
528 | + } |
529 | + |
530 | + function resetRunningApplications() { |
531 | + fakeRunningAppsModel.clear() |
532 | + fakeRunningAppsModel.add(phoneApp) |
533 | + fakeRunningAppsModel.add(calendarApp) |
534 | + } |
535 | + |
536 | + Component.onCompleted: { |
537 | + resetRunningApplications() |
538 | + } |
539 | + |
540 | + // The component under test |
541 | + RunningApplicationsGrid { |
542 | + id: runningApplicationsGrid |
543 | + anchors.fill: parent |
544 | + firstModel: fakeRunningAppsModel |
545 | + } |
546 | + |
547 | + UT.UnityTestCase { |
548 | + name: "RunningApplicationsGrid" |
549 | + when: windowShown |
550 | + |
551 | + function init() { |
552 | + runningApplicationsGrid.terminationModeEnabled = false |
553 | + resetRunningApplications() |
554 | + } |
555 | + |
556 | + property var calendarTile |
557 | + property var phoneTile |
558 | + |
559 | + property var isCalendarLongPressed: false |
560 | + function onCalendarLongPressed() {isCalendarLongPressed = true} |
561 | + |
562 | + property var isPhoneLongPressed: false |
563 | + function onPhoneLongPressed() {isPhoneLongPressed = true} |
564 | + |
565 | + // Tiles should go to termination mode when any one of them is long-pressed. |
566 | + // Long-pressing when they're in termination mode brings them back to activation mode |
567 | + function test_enterTerminationMode() { |
568 | + calendarTile = findChild(runningApplicationsGrid, "runningAppTile Calendar") |
569 | + verify(calendarTile != undefined) |
570 | + calendarTile.onPressAndHold.connect(onCalendarLongPressed) |
571 | + |
572 | + phoneTile = findChild(runningApplicationsGrid, "runningAppTile Phone") |
573 | + verify(phoneTile != undefined) |
574 | + phoneTile.onPressAndHold.connect(onPhoneLongPressed) |
575 | + |
576 | + compare(calendarTile.terminationModeEnabled, false) |
577 | + compare(phoneTile.terminationModeEnabled, false) |
578 | + compare(runningApplicationsGrid.terminationModeEnabled, false) |
579 | + |
580 | + isCalendarLongPressed = false |
581 | + mousePress(calendarTile, calendarTile.width/2, calendarTile.height/2) |
582 | + tryCompareFunction(checkSwitchToTerminationModeAfterLongPress, true) |
583 | + |
584 | + mouseRelease(calendarTile, calendarTile.width/2, calendarTile.height/2) |
585 | + |
586 | + compare(calendarTile.terminationModeEnabled, true) |
587 | + compare(phoneTile.terminationModeEnabled, true) |
588 | + compare(runningApplicationsGrid.terminationModeEnabled, true) |
589 | + |
590 | + isPhoneLongPressed = false |
591 | + mousePress(phoneTile, phoneTile.width/2, phoneTile.height/2) |
592 | + tryCompareFunction(checkSwitchToActivationModeAfterLongPress, true) |
593 | + |
594 | + mouseRelease(phoneTile, phoneTile.width/2, phoneTile.height/2) |
595 | + |
596 | + compare(calendarTile.terminationModeEnabled, false) |
597 | + compare(phoneTile.terminationModeEnabled, false) |
598 | + compare(runningApplicationsGrid.terminationModeEnabled, false) |
599 | + |
600 | + calendarTile.onPressAndHold.disconnect(onCalendarLongPressed) |
601 | + phoneTile.onPressAndHold.disconnect(onPhoneLongPressed) |
602 | + } |
603 | + |
604 | + // Checks that components swicth to termination mode after (and only after) a long |
605 | + // press happens on Calendar tile. |
606 | + function checkSwitchToTerminationModeAfterLongPress() { |
607 | + compare(calendarTile.terminationModeEnabled, isCalendarLongPressed) |
608 | + compare(phoneTile.terminationModeEnabled, isCalendarLongPressed) |
609 | + compare(runningApplicationsGrid.terminationModeEnabled, isCalendarLongPressed) |
610 | + |
611 | + return isCalendarLongPressed && |
612 | + calendarTile.terminationModeEnabled && |
613 | + phoneTile.terminationModeEnabled && |
614 | + runningApplicationsGrid.terminationModeEnabled |
615 | + } |
616 | + |
617 | + // Checks that components swicth to activation mode after (and only after) a long |
618 | + // press happens on Phone tile. |
619 | + function checkSwitchToActivationModeAfterLongPress() { |
620 | + compare(calendarTile.terminationModeEnabled, !isPhoneLongPressed) |
621 | + compare(phoneTile.terminationModeEnabled, !isPhoneLongPressed) |
622 | + compare(runningApplicationsGrid.terminationModeEnabled, !isPhoneLongPressed) |
623 | + |
624 | + return isPhoneLongPressed && |
625 | + !calendarTile.terminationModeEnabled && |
626 | + !phoneTile.terminationModeEnabled && |
627 | + !runningApplicationsGrid.terminationModeEnabled |
628 | + } |
629 | + |
630 | + // While on termination mode, clicking a running application tile causes the |
631 | + // corresponding application to be terminated. |
632 | + function test_clickTileToTerminateApp() { |
633 | + runningApplicationsGrid.terminationModeEnabled = true |
634 | + |
635 | + var calendarTile = findChild(runningApplicationsGrid, "runningAppTile Calendar") |
636 | + verify(calendarTile != undefined) |
637 | + |
638 | + verify(fakeRunningAppsModel.contains(calendarApp)) |
639 | + |
640 | + mouseClick(calendarTile, calendarTile.width/2, calendarTile.height/2) |
641 | + |
642 | + verify(!fakeRunningAppsModel.contains(calendarApp)) |
643 | + |
644 | + // The tile for the Calendar app should eventually vanish since the |
645 | + // application has been terminated |
646 | + tryCompareFunction(checkCalendarTileExists, false) |
647 | + } |
648 | + |
649 | + function checkCalendarTileExists() { |
650 | + return findChild(runningApplicationsGrid, "runningAppTile Calendar") |
651 | + != undefined |
652 | + } |
653 | + } |
654 | +} |
FAILED: Continuous integration, rev:617 jenkins. qa.ubuntu. com/job/ unity-phablet- ci/661/ s-jenkins: 8080/job/ unity-phablet- qmluitests/ 470 jenkins. qa.ubuntu. com/job/ unity-phablet- quantal- armhf-ci/ 663/console jenkins. qa.ubuntu. com/job/ unity-phablet- quantal- i386-ci/ 661/console jenkins. qa.ubuntu. com/job/ unity-phablet- raring- armhf-ci/ 537/console jenkins. qa.ubuntu. com/job/ unity-phablet- raring- i386-ci/ 541/console
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ unity-phablet- ci/661/ rebuild
http://