~unity-team/+junk/dashboard-playground

« back to all changes in this revision

Viewing changes to tests/qmltests/Components/tst_Stage.qml

  • Committer: Michał Sawicz
  • Date: 2013-06-05 22:03:08 UTC
  • Revision ID: michal.sawicz@canonical.com-20130605220308-yny8fv3futtr04fg
Inital unity8 commit.

Previous history can be found at https://code.launchpad.net/~unity-team/unity/phablet

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2013 Canonical Ltd.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; version 3.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 */
 
16
 
 
17
import QtQuick 2.0
 
18
import QtTest 1.0
 
19
import ".."
 
20
import "../../../Components"
 
21
import Ubuntu.Application 0.1
 
22
import Ubuntu.Components 0.1
 
23
import Unity.Test 0.1 as UT
 
24
import "tst_Stage"
 
25
 
 
26
Rectangle {
 
27
    width: units.gu(70)
 
28
    height: stageRect.height
 
29
 
 
30
    // Even though we replace the ApplicationScreenshot instances in Stage
 
31
    // with our own fake ones, ApplicationScreenshot.qml still gives out a warning
 
32
    // if shell.importUbuntuApplicationAvailable is missing.
 
33
    // For we have this here for the sake of keeping a clean log output.
 
34
    Item {
 
35
        id: shell
 
36
        property bool importUbuntuApplicationAvailable: false
 
37
    }
 
38
 
 
39
    // A fake ApplicationManager implementation to be passed to Stage
 
40
    QtObject {
 
41
        id: fakeAppManager
 
42
        property ListModel mainStageApplications: ListModel {}
 
43
        property ListModel sideStageApplications: ListModel {}
 
44
        property var mainStageFocusedApplication
 
45
 
 
46
        property Component fakeAppWindowComponent: Component {
 
47
            Rectangle {
 
48
                width: stage.width
 
49
                height: stage.height
 
50
                property alias text : txt.text
 
51
                Text {id:txt}
 
52
            }
 
53
        }
 
54
 
 
55
        function activateApplication(desktopFile, argument) {
 
56
            var appWindow = fakeAppWindowComponent.createObject(fakeWindowContainer)
 
57
            var application = {
 
58
                'icon': "foo",
 
59
                'handle': desktopFile,
 
60
                'name': "Foo",
 
61
                'fullscreen': false,
 
62
                'desktopFile': desktopFile,
 
63
                'stage': ApplicationInfo.MainStage,
 
64
                'argument': 0,
 
65
                'color': desktopFile,
 
66
                'window': appWindow
 
67
            };
 
68
            appWindow.color = application.color
 
69
            appWindow.text = desktopFile + " actual";
 
70
 
 
71
            mainStageApplications.append(application)
 
72
            updateZOrderOfWindows(mainStageApplications)
 
73
 
 
74
            return application
 
75
        }
 
76
 
 
77
        function focusApplication(application) {
 
78
            mainStageFocusedApplication = application
 
79
        }
 
80
 
 
81
        function getApplicationFromDesktopFile(desktopFile, stageType) {
 
82
            var sideStage = (stage == ApplicationInfo.SideStage);
 
83
            var applications = sideStage ? sideStageApplications
 
84
                                         : mainStageApplications;
 
85
 
 
86
            for (var i = 0; i < applications.count; i++ ) {
 
87
                var application = applications.get(i);
 
88
                if (application.desktopFile === desktopFile) {
 
89
                    return application;
 
90
                }
 
91
            }
 
92
            return null;
 
93
        }
 
94
 
 
95
        function moveRunningApplicationStackPosition(from, to, stage) {
 
96
            var sideStage = (stage == ApplicationInfo.SideStage);
 
97
            var applications = sideStage ? sideStageApplications
 
98
                                         : mainStageApplications;
 
99
 
 
100
            if (from !== to && applications.count > 0 && from >= 0 && to >= 0) {
 
101
                applications.move(from, to, 1);
 
102
            }
 
103
 
 
104
            updateZOrderOfWindows(applications)
 
105
        }
 
106
 
 
107
        function updateZOrderOfWindows(applications) {
 
108
            var nextZ = 100
 
109
            for (var i = 0; i < applications.count; i++ ) {
 
110
                var application = applications.get(i);
 
111
                application.window.z = nextZ--;
 
112
            }
 
113
        }
 
114
 
 
115
        function deacticateApplication(desktopFile) {
 
116
            for (var i = 0; i < mainStageApplications.count; i++ ) {
 
117
                var application = mainStageApplications.get(i)
 
118
                if (application.desktopFile === desktopFile) {
 
119
                    focusApplication(null)
 
120
                    application.window.destroy();
 
121
                    mainStageApplications.remove(i)
 
122
                    updateZOrderOfWindows(mainStageApplications)
 
123
                    return;
 
124
                }
 
125
            }
 
126
        }
 
127
    }
 
128
 
 
129
    Rectangle {
 
130
        id: stageRect
 
131
        x:0
 
132
        y:0
 
133
        width: childrenRect.width
 
134
        height: childrenRect.height
 
135
 
 
136
        color: "grey"
 
137
 
 
138
        // This is where the fake windows are held.
 
139
        // They stay behind the stage, so that the stage's screenshots are shown
 
140
        // on top of them
 
141
        // On a real usage scenario, the current application's surface is composited behind
 
142
        // the shell's surface (where Stage lives). fakeWindowContainer simulates this stacking
 
143
        Item {
 
144
            id: fakeWindowContainer
 
145
            anchors.fill: parent
 
146
        }
 
147
 
 
148
 
 
149
        // A black rectangle behind the stage so that the window switch animations
 
150
        // look good, just like in Stage's real usage.
 
151
        Rectangle {
 
152
            anchors.fill: parent
 
153
            color: "black"
 
154
            visible: stage.usingScreenshots
 
155
        }
 
156
 
 
157
        Stage {
 
158
            id: stage
 
159
            y: 0
 
160
            shouldUseScreenshots: false
 
161
            applicationManager: fakeAppManager
 
162
            rightEdgeDraggingAreaWidth: units.gu(2)
 
163
            fullyShown: true
 
164
            newApplicationScreenshot: FakeApplicationScreenshot {
 
165
                    id: newAppScreenshot
 
166
                    parent: stage
 
167
                    width: stage.width
 
168
                    height: stage.height - stage.y}
 
169
            oldApplicationScreenshot: FakeApplicationScreenshot {
 
170
                    id: oldAppScreenshot
 
171
                    parent: stage
 
172
                    width: stage.width
 
173
                    height: stage.height - stage.y}
 
174
        }
 
175
    }
 
176
 
 
177
    Rectangle {
 
178
        id: controlsRect
 
179
        anchors.top: parent.top
 
180
        anchors.bottom: parent.bottom
 
181
        anchors.left: stageRect.right
 
182
        anchors.right: parent.right
 
183
        color: "lightgrey"
 
184
 
 
185
        Column {
 
186
            id: controls
 
187
            spacing: units.gu(1)
 
188
            AppControl {id: redControl; desktopFile:"red"}
 
189
            AppControl {id: greenControl; desktopFile:"green"}
 
190
            AppControl {id: blueControl; desktopFile:"blue"}
 
191
        }
 
192
    }
 
193
 
 
194
    UT.UnityTestCase {
 
195
        name: "Stage"
 
196
        when: windowShown
 
197
 
 
198
        /* If you press Stage's right edge it should show the hint that it's possible to
 
199
           switch to the next running application. This means (graphically) sliding the
 
200
           next application window from Stage's right edge for a small part of its width */
 
201
        function test_pressingRightEdgeShowsHint() {
 
202
            redControl.checked = true
 
203
 
 
204
            tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
 
205
            tryCompare(stage, "usingScreenshots", false) // and then for it to end
 
206
            compare(fakeAppManager.mainStageFocusedApplication.desktopFile, "red")
 
207
            compare(fakeAppManager.mainStageApplications.get(0).desktopFile, "red")
 
208
 
 
209
            greenControl.checked = true
 
210
 
 
211
            tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
 
212
            tryCompare(stage, "usingScreenshots", false) // and then for it to end
 
213
            compare(fakeAppManager.mainStageFocusedApplication.desktopFile, "green")
 
214
            compare(fakeAppManager.mainStageApplications.get(0).desktopFile, "green")
 
215
 
 
216
            var draggingAreaCenterX = stage.width - (stage.rightEdgeDraggingAreaWidth / 2)
 
217
            var draggingAreaCenterY = stage.height / 2
 
218
            touchPress(stage, draggingAreaCenterX, draggingAreaCenterY)
 
219
 
 
220
            // wait for the animation to start
 
221
            tryCompare(stage, "usingScreenshots", true)
 
222
 
 
223
            // "red" should be the new/next application being shown
 
224
            compare(newAppScreenshot.application.desktopFile, "red")
 
225
            tryCompareFunction(isShowingABitOfNewApp, true);
 
226
 
 
227
            // "green" should be the current application being shown
 
228
            compare(oldAppScreenshot.application.desktopFile, "green")
 
229
            tryCompareFunction(isCurrentAppFadingOut, true);
 
230
 
 
231
            touchRelease(stage, draggingAreaCenterX, draggingAreaCenterY)
 
232
        }
 
233
 
 
234
        function isShowingABitOfNewApp() {
 
235
            // it should come from the right and take less than half of the screen
 
236
            // but at least 5% of it
 
237
            return newAppScreenshot.x > stage.width/2
 
238
                && newAppScreenshot.x < stage.width*(95/100)
 
239
                && newAppScreenshot.y === 0
 
240
                && newAppScreenshot.visible
 
241
        }
 
242
 
 
243
        function isCurrentAppFadingOut() {
 
244
            // it should get a bit translucent and smaller
 
245
            return oldAppScreenshot.opacity < 0.99
 
246
                && oldAppScreenshot.opacity >= 0.1
 
247
                && oldAppScreenshot.scale < 0.99
 
248
                && oldAppScreenshot.scale >= 0.1
 
249
                && oldAppScreenshot.visible
 
250
        }
 
251
 
 
252
        function init() {
 
253
            redControl.checked = false;
 
254
            greenControl.checked = false;
 
255
            blueControl.checked = false;
 
256
            // give some room for animations to start
 
257
            wait(50)
 
258
            // wait until animations end, if any
 
259
            tryCompare(stage, "usingScreenshots", false)
 
260
        }
 
261
 
 
262
        /* If you flick from the right edge of the stage leftwards it should cause an
 
263
           application switch.  */
 
264
        function test_dragFromRightEdgeToSwitchApplication() {
 
265
            redControl.checked = true
 
266
 
 
267
            tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
 
268
            tryCompare(stage, "usingScreenshots", false) // and then for it to end
 
269
            compare(fakeAppManager.mainStageFocusedApplication.desktopFile, "red")
 
270
            compare(fakeAppManager.mainStageApplications.get(0).desktopFile, "red")
 
271
 
 
272
            greenControl.checked = true
 
273
 
 
274
            tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
 
275
            tryCompare(stage, "usingScreenshots", false) // and then for it to end
 
276
            compare(fakeAppManager.mainStageFocusedApplication.desktopFile, "green")
 
277
            compare(fakeAppManager.mainStageApplications.get(0).desktopFile, "green")
 
278
 
 
279
            var touchX = stage.width - (stage.rightEdgeDraggingAreaWidth / 2)
 
280
            var touchY = stage.height / 2
 
281
            touchFlick(stage, touchX, touchY,
 
282
                       touchX - units.gu(5), touchY)
 
283
 
 
284
            // wait until animations end, if any
 
285
            tryCompare(stage, "usingScreenshots", false)
 
286
 
 
287
            // "red" should be the new topmost, focused, application
 
288
            compare(fakeAppManager.mainStageFocusedApplication.desktopFile, "red")
 
289
            compare(fakeAppManager.mainStageApplications.get(0).desktopFile, "red")
 
290
        }
 
291
 
 
292
        /* When an application is launched, it needs a background before it's drawn on screen
 
293
           so that the user does not see the previous running app while the new one is launching.
 
294
           When switching between applications, backgrounds are unnecessary, 'cause the
 
295
           applications are in front of them. */
 
296
        function test_background() {
 
297
            redControl.checked = true
 
298
            tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
 
299
 
 
300
            compare(newAppScreenshot.withBackground, true, "starting app screenshot does not have background enabled")
 
301
 
 
302
            tryCompare(stage, "usingScreenshots", false) // wait for the animation to finish
 
303
 
 
304
            greenControl.checked = true
 
305
            tryCompare(stage, "usingScreenshots", true) // wait for the animation to start
 
306
            tryCompare(stage, "usingScreenshots", false) // and finish
 
307
 
 
308
            var draggingAreaCenterX = stage.width - (stage.rightEdgeDraggingAreaWidth / 2)
 
309
            var draggingAreaCenterY = stage.height / 2
 
310
            touchPress(stage, draggingAreaCenterX, draggingAreaCenterY)
 
311
 
 
312
            // wait for the animation to start
 
313
            tryCompare(stage, "usingScreenshots", true)
 
314
 
 
315
            compare(newAppScreenshot.withBackground, false, "switched app does have background enabled")
 
316
 
 
317
            tryCompareFunction(isShowingABitOfNewApp, true); // wait for the hint animation to finish
 
318
            touchRelease(stage, draggingAreaCenterX, draggingAreaCenterY)
 
319
        }
 
320
    }
 
321
}