Merge lp:~gerboland/unity/8-refactor-wm-and-test into lp:unity/8.0
- 8-refactor-wm-and-test
- Merge into 8.0
Status: | Superseded |
---|---|
Proposed branch: | lp:~gerboland/unity/8-refactor-wm-and-test |
Merge into: | lp:unity/8.0 |
Diff against target: |
1925 lines (+1260/-289) 17 files modified
CMakeLists.txt (+1/-1) Shell.qml (+24/-241) Stages/SideStage.qml (+1/-1) Stages/Stage.qml (+6/-1) Stages/StageManager.qml (+287/-0) debian/unity8.install (+1/-1) tests/mocks/Ubuntu/Application/ApplicationListModel.cpp (+2/-2) tests/mocks/Ubuntu/Application/ApplicationManager.cpp (+73/-34) tests/mocks/Ubuntu/Application/ApplicationManager.h (+9/-0) tests/qmltests/CMakeLists.txt (+4/-6) tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml (+2/-0) tests/qmltests/Stages/tst_SideStage.qml (+1/-1) tests/qmltests/Stages/tst_Stage.qml (+1/-1) tests/qmltests/Stages/tst_StageManager-phone.qml (+255/-0) tests/qmltests/Stages/tst_StageManager-tablet.qml (+394/-0) tests/qmltests/Stages/tst_StageManager/ListSelector.qml (+101/-0) tests/qmltests/Stages/tst_StageManager/StageManagerTestCase.qml (+98/-0) |
To merge this branch: | bzr merge lp:~gerboland/unity/8-refactor-wm-and-test |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michał Sawicz | Needs Fixing | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Michael Zanetti (community) | Needs Fixing | ||
Review via email: mp+168051@code.launchpad.net |
This proposal supersedes a proposal from 2013-05-30.
This proposal has been superseded by a proposal from 2013-07-02.
Commit message
Refactor window management into a separate component, add tests and fix bug
- move the window management code out of Shell into new component called StageManager
- place StageManager and related components (Stage,SideStage) into a Stages directory, replacing the old SideStage directory
- Add tests for StageManager.
- Modify the mock Ubuntu.Application plugin to:
- fix crash where view not initialized when plugin initialized
- prepend new applications to the application list
- always emit {side,main}
- Fix bug where if one stage animation started before the cleanup of the previous animation had completed, the new application would not be focused
Description of the change
Refactor the window management into separate component (StageManager), add tests and fix a hard-to-reproduce bug that the tests revealed
- move the window management code out of Shell into new component called StageManager
- place StageManager and related components (Stage,SideStage) into a Stages directory, replacing the old SideStage directory
- Add tests for StageManager.
- Modify the mock Ubuntu.Application plugin to:
- fix crash where view not initialized when plugin initialized
- prepend new applications to the application list
- always emit {side,main}
- Fix bug where if one stage animation started before the cleanup of the previous animation had completed, the new application would not be focused
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:707
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:708
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:709
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
765 + //hides: [launcher, panel.indicators]
This will never be used in here... can go away
1454 + function rightEdgeSwipe(
1455 + if (distance == undefined) distance = units.gu(
1456 +
1457 + var x = stageManagerUnd
1458 + var y = stageManagerUnd
1459 + mouseFlick(
1460 + x - distance, y)
1461 + }
1462 +
1463 + function sideStageHandle
1464 + if (distance == undefined) distance = units.gu(
1465 +
1466 + var x = sideStage.x - (sideStage.
1467 + var y = sideStage.height / 2
1468 + mouseFlick(
1469 + x + distance, y)
1470 + }
whats the difference between those two? wouldn't the first one be enough?
1474 + compare(
would it make sense to add a message to compare()s for easier debugging in case the test fails? I think for some of your compare()s it does make sense, not necessarily for all tho.
836 + skip("FIXME: application not unfocused when dismissed with left edge swipe")
837 + tryCompare(
This merge seems to be right place to fix this, unless it causes lots of other changes too. Also, when this is fixed, the tryCompare() seems like a good addition to checkStageManag
1026 + width: units.gu(160)
This seems a bit much and not really needed. Can we make this a bit smaller so the tests can run and seen on smaller displays too?
When running the test files in qmlscene (for manual testing/debuggin) they segfault:
# qmlscene ../tests/
ASSERT failure in QList<T>
Aborted (core dumped)
We try to create testcases that are able to run standalone for manual testing/debugging which I think is quite useful once a test fails.
Overall really nice test set. Well done!
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
All comments acted upon except where I've replied below:
> 1454 + function rightEdgeSwipe(
> 1457 + var x = stageManagerUnd
> (stageManagerUn
> 1463 + function sideStageHandle
> 1466 + var x = sideStage.x - (sideStage.
> whats the difference between those two? wouldn't the first one be enough?
One performs a right-edge swipe on the StageManager. The other grabs the side-stage handle and drags it to the right. They really only differ on their calculation of the starting x of the gesture, but I used different functions as there are only a small number of gestures relevant and I like verbose functions names.
> 836 + skip("FIXME: application not unfocused when dismissed with left edge
> swipe")
> 837 + tryCompare(
>
> This merge seems to be right place to fix this, unless it causes lots of other
> changes too.
It's a change that needs to be made in qtubuntu. StageManager does call unfocus here, but qtubuntu doesn't update the value of mainStageFocuse
> When running the test files in qmlscene (for manual testing/debuggin) they
> segfault:
> # qmlscene ../tests/
> ./tests/mocks/ -I tests/utils/
> ASSERT failure in QList<T>
> /usr/include/
> Aborted (core dumped)
I need to dig into this, not sure what's wrong.
> We try to create testcases that are able to run standalone for manual
> testing/debugging which I think is quite useful once a test fails.
To do this, I'd need to emulate tst_Stage.qml and add checkboxes to launch/quit applications. Shall I?
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
> One performs a right-edge swipe on the StageManager. The other grabs the side-
> stage handle and drags it to the right. They really only differ on their
> calculation of the starting x of the gesture, but I used different functions
> as there are only a small number of gestures relevant and I like verbose
> functions names.
Ok, fine with me.
> > 836 + skip("FIXME: application not unfocused when dismissed with left
> edge
> > swipe")
> > 837 + tryCompare(
> null)
> >
> > This merge seems to be right place to fix this, unless it causes lots of
> other
> > changes too.
> It's a change that needs to be made in qtubuntu. StageManager does call
> unfocus here, but qtubuntu doesn't update the value of
> mainStageFocuse
Ack. Lets leave it. I'm wondering how we would keep track of this to not forget to enable it once the bug is fixed.
> > When running the test files in qmlscene (for manual testing/debuggin) they
> > segfault:
> > # qmlscene ../tests/
> > ./tests/mocks/ -I tests/utils/
> > ASSERT failure in QList<T>
> > /usr/include/
> > Aborted (core dumped)
>
> I need to dig into this, not sure what's wrong.
>
> > We try to create testcases that are able to run standalone for manual
> > testing/debugging which I think is quite useful once a test fails.
>
> To do this, I'd need to emulate tst_Stage.qml and add checkboxes to
> launch/quit applications. Shall I?
Unless it would take you ages to do so I think its quite useful. For instance only today we used the tst_Revealer in a qmlscene to find out if its the revealer itself that causes the freeze we had today.
Don't overdo it. Checkboxes for basic features are enough so that most use cases can be reproduced manually. A checkbox for every single test function is not needed.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:714
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
Could you rephrase your commit message to the following format:
"""
Short, single line, summary
Detailed, multi-line, description.
"""
Many history/log views show only the first line of each commit message.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:715
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:727
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:732
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
All comments acted upon, unfortunately changing the diff more than I'd like. Please have a look again.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:735
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:735
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:4
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 8. By Gerry Boland
-
Fix RunningApplicat
ionsGrid test which seems to fail because of this branch
Michael Zanetti (mzanetti) wrote : | # |
- Close all apps
- run the phone-app
- open the notes-app
- edit some note, finish editing, so the OSK hides again
- now swipe from the right
-> expected result: phone-app shows up
-> actual result: only the notes-app shows up in the right-edge swipe
I cannot reproduce this with a freshly flashed phone without modifications.
Also, sometimes I could get it into a weird state without the OSK being involved, but I haven't found a way to reliably reproduce that.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:7
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:7
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:8
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:8
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 9. By Gerry Boland
-
Restore broken property needed by greeter
- 10. By Gerry Boland
-
Merge trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:10
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:10
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
Hey, https:/
Does this branch contain a test that this works correctly on the shell side?
Newly born sessions should move to the front.
- 11. By Gerry Boland
-
Merge trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:11
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:11
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
- 12. By Gerry Boland
-
No need to refer to shell here
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:12
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:12
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
- 13. By Gerry Boland
-
Gah, conflict I missed fixed
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:13
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: 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:13
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
Failed tests:
testStageMa
testStageMa
Output:
process 27977: D-Bus library appears to be incorrectly set up; failed to read machine uuid: Failed to open "/etc/machine-id": No such file or directory
See the manual page for dbus-uuidgen to correct this issue.
process 27977: D-Bus library appears to be incorrectly set up; failed to read machine uuid: Failed to open "/etc/machine-id": No such file or directory
See the manual page for dbus-uuidgen to correct this issue.
???
- 14. By Gerry Boland
-
Mock ApplicationManager possible fix for crash
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:14
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: 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:14
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 15. By Gerry Boland
-
Revert last fix, does not work
- 16. By Gerry Boland
-
Experiment 2 to fix crash
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:16
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 17. By Gerry Boland
-
Whitespace
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:17
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: 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:17
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: 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:17
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
Hey, there's a conflict in Shell.qml
Unmerged revisions
- 17. By Gerry Boland
-
Whitespace
- 16. By Gerry Boland
-
Experiment 2 to fix crash
- 15. By Gerry Boland
-
Revert last fix, does not work
- 14. By Gerry Boland
-
Mock ApplicationManager possible fix for crash
- 13. By Gerry Boland
-
Gah, conflict I missed fixed
- 12. By Gerry Boland
-
No need to refer to shell here
- 11. By Gerry Boland
-
Merge trunk
- 10. By Gerry Boland
-
Merge trunk
- 9. By Gerry Boland
-
Restore broken property needed by greeter
- 8. By Gerry Boland
-
Fix RunningApplicat
ionsGrid test which seems to fail because of this branch
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2013-06-05 22:03:08 +0000 |
3 | +++ CMakeLists.txt 2013-06-13 14:42:44 +0000 |
4 | @@ -144,7 +144,7 @@ |
5 | Hud |
6 | Panel |
7 | Launcher |
8 | - SideStage |
9 | + Stages |
10 | Notifications |
11 | ) |
12 | |
13 | |
14 | === modified file 'Shell.qml' |
15 | --- Shell.qml 2013-06-12 08:48:37 +0000 |
16 | +++ Shell.qml 2013-06-13 14:42:44 +0000 |
17 | @@ -26,7 +26,7 @@ |
18 | import "Components" |
19 | import "Components/Math.js" as MathLocal |
20 | import "Bottombar" |
21 | -import "SideStage" |
22 | +import "Stages" |
23 | |
24 | FocusScope { |
25 | id: shell |
26 | @@ -42,71 +42,14 @@ |
27 | readonly property real panelHeight: panel.panelHeight |
28 | |
29 | property bool dashShown: dash.shown |
30 | - property bool stageScreenshotsReady: { |
31 | - if (sideStage.shown) { |
32 | - if (mainStage.applications.count > 0) { |
33 | - return mainStage.usingScreenshots && sideStage.usingScreenshots; |
34 | - } else { |
35 | - return sideStage.usingScreenshots; |
36 | - } |
37 | - } else { |
38 | - return mainStage.usingScreenshots; |
39 | - } |
40 | - } |
41 | + readonly property bool stageScreenshotsReady: stageManager.stageScreenshotsReady |
42 | |
43 | property ListModel searchHistory: SearchHistoryModel {} |
44 | |
45 | property var applicationManager: ApplicationManagerWrapper {} |
46 | |
47 | - Component.onCompleted: { |
48 | - applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled }) |
49 | - |
50 | - // FIXME: if application focused before shell starts, shell draws on top of it only. |
51 | - // We should detect already running applications on shell start and bring them to the front. |
52 | - applicationManager.unfocusCurrentApplication(); |
53 | - } |
54 | - |
55 | - readonly property bool fullscreenMode: { |
56 | - if (greeter.shown || lockscreen.shown) { |
57 | - return false; |
58 | - } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode |
59 | - return mainStage.switchingFromFullscreenToFullscreen; |
60 | - } else if (applicationManager.mainStageFocusedApplication) { |
61 | - return applicationManager.mainStageFocusedApplication.fullscreen; |
62 | - } else { |
63 | - return false; |
64 | - } |
65 | - } |
66 | - |
67 | - Connections { |
68 | - target: applicationManager |
69 | - ignoreUnknownSignals: true |
70 | - onFocusRequested: { |
71 | - // TODO: this should be protected to only unlock for certain applications / certain usecases |
72 | - // potentially only in connection with a notification |
73 | - greeter.hide(); |
74 | - shell.activateApplication(desktopFile); |
75 | - } |
76 | - } |
77 | - |
78 | function activateApplication(desktopFile, argument) { |
79 | - if (applicationManager) { |
80 | - // For newly started applications, as it takes them time to draw their first frame |
81 | - // we add a delay before we hide the animation screenshots to compensate. |
82 | - var addDelay = !applicationManager.getApplicationFromDesktopFile(desktopFile); |
83 | - |
84 | - var application; |
85 | - application = applicationManager.activateApplication(desktopFile, argument); |
86 | - if (application == null) { |
87 | - return; |
88 | - } |
89 | - if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) { |
90 | - mainStage.activateApplication(desktopFile, addDelay); |
91 | - } else { |
92 | - sideStage.activateApplication(desktopFile, addDelay); |
93 | - } |
94 | - stages.show(); |
95 | - } |
96 | + stageManager.activateApplication(desktopFile, argument); |
97 | } |
98 | |
99 | VolumeControl { |
100 | @@ -126,9 +69,7 @@ |
101 | id: underlay |
102 | anchors.fill: parent |
103 | visible: !(panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth) |
104 | - && (stages.fullyHidden |
105 | - || (stages.fullyShown && mainStage.usingScreenshots) |
106 | - || !stages.fullyShown && (mainStage.usingScreenshots || (sideStage.shown && sideStage.usingScreenshots))) |
107 | + && stageManager.needUnderlay |
108 | |
109 | Image { |
110 | id: backgroundImage |
111 | @@ -148,7 +89,7 @@ |
112 | id: dash |
113 | |
114 | available: !greeter.shown && !lockscreen.shown |
115 | - hides: [stages, launcher, panel.indicators] |
116 | + hides: [stageManager, launcher, panel.indicators] |
117 | shown: disappearingAnimationProgress !== 1.0 |
118 | enabled: disappearingAnimationProgress === 0.0 |
119 | // FIXME: unfocus all applications when going back to the dash |
120 | @@ -165,182 +106,24 @@ |
121 | |
122 | contentScale: 1.0 - 0.2 * disappearingAnimationProgress |
123 | opacity: 1.0 - disappearingAnimationProgress |
124 | - property real disappearingAnimationProgress: ((greeter.shown) ? greeterRevealer.animatedProgress : stagesRevealer.animatedProgress) |
125 | - // FIXME: only necessary because stagesRevealer.animatedProgress and |
126 | + property real disappearingAnimationProgress: ((greeter.shown) ? greeterRevealer.animatedProgress : stageManager.animatedProgress) |
127 | + // FIXME: only necessary because stageManager.animatedProgress and |
128 | // greeterRevealer.animatedProgress are not animated |
129 | Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }} |
130 | } |
131 | } |
132 | |
133 | - |
134 | - Item { |
135 | - |
136 | - width: parent.width |
137 | - height: parent.height |
138 | - x: launcher.progress |
139 | - Behavior on x {SmoothedAnimation{velocity: 600}} |
140 | - |
141 | - |
142 | - Showable { |
143 | - id: stages |
144 | - |
145 | - property bool fullyShown: shown && stages[stagesRevealer.boundProperty] == stagesRevealer.openedValue |
146 | - && parent.x == 0 |
147 | - property bool fullyHidden: !shown && stages[stagesRevealer.boundProperty] == stagesRevealer.closedValue |
148 | - available: !greeter.shown |
149 | - hides: [launcher, panel.indicators] |
150 | - shown: false |
151 | - opacity: 1.0 |
152 | - showAnimation: StandardAnimation { property: "x"; duration: 350; to: stagesRevealer.openedValue; easing.type: Easing.OutCubic } |
153 | - hideAnimation: StandardAnimation { property: "x"; duration: 350; to: stagesRevealer.closedValue; easing.type: Easing.OutCubic } |
154 | - |
155 | - width: parent.width |
156 | - height: parent.height |
157 | - |
158 | - // close the stages when no focused application remains |
159 | - Connections { |
160 | - target: shell.applicationManager |
161 | - onMainStageFocusedApplicationChanged: stages.closeIfNoApplications() |
162 | - onSideStageFocusedApplicationChanged: stages.closeIfNoApplications() |
163 | - ignoreUnknownSignals: true |
164 | - } |
165 | - |
166 | - function closeIfNoApplications() { |
167 | - if (!shell.applicationManager.mainStageFocusedApplication |
168 | - && !shell.applicationManager.sideStageFocusedApplication |
169 | - && shell.applicationManager.mainStageApplications.count == 0 |
170 | - && shell.applicationManager.sideStageApplications.count == 0) { |
171 | - stages.hide(); |
172 | - } |
173 | - } |
174 | - |
175 | - // show the stages when an application gets the focus |
176 | - Connections { |
177 | - target: shell.applicationManager |
178 | - onMainStageFocusedApplicationChanged: { |
179 | - if (shell.applicationManager.mainStageFocusedApplication) { |
180 | - mainStage.show(); |
181 | - stages.show(); |
182 | - } |
183 | - } |
184 | - onSideStageFocusedApplicationChanged: { |
185 | - if (shell.applicationManager.sideStageFocusedApplication) { |
186 | - sideStage.show(); |
187 | - stages.show(); |
188 | - } |
189 | - } |
190 | - ignoreUnknownSignals: true |
191 | - } |
192 | - |
193 | - |
194 | - Stage { |
195 | - id: mainStage |
196 | - |
197 | - anchors.fill: parent |
198 | - fullyShown: stages.fullyShown |
199 | - shouldUseScreenshots: !fullyShown |
200 | - rightEdgeEnabled: !sideStage.enabled |
201 | - |
202 | - applicationManager: shell.applicationManager |
203 | - rightEdgeDraggingAreaWidth: shell.edgeSize |
204 | - normalApplicationY: shell.panelHeight |
205 | - |
206 | - shown: true |
207 | - function show() { |
208 | - stages.show(); |
209 | - } |
210 | - function showWithoutAnimation() { |
211 | - stages.showWithoutAnimation(); |
212 | - } |
213 | - function hide() { |
214 | - } |
215 | - |
216 | - // FIXME: workaround the fact that focusing a main stage application |
217 | - // raises its surface on top of all other surfaces including the ones |
218 | - // that belong to side stage applications. |
219 | - onFocusedApplicationChanged: { |
220 | - if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) { |
221 | - shell.applicationManager.focusApplication(sideStage.focusedApplication); |
222 | - } |
223 | - } |
224 | - } |
225 | - |
226 | - SideStage { |
227 | - id: sideStage |
228 | - |
229 | - applicationManager: shell.applicationManager |
230 | - rightEdgeDraggingAreaWidth: shell.edgeSize |
231 | - normalApplicationY: shell.panelHeight |
232 | - |
233 | - onShownChanged: { |
234 | - if (!shown && mainStage.applications.count == 0) { |
235 | - stages.hide(); |
236 | - } |
237 | - } |
238 | - // FIXME: when hiding the side stage, refocus the main stage |
239 | - // application so that it goes in front of the side stage |
240 | - // application and hides it |
241 | - onFullyShownChanged: { |
242 | - if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) { |
243 | - shell.applicationManager.focusApplication(mainStage.focusedApplication); |
244 | - } |
245 | - } |
246 | - |
247 | - enabled: shell.width >= units.gu(60) |
248 | - visible: enabled |
249 | - fullyShown: stages.fullyShown && shown |
250 | - && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue |
251 | - shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed |
252 | - |
253 | - available: !greeter.shown && !lockscreen.shown && enabled |
254 | - hides: [launcher, panel.indicators] |
255 | - shown: false |
256 | - showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint } |
257 | - hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint } |
258 | - |
259 | - width: units.gu(40) |
260 | - height: stages.height |
261 | - handleExpanded: sideStageRevealer.pressed |
262 | - } |
263 | - |
264 | - Revealer { |
265 | - id: sideStageRevealer |
266 | - |
267 | - enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0 |
268 | - && sideStage.available |
269 | - direction: Qt.RightToLeft |
270 | - openedValue: parent.width - sideStage.width |
271 | - hintDisplacement: units.gu(3) |
272 | - /* The size of the sidestage handle needs to be bigger than the |
273 | - typical size used for edge detection otherwise it is really |
274 | - hard to grab. |
275 | - */ |
276 | - handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize |
277 | - closedValue: parent.width + sideStage.handleSizeCollapsed |
278 | - target: sideStage |
279 | - x: parent.width - width |
280 | - width: sideStage.width + handleSize * 0.7 |
281 | - height: sideStage.height |
282 | - orientation: Qt.Horizontal |
283 | - } |
284 | - } |
285 | - } |
286 | - |
287 | - |
288 | - Revealer { |
289 | - id: stagesRevealer |
290 | - |
291 | - property real animatedProgress: MathLocal.clamp((-dragPosition - launcher.progress) / closedValue, 0, 1) |
292 | - enabled: mainStage.applications.count > 0 || sideStage.applications.count > 0 |
293 | - direction: Qt.RightToLeft |
294 | - openedValue: 0 |
295 | - hintDisplacement: units.gu(3) |
296 | - handleSize: shell.edgeSize |
297 | - closedValue: width |
298 | - target: stages |
299 | - width: stages.width |
300 | - height: stages.height |
301 | - orientation: Qt.Horizontal |
302 | + StageManager { |
303 | + id: stageManager |
304 | + |
305 | + anchors.fill: parent |
306 | + |
307 | + enabled: !greeter.shown |
308 | + hides: [launcher, panel.indicators] |
309 | + applicationManager: shell.applicationManager |
310 | + leftSwipePosition: launcher.progress |
311 | + panelHeight: panel.panelHeight |
312 | + edgeHandleSize: shell.edgeSize |
313 | } |
314 | |
315 | Lockscreen { |
316 | @@ -409,8 +192,8 @@ |
317 | greeter.forceActiveFocus(); |
318 | // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether |
319 | // the stage was actually shown |
320 | - if (mainStage.fullyShown) greeter.previousMainApp = applicationManager.mainStageFocusedApplication; |
321 | - if (sideStage.fullyShown) greeter.previousSideApp = applicationManager.sideStageFocusedApplication; |
322 | + if (stageManager.mainStageFullyShown) greeter.previousMainApp = applicationManager.mainStageFocusedApplication; |
323 | + if (stageManager.sideStageFullyShown) greeter.previousSideApp = applicationManager.sideStageFocusedApplication; |
324 | applicationManager.unfocusCurrentApplication(); |
325 | } else { |
326 | if (greeter.previousMainApp) { |
327 | @@ -461,7 +244,7 @@ |
328 | indicators { |
329 | hides: [launcher] |
330 | } |
331 | - fullscreenMode: shell.fullscreenMode |
332 | + fullscreenMode: stageManager.fullscreenMode |
333 | searchVisible: !greeter.shown && !lockscreen.shown |
334 | |
335 | InputFilterArea { |
336 | @@ -537,16 +320,16 @@ |
337 | onDashItemSelected: { |
338 | greeter.hide() |
339 | // Animate if moving between application and dash |
340 | - if (!stages.shown) { |
341 | + if (!stageManager.shown) { |
342 | dash.setCurrentLens("home.lens", true, false) |
343 | } else { |
344 | dash.setCurrentLens("home.lens", false, false) |
345 | } |
346 | - stages.hide(); |
347 | + stageManager.hide(); |
348 | } |
349 | onDash: { |
350 | dash.setCurrentLens("applications.lens", true, false) |
351 | - stages.hide(); |
352 | + stageManager.hide(); |
353 | } |
354 | onLauncherApplicationSelected:{ |
355 | greeter.hide() |
356 | |
357 | === removed directory 'SideStage' |
358 | === added directory 'Stages' |
359 | === renamed file 'SideStage/SideStage.qml' => 'Stages/SideStage.qml' |
360 | --- SideStage/SideStage.qml 2013-06-05 22:03:08 +0000 |
361 | +++ Stages/SideStage.qml 2013-06-13 14:42:44 +0000 |
362 | @@ -38,7 +38,7 @@ |
363 | left: parent.left |
364 | right: parent.right |
365 | } |
366 | - height: shell.panelHeight |
367 | + height: normalApplicationY |
368 | color: background.color |
369 | z: -1 |
370 | } |
371 | |
372 | === renamed file 'SideStage/SidestageHandle.qml' => 'Stages/SidestageHandle.qml' |
373 | === renamed file 'Components/Stage.qml' => 'Stages/Stage.qml' |
374 | --- Components/Stage.qml 2013-06-07 18:01:50 +0000 |
375 | +++ Stages/Stage.qml 2013-06-13 14:42:44 +0000 |
376 | @@ -18,6 +18,7 @@ |
377 | import Ubuntu.Application 0.1 |
378 | import Ubuntu.Components 0.1 |
379 | import Ubuntu.Gestures 0.1 |
380 | +import "../Components" |
381 | |
382 | /* |
383 | Responsible for application switching. |
384 | @@ -179,7 +180,11 @@ |
385 | delayedHideScreenshots.stop(); |
386 | applicationManager.focusApplication(application); |
387 | } |
388 | - stage.focusedApplicationWhenUsingScreenshots = null; |
389 | + |
390 | + // Don't over-write this if another animation has begun, as another app will get focus then |
391 | + if (!showStartingApplicationAnimation.running && !switchToApplicationAnimation.running) { |
392 | + stage.focusedApplicationWhenUsingScreenshots = null; |
393 | + } |
394 | } |
395 | |
396 | function __focusApplicationUsingScreenshots(application) { |
397 | |
398 | === added file 'Stages/StageManager.qml' |
399 | --- Stages/StageManager.qml 1970-01-01 00:00:00 +0000 |
400 | +++ Stages/StageManager.qml 2013-06-13 14:42:44 +0000 |
401 | @@ -0,0 +1,287 @@ |
402 | +/* |
403 | + * Copyright (C) 2013 Canonical, Ltd. |
404 | + * |
405 | + * This program is free software; you can redistribute it and/or modify |
406 | + * it under the terms of the GNU General Public License as published by |
407 | + * the Free Software Foundation; version 3. |
408 | + * |
409 | + * This program is distributed in the hope that it will be useful, |
410 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
411 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
412 | + * GNU General Public License for more details. |
413 | + * |
414 | + * You should have received a copy of the GNU General Public License |
415 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
416 | + */ |
417 | + |
418 | +import QtQuick 2.0 |
419 | +import Ubuntu.Application 0.1 |
420 | +import "../Components" |
421 | +import "../Components/Math.js" as MathLocal |
422 | + |
423 | +Item { |
424 | + id: stageManager |
425 | + |
426 | + property var applicationManager |
427 | + property real leftSwipePosition: 0 |
428 | + property real panelHeight: 0 |
429 | + property real edgeHandleSize |
430 | + property bool enabled |
431 | + property var hides: [] |
432 | + readonly property bool shown: stages.shown |
433 | + readonly property real animatedProgress: MathLocal.clamp((-stagesRevealer.dragPosition - leftSwipePosition) |
434 | + / stagesRevealer.closedValue, 0, 1) |
435 | + |
436 | + readonly property bool stageScreenshotsReady: { |
437 | + if (sideStage.shown) { |
438 | + if (mainStage.applications.count > 0) { |
439 | + return mainStage.usingScreenshots || sideStage.usingScreenshots; |
440 | + } else { |
441 | + return sideStage.usingScreenshots; |
442 | + } |
443 | + } else { |
444 | + return mainStage.usingScreenshots; |
445 | + } |
446 | + } |
447 | + |
448 | + readonly property bool needUnderlay: (stages.fullyHidden |
449 | + || (stages.fullyShown && mainStage.usingScreenshots) |
450 | + || !stages.fullyShown && (mainStage.usingScreenshots || (sideStage.shown && sideStage.usingScreenshots))) |
451 | + |
452 | + readonly property bool fullscreenMode: { |
453 | + if (!enabled) { |
454 | + return false; |
455 | + } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode |
456 | + return mainStage.switchingFromFullscreenToFullscreen; |
457 | + } else if (applicationManager.mainStageFocusedApplication) { |
458 | + return applicationManager.mainStageFocusedApplication.fullscreen; |
459 | + } else { |
460 | + return false; |
461 | + } |
462 | + } |
463 | + |
464 | + readonly property alias mainStageFullyShown: mainStage.fullyShown |
465 | + readonly property alias sideStageFullyShown: sideStage.fullyShown |
466 | + |
467 | + function hide() { |
468 | + stages.hide() |
469 | + } |
470 | + |
471 | + Component.onCompleted: { |
472 | + applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled }) |
473 | + |
474 | + // FIXME: if application focused before shell starts, shell draws on top of it only. |
475 | + // We should detect already running applications on shell start and bring them to the front. |
476 | + applicationManager.unfocusCurrentApplication(); |
477 | + } |
478 | + |
479 | + Connections { |
480 | + target: applicationManager |
481 | + ignoreUnknownSignals: true |
482 | + onFocusRequested: { |
483 | + // TODO: this should be protected to only unlock for certain applications / certain usecases |
484 | + // potentially only in connection with a notification |
485 | + shell.greeter.hide(); |
486 | + activateApplication(desktopFile); |
487 | + } |
488 | + } |
489 | + |
490 | + function activateApplication(desktopFile, argument) { |
491 | + if (applicationManager) { |
492 | + // For newly started applications, as it takes them time to draw their first frame |
493 | + // we add a delay before we hide the animation screenshots to compensate. |
494 | + var addDelay = !applicationManager.getApplicationFromDesktopFile(desktopFile); |
495 | + |
496 | + var application; |
497 | + application = applicationManager.activateApplication(desktopFile, argument); |
498 | + if (application == null) { |
499 | + return; |
500 | + } |
501 | + if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) { |
502 | + mainStage.activateApplication(desktopFile, addDelay); |
503 | + } else { |
504 | + sideStage.activateApplication(desktopFile, addDelay); |
505 | + } |
506 | + stages.show(); |
507 | + } |
508 | + } |
509 | + Item { |
510 | + id: windowsContainer |
511 | + |
512 | + x: leftSwipePosition |
513 | + Behavior on x {SmoothedAnimation{velocity: 600}} |
514 | + |
515 | + width: parent.width |
516 | + anchors { |
517 | + top: parent.top |
518 | + bottom: parent.bottom |
519 | + } |
520 | + |
521 | + Showable { |
522 | + id: stages |
523 | + |
524 | + property bool fullyShown: shown && stages[stagesRevealer.boundProperty] == stagesRevealer.openedValue |
525 | + && parent.x == 0 |
526 | + property bool fullyHidden: !shown && stages[stagesRevealer.boundProperty] == stagesRevealer.closedValue |
527 | + available: stageManager.enabled |
528 | + hides: stageManager.hides |
529 | + shown: false |
530 | + opacity: 1.0 |
531 | + showAnimation: StandardAnimation { property: "x"; duration: 350; to: stagesRevealer.openedValue; easing.type: Easing.OutCubic } |
532 | + hideAnimation: StandardAnimation { property: "x"; duration: 350; to: stagesRevealer.closedValue; easing.type: Easing.OutCubic } |
533 | + |
534 | + width: parent.width |
535 | + height: parent.height |
536 | + |
537 | + // close the stages when no focused application remains |
538 | + Connections { |
539 | + target: applicationManager |
540 | + onMainStageFocusedApplicationChanged: stages.closeIfNoApplications() |
541 | + onSideStageFocusedApplicationChanged: stages.closeIfNoApplications() |
542 | + ignoreUnknownSignals: true |
543 | + } |
544 | + Connections { |
545 | + target: applicationManager.mainStageApplications |
546 | + onCountChanged: stages.closeIfNoApplications(); |
547 | + } |
548 | + Connections { |
549 | + target: applicationManager.sideStageApplications |
550 | + onCountChanged: stages.closeIfNoApplications(); |
551 | + } |
552 | + |
553 | + function closeIfNoApplications() { |
554 | + if (!applicationManager.mainStageFocusedApplication |
555 | + && !applicationManager.sideStageFocusedApplication |
556 | + && applicationManager.mainStageApplications.count == 0 |
557 | + && applicationManager.sideStageApplications.count == 0) { |
558 | + stages.hide(); |
559 | + } |
560 | + } |
561 | + |
562 | + // show the stages when an application gets the focus |
563 | + Connections { |
564 | + target: applicationManager |
565 | + onMainStageFocusedApplicationChanged: { |
566 | + if (applicationManager.mainStageFocusedApplication) { |
567 | + mainStage.show(); |
568 | + stages.show(); |
569 | + } |
570 | + } |
571 | + onSideStageFocusedApplicationChanged: { |
572 | + if (applicationManager.sideStageFocusedApplication) { |
573 | + sideStage.show(); |
574 | + stages.show(); |
575 | + } } |
576 | + ignoreUnknownSignals: true |
577 | + } |
578 | + |
579 | + Stage { |
580 | + id: mainStage |
581 | + objectName: "mainStage" |
582 | + |
583 | + anchors.fill: parent |
584 | + fullyShown: stages.fullyShown |
585 | + shouldUseScreenshots: !fullyShown |
586 | + rightEdgeEnabled: !sideStage.enabled |
587 | + |
588 | + applicationManager: stageManager.applicationManager |
589 | + rightEdgeDraggingAreaWidth: edgeHandleSize |
590 | + normalApplicationY: panelHeight |
591 | + |
592 | + shown: true |
593 | + function show() { |
594 | + stages.show(); |
595 | + } |
596 | + function showWithoutAnimation() { |
597 | + stages.showWithoutAnimation(); |
598 | + } |
599 | + function hide() { |
600 | + } |
601 | + |
602 | + // FIXME: workaround the fact that focusing a main stage application |
603 | + // raises its surface on top of all other surfaces including the ones |
604 | + // that belong to side stage applications. |
605 | + onFocusedApplicationChanged: { |
606 | + if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) { |
607 | + applicationManager.focusApplication(sideStage.focusedApplication); |
608 | + } |
609 | + } |
610 | + } |
611 | + |
612 | + SideStage { |
613 | + id: sideStage |
614 | + objectName: "sideStage" |
615 | + |
616 | + applicationManager: stageManager.applicationManager |
617 | + rightEdgeDraggingAreaWidth: edgeHandleSize |
618 | + normalApplicationY: panelHeight |
619 | + |
620 | + onShownChanged: { |
621 | + if (!shown && mainStage.applications.count == 0) { |
622 | + stages.hide(); |
623 | + } |
624 | + } |
625 | + // FIXME: when hiding the side stage, refocus the main stage |
626 | + // application so that it goes in front of the side stage |
627 | + // application and hides it |
628 | + onFullyShownChanged: { |
629 | + if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) { |
630 | + applicationManager.focusApplication(mainStage.focusedApplication); |
631 | + } |
632 | + } |
633 | + |
634 | + enabled: stageManager.width >= units.gu(60) |
635 | + visible: enabled |
636 | + fullyShown: stages.fullyShown && shown |
637 | + && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue |
638 | + shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed |
639 | + |
640 | + available: stageManager.enabled && enabled |
641 | + hides: stageManager.hides |
642 | + shown: false |
643 | + showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint } |
644 | + hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint } |
645 | + |
646 | + width: units.gu(40) |
647 | + height: stages.height |
648 | + handleExpanded: sideStageRevealer.pressed |
649 | + } |
650 | + |
651 | + Revealer { |
652 | + id: sideStageRevealer |
653 | + |
654 | + enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0 |
655 | + && sideStage.available |
656 | + direction: Qt.RightToLeft |
657 | + openedValue: parent.width - sideStage.width |
658 | + hintDisplacement: units.gu(3) |
659 | + /* The size of the sidestage handle needs to be bigger than the |
660 | + typical size used for edge detection otherwise it is really |
661 | + hard to grab. |
662 | + */ |
663 | + handleSize: sideStage.shown ? units.gu(4) : edgeHandleSize |
664 | + closedValue: parent.width + sideStage.handleSizeCollapsed |
665 | + target: sideStage |
666 | + x: parent.width - width |
667 | + width: sideStage.width + handleSize * 0.7 |
668 | + height: sideStage.height |
669 | + orientation: Qt.Horizontal |
670 | + } |
671 | + } |
672 | + } |
673 | + |
674 | + Revealer { |
675 | + id: stagesRevealer |
676 | + |
677 | + enabled: mainStage.applications.count > 0 || sideStage.applications.count > 0 |
678 | + direction: Qt.RightToLeft |
679 | + openedValue: 0 |
680 | + hintDisplacement: units.gu(3) |
681 | + handleSize: edgeHandleSize |
682 | + closedValue: width |
683 | + target: stages |
684 | + width: stages.width |
685 | + height: stages.height |
686 | + orientation: Qt.Horizontal |
687 | + } |
688 | +} |
689 | |
690 | === renamed directory 'SideStage/graphics' => 'Stages/graphics' |
691 | === modified file 'debian/unity8.install' |
692 | --- debian/unity8.install 2013-06-05 22:03:08 +0000 |
693 | +++ debian/unity8.install 2013-06-13 14:42:44 +0000 |
694 | @@ -11,7 +11,7 @@ |
695 | /usr/share/unity8/Notifications/* |
696 | /usr/share/unity8/Panel/* |
697 | /usr/share/unity8/Shell.qml |
698 | -/usr/share/unity8/SideStage/* |
699 | +/usr/share/unity8/Stages/* |
700 | /usr/share/unity8/graphics/* |
701 | /usr/share/unity8/plugins/HudClient/* |
702 | /usr/share/unity8/plugins/LightDM/* |
703 | |
704 | === modified file 'tests/mocks/Ubuntu/Application/ApplicationListModel.cpp' |
705 | --- tests/mocks/Ubuntu/Application/ApplicationListModel.cpp 2013-06-05 22:03:08 +0000 |
706 | +++ tests/mocks/Ubuntu/Application/ApplicationListModel.cpp 2013-06-13 14:42:44 +0000 |
707 | @@ -64,8 +64,8 @@ |
708 | |
709 | void ApplicationListModel::add(ApplicationInfo* application) |
710 | { |
711 | - beginInsertRows(QModelIndex(), m_applications.size(), m_applications.size()); |
712 | - m_applications.append(application); |
713 | + beginInsertRows(QModelIndex(), 0, 0); |
714 | + m_applications.prepend(application); |
715 | endInsertRows(); |
716 | Q_EMIT countChanged(); |
717 | } |
718 | |
719 | === modified file 'tests/mocks/Ubuntu/Application/ApplicationManager.cpp' |
720 | --- tests/mocks/Ubuntu/Application/ApplicationManager.cpp 2013-06-05 22:03:08 +0000 |
721 | +++ tests/mocks/Ubuntu/Application/ApplicationManager.cpp 2013-06-13 14:42:44 +0000 |
722 | @@ -24,6 +24,21 @@ |
723 | #include <QQuickItem> |
724 | #include <QQuickView> |
725 | #include <QQmlComponent> |
726 | +#include <QWaitCondition> |
727 | +#include <QMutex> |
728 | + |
729 | +struct Sleeper { |
730 | + QMutex mutex; |
731 | + QWaitCondition sleeper; |
732 | + |
733 | + Sleeper() { mutex.lock(); } |
734 | + ~Sleeper() { mutex.unlock(); } |
735 | + |
736 | + void sleep(unsigned long duration) |
737 | + { |
738 | + sleeper.wait(&mutex, duration); |
739 | + } |
740 | +}; |
741 | |
742 | ApplicationManager::ApplicationManager(QObject *parent) |
743 | : QObject(parent) |
744 | @@ -35,10 +50,11 @@ |
745 | , m_mainStage(0) |
746 | , m_sideStageComponent(0) |
747 | , m_sideStage(0) |
748 | + , m_quickView(0) |
749 | { |
750 | buildListOfAvailableApplications(); |
751 | - createMainStageComponent(); |
752 | - createSideStageComponent(); |
753 | + |
754 | + QGuiApplication::instance()->installEventFilter(this); |
755 | } |
756 | |
757 | ApplicationManager::~ApplicationManager() |
758 | @@ -47,6 +63,19 @@ |
759 | delete m_sideStageApplications; |
760 | } |
761 | |
762 | +bool ApplicationManager::eventFilter(QObject *object, QEvent *event) |
763 | +{ |
764 | + // best to wait for this event before locating the view |
765 | + if (!m_quickView && (event->type() == QEvent::ApplicationActivate)) { |
766 | + m_quickView = qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]); |
767 | + |
768 | + createMainStageComponent(); |
769 | + createSideStageComponent(); |
770 | + } |
771 | + |
772 | + return QObject::eventFilter(object, event); |
773 | +} |
774 | + |
775 | int ApplicationManager::keyboardHeight() const |
776 | { |
777 | return 0; |
778 | @@ -92,6 +121,22 @@ |
779 | return m_sideStageFocusedApplication; |
780 | } |
781 | |
782 | +void ApplicationManager::setMainStageFocusedApplication(ApplicationInfo *app) |
783 | +{ |
784 | + if (app != m_mainStageFocusedApplication) { |
785 | + m_mainStageFocusedApplication = app; |
786 | + Q_EMIT mainStageFocusedApplicationChanged(); |
787 | + } |
788 | +} |
789 | + |
790 | +void ApplicationManager::setSideStageFocusedApplication(ApplicationInfo *app) |
791 | +{ |
792 | + if (app != m_sideStageFocusedApplication) { |
793 | + m_sideStageFocusedApplication = app; |
794 | + Q_EMIT sideStageFocusedApplicationChanged(); |
795 | + } |
796 | +} |
797 | + |
798 | ApplicationInfo* ApplicationManager::startProcess(QString desktopFile, |
799 | ExecFlags flags, |
800 | QStringList arguments) |
801 | @@ -112,9 +157,13 @@ |
802 | |
803 | if (flags.testFlag(ApplicationManager::ForceMainStage) |
804 | || application->stage() == ApplicationInfo::MainStage) { |
805 | - m_mainStageApplications->add(application); |
806 | + if (!m_mainStageApplications->contains(application)) { |
807 | + m_mainStageApplications->add(application); |
808 | + } |
809 | } else { |
810 | - m_sideStageApplications->add(application); |
811 | + if (!m_sideStageApplications->contains(application)) { |
812 | + m_sideStageApplications->add(application); |
813 | + } |
814 | } |
815 | |
816 | return application; |
817 | @@ -123,18 +172,18 @@ |
818 | void ApplicationManager::stopProcess(ApplicationInfo* application) |
819 | { |
820 | if (m_mainStageApplications->contains(application)) { |
821 | + application->hideWindow(); |
822 | m_mainStageApplications->remove(application); |
823 | |
824 | if (m_mainStageFocusedApplication == application) { |
825 | - m_mainStageFocusedApplication = 0; |
826 | - Q_EMIT mainStageFocusedApplicationChanged(); |
827 | + setMainStageFocusedApplication(0); |
828 | } |
829 | } else if (m_sideStageApplications->contains(application)){ |
830 | + application->hideWindow(); |
831 | m_sideStageApplications->remove(application); |
832 | |
833 | if (m_sideStageFocusedApplication == application) { |
834 | - m_sideStageFocusedApplication = 0; |
835 | - Q_EMIT sideStageFocusedApplicationChanged(); |
836 | + setSideStageFocusedApplication(0); |
837 | } |
838 | } |
839 | } |
840 | @@ -146,14 +195,13 @@ |
841 | if (application->handle() == handle) { |
842 | if (m_mainStageFocusedApplication) |
843 | m_mainStageFocusedApplication->hideWindow(); |
844 | - m_mainStageFocusedApplication = application; |
845 | if (!m_mainStage) |
846 | createMainStage(); |
847 | application->showWindow(m_mainStage); |
848 | m_mainStage->setZ(-1000); |
849 | if (m_sideStage) |
850 | m_sideStage->setZ(-2000); |
851 | - Q_EMIT mainStageFocusedApplicationChanged(); |
852 | + setMainStageFocusedApplication(application); |
853 | return; |
854 | } |
855 | } |
856 | @@ -163,14 +211,13 @@ |
857 | if (application->handle() == handle) { |
858 | if (m_sideStageFocusedApplication) |
859 | m_sideStageFocusedApplication->hideWindow(); |
860 | - m_sideStageFocusedApplication = application; |
861 | if (!m_sideStage) |
862 | createSideStage(); |
863 | application->showWindow(m_sideStage); |
864 | m_sideStage->setZ(-1000); |
865 | if (m_mainStage) |
866 | m_mainStage->setZ(-2000); |
867 | - Q_EMIT sideStageFocusedApplicationChanged(); |
868 | + setSideStageFocusedApplication(application); |
869 | return; |
870 | } |
871 | } |
872 | @@ -181,14 +228,12 @@ |
873 | if (stageHint == SideStage) { |
874 | if (m_sideStageFocusedApplication) { |
875 | m_sideStageFocusedApplication->hideWindow(); |
876 | - m_sideStageFocusedApplication = 0; |
877 | - Q_EMIT sideStageFocusedApplicationChanged(); |
878 | + setSideStageFocusedApplication(0); |
879 | } |
880 | } else { |
881 | if (m_mainStageFocusedApplication) { |
882 | m_mainStageFocusedApplication->hideWindow(); |
883 | - m_mainStageFocusedApplication = 0; |
884 | - Q_EMIT mainStageFocusedApplicationChanged(); |
885 | + setMainStageFocusedApplication(0); |
886 | } |
887 | } |
888 | } |
889 | @@ -384,11 +429,7 @@ |
890 | |
891 | void ApplicationManager::createMainStageComponent() |
892 | { |
893 | - // The assumptions I make here really should hold. |
894 | - QQuickView *quickView = |
895 | - qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]); |
896 | - |
897 | - QQmlEngine *engine = quickView->engine(); |
898 | + QQmlEngine *engine = m_quickView->engine(); |
899 | |
900 | m_mainStageComponent = new QQmlComponent(engine, this); |
901 | QString mainStageQml = |
902 | @@ -403,11 +444,12 @@ |
903 | |
904 | void ApplicationManager::createMainStage() |
905 | { |
906 | - // The assumptions I make here really should hold. |
907 | - QQuickView *quickView = |
908 | - qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]); |
909 | + Sleeper sleeper; |
910 | + while (m_quickView->status() != QQuickView::Ready) { |
911 | + sleeper.sleep(500); |
912 | + } |
913 | |
914 | - QQuickItem *shell = quickView->rootObject(); |
915 | + QQuickItem *shell = m_quickView->rootObject(); |
916 | |
917 | m_mainStage = qobject_cast<QQuickItem *>(m_mainStageComponent->create()); |
918 | m_mainStage->setParentItem(shell); |
919 | @@ -415,11 +457,7 @@ |
920 | |
921 | void ApplicationManager::createSideStageComponent() |
922 | { |
923 | - // The assumptions I make here really should hold. |
924 | - QQuickView *quickView = |
925 | - qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]); |
926 | - |
927 | - QQmlEngine *engine = quickView->engine(); |
928 | + QQmlEngine *engine = m_quickView->engine(); |
929 | |
930 | m_sideStageComponent = new QQmlComponent(engine, this); |
931 | QString sideStageQml = |
932 | @@ -437,11 +475,12 @@ |
933 | |
934 | void ApplicationManager::createSideStage() |
935 | { |
936 | - // The assumptions I make here really should hold. |
937 | - QQuickView *quickView = |
938 | - qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]); |
939 | + Sleeper sleeper; |
940 | + while (m_quickView->status() != QQuickView::Ready) { |
941 | + sleeper.sleep(500); |
942 | + } |
943 | |
944 | - QQuickItem *shell = quickView->rootObject(); |
945 | + QQuickItem *shell = m_quickView->rootObject(); |
946 | |
947 | m_sideStage = qobject_cast<QQuickItem *>(m_sideStageComponent->create()); |
948 | m_sideStage->setParentItem(shell); |
949 | |
950 | === modified file 'tests/mocks/Ubuntu/Application/ApplicationManager.h' |
951 | --- tests/mocks/Ubuntu/Application/ApplicationManager.h 2013-06-05 22:03:08 +0000 |
952 | +++ tests/mocks/Ubuntu/Application/ApplicationManager.h 2013-06-13 14:42:44 +0000 |
953 | @@ -24,6 +24,8 @@ |
954 | #include "ApplicationInfo.h" |
955 | |
956 | class QQuickItem; |
957 | +class QQuickView; |
958 | +class QEvent; |
959 | |
960 | class ApplicationManager : public QObject { |
961 | Q_OBJECT |
962 | @@ -95,6 +97,12 @@ |
963 | void sideStageFocusedApplicationChanged(); |
964 | void focusRequested(FavoriteApplication favoriteApplication); |
965 | |
966 | +protected: |
967 | + bool eventFilter(QObject *, QEvent *); |
968 | + |
969 | + void setMainStageFocusedApplication(ApplicationInfo *); |
970 | + void setSideStageFocusedApplication(ApplicationInfo *); |
971 | + |
972 | private: |
973 | void showApplicationWindow(ApplicationInfo *application); |
974 | void buildListOfAvailableApplications(); |
975 | @@ -114,6 +122,7 @@ |
976 | QQuickItem *m_mainStage; |
977 | QQmlComponent *m_sideStageComponent; |
978 | QQuickItem *m_sideStage; |
979 | + QQuickView *m_quickView; |
980 | }; |
981 | |
982 | Q_DECLARE_OPERATORS_FOR_FLAGS(ApplicationManager::ExecFlags) |
983 | |
984 | === modified file 'tests/qmltests/CMakeLists.txt' |
985 | --- tests/qmltests/CMakeLists.txt 2013-06-12 16:10:47 +0000 |
986 | +++ tests/qmltests/CMakeLists.txt 2013-06-13 14:42:44 +0000 |
987 | @@ -32,9 +32,6 @@ |
988 | add_qml_test(Components ResponsiveGridView) |
989 | add_qml_test(Components Revealer) |
990 | add_qml_test(Components Showable) |
991 | -add_qml_test(Components Stage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} |
992 | - ${CMAKE_BINARY_DIR}/tests/mocks |
993 | - ${CMAKE_BINARY_DIR}/plugins) |
994 | add_qml_test(Components Tile) |
995 | add_qml_test(Components PageHeader) |
996 | add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}) |
997 | @@ -67,6 +64,7 @@ |
998 | add_qml_test(Panel Panel) |
999 | add_qml_test(Panel SearchIndicator) |
1000 | add_qml_test(Panel/Menus IndicatorMenuWindow IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}) |
1001 | -add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} |
1002 | - ${CMAKE_BINARY_DIR}/tests/mocks |
1003 | - ${CMAKE_BINARY_DIR}/plugins) |
1004 | +add_qml_test(Stages Stage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks ${CMAKE_BINARY_DIR}/plugins) |
1005 | +add_qml_test(Stages StageManager-phone IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks ${CMAKE_BINARY_DIR}/plugins) |
1006 | +add_qml_test(Stages StageManager-tablet IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks ${CMAKE_BINARY_DIR}/plugins) |
1007 | +add_qml_test(Stages SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks ${CMAKE_BINARY_DIR}/plugins) |
1008 | |
1009 | === modified file 'tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml' |
1010 | --- tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml 2013-06-05 22:03:08 +0000 |
1011 | +++ tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml 2013-06-13 14:42:44 +0000 |
1012 | @@ -128,6 +128,7 @@ |
1013 | compare(runningApplicationsGrid.terminationModeEnabled, false) |
1014 | |
1015 | isCalendarLongPressed = false |
1016 | + waitForRendering(runningApplicationsGrid) |
1017 | mousePress(calendarTile, calendarTile.width/2, calendarTile.height/2) |
1018 | tryCompareFunction(checkSwitchToTerminationModeAfterLongPress, true) |
1019 | |
1020 | @@ -186,6 +187,7 @@ |
1021 | verify(calendarTile != undefined) |
1022 | |
1023 | verify(fakeRunningAppsModel.contains(calendarApp)) |
1024 | + waitForRendering(runningApplicationsGrid) //ensure populating animation has stopped |
1025 | |
1026 | mouseClick(calendarTile, calendarTile.width/2, calendarTile.height/2) |
1027 | |
1028 | |
1029 | === removed directory 'tests/qmltests/SideStage' |
1030 | === added directory 'tests/qmltests/Stages' |
1031 | === renamed file 'tests/qmltests/SideStage/tst_SideStage.qml' => 'tests/qmltests/Stages/tst_SideStage.qml' |
1032 | --- tests/qmltests/SideStage/tst_SideStage.qml 2013-06-05 22:03:08 +0000 |
1033 | +++ tests/qmltests/Stages/tst_SideStage.qml 2013-06-13 14:42:44 +0000 |
1034 | @@ -18,7 +18,7 @@ |
1035 | import QtTest 1.0 |
1036 | import Unity.Test 0.1 as UT |
1037 | import ".." |
1038 | -import "../../../SideStage" |
1039 | +import "../../../Stages" |
1040 | import Ubuntu.Components 0.1 |
1041 | |
1042 | UT.UnityTestCase { |
1043 | |
1044 | === renamed directory 'tests/qmltests/Components/tst_Stage' => 'tests/qmltests/Stages/tst_Stage' |
1045 | === renamed file 'tests/qmltests/Components/tst_Stage.qml' => 'tests/qmltests/Stages/tst_Stage.qml' |
1046 | --- tests/qmltests/Components/tst_Stage.qml 2013-06-10 16:50:18 +0000 |
1047 | +++ tests/qmltests/Stages/tst_Stage.qml 2013-06-13 14:42:44 +0000 |
1048 | @@ -17,7 +17,7 @@ |
1049 | import QtQuick 2.0 |
1050 | import QtTest 1.0 |
1051 | import ".." |
1052 | -import "../../../Components" |
1053 | +import "../../../Stages" |
1054 | import Ubuntu.Application 0.1 |
1055 | import Ubuntu.Components 0.1 |
1056 | import Unity.Test 0.1 as UT |
1057 | |
1058 | === added directory 'tests/qmltests/Stages/tst_StageManager' |
1059 | === added file 'tests/qmltests/Stages/tst_StageManager-phone.qml' |
1060 | --- tests/qmltests/Stages/tst_StageManager-phone.qml 1970-01-01 00:00:00 +0000 |
1061 | +++ tests/qmltests/Stages/tst_StageManager-phone.qml 2013-06-13 14:42:44 +0000 |
1062 | @@ -0,0 +1,255 @@ |
1063 | +/* |
1064 | + * Copyright 2013 Canonical Ltd. |
1065 | + * |
1066 | + * This program is free software; you can redistribute it and/or modify |
1067 | + * it under the terms of the GNU General Public License as published by |
1068 | + * the Free Software Foundation; version 3. |
1069 | + * |
1070 | + * This program is distributed in the hope that it will be useful, |
1071 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1072 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1073 | + * GNU General Public License for more details. |
1074 | + * |
1075 | + * You should have received a copy of the GNU General Public License |
1076 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1077 | + */ |
1078 | + |
1079 | +import QtQuick 2.0 |
1080 | +import Ubuntu.Application 0.1 |
1081 | +import "../../../Stages" |
1082 | +import "../../../Components" |
1083 | +import "tst_StageManager" |
1084 | + |
1085 | +Item { |
1086 | + id: root |
1087 | + width: units.gu(40) |
1088 | + height: units.gu(72) |
1089 | + |
1090 | + property var applicationManager: ApplicationManagerWrapper {} |
1091 | + |
1092 | + Rectangle { //fake background |
1093 | + anchors.fill: parent |
1094 | + color: "black" |
1095 | + visible: stageManager.needUnderlay |
1096 | + } |
1097 | + |
1098 | + StageManager { |
1099 | + id: stageManager |
1100 | + |
1101 | + anchors.fill: parent |
1102 | + |
1103 | + applicationManager: root.applicationManager |
1104 | + leftSwipePosition: 0 |
1105 | + panelHeight: units.gu(3) + units.dp(2) |
1106 | + edgeHandleSize: units.gu(2) |
1107 | + enabled: true |
1108 | + } |
1109 | + |
1110 | + ListSelector { |
1111 | + id: applications |
1112 | + anchors { |
1113 | + left: parent.left |
1114 | + right: parent.right |
1115 | + bottom: parent.bottom |
1116 | + } |
1117 | + |
1118 | + list: ["phone-app", "gallery-app", "camera-app"] |
1119 | + onActivated: stageManager.activateApplication(desktopFileOf(entry)) |
1120 | + onDeactivated: applicationManager.stopProcess(applicationManager.getApplicationFromDesktopFile(desktopFileOf(entry))) |
1121 | + } |
1122 | + |
1123 | + function desktopFileOf(entry) { |
1124 | + return "/usr/share/applications/" + entry + ".desktop" |
1125 | + } |
1126 | + |
1127 | + StageManagerTestCase { |
1128 | + name: "StageManager - phone - 0 window case" |
1129 | + when: windowShown |
1130 | + stageManagerUnderTest: stageManager |
1131 | + |
1132 | + // left swipe does nothing when no applications open |
1133 | + function test_leftEdgeSwipeDisabledWithNoApplicationsOpen() { |
1134 | + rightEdgeSwipe() |
1135 | + checkStageManagerOffScreen() |
1136 | + } |
1137 | + |
1138 | + function test_stageManagerOffScreenByDefault() { |
1139 | + checkStageManagerOffScreen() |
1140 | + } |
1141 | + } |
1142 | + |
1143 | + StageManagerTestCase { |
1144 | + name: "StageManager - phone - 1 window case" |
1145 | + when: windowShown |
1146 | + stageManagerUnderTest: stageManager |
1147 | + |
1148 | + function init() { |
1149 | + applications.activate("phone-app") |
1150 | + waitForAnimationsToFinish() |
1151 | + } |
1152 | + |
1153 | + // When application started and StageManager hidden, StageManager shows immediately |
1154 | + function test_onLaunchStageManagerShown() { |
1155 | + checkStageManagerOnScreen() |
1156 | + } |
1157 | + |
1158 | + // Left-edge swipe the StageManager away animates the StageManager away |
1159 | + function test_leftSwipeHidesStageManager() { |
1160 | + leftEdgeSwipe() |
1161 | + checkStageManagerOffScreen() |
1162 | + } |
1163 | + |
1164 | + // Left-edge swipe the StageManager away unfocuses the application |
1165 | + function test_leftSwipeUnfocusesApplication() { |
1166 | + leftEdgeSwipe() |
1167 | + checkStageManagerOffScreen() |
1168 | + |
1169 | + skip("FIXME: mainStageFocusedApplication not updated when application unfocused, see lp:1186980") |
1170 | + tryCompare(applicationManager, "mainStageFocusedApplication", null) |
1171 | + } |
1172 | + |
1173 | + // Left-edge swipe StageManager away. Right-edge swipe should restore it |
1174 | + function test_rightSwipeRestoresApplication() { |
1175 | + leftEdgeSwipe() |
1176 | + checkStageManagerOffScreen() |
1177 | + |
1178 | + rightEdgeSwipe() |
1179 | + checkStageManagerOnScreen() |
1180 | + |
1181 | + waitForAnimationsToFinish() |
1182 | + |
1183 | + tryCompare(applicationManager.mainStageFocusedApplication, "desktopFile", |
1184 | + desktopFileOf("phone-app")) |
1185 | + } |
1186 | + |
1187 | + // Activate application. Left-edge swipe stages away. Use launcher to activate application |
1188 | + // again - the StageManager should slide in and focus application |
1189 | + function test_activateApplicationWhenStageHiddenRevealsApplication() { |
1190 | + leftEdgeSwipe() |
1191 | + checkStageManagerOffScreen() |
1192 | + |
1193 | + applications.activate("phone-app") |
1194 | + checkStageManagerOnScreen() |
1195 | + |
1196 | + waitForAnimationsToFinish() |
1197 | + |
1198 | + tryCompare(applicationManager.mainStageFocusedApplication, "desktopFile", |
1199 | + desktopFileOf("phone-app")) |
1200 | + } |
1201 | + |
1202 | + // Kill focused application. StageManager should hide |
1203 | + function test_killingApplicationShouldHideStageManager() { |
1204 | + applications.deactivate("phone-app") |
1205 | + |
1206 | + checkStageManagerOffScreen() |
1207 | + } |
1208 | + |
1209 | + // Starting a second app while StageManager on-screen does nothing to StageManager |
1210 | + function test_openingSecondAppWhileStageManagerOnScreen(){ |
1211 | + applications.activate("gallery-app") |
1212 | + |
1213 | + checkStageManagerOnScreen() |
1214 | + |
1215 | + waitForAnimationsToFinish() |
1216 | + |
1217 | + tryCompare(applicationManager.mainStageFocusedApplication, "desktopFile", |
1218 | + desktopFileOf("gallery-app")) |
1219 | + } |
1220 | + |
1221 | + // Starting a second app while StageManager off-screen shows StageManager |
1222 | + function test_openingSecondAppWhileStageManagerOffScreen(){ |
1223 | + leftEdgeSwipe() |
1224 | + |
1225 | + applications.activate("gallery-app") |
1226 | + checkStageManagerOnScreen() |
1227 | + |
1228 | + waitForAnimationsToFinish() |
1229 | + |
1230 | + tryCompare(applicationManager.mainStageFocusedApplication, "desktopFile", |
1231 | + desktopFileOf("gallery-app")) |
1232 | + } |
1233 | + |
1234 | + // Application focus change after animations complete |
1235 | + function test_onLaunchApplicationGetsFocusedOnlyAfterAnimation() { |
1236 | + applications.activate("gallery-app") |
1237 | + |
1238 | + verify(applicationManager.mainStageFocusedApplication.desktopFile !== desktopFileOf("gallery-app")) |
1239 | + |
1240 | + waitForAnimationsToFinish() |
1241 | + |
1242 | + compare(applicationManager.mainStageFocusedApplication.desktopFile, desktopFileOf("gallery-app"), |
1243 | + "Focus not on newly activated application after animation") |
1244 | + } |
1245 | + } |
1246 | + |
1247 | + StageManagerTestCase { |
1248 | + name: "StageManager - phone - 2 window case" |
1249 | + when: windowShown |
1250 | + stageManagerUnderTest: stageManager |
1251 | + |
1252 | + function init() { |
1253 | + applications.activate("phone-app") |
1254 | + applications.activate("camera-app") |
1255 | + waitForAnimationsToFinish() |
1256 | + } |
1257 | + |
1258 | + function test_focusOrder() { |
1259 | + compare(applicationManager.mainStageFocusedApplication.desktopFile, desktopFileOf("camera-app"), |
1260 | + "Focus not on last launched application") |
1261 | + } |
1262 | + |
1263 | + // Check hiding and then revealing StageManager doesn't change the focus order |
1264 | + function test_focusOrderAfterUnfocus() { |
1265 | + leftEdgeSwipe() |
1266 | + |
1267 | + rightEdgeSwipe() |
1268 | + waitForAnimationsToFinish() |
1269 | + |
1270 | + compare(applicationManager.mainStageFocusedApplication.desktopFile, desktopFileOf("camera-app"), |
1271 | + "Focus order changed somehow by hide/reveal of StageManager") |
1272 | + } |
1273 | + |
1274 | + // Check that a hidden StageManager reacts correctly when background application activated |
1275 | + function test_focusOrderWhenActivating() { |
1276 | + leftEdgeSwipe() |
1277 | + |
1278 | + applications.activate("phone-app") |
1279 | + |
1280 | + waitForAnimationsToFinish() |
1281 | + checkStageManagerOnScreen() |
1282 | + |
1283 | + tryCompare(applicationManager.mainStageFocusedApplication, "desktopFile", desktopFileOf("phone-app")) |
1284 | + |
1285 | + compare(applicationManager.mainStageFocusedApplication.desktopFile, desktopFileOf("phone-app"), |
1286 | + "Focus not on newly activated application when StageManager hidden") |
1287 | + } |
1288 | + |
1289 | + // If the focused application dies, the StageManager should hide |
1290 | + function test_foregroundApplicationDeathDismissesStageManager() { |
1291 | + tryCompare(applicationManager.mainStageFocusedApplication, "desktopFile", desktopFileOf("camera-app")) |
1292 | + |
1293 | + skip("FIXME: StageManager does not hide when foreground application dies") |
1294 | + applications.deactivate("camera-app") |
1295 | + |
1296 | + checkStageManagerOffScreen() |
1297 | + } |
1298 | + |
1299 | + // If a background application dies, the StageManager should not react |
1300 | + function test_nonForegroundApplicationDeathDoesNothing() { |
1301 | + tryCompare(applicationManager.mainStageFocusedApplication, "desktopFile", desktopFileOf("camera-app")) |
1302 | + applications.deactivate("phone-app") |
1303 | + |
1304 | + checkStageManagerOnScreen() |
1305 | + } |
1306 | + |
1307 | + function test_fullScreenMode() { |
1308 | + tryCompare(applicationManager.mainStageFocusedApplication, "desktopFile", desktopFileOf("camera-app")) |
1309 | + |
1310 | + tryCompare(stageManager, "fullscreenMode", true) |
1311 | + |
1312 | + rightEdgeSwipe() |
1313 | + |
1314 | + tryCompare(stageManager, "fullscreenMode", false) |
1315 | + } |
1316 | + } |
1317 | +} |
1318 | |
1319 | === added file 'tests/qmltests/Stages/tst_StageManager-tablet.qml' |
1320 | --- tests/qmltests/Stages/tst_StageManager-tablet.qml 1970-01-01 00:00:00 +0000 |
1321 | +++ tests/qmltests/Stages/tst_StageManager-tablet.qml 2013-06-13 14:42:44 +0000 |
1322 | @@ -0,0 +1,394 @@ |
1323 | +/* |
1324 | + * Copyright 2013 Canonical Ltd. |
1325 | + * |
1326 | + * This program is free software; you can redistribute it and/or modify |
1327 | + * it under the terms of the GNU General Public License as published by |
1328 | + * the Free Software Foundation; version 3. |
1329 | + * |
1330 | + * This program is distributed in the hope that it will be useful, |
1331 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1332 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1333 | + * GNU General Public License for more details. |
1334 | + * |
1335 | + * You should have received a copy of the GNU General Public License |
1336 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1337 | + */ |
1338 | + |
1339 | +import QtQuick 2.0 |
1340 | +import Ubuntu.Application 0.1 |
1341 | +import "../../../Stages" |
1342 | +import "../../../Components" |
1343 | +import "tst_StageManager" |
1344 | + |
1345 | +Item { |
1346 | + id: root |
1347 | + width: units.gu(100) |
1348 | + height: units.gu(72) |
1349 | + |
1350 | + property var applicationManager: ApplicationManagerWrapper {} |
1351 | + |
1352 | + Rectangle { //fake background |
1353 | + anchors.fill: parent |
1354 | + color: "black" |
1355 | + visible: stageManager.needUnderlay |
1356 | + } |
1357 | + |
1358 | + StageManager { |
1359 | + id: stageManager |
1360 | + |
1361 | + anchors.fill: parent |
1362 | + |
1363 | + applicationManager: root.applicationManager |
1364 | + leftSwipePosition: 0 |
1365 | + panelHeight: units.gu(3) + units.dp(2) |
1366 | + edgeHandleSize: units.gu(2) |
1367 | + enabled: true |
1368 | + } |
1369 | + |
1370 | + ListSelector { |
1371 | + id: applications |
1372 | + anchors { |
1373 | + left: parent.left |
1374 | + right: parent.right |
1375 | + bottom: parent.bottom |
1376 | + } |
1377 | + |
1378 | + list: ["phone-app", "facebook-webapp", "gallery-app"] |
1379 | + onActivated: stageManager.activateApplication(desktopFileOf(entry)) |
1380 | + onDeactivated: applicationManager.stopProcess(applicationManager.getApplicationFromDesktopFile(desktopFileOf(entry))) |
1381 | + } |
1382 | + |
1383 | + function desktopFileOf(entry) { |
1384 | + return "/usr/share/applications/" + entry + ".desktop" |
1385 | + } |
1386 | + |
1387 | + StageManagerTestCase { |
1388 | + name: "StageManager - tablet - 1 main-stage window case" |
1389 | + when: windowShown |
1390 | + stageManagerUnderTest: stageManager |
1391 | + |
1392 | + function init() { |
1393 | + applications.activate("gallery-app") //main-stage app |
1394 | + waitForAnimationsToFinish() |
1395 | + } |
1396 | + |
1397 | + // Right-edge press does not change main-stage app |
1398 | + function test_rightEdgeSwipeDoesNotChangeMainStageApp() { |
1399 | + rightEdgePress() |
1400 | + waitForRendering(stageManager) |
1401 | + compare(mainStage.oldApplicationScreenshot.visible, false) // i.e. no screenshot animation occurs |
1402 | + } |
1403 | + } |
1404 | + |
1405 | + StageManagerTestCase { |
1406 | + name: "StageManager - tablet - 1 side-stage window case" |
1407 | + when: windowShown |
1408 | + stageManagerUnderTest: stageManager |
1409 | + |
1410 | + function init() { |
1411 | + applications.activate("phone-app") // side-stage app |
1412 | + waitForAnimationsToFinish() |
1413 | + } |
1414 | + |
1415 | + // Check loaded as side-stage application |
1416 | + function test_sideStage() { |
1417 | + tryCompare(applicationManager.sideStageFocusedApplication, "desktopFile", desktopFileOf("phone-app")) |
1418 | + compare(applicationManager.mainStageFocusedApplication, null) |
1419 | + } |
1420 | + |
1421 | + // When application started and StageManager hidden, StageManager shows immediately |
1422 | + function test_onLaunchStageManagerShown() { |
1423 | + checkStageManagerOnScreen() |
1424 | + } |
1425 | + |
1426 | + // Check side-stage positioned correctly |
1427 | + function test_sideStagePositionedCorrectly() { |
1428 | + compare(sideStage.x, stageManager.width - units.gu(40), "Sidestage not positioned correctly") |
1429 | + } |
1430 | + |
1431 | + // Left-edge swipe the StageManager away animates the StageManager away |
1432 | + function test_leftSwipeHidesStageManager() { |
1433 | + leftEdgeSwipe() |
1434 | + checkStageManagerOffScreen() |
1435 | + } |
1436 | + |
1437 | + // Left-edge swipe the StageManager away unfocuses the application |
1438 | + function test_leftSwipeUnfocusesApplication() { |
1439 | + leftEdgeSwipe() |
1440 | + checkStageManagerOffScreen() |
1441 | + |
1442 | + skip("FIXME: sideStageFocusedApplication not updated when application unfocused, see lp:1186980") |
1443 | + tryCompare(applicationManager, "sideStageFocusedApplication", null) |
1444 | + } |
1445 | + |
1446 | + // Left-edge swipe StageManager away. Right-edge swipe should restore it |
1447 | + function test_rightSwipeRestoresApplication() { |
1448 | + leftEdgeSwipe() |
1449 | + checkStageManagerOffScreen() |
1450 | + |
1451 | + rightEdgeSwipe() |
1452 | + checkStageManagerOnScreen() |
1453 | + |
1454 | + waitForAnimationsToFinish() |
1455 | + |
1456 | + tryCompare(applicationManager.sideStageFocusedApplication, "desktopFile", desktopFileOf("phone-app")) |
1457 | + } |
1458 | + |
1459 | + // Activate application. Left-edge swipe stages away. Use launcher to activate application |
1460 | + // again - the StageManager should slide in and focus application |
1461 | + function test_activateApplicationWhenStageHiddenRevealsApplication() { |
1462 | + leftEdgeSwipe() |
1463 | + checkStageManagerOffScreen() |
1464 | + |
1465 | + applications.activate("phone-app") |
1466 | + checkStageManagerOnScreen() |
1467 | + |
1468 | + waitForAnimationsToFinish() |
1469 | + |
1470 | + tryCompare(applicationManager.sideStageFocusedApplication, "desktopFile", desktopFileOf("phone-app")) |
1471 | + } |
1472 | + |
1473 | + // Kill focused application. StageManager should hide |
1474 | + function test_killingApplicationShouldHideStageManager() { |
1475 | + applications.deactivate("phone-app") |
1476 | + |
1477 | + checkStageManagerOffScreen() |
1478 | + } |
1479 | + |
1480 | + // Starting a second side-stage app while StageManager on-screen does nothing to StageManager |
1481 | + function test_openingSecondSideStageAppWhileStageManagerOnScreen(){ |
1482 | + applications.activate("facebook-webapp") //side-stage app |
1483 | + checkStageManagerOnScreen() |
1484 | + |
1485 | + waitForAnimationsToFinish() |
1486 | + tryCompare(applicationManager.sideStageFocusedApplication, "desktopFile", desktopFileOf("facebook-webapp")) |
1487 | + } |
1488 | + |
1489 | + // Starting a second side-stage app while StageManager off-screen shows StageManager |
1490 | + function test_openingSecondSideStageAppWhileStageManagerOffScreen(){ |
1491 | + leftEdgeSwipe() |
1492 | + |
1493 | + applications.activate("facebook-webapp") //side-stage app |
1494 | + checkStageManagerOnScreen() |
1495 | + |
1496 | + waitForAnimationsToFinish() |
1497 | + tryCompare(applicationManager.sideStageFocusedApplication, "desktopFile", desktopFileOf("facebook-webapp")) |
1498 | + } |
1499 | + |
1500 | + |
1501 | + // Starting a main-stage app while StageManager off-screen shows StageManager |
1502 | + function test_openingMainStageAppWhileStageManagerOffScreen(){ |
1503 | + leftEdgeSwipe() |
1504 | + checkStageManagerOffScreen() |
1505 | + |
1506 | + applications.activate("gallery-app") //main-stage app |
1507 | + checkStageManagerOnScreen() |
1508 | + |
1509 | + waitForAnimationsToFinish() |
1510 | + tryCompare(applicationManager.mainStageFocusedApplication, "desktopFile", desktopFileOf("gallery-app")) |
1511 | + } |
1512 | + |
1513 | + // Application focus change after animations complete |
1514 | + function test_onLaunchApplicationGetsFocusedOnlyAfterAnimation() { |
1515 | + applications.activate("facebook-webapp") //side-stage app |
1516 | + |
1517 | + verify(applicationManager.sideStageFocusedApplication.desktopFile !== desktopFileOf("facebook-webapp")) |
1518 | + |
1519 | + waitForAnimationsToFinish() |
1520 | + compare(applicationManager.sideStageFocusedApplication.desktopFile, desktopFileOf("facebook-webapp"), |
1521 | + "Newly activated application does not have focus after animation") |
1522 | + } |
1523 | + |
1524 | + // Right-edge press changes side-stage app |
1525 | + function test_rightEdgeSwipeChangesSideStageOnly() { |
1526 | + rightEdgePress() |
1527 | + tryCompareFunction( function() { |
1528 | + return sideStage.oldApplicationScreenshot.scale < 1 |
1529 | + }, true) |
1530 | + } |
1531 | + |
1532 | + // Right-swipe of side-stage handle does nothing |
1533 | + function test_rightSwipeOfSideStageHandleDoesNothing() { |
1534 | + sideStageHandleRightSwipe() |
1535 | + |
1536 | + compare(sideStage.x, stageManager.width - units.gu(40), |
1537 | + "Side-stage was incorrectly dismissed when no main-stage application open") |
1538 | + } |
1539 | + } |
1540 | + |
1541 | + StageManagerTestCase { |
1542 | + name: "StageManager - tablet - 1 side-stage & 1 main-stage window case" |
1543 | + when: windowShown |
1544 | + stageManagerUnderTest: stageManager |
1545 | + |
1546 | + function init() { |
1547 | + applications.activate("gallery-app") //main-stage app |
1548 | + applications.activate("phone-app") //side-stage app |
1549 | + waitForAnimationsToFinish() |
1550 | + } |
1551 | + |
1552 | + function test_focusOrder() { |
1553 | + compare(applicationManager.mainStageFocusedApplication.desktopFile, desktopFileOf("gallery-app"), |
1554 | + "Main-stage application not got focus after activation") |
1555 | + compare(applicationManager.sideStageFocusedApplication.desktopFile, desktopFileOf("phone-app"), |
1556 | + "Side-stage application not got focus after activation") |
1557 | + } |
1558 | + |
1559 | + // Check hiding and then revealing StageManager doesn't change the focus order |
1560 | + function test_focusOrderAfterUnfocus() { |
1561 | + leftEdgeSwipe() |
1562 | + |
1563 | + rightEdgeSwipe() |
1564 | + waitForAnimationsToFinish() |
1565 | + |
1566 | + compare(applicationManager.mainStageFocusedApplication.desktopFile, desktopFileOf("gallery-app"), |
1567 | + "Main-stage application lost focus from StageManager hide/show") |
1568 | + compare(applicationManager.sideStageFocusedApplication.desktopFile, desktopFileOf("phone-app"), |
1569 | + "Side-stage application lost focus from StageManager hide/show") |
1570 | + } |
1571 | + |
1572 | + // Check that a hidden StageManager reacts correctly when already-open side-stage application activated |
1573 | + function test_focusOrderWhenActivatingSideStage() { |
1574 | + leftEdgeSwipe() |
1575 | + |
1576 | + applications.activate("phone-app") //side-stage app |
1577 | + |
1578 | + checkStageManagerOnScreen() |
1579 | + } |
1580 | + |
1581 | + // Check that a hidden StageManager reacts correctly when already-open main-stage application activated |
1582 | + function test_focusOrderWhenActivatingMainStage() { |
1583 | + leftEdgeSwipe() |
1584 | + |
1585 | + applications.activate("gallery-app") //main-stage app |
1586 | + |
1587 | + checkStageManagerOnScreen() |
1588 | + } |
1589 | + |
1590 | + // If the main-stage application dies, the StageManager should stay on screen |
1591 | + function test_foregroundMainStageApplicationDeathDoesNothing() { |
1592 | + applications.deactivate("gallery-app") //main-stage app |
1593 | + |
1594 | + checkStageManagerOnScreen() |
1595 | + compare(applicationManager.sideStageFocusedApplication.desktopFile, desktopFileOf("phone-app"), |
1596 | + "Side-stage application lost focus after main-stage application died") |
1597 | + } |
1598 | + |
1599 | + // If the side-stage application dies, the StageManager should stay on screen |
1600 | + function test_foregroundSideStageApplicationDeathDoesNothing() { |
1601 | + applications.deactivate("phone-app") //side-stage app |
1602 | + |
1603 | + checkStageManagerOnScreen() |
1604 | + compare(applicationManager.mainStageFocusedApplication.desktopFile, desktopFileOf("gallery-app"), |
1605 | + "Main-stage application lost focus after side-stage application died") |
1606 | + } |
1607 | + |
1608 | + // If the side-stage application dies, the side stage should hide |
1609 | + function test_foregroundSideStageApplicationDeathHidesSideStage() { |
1610 | + applications.deactivate("phone-app") //side-stage app |
1611 | + |
1612 | + tryCompareFunction( function() { |
1613 | + return sideStage.x > stageManager.width |
1614 | + }, true) |
1615 | + } |
1616 | + |
1617 | + // Right-edge swipe changes side-stage app |
1618 | + function test_rightEdgeSwipeChangesSideStage() { |
1619 | + tryCompare(sideStage, "x", stageManager.width - sideStage.width) //ensure side-stage open |
1620 | + |
1621 | + waitForAnimationsToFinish() |
1622 | + rightEdgePress() |
1623 | + waitForRendering(stageManager) |
1624 | + tryCompareFunction( function() { |
1625 | + return sideStage.oldApplicationScreenshot.scale < 1 |
1626 | + }, true) |
1627 | + } |
1628 | + |
1629 | + // Right-edge swipe does not change main-stage app |
1630 | + function test_rightEdgeSwipeDoesNotChangeMainStage() { |
1631 | + rightEdgePress() |
1632 | + waitForRendering(stageManager) |
1633 | + compare(mainStage.oldApplicationScreenshot.scale, 1, |
1634 | + "Right-edge swipe animating main-stage while side-stage app open") |
1635 | + } |
1636 | + |
1637 | + // Right-swipe of side-stage handle dismisses side-stage |
1638 | + function test_rightSwipeOfSideStageHandleHidesSideStage() { |
1639 | + sideStageHandleRightSwipe() |
1640 | + waitForAnimationsToFinish() |
1641 | + |
1642 | + tryCompare(sideStage, "x", stageManager.width + sideStage.handleSizeCollapsed) |
1643 | + } |
1644 | + |
1645 | + // Right-swipe of side-stage unfocuses side-stage app |
1646 | + function test_rightSwipeOfSideStageHandleUnfocusesSideStageApp() { |
1647 | + tryCompare(sideStage, "x", stageManager.width - sideStage.width) //ensure side-stage open |
1648 | + |
1649 | + sideStageHandleRightSwipe() |
1650 | + waitForAnimationsToFinish() |
1651 | + |
1652 | + compare(applicationManager.mainStageFocusedApplication.desktopFile, desktopFileOf("gallery-app"), |
1653 | + "Right-edge swipe of side-stage app changed main-stage focus") |
1654 | + skip("FIXME: sideStageFocusedApplication not updated when application unfocused, see lp:1186980") |
1655 | + //tryCompare(applicationManager, "sideStageFocusedApplication", null) |
1656 | + } |
1657 | + |
1658 | + // Hidden side-stage can be right-edge swiped back |
1659 | + function test_rightEdgeSwipeRestoresHiddenSideStageApp() { |
1660 | + sideStageHandleRightSwipe() |
1661 | + waitForAnimationsToFinish() |
1662 | + |
1663 | + rightEdgeSwipe() |
1664 | + waitForAnimationsToFinish() |
1665 | + |
1666 | + tryCompare(sideStage, "x", stageManager.width - units.gu(40)) |
1667 | + } |
1668 | + |
1669 | + // Hidden side-stage app when right-edge swiped has focus restored |
1670 | + function test_rightEdgeSwipeRestoresFocusToSideStageApp() { |
1671 | + sideStageHandleRightSwipe() |
1672 | + waitForAnimationsToFinish() |
1673 | + |
1674 | + rightEdgeSwipe() |
1675 | + waitForAnimationsToFinish() |
1676 | + |
1677 | + compare(applicationManager.sideStageFocusedApplication.desktopFile, desktopFileOf("phone-app"), |
1678 | + "Side-stage app not returned focus after StageManager un-hidden") |
1679 | + compare(applicationManager.mainStageFocusedApplication.desktopFile, desktopFileOf("gallery-app"), |
1680 | + "Main-stage app not returned focus after StageManager un-hidden") |
1681 | + } |
1682 | + |
1683 | + // Hide side-stage, then activate the side-stage application. It should slide back in |
1684 | + function test_activatingHiddenSideStageAppSlidesItIn() { |
1685 | + sideStageHandleRightSwipe() |
1686 | + waitForAnimationsToFinish() |
1687 | + |
1688 | + applications.activate("phone-app") //side-stage app |
1689 | + waitForAnimationsToFinish() |
1690 | + |
1691 | + tryCompare(sideStage, "x", stageManager.width - sideStage.width) |
1692 | + } |
1693 | + |
1694 | + // Hide side-stage, then left-swipe to hide whole StageManager. Activate side-stage app |
1695 | + // StageManager should slide in, with side-stage app fixed in place (i.e. not sliding independently) |
1696 | + function test_activatingHiddenSideStageAppWhenStageManagerHidden() { |
1697 | + sideStageHandleRightSwipe() |
1698 | + waitForAnimationsToFinish() |
1699 | + |
1700 | + leftEdgeSwipe(units.gu(160)) |
1701 | + checkStageManagerOffScreen() |
1702 | + |
1703 | + applications.activate("phone-app") //side-stage app |
1704 | + tryCompare(sideStage, "x", stageManager.width - units.gu(40)) |
1705 | + } |
1706 | + |
1707 | + // Starting a main-stage app while StageManager on-screen does nothing to StageManager |
1708 | + function test_openingSecondMainStageAppWhileStageManagerOnScreen(){ |
1709 | + applications.activate("gallery-app") //main-stage app |
1710 | + checkStageManagerOnScreen() |
1711 | + |
1712 | + waitForAnimationsToFinish() |
1713 | + tryCompare(applicationManager.mainStageFocusedApplication, "desktopFile", desktopFileOf("gallery-app")) |
1714 | + } |
1715 | + } |
1716 | +} |
1717 | |
1718 | === added file 'tests/qmltests/Stages/tst_StageManager/ListSelector.qml' |
1719 | --- tests/qmltests/Stages/tst_StageManager/ListSelector.qml 1970-01-01 00:00:00 +0000 |
1720 | +++ tests/qmltests/Stages/tst_StageManager/ListSelector.qml 2013-06-13 14:42:44 +0000 |
1721 | @@ -0,0 +1,101 @@ |
1722 | +/* |
1723 | + * Copyright 2013 Canonical Ltd. |
1724 | + * |
1725 | + * This program is free software; you can redistribute it and/or modify |
1726 | + * it under the terms of the GNU General Public License as published by |
1727 | + * the Free Software Foundation; version 3. |
1728 | + * |
1729 | + * This program is distributed in the hope that it will be useful, |
1730 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1731 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1732 | + * GNU General Public License for more details. |
1733 | + * |
1734 | + * You should have received a copy of the GNU General Public License |
1735 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1736 | + */ |
1737 | + |
1738 | +import QtQuick 2.0 |
1739 | +import Ubuntu.Application 0.1 |
1740 | +import Ubuntu.Components 0.1 |
1741 | + |
1742 | +Rectangle { |
1743 | + id: root |
1744 | + color: "#ccffffff" |
1745 | + height: childrenRect.height |
1746 | + |
1747 | + property alias list: repeater.model |
1748 | + signal activated(string entry) |
1749 | + signal deactivated(string entry) |
1750 | + |
1751 | + function activate(entry) { |
1752 | + lister.changeEntry(entry, true); |
1753 | + } |
1754 | + |
1755 | + function deactivate(entry) { |
1756 | + lister.changeEntry(entry, false); |
1757 | + } |
1758 | + |
1759 | + function deactivateAll() { |
1760 | + for (var i=0; i<list.length; i++) { |
1761 | + lister.changeEntry(list[i], false); |
1762 | + } |
1763 | + } |
1764 | + |
1765 | + Flow { |
1766 | + id: lister |
1767 | + anchors { |
1768 | + top: parent.top |
1769 | + left: parent.left |
1770 | + right: parent.right |
1771 | + } |
1772 | + |
1773 | + function changeEntry(entry, setting) { |
1774 | + for (var i=0; i<lister.children.length; i++) { |
1775 | + var child = lister.children[i]; |
1776 | + if (child === lister) continue; |
1777 | + if (child.label == entry) { |
1778 | + if (child.checked == setting) { |
1779 | + if (setting) root.activated(child.label); //ensure we fire activated again |
1780 | + } else { |
1781 | + child.checked = setting; |
1782 | + } |
1783 | + break; |
1784 | + } |
1785 | + } |
1786 | + } |
1787 | + Repeater { |
1788 | + id: repeater |
1789 | + delegate: entry |
1790 | + } |
1791 | + |
1792 | + Component { |
1793 | + id: entry |
1794 | + |
1795 | + Row { |
1796 | + height: units.gu(5) |
1797 | + width: units.gu(20) |
1798 | + |
1799 | + property alias checked: checkbox.checked |
1800 | + property string label: modelData |
1801 | + |
1802 | + CheckBox { |
1803 | + id: checkbox |
1804 | + onCheckedChanged: { |
1805 | + if (checked) { |
1806 | + activated(modelData) |
1807 | + } else { |
1808 | + deactivated(modelData) |
1809 | + } |
1810 | + } |
1811 | + } |
1812 | + Button { |
1813 | + text: parent.label |
1814 | + width: parent.width - checkbox.width |
1815 | + anchors.verticalCenter: checkbox.verticalCenter |
1816 | + enabled: checkbox.checked |
1817 | + onClicked: activated(modelData) |
1818 | + } |
1819 | + } |
1820 | + } |
1821 | + } |
1822 | +} |
1823 | |
1824 | === added file 'tests/qmltests/Stages/tst_StageManager/StageManagerTestCase.qml' |
1825 | --- tests/qmltests/Stages/tst_StageManager/StageManagerTestCase.qml 1970-01-01 00:00:00 +0000 |
1826 | +++ tests/qmltests/Stages/tst_StageManager/StageManagerTestCase.qml 2013-06-13 14:42:44 +0000 |
1827 | @@ -0,0 +1,98 @@ |
1828 | +/* |
1829 | + * Copyright 2013 Canonical Ltd. |
1830 | + * |
1831 | + * This program is free software; you can redistribute it and/or modify |
1832 | + * it under the terms of the GNU General Public License as published by |
1833 | + * the Free Software Foundation; version 3. |
1834 | + * |
1835 | + * This program is distributed in the hope that it will be useful, |
1836 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1837 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1838 | + * GNU General Public License for more details. |
1839 | + * |
1840 | + * You should have received a copy of the GNU General Public License |
1841 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1842 | + */ |
1843 | + |
1844 | +import QtQuick 2.0 |
1845 | +import QtTest 1.0 |
1846 | +import Unity.Test 0.1 as UT |
1847 | +import "../../../../Stages" |
1848 | + |
1849 | +UT.UnityTestCase { |
1850 | + property StageManager stageManagerUnderTest |
1851 | + property point __lastMouseEvent: Qt.point(-1, -1) |
1852 | + property SideStage sideStage: null |
1853 | + property Stage mainStage: null |
1854 | + |
1855 | + onStageManagerUnderTestChanged: { |
1856 | + mainStage = findChild(stageManagerUnderTest, "mainStage") |
1857 | + sideStage = findChild(stageManagerUnderTest, "sideStage") |
1858 | + } |
1859 | + |
1860 | + function cleanup() { |
1861 | + resetMouseState() |
1862 | + applications.deactivateAll() |
1863 | + compare(applicationManager.mainStageApplications.count, 0, "Some main-stage application failed to quit") |
1864 | + compare(applicationManager.sideStageApplications.count, 0, "Some side-stage application failed to quit") |
1865 | + checkStageManagerOffScreen() |
1866 | + } |
1867 | + |
1868 | + function rightEdgePress() { |
1869 | + __lastMouseEvent.x = stageManagerUnderTest.width - (stageManagerUnderTest.edgeHandleSize / 2) |
1870 | + __lastMouseEvent.y = stageManagerUnderTest.height / 2 |
1871 | + touchPress(stageManagerUnderTest, __lastMouseEvent.x, __lastMouseEvent.y) |
1872 | + } |
1873 | + |
1874 | + function rightEdgeRelease() { |
1875 | + touchRelease(stageManagerUnderTest, __lastMouseEvent.x, __lastMouseEvent.y) |
1876 | + __lastMouseEvent = Qt.point(-1, -1) |
1877 | + } |
1878 | + |
1879 | + function resetMouseState() { |
1880 | + if (__lastMouseEvent !== Qt.point(-1, -1)) { |
1881 | + rightEdgeRelease() |
1882 | + } |
1883 | + } |
1884 | + |
1885 | + function waitForAnimationsToFinish() { |
1886 | + tryCompare(stageManagerUnderTest, "stageScreenshotsReady", false) |
1887 | + } |
1888 | + |
1889 | + function leftEdgeSwipe(distance) { |
1890 | + if (distance == undefined) distance = stageManagerUnderTest.width / 3 * 2 |
1891 | + |
1892 | + var x = stageManagerUnderTest.edgeHandleSize / 2 |
1893 | + var y = stageManagerUnderTest.height / 2 |
1894 | + touchFlick(stageManagerUnderTest, x, y, |
1895 | + x + distance, y) |
1896 | + } |
1897 | + |
1898 | + function rightEdgeSwipe(distance) { |
1899 | + if (distance == undefined) distance = stageManagerUnderTest.width / 3 * 2 |
1900 | + |
1901 | + var x = stageManagerUnderTest.width - (stageManagerUnderTest.edgeHandleSize / 2) |
1902 | + var y = stageManagerUnderTest.height / 2 |
1903 | + touchFlick(stageManagerUnderTest, x, y, |
1904 | + x - distance, y) |
1905 | + } |
1906 | + |
1907 | + function sideStageHandleRightSwipe(distance) { |
1908 | + if (distance == undefined) distance = sideStage.width / 3 * 2 |
1909 | + |
1910 | + var x = sideStage.x - (sideStage.rightEdgeDraggingAreaWidth / 2) |
1911 | + var y = sideStage.height / 2 |
1912 | + touchFlick(stageManagerUnderTest, x, y, |
1913 | + x + distance, y) |
1914 | + } |
1915 | + |
1916 | + function checkStageManagerOffScreen() { |
1917 | + tryCompare(stageManagerUnderTest, "animatedProgress", 0) //0 means off-screen |
1918 | + tryCompare(stageManagerUnderTest, "shown", false) |
1919 | + } |
1920 | + |
1921 | + function checkStageManagerOnScreen() { |
1922 | + tryCompare(stageManagerUnderTest, "animatedProgress", 1) //1 means on-screen |
1923 | + tryCompare(stageManagerUnderTest, "shown", true) |
1924 | + } |
1925 | +} |
FAILED: Continuous integration, rev:706 jenkins. qa.ubuntu. com/job/ unity-phablet- ci/1075/ s-jenkins: 8080/job/ unity-phablet- qmluitests/ 1083/console jenkins. qa.ubuntu. com/job/ unity-phablet- raring- armhf-ci/ 950/console jenkins. qa.ubuntu. com/job/ unity-phablet- raring- i386-ci/ 954/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ unity-phablet- ci/1075/ rebuild
http://