Merge lp:~dandrader/unity8/lifecycle into lp:unity8
- lifecycle
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Michael Zanetti | ||||||||
Approved revision: | 1161 | ||||||||
Merged at revision: | 1201 | ||||||||
Proposed branch: | lp:~dandrader/unity8/lifecycle | ||||||||
Merge into: | lp:unity8 | ||||||||
Diff against target: |
3182 lines (+1502/-760) 40 files modified
debian/control (+3/-3) include/paths.h.in (+8/-0) plugins/Unity/Launcher/CMakeLists.txt (+1/-1) qml/Stages/AppSurfaceContainer.qml (+0/-96) qml/Stages/ApplicationWindow.qml (+258/-0) qml/Stages/PhoneStage.qml (+16/-4) qml/Stages/SpreadDelegate.qml (+34/-59) qml/Stages/SurfaceContainer.qml (+5/-11) qml/Stages/TabletStage.qml (+13/-3) qml/Stages/TransformedSpreadDelegate.qml (+1/-1) tests/mocks/Unity/Application/Application.qmltypes (+0/-19) tests/mocks/Unity/Application/ApplicationImage.cpp (+0/-123) tests/mocks/Unity/Application/ApplicationImage.h (+0/-79) tests/mocks/Unity/Application/ApplicationInfo.cpp (+83/-14) tests/mocks/Unity/Application/ApplicationInfo.h (+52/-46) tests/mocks/Unity/Application/ApplicationManager.cpp (+91/-106) tests/mocks/Unity/Application/ApplicationManager.h (+8/-4) tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp (+2/-4) tests/mocks/Unity/Application/CMakeLists.txt (+1/-3) tests/mocks/Unity/Application/InputFilterArea.qml (+0/-21) tests/mocks/Unity/Application/MirSurfaceItem.cpp (+87/-16) tests/mocks/Unity/Application/MirSurfaceItem.h (+14/-11) tests/mocks/Unity/Application/MirSurfaceItem.qml (+57/-0) tests/mocks/Unity/Application/OSKController.qml (+0/-20) tests/mocks/Unity/Application/SurfaceManager.cpp (+14/-3) tests/mocks/Unity/Application/SurfaceManager.h (+1/-2) tests/mocks/Unity/Application/VirtualKeyboard.cpp (+0/-55) tests/mocks/Unity/Application/VirtualKeyboard.h (+0/-35) tests/mocks/Unity/Application/VirtualKeyboard.qml (+40/-0) tests/mocks/Unity/Application/plugin.cpp (+0/-3) tests/mocks/Unity/Application/qmldir (+0/-3) tests/plugins/Unity/Launcher/CMakeLists.txt (+1/-1) tests/plugins/Unity/Launcher/launchermodeltest.cpp (+0/-1) tests/qmltests/CMakeLists.txt (+3/-0) tests/qmltests/Stages/tst_ApplicationWindow.qml (+346/-0) tests/qmltests/Stages/tst_PhoneStage.qml (+35/-9) tests/qmltests/Stages/tst_SpreadDelegate.qml (+167/-0) tests/qmltests/Stages/tst_SurfaceContainer.qml (+154/-0) tests/qmltests/tst_Shell.qml (+2/-2) tests/utils/modules/Unity/Test/UnityTestCase.qml (+5/-2) |
||||||||
To merge this branch: | bzr merge lp:~dandrader/unity8/lifecycle | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Michael Zanetti (community) | Approve | ||
Michał Sawicz | Approve | ||
Gerry Boland (community) | Needs Information | ||
Review via email: mp+230090@code.launchpad.net |
Commit message
SpreadDelegate - properly transition between splash screen, surface and screenshot
- A new component, ApplicationWindow, was created to hold the
splash+
responsibility of SpreadDelegate is just to do the vertical swipe to close
the app.
- qml tests were added for both SpreadDelegate and ApplicationWindow
- Fixed UnityTestCase.tap()
Description of the change
* Are there any related MPs required for this MP to build/function as expected? Please list.
https:/
https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes.
* Did you make sure that your branch does not contain spurious tags?
Yes.
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Didn't change.
* If you changed the UI, has there been a design review?
Not applicable.
PS Jenkins bot (ps-jenkins) wrote : | # |
Michael Zanetti (mzanetti) wrote : | # |
Fails to build here. Seems you are mixing requirements of unity-shell-
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1141
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
Please run http://
Michael Zanetti (mzanetti) wrote : | # |
see some inline comments.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1142
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
Addressed all review comments (replied inline).
Daniel d'Andrada (dandrader) wrote : | # |
> Please run http://
> this branch and any local checkouts you might have.
Done.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1143
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
The dropshadow doesn't match with the surface's size any more
Michael Zanetti (mzanetti) wrote : | # |
Surface sizes are not correct in tablet mode any more. (In Shell.qml change tablet to true and run make testShell)
Michael Zanetti (mzanetti) wrote : | # |
The surface position in the spread is not correct any more. Surfaces should be aligned on their bottom edge and then scaled so that when reaching the left edge they're all the same size. Currently they are aligned at the top edge and the scaling doesn't work at all
Michael Zanetti (mzanetti) wrote : | # |
replied to your inline replies. Soem very few still open.
Michael Zanetti (mzanetti) wrote : | # |
plugins/
Besides wondering why that even works (shouldn't =1 fail now that we have 3 installed?) I'm also wondering if this what we want.
Saviq?
Michał Sawicz (saviq) wrote : | # |
> plugins/
> while the other places want unity-shell-
>
> Besides wondering why that even works (shouldn't =1 fail now that we have 3
> installed?) I'm also wondering if this what we want.
I think CMake might be caching the output of the first ever call to find_package() for a certain package, so it passes the first check and just ignores the next one.
No, they should all be the same.
Daniel d'Andrada (dandrader) wrote : | # |
> > plugins/
> application=1
> > while the other places want unity-shell-
> >
> > Besides wondering why that even works (shouldn't =1 fail now that we have 3
> > installed?) I'm also wondering if this what we want.
>
> I think CMake might be caching the output of the first ever call to
> find_package() for a certain package, so it passes the first check and just
> ignores the next one.
>
> No, they should all be the same.
Sneaky one. Fixed.
Michael Zanetti (mzanetti) wrote : | # |
And our all time favorite test :)
/build/
Daniel d'Andrada (dandrader) wrote : | # |
> replied to your inline replies. Soem very few still open.
Done.
Daniel d'Andrada (dandrader) wrote : | # |
> replied to your inline replies. Soem very few still open.
Done.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1145
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
Some minor new inline comments after having another read through the latest revision.
Also, I've had a run with tryApplicationW
* check/uncheck the surface checkbox, you'll see the red shine through, which makes me believe we might have an issue with one of the transitions... No matter which state, the app shouldn't become transparent, no?
* Set the application state to Stopped, then check the surface checkbox. It'll break the state machine quite badly...
Michael Zanetti (mzanetti) wrote : | # |
> The surface position in the spread is not correct any more. Surfaces should be
> aligned on their bottom edge and then scaled so that when reaching the left
> edge they're all the same size. Currently they are aligned at the top edge and
> the scaling doesn't work at all
Weird thing is, I cannot reproduce this in tryPhoneStage, but I can in tryShell. What's the difference?
Daniel d'Andrada (dandrader) wrote : | # |
> The dropshadow doesn't match with the surface's size any more
Fixed. The problem in the MirSurfaceItem mock: Its contents were not getting resized as they should.
Daniel d'Andrada (dandrader) wrote : | # |
> Surface sizes are not correct in tablet mode any more. (In Shell.qml change
> tablet to true and run make testShell)
Same thing. The problem was in the MirSurfaceItem mock: Its contents were not getting resized as they should.
Daniel d'Andrada (dandrader) wrote : | # |
> The surface position in the spread is not correct any more. Surfaces should be
> aligned on their bottom edge and then scaled so that when reaching the left
> edge they're all the same size. Currently they are aligned at the top edge and
> the scaling doesn't work at all
Same thing. The problem was in the MirSurfaceItem mock: Its contents were not getting resized as they should.
Daniel d'Andrada (dandrader) wrote : | # |
> And our all time favorite test :)
>
> /build/
> onWindow.qml: multiple new lines at end of file
Fixed.
Daniel d'Andrada (dandrader) wrote : | # |
>* check/uncheck the surface checkbox, you'll see the red shine through, which makes me believe we might have an issue with one of the transitions... No matter which state, the app shouldn't become transparent, no?
>
>* Set the application state to Stopped, then check the surface checkbox. It'll break the state machine quite badly...
You've triggered invalid situations that I didn't bother to cover with nice state transitions. Those are situations don't make sense and won't happen in real life (unless there's a nasty bug in AppMan or elsewhere).
Replied to your diff comments as well.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1147
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1152
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
Functional testing:
Bug 1: launch clock, then kill it with "kill `pgrep -f clock`" - the clock should vanish immediately - instead there's a weird fade out to splash screen, then vanish.
Bug 2: launch clock. Switch to Dash. wait 3 seconds for clock to be lifecycle stopped. Run "kill `pgrep -f clock`" Open spread, see Clock there, select Clock - I don't see clock being resumed, instead it just fades to the Dash.
Are these not the kind of issues this MR is tackling?
Michael Zanetti (mzanetti) wrote : | # |
Seems the OSK in tablet mode is still positioned wrong
Daniel d'Andrada (dandrader) wrote : | # |
> Functional testing:
> Bug 1: launch clock, then kill it with "kill `pgrep -f clock`" - the clock
> should vanish immediately - instead there's a weird fade out to splash screen,
> then vanish.
Fixed.
> Bug 2: launch clock. Switch to Dash. wait 3 seconds for clock to be lifecycle
> stopped. Run "kill `pgrep -f clock`" Open spread, see Clock there, select
> Clock - I don't see clock being resumed, instead it just fades to the Dash.
The SIGTERM is only acted upon once the process is resumed.
Daniel d'Andrada (dandrader) wrote : | # |
> Seems the OSK in tablet mode is still positioned wrong
Fixed. Thanks for spotting this. I forgot to update it.
Gerry Boland (gerboland) wrote : | # |
> Functional testing:
> Bug 1: launch clock, then kill it with "kill `pgrep -f clock`" - the clock
> should vanish immediately - instead there's a weird fade out to splash screen,
> then vanish.
>
> Bug 2: launch clock. Switch to Dash. wait 3 seconds for clock to be lifecycle
> stopped. Run "kill `pgrep -f clock`" Open spread, see Clock there, select
> Clock - I don't see clock being resumed, instead it just fades to the Dash.
>
> Are these not the kind of issues this MR is tackling?
Ok I wasn't doing accurate testing. Here I was sending TERM signals to apps, which as soon as they were resumed, would shut themselves down. Sending KILL to apps worked correctly.
The fade-out to splash is still wrong though, and can be exhibited by opening media player and pressing the Ok button which quits it.
Michał Sawicz (saviq) wrote : | # |
Not sure if it'll happen here, but a design request for "resuming" apps:
- display a desaturated B&W screenshot
- if no frame for 2s or so, display a "Resuming..." and a spinner (will get a visual tomorrow)
- cross-fade to app
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1155
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
> Not sure if it'll happen here, but a design request for "resuming" apps:
>
> - display a desaturated B&W screenshot
> - if no frame for 2s or so, display a "Resuming..." and a spinner (will get a
> visual tomorrow)
> - cross-fade to app
Good to know. But I think it should be done in a separate MP. Thus one is already big enough as has been hanging around for too long.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1156
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
FAIL! : qmltestrunner:
Actual (): true
Expected (): false
Loc: [/home/
Daniel d'Andrada (dandrader) wrote : | # |
> FAIL! : qmltestrunner:
> Actual (): true
> Expected (): false
> Loc: [/home/
> .qml(407)]
Fixed.
Michael Zanetti (mzanetti) wrote : | # |
looks good to me now!
* Did you perform an exploratory manual test run of the code change and any related functionality?
yip yip
* Did CI run pass? If not, please explain why.
no... missing deps, but it building fine in PPA. Related tests seem to pass here.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1157
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) : | # |
Daniel d'Andrada (dandrader) wrote : | # |
>Michał Sawicz (saviq) wrote 1 hour ago:
> unity8-common needs a runtime bump of the unity-applicati
Ok. Done.
Michał Sawicz (saviq) : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1158
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
still looking good to me.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1161
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'debian/control' |
2 | --- debian/control 2014-08-22 09:27:40 +0000 |
3 | +++ debian/control 2014-08-25 08:53:17 +0000 |
4 | @@ -24,7 +24,7 @@ |
5 | libpulse-dev, |
6 | libqmenumodel-dev (>= 0.2.8), |
7 | libqt5xmlpatterns5-dev, |
8 | - libunity-api-dev (>= 7.88), |
9 | + libunity-api-dev (>= 7.89), |
10 | libusermetricsoutput1-dev, |
11 | libxcb1-dev, |
12 | pkg-config, |
13 | @@ -112,7 +112,7 @@ |
14 | qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 0.1.49) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 0.1.49), |
15 | qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl, |
16 | ubuntu-thumbnailer-impl-0, |
17 | - unity-application-impl-2, |
18 | + unity-application-impl-3, |
19 | unity-notifications-impl-3, |
20 | unity-plugin-scopes | unity-scopes-impl, |
21 | unity-scopes-impl-4, |
22 | @@ -159,7 +159,7 @@ |
23 | Depends: ${misc:Depends}, |
24 | ${shlibs:Depends}, |
25 | Provides: unity-application-impl, |
26 | - unity-application-impl-2, |
27 | + unity-application-impl-3, |
28 | Description: Fake environment for running Unity 8 shell |
29 | Provides fake implementations of some QML modules used by Unity 8 shell |
30 | (e.g Ubuntu.Application) so that you can run it in a sandboxed environment. |
31 | |
32 | === modified file 'include/paths.h.in' |
33 | --- include/paths.h.in 2014-04-17 08:06:29 +0000 |
34 | +++ include/paths.h.in 2014-08-25 08:53:17 +0000 |
35 | @@ -80,6 +80,14 @@ |
36 | return paths; |
37 | } |
38 | |
39 | +inline QString mockPluginsDir() { |
40 | + if (isRunningInstalled()) { |
41 | + return QString("@CMAKE_INSTALL_PREFIX@/@SHELL_INSTALL_QML@/mocks"); |
42 | + } else { |
43 | + return QString("@CMAKE_BINARY_DIR@/tests/mocks"); |
44 | + } |
45 | +} |
46 | + |
47 | inline QStringList shellDataDirs() { |
48 | QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); |
49 | if (!isRunningInstalled()) { |
50 | |
51 | === modified file 'plugins/Unity/Launcher/CMakeLists.txt' |
52 | --- plugins/Unity/Launcher/CMakeLists.txt 2014-05-30 09:22:58 +0000 |
53 | +++ plugins/Unity/Launcher/CMakeLists.txt 2014-08-25 08:53:17 +0000 |
54 | @@ -1,6 +1,6 @@ |
55 | include(FindPkgConfig) |
56 | pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3) |
57 | -pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=1) |
58 | +pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=3) |
59 | pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt) |
60 | |
61 | add_definitions(-DSM_BUSNAME=systemBus) |
62 | |
63 | === modified file 'qml/Dash/graphics/phone/screenshots/vkb_portrait.png' |
64 | Binary files qml/Dash/graphics/phone/screenshots/vkb_portrait.png 2014-07-22 10:29:25 +0000 and qml/Dash/graphics/phone/screenshots/vkb_portrait.png 2014-08-25 08:53:17 +0000 differ |
65 | === removed file 'qml/Stages/AppSurfaceContainer.qml' |
66 | --- qml/Stages/AppSurfaceContainer.qml 2014-08-08 09:40:41 +0000 |
67 | +++ qml/Stages/AppSurfaceContainer.qml 1970-01-01 00:00:00 +0000 |
68 | @@ -1,96 +0,0 @@ |
69 | -/* |
70 | - * Copyright 2014 Canonical Ltd. |
71 | - * |
72 | - * This program is free software; you can redistribute it and/or modify |
73 | - * it under the terms of the GNU Lesser General Public License as published by |
74 | - * the Free Software Foundation; version 3. |
75 | - * |
76 | - * This program is distributed in the hope that it will be useful, |
77 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
78 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
79 | - * GNU Lesser General Public License for more details. |
80 | - * |
81 | - * You should have received a copy of the GNU Lesser General Public License |
82 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
83 | -*/ |
84 | - |
85 | -import QtQuick 2.0 |
86 | -import "Animations" |
87 | - |
88 | -SurfaceContainer { |
89 | - id: container |
90 | - property var promptSurfaces |
91 | - |
92 | - property bool appHasCreatedASurface: false |
93 | - |
94 | - onSurfaceChanged: { |
95 | - if (surface) { |
96 | - if (!appHasCreatedASurface) { |
97 | - surface.visible = false; // hide until splash screen removed |
98 | - appHasCreatedASurface = true; |
99 | - } |
100 | - } |
101 | - } |
102 | - |
103 | - function revealSurface() { |
104 | - surface.visible = true; |
105 | - splashLoader.source = ""; |
106 | - } |
107 | - |
108 | - Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete |
109 | - id: surfaceRevealDelay |
110 | - interval: 100 |
111 | - onTriggered: surfaceContainer.revealSurface() |
112 | - } |
113 | - |
114 | - Loader { |
115 | - z: 3 |
116 | - id: splashLoader |
117 | - anchors.fill: parent |
118 | - } |
119 | - |
120 | - Repeater { |
121 | - model: container.promptSurfaces |
122 | - |
123 | - delegate: SurfaceContainer { |
124 | - anchors { |
125 | - fill: container |
126 | - topMargin: container.surface.anchors.topMargin |
127 | - rightMargin: container.surface.anchors.rightMargin |
128 | - bottomMargin: container.surface.anchors.bottomMargin |
129 | - leftMargin: container.surface.anchors.leftMargin |
130 | - } |
131 | - |
132 | - z: 4 + index |
133 | - surface: modelData |
134 | - |
135 | - Component.onCompleted: { |
136 | - animateIn(); |
137 | - } |
138 | - } |
139 | - } |
140 | - |
141 | - StateGroup { |
142 | - id: appSurfaceState |
143 | - states: [ |
144 | - State { |
145 | - name: "noSurfaceYet" |
146 | - when: !surfaceContainer.appHasCreatedASurface |
147 | - StateChangeScript { |
148 | - script: { splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); } |
149 | - } |
150 | - }, |
151 | - State { |
152 | - name: "hasSurface" |
153 | - when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface !== null) |
154 | - StateChangeScript { script: { surfaceRevealDelay.start(); } } |
155 | - }, |
156 | - State { |
157 | - name: "surfaceLostButAppStillAlive" |
158 | - when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface === null) |
159 | - // TODO - use app snapshot |
160 | - } |
161 | - ] |
162 | - state: "noSurfaceYet" |
163 | - } |
164 | -} |
165 | |
166 | === added file 'qml/Stages/ApplicationWindow.qml' |
167 | --- qml/Stages/ApplicationWindow.qml 1970-01-01 00:00:00 +0000 |
168 | +++ qml/Stages/ApplicationWindow.qml 2014-08-25 08:53:17 +0000 |
169 | @@ -0,0 +1,258 @@ |
170 | +/* |
171 | + * Copyright 2014 Canonical Ltd. |
172 | + * |
173 | + * This program is free software; you can redistribute it and/or modify |
174 | + * it under the terms of the GNU Lesser General Public License as published by |
175 | + * the Free Software Foundation; version 3. |
176 | + * |
177 | + * This program is distributed in the hope that it will be useful, |
178 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
179 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
180 | + * GNU Lesser General Public License for more details. |
181 | + * |
182 | + * You should have received a copy of the GNU Lesser General Public License |
183 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
184 | + */ |
185 | + |
186 | +import QtQuick 2.0 |
187 | +import Ubuntu.Components 1.1 |
188 | +import Unity.Application 0.1 |
189 | + |
190 | +Item { |
191 | + id: root |
192 | + |
193 | + // to be read from outside |
194 | + readonly property bool fullscreen: application ? application.fullscreen : false |
195 | + |
196 | + // to be set from outside |
197 | + property bool interactive: true |
198 | + property QtObject application |
199 | + |
200 | + QtObject { |
201 | + id: d |
202 | + |
203 | + // helpers so that we don't have to check for the existence of an application everywhere |
204 | + // (in order to avoid breaking qml binding due to a javascript exception) |
205 | + readonly property string name: root.application ? root.application.name : "" |
206 | + readonly property url icon: root.application ? root.application.icon : "" |
207 | + readonly property Item surface: root.application ? root.application.surface : null |
208 | + readonly property int applicationState: root.application ? root.application.state : -1 |
209 | + readonly property var promptSurfaces: root.application ? root.application.promptSurfaces : null |
210 | + |
211 | + // Whether the Application had a surface before but lost it. |
212 | + property bool hadSurface: false |
213 | + |
214 | + property bool needToTakeScreenshot: |
215 | + d.surface && d.surfaceInitialized && screenshotImage.status === Image.Null |
216 | + && d.applicationState === ApplicationInfo.Stopped |
217 | + onNeedToTakeScreenshotChanged: { |
218 | + if (needToTakeScreenshot) { |
219 | + screenshotImage.take(); |
220 | + } |
221 | + } |
222 | + |
223 | + //FIXME - this is a hack to avoid the first few rendered frames as they |
224 | + // might show the UI accommodating due to surface resizes on startup. |
225 | + // Remove this when possible |
226 | + property bool surfaceInitialized: false |
227 | + onSurfaceChanged: { |
228 | + if (surface) { |
229 | + surfaceInitTimer.start(); |
230 | + } else { |
231 | + hadSurface = true; |
232 | + surfaceInitialized = false; |
233 | + } |
234 | + } |
235 | + } |
236 | + |
237 | + Timer { |
238 | + id: surfaceInitTimer |
239 | + interval: 100 |
240 | + onTriggered: { if (d.surface) {d.surfaceInitialized = true;} } |
241 | + } |
242 | + |
243 | + Binding { |
244 | + target: d.surface |
245 | + when: d.surface |
246 | + property: "enabled" |
247 | + value: root.interactive |
248 | + } |
249 | + Binding { |
250 | + target: d.surface |
251 | + when: d.surface |
252 | + property: "focus" |
253 | + value: root.interactive |
254 | + } |
255 | + Connections { |
256 | + target: d.surface |
257 | + // FIXME: I would rather not need to do this, but currently it doesn't get |
258 | + // active focus without it and I don't know why. |
259 | + onFocusChanged: forceSurfaceActiveFocusIfReady(); |
260 | + onParentChanged: forceSurfaceActiveFocusIfReady(); |
261 | + onEnabledChanged: forceSurfaceActiveFocusIfReady(); |
262 | + function forceSurfaceActiveFocusIfReady() { |
263 | + if (d.surface.focus && d.surface.parent === surfaceContainer && d.surface.enabled) { |
264 | + d.surface.forceActiveFocus(); |
265 | + } |
266 | + } |
267 | + } |
268 | + |
269 | + SurfaceContainer { |
270 | + id: surfaceContainer |
271 | + objectName: "surfaceContainer" |
272 | + anchors.fill: parent |
273 | + surface: d.surface |
274 | + } |
275 | + |
276 | + Image { |
277 | + id: screenshotImage |
278 | + objectName: "screenshotImage" |
279 | + source: "" |
280 | + anchors.fill: parent |
281 | + |
282 | + function take() { |
283 | + // Format: "image://application/$APP_ID/$CURRENT_TIME_MS" |
284 | + // eg: "image://application/calculator-app/123456" |
285 | + var timeMs = new Date().getTime(); |
286 | + source = "image://application/" + root.application.appId + "/" + timeMs; |
287 | + } |
288 | + |
289 | + // Save memory by using a half-resolution (thus quarter size) screenshot |
290 | + sourceSize.width: root.width / 2 |
291 | + sourceSize.height: root.height / 2 |
292 | + } |
293 | + |
294 | + Loader { |
295 | + id: splashLoader |
296 | + visible: active |
297 | + active: false |
298 | + anchors.fill: surfaceContainer |
299 | + sourceComponent: Component { |
300 | + Splash { name: d.name; image: d.icon } |
301 | + } |
302 | + } |
303 | + |
304 | + Repeater { |
305 | + model: d.promptSurfaces |
306 | + |
307 | + delegate: SurfaceContainer { |
308 | + anchors { |
309 | + fill: surfaceContainer |
310 | + } |
311 | + |
312 | + surface: modelData |
313 | + |
314 | + Component.onCompleted: { |
315 | + animateIn(); |
316 | + } |
317 | + } |
318 | + } |
319 | + |
320 | + StateGroup { |
321 | + objectName: "applicationWindowStateGroup" |
322 | + states: [ |
323 | + State { |
324 | + name: "void" |
325 | + when: |
326 | + d.hadSurface && (!d.surface || !d.surfaceInitialized) |
327 | + && |
328 | + screenshotImage.status !== Image.Ready |
329 | + }, |
330 | + State { |
331 | + name: "splashScreen" |
332 | + when: |
333 | + !d.hadSurface && (!d.surface || !d.surfaceInitialized) |
334 | + && |
335 | + screenshotImage.status !== Image.Ready |
336 | + }, |
337 | + State { |
338 | + name: "surface" |
339 | + when: |
340 | + (d.surface && d.surfaceInitialized) |
341 | + && |
342 | + (d.applicationState !== ApplicationInfo.Stopped |
343 | + || screenshotImage.status !== Image.Ready) |
344 | + }, |
345 | + State { |
346 | + name: "screenshot" |
347 | + when: |
348 | + screenshotImage.status === Image.Ready |
349 | + && |
350 | + (d.applicationState === ApplicationInfo.Stopped |
351 | + || !d.surface || !d.surfaceInitialized) |
352 | + } |
353 | + ] |
354 | + |
355 | + transitions: [ |
356 | + Transition { |
357 | + from: ""; to: "splashScreen" |
358 | + PropertyAction { target: splashLoader; property: "active"; value: true } |
359 | + }, |
360 | + Transition { |
361 | + from: "splashScreen"; to: "surface" |
362 | + SequentialAnimation { |
363 | + PropertyAction { target: surfaceContainer |
364 | + property: "visible"; value: true } |
365 | + UbuntuNumberAnimation { target: splashLoader; property: "opacity"; |
366 | + from: 1.0; to: 0.0 |
367 | + duration: UbuntuAnimation.BriskDuration } |
368 | + PropertyAction { target: splashLoader; property: "active"; value: false } |
369 | + } |
370 | + }, |
371 | + Transition { |
372 | + from: "surface"; to: "splashScreen" |
373 | + SequentialAnimation { |
374 | + PropertyAction { target: splashLoader; property: "active"; value: true } |
375 | + PropertyAction { target: surfaceContainer |
376 | + property: "visible"; value: true } |
377 | + UbuntuNumberAnimation { target: splashLoader; property: "opacity"; |
378 | + from: 0.0; to: 1.0 |
379 | + duration: UbuntuAnimation.BriskDuration } |
380 | + } |
381 | + }, |
382 | + Transition { |
383 | + from: "surface"; to: "screenshot" |
384 | + SequentialAnimation { |
385 | + PropertyAction { target: screenshotImage |
386 | + property: "visible"; value: true } |
387 | + UbuntuNumberAnimation { target: screenshotImage; property: "opacity"; |
388 | + from: 0.0; to: 1.0 |
389 | + duration: UbuntuAnimation.BriskDuration } |
390 | + PropertyAction { target: surfaceContainer |
391 | + property: "visible"; value: false } |
392 | + ScriptAction { script: { if (d.surface) { d.surface.release(); } } } |
393 | + } |
394 | + }, |
395 | + Transition { |
396 | + from: "screenshot"; to: "surface" |
397 | + SequentialAnimation { |
398 | + PropertyAction { target: surfaceContainer |
399 | + property: "visible"; value: true } |
400 | + UbuntuNumberAnimation { target: screenshotImage; property: "opacity"; |
401 | + from: 1.0; to: 0.0 |
402 | + duration: UbuntuAnimation.BriskDuration } |
403 | + PropertyAction { target: screenshotImage; property: "visible"; value: false } |
404 | + PropertyAction { target: screenshotImage; property: "source"; value: "" } |
405 | + } |
406 | + }, |
407 | + Transition { |
408 | + from: "surface"; to: "void" |
409 | + SequentialAnimation { |
410 | + PropertyAction { target: surfaceContainer; property: "visible"; value: false } |
411 | + ScriptAction { script: { if (d.surface) { d.surface.release(); } } } |
412 | + } |
413 | + }, |
414 | + Transition { |
415 | + from: "void"; to: "surface" |
416 | + SequentialAnimation { |
417 | + PropertyAction { target: surfaceContainer; property: "opacity"; value: 0.0 } |
418 | + PropertyAction { target: surfaceContainer; property: "visible"; value: true } |
419 | + UbuntuNumberAnimation { target: surfaceContainer; property: "opacity"; |
420 | + from: 0.0; to: 1.0 |
421 | + duration: UbuntuAnimation.BriskDuration } |
422 | + } |
423 | + } |
424 | + ] |
425 | + } |
426 | + |
427 | +} |
428 | |
429 | === modified file 'qml/Stages/PhoneStage.qml' |
430 | --- qml/Stages/PhoneStage.qml 2014-07-29 15:22:08 +0000 |
431 | +++ qml/Stages/PhoneStage.qml 2014-08-25 08:53:17 +0000 |
432 | @@ -110,7 +110,8 @@ |
433 | id: spreadView |
434 | objectName: "spreadView" |
435 | anchors.fill: parent |
436 | - interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) && draggedIndex == -1 |
437 | + interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) |
438 | + && draggedDelegateCount === 0 |
439 | contentWidth: spreadRow.width - shift |
440 | contentX: -shift |
441 | |
442 | @@ -148,7 +149,7 @@ |
443 | property int phase: 0 |
444 | |
445 | property int selectedIndex: -1 |
446 | - property int draggedIndex: -1 |
447 | + property int draggedDelegateCount: 0 |
448 | property int closingIndex: -1 |
449 | |
450 | property bool focusChanging: false |
451 | @@ -269,7 +270,7 @@ |
452 | swipeToCloseEnabled: spreadView.interactive |
453 | maximizedAppTopMargin: root.maximizedAppTopMargin |
454 | dropShadow: spreadView.active || |
455 | - priv.focusedAppDelegate.x !== 0 |
456 | + (priv.focusedAppDelegate && priv.focusedAppDelegate.x !== 0) |
457 | |
458 | readonly property bool isDash: model.appId == "unity8-dash" |
459 | |
460 | @@ -290,6 +291,10 @@ |
461 | // Otherwise line up for the spread |
462 | return spreadView.width + (index - 1) * spreadView.tileDistance; |
463 | } |
464 | + |
465 | + application: ApplicationManager.get(index) |
466 | + closeable: !isDash |
467 | + |
468 | property real behavioredIndex: index |
469 | Behavior on behavioredIndex { |
470 | enabled: spreadView.closingIndex >= 0 |
471 | @@ -372,8 +377,15 @@ |
472 | } |
473 | } |
474 | |
475 | + onDraggedChanged: { |
476 | + if (dragged) { |
477 | + spreadView.draggedDelegateCount++; |
478 | + } else { |
479 | + spreadView.draggedDelegateCount--; |
480 | + } |
481 | + } |
482 | + |
483 | onClosed: { |
484 | - spreadView.draggedIndex = -1; |
485 | spreadView.closingIndex = index; |
486 | ApplicationManager.stopApplication(ApplicationManager.get(index).appId); |
487 | } |
488 | |
489 | === modified file 'qml/Stages/SpreadDelegate.qml' |
490 | --- qml/Stages/SpreadDelegate.qml 2014-08-08 09:40:41 +0000 |
491 | +++ qml/Stages/SpreadDelegate.qml 2014-08-25 08:53:17 +0000 |
492 | @@ -14,75 +14,43 @@ |
493 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
494 | * |
495 | * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
496 | -*/ |
497 | + * Daniel d'Andrada <daniel.dandrada@canonical.com> |
498 | + */ |
499 | |
500 | import QtQuick 2.0 |
501 | -import Unity.Application 0.1 |
502 | import Ubuntu.Components 1.1 |
503 | import "../Components" |
504 | |
505 | Item { |
506 | id: root |
507 | |
508 | + // to be read from outside |
509 | + readonly property bool dragged: dragArea.moving |
510 | + signal clicked() |
511 | + signal closed() |
512 | + |
513 | // to be set from outside |
514 | property bool interactive: true |
515 | property bool dropShadow: true |
516 | property real maximizedAppTopMargin |
517 | property alias swipeToCloseEnabled: dragArea.enabled |
518 | - |
519 | - readonly property bool isFullscreen: surface !== null && surfaceContainer.surface.anchors.topMargin == 0 |
520 | - |
521 | - signal clicked() |
522 | - signal closed() |
523 | - |
524 | - AppSurfaceContainer { |
525 | - id: surfaceContainer |
526 | - objectName: "surfaceContainer" |
527 | - anchors.fill: parent |
528 | - surface: model.surface |
529 | - promptSurfaces: model.application.promptSurfaces |
530 | - |
531 | - Binding { |
532 | - target: surfaceContainer.surface |
533 | - property: "anchors.topMargin" |
534 | - value: { |
535 | - return surfaceContainer.surface.state === MirSurfaceItem.Fullscreen ? 0 : maximizedAppTopMargin; |
536 | - } |
537 | - } |
538 | - |
539 | - Binding { |
540 | - target: surface |
541 | - property: "enabled" |
542 | - value: root.interactive |
543 | - } |
544 | - Binding { |
545 | - target: surface |
546 | - property: "focus" |
547 | - value: root.interactive |
548 | - } |
549 | - |
550 | - Connections { |
551 | - target: surface |
552 | - // FIXME: I would rather not need to do this, but currently it doesn't get |
553 | - // active focus without it and I don't know why. |
554 | - onFocusChanged: forceSurfaceActiveFocusIfReady(); |
555 | - onParentChanged: forceSurfaceActiveFocusIfReady(); |
556 | - onEnabledChanged: forceSurfaceActiveFocusIfReady(); |
557 | - function forceSurfaceActiveFocusIfReady() { |
558 | - if (surface.focus && surface.parent === surfaceContainer && surface.enabled) { |
559 | - surface.forceActiveFocus(); |
560 | - } |
561 | - } |
562 | - } |
563 | + property bool closeable |
564 | + property alias application: appWindow.application |
565 | + |
566 | + Item { |
567 | + objectName: "appWindowWithShadow" |
568 | + |
569 | + y: dragArea.distance |
570 | + width: parent.width |
571 | + height: parent.height |
572 | |
573 | BorderImage { |
574 | - id: dropShadowImage |
575 | anchors { |
576 | - fill: parent |
577 | + fill: appWindow |
578 | leftMargin: -units.gu(2) |
579 | rightMargin: -units.gu(2) |
580 | bottomMargin: -units.gu(2) |
581 | - topMargin: -units.gu(2) + (root.isFullscreen ? 0 : maximizedAppTopMargin) |
582 | + topMargin: -units.gu(2) |
583 | } |
584 | source: "graphics/dropshadow.png" |
585 | border { left: 50; right: 50; top: 50; bottom: 50 } |
586 | @@ -90,21 +58,26 @@ |
587 | Behavior on opacity { UbuntuNumberAnimation {} } |
588 | } |
589 | |
590 | - transform: Translate { |
591 | - y: dragArea.distance |
592 | + ApplicationWindow { |
593 | + id: appWindow |
594 | + anchors { |
595 | + fill: parent |
596 | + topMargin: appWindow.fullscreen ? 0 : maximizedAppTopMargin |
597 | + } |
598 | + |
599 | + interactive: root.interactive |
600 | } |
601 | } |
602 | |
603 | DraggingArea { |
604 | id: dragArea |
605 | + objectName: "dragArea" |
606 | anchors.fill: parent |
607 | |
608 | property bool moving: false |
609 | property real distance: 0 |
610 | |
611 | - onMovingChanged: { |
612 | - spreadView.draggedIndex = moving ? index : -1 |
613 | - } |
614 | + readonly property real minSpeedToClose: units.gu(40) |
615 | |
616 | onDragValueChanged: { |
617 | if (!dragging) { |
618 | @@ -123,15 +96,15 @@ |
619 | } |
620 | |
621 | onDragEnd: { |
622 | - if (model.appId == "unity8-dash") { |
623 | + if (!root.closeable) { |
624 | animation.animate("center") |
625 | return; |
626 | } |
627 | |
628 | // velocity and distance values specified by design prototype |
629 | - if ((dragVelocity < -units.gu(40) && distance < -units.gu(8)) || distance < -root.height / 2) { |
630 | + if ((dragVelocity < -minSpeedToClose && distance < -units.gu(8)) || distance < -root.height / 2) { |
631 | animation.animate("up") |
632 | - } else if ((dragVelocity > units.gu(40) && distance > units.gu(8)) || distance > root.height / 2) { |
633 | + } else if ((dragVelocity > minSpeedToClose && distance > units.gu(8)) || distance > root.height / 2) { |
634 | animation.animate("down") |
635 | } else { |
636 | animation.animate("center") |
637 | @@ -140,6 +113,7 @@ |
638 | |
639 | UbuntuNumberAnimation { |
640 | id: animation |
641 | + objectName: "closeAnimation" |
642 | target: dragArea |
643 | property: "distance" |
644 | property bool requestClose: false |
645 | @@ -164,9 +138,10 @@ |
646 | onRunningChanged: { |
647 | if (!running) { |
648 | dragArea.moving = false; |
649 | - dragArea.distance = 0; |
650 | if (requestClose) { |
651 | root.closed(); |
652 | + } else { |
653 | + dragArea.distance = 0; |
654 | } |
655 | } |
656 | } |
657 | |
658 | === modified file 'qml/Stages/SurfaceContainer.qml' |
659 | --- qml/Stages/SurfaceContainer.qml 2014-08-07 17:15:00 +0000 |
660 | +++ qml/Stages/SurfaceContainer.qml 2014-08-25 08:53:17 +0000 |
661 | @@ -26,9 +26,12 @@ |
662 | if (surface) { |
663 | surface.parent = container; |
664 | surface.z = 1; |
665 | - state = "initial" |
666 | } |
667 | } |
668 | + Binding { |
669 | + target: surface |
670 | + property: "anchors.fill"; value: container |
671 | + } |
672 | |
673 | Connections { |
674 | target: surface |
675 | @@ -45,7 +48,7 @@ |
676 | } |
677 | |
678 | Repeater { |
679 | - model: surface.childSurfaces |
680 | + model: surface ? surface.childSurfaces : null |
681 | |
682 | delegate: Loader { |
683 | z: 2 |
684 | @@ -81,8 +84,6 @@ |
685 | var popped = tmp.pop(); |
686 | popped.end(); |
687 | d.animations = tmp; |
688 | - } else { |
689 | - container.state = "initial"; |
690 | } |
691 | } |
692 | |
693 | @@ -96,11 +97,4 @@ |
694 | id: swipeFromBottom |
695 | SwipeFromBottomAnimation {} |
696 | } |
697 | - |
698 | - states: [ |
699 | - State { |
700 | - name: "initial" |
701 | - PropertyChanges { target: surface; anchors.fill: container } |
702 | - } |
703 | - ] |
704 | } |
705 | |
706 | === modified file 'qml/Stages/TabletStage.qml' |
707 | --- qml/Stages/TabletStage.qml 2014-07-29 13:45:30 +0000 |
708 | +++ qml/Stages/TabletStage.qml 2014-08-25 08:53:17 +0000 |
709 | @@ -145,7 +145,8 @@ |
710 | Flickable { |
711 | id: spreadView |
712 | anchors.fill: parent |
713 | - interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) && draggedIndex == -1 |
714 | + interactive: (spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1) |
715 | + && draggedDelegateCount === 0 |
716 | contentWidth: spreadRow.width - shift |
717 | contentX: -shift |
718 | |
719 | @@ -189,7 +190,7 @@ |
720 | readonly property real snapPosition: 0.75 |
721 | |
722 | property int selectedIndex: -1 |
723 | - property int draggedIndex: -1 |
724 | + property int draggedDelegateCount: 0 |
725 | property int closingIndex: -1 |
726 | |
727 | property bool sideStageDragging: sideStageDragHandle.dragging |
728 | @@ -475,6 +476,8 @@ |
729 | swipeToCloseEnabled: spreadView.interactive |
730 | maximizedAppTopMargin: root.maximizedAppTopMargin |
731 | dragOffset: !isDash && model.appId == priv.mainStageAppId && root.inverseProgress > 0 ? root.inverseProgress : 0 |
732 | + application: ApplicationManager.get(index) |
733 | + closeable: !isDash |
734 | |
735 | readonly property bool isDash: model.appId == "unity8-dash" |
736 | |
737 | @@ -533,8 +536,15 @@ |
738 | } |
739 | } |
740 | |
741 | + onDraggedChanged: { |
742 | + if (dragged) { |
743 | + spreadView.draggedDelegateCount++; |
744 | + } else { |
745 | + spreadView.draggedDelegateCount--; |
746 | + } |
747 | + } |
748 | + |
749 | onClosed: { |
750 | - spreadView.draggedIndex = -1; |
751 | spreadView.closingIndex = index; |
752 | ApplicationManager.stopApplication(ApplicationManager.get(index).appId); |
753 | } |
754 | |
755 | === modified file 'qml/Stages/TransformedSpreadDelegate.qml' |
756 | --- qml/Stages/TransformedSpreadDelegate.qml 2014-07-29 13:45:30 +0000 |
757 | +++ qml/Stages/TransformedSpreadDelegate.qml 2014-08-25 08:53:17 +0000 |
758 | @@ -309,7 +309,7 @@ |
759 | Scale { |
760 | origin { x: 0; y: (spreadView.height * priv.scale) + maximizedAppTopMargin * 3 } |
761 | xScale: 1 |
762 | - yScale: isFullscreen ? 1 - priv.topMarginProgress * maximizedAppTopMargin / spreadView.height : 1 |
763 | + yScale: fullscreen ? 1 - priv.topMarginProgress * maximizedAppTopMargin / spreadView.height : 1 |
764 | }, |
765 | Translate { |
766 | x: priv.xTranslate |
767 | |
768 | === modified file 'tests/mocks/Unity/Application/Application.qmltypes' |
769 | --- tests/mocks/Unity/Application/Application.qmltypes 2014-08-14 01:28:06 +0000 |
770 | +++ tests/mocks/Unity/Application/Application.qmltypes 2014-08-25 08:53:17 +0000 |
771 | @@ -8,25 +8,6 @@ |
772 | |
773 | Module { |
774 | Component { |
775 | - name: "ApplicationImage" |
776 | - defaultProperty: "data" |
777 | - prototype: "QQuickItem" |
778 | - exports: ["Unity.Application/ApplicationImage 0.1"] |
779 | - exportMetaObjectRevisions: [0] |
780 | - Enum { |
781 | - name: "FillMode" |
782 | - values: { |
783 | - "Stretch": 0, |
784 | - "PreserveAspectCrop": 1 |
785 | - } |
786 | - } |
787 | - Property { name: "source"; type: "ApplicationInfo"; isPointer: true } |
788 | - Property { name: "fillMode"; type: "FillMode" } |
789 | - Property { name: "ready"; type: "bool" } |
790 | - Method { name: "scheduleUpdate" } |
791 | - Method { name: "updateFromCache" } |
792 | - } |
793 | - Component { |
794 | name: "ApplicationInfo" |
795 | prototype: "unity::shell::application::ApplicationInfoInterface" |
796 | exports: ["Unity.Application/ApplicationInfo 0.1"] |
797 | |
798 | === removed file 'tests/mocks/Unity/Application/ApplicationImage.cpp' |
799 | --- tests/mocks/Unity/Application/ApplicationImage.cpp 2013-06-05 22:03:08 +0000 |
800 | +++ tests/mocks/Unity/Application/ApplicationImage.cpp 1970-01-01 00:00:00 +0000 |
801 | @@ -1,123 +0,0 @@ |
802 | -/* |
803 | - * Copyright (C) 2013 Canonical, Ltd. |
804 | - * |
805 | - * This program is free software; you can redistribute it and/or modify |
806 | - * it under the terms of the GNU General Public License as published by |
807 | - * the Free Software Foundation; version 3. |
808 | - * |
809 | - * This program is distributed in the hope that it will be useful, |
810 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
811 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
812 | - * GNU General Public License for more details. |
813 | - * |
814 | - * You should have received a copy of the GNU General Public License |
815 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
816 | - */ |
817 | - |
818 | -#include "ApplicationImage.h" |
819 | -#include "ApplicationInfo.h" |
820 | - |
821 | -#include <QQmlEngine> |
822 | -#include <QQmlComponent> |
823 | -#include <QQmlContext> |
824 | - |
825 | -ApplicationImage::ApplicationImage(QQuickItem* parent) |
826 | - : QQuickItem(parent), |
827 | - m_source(NULL), |
828 | - m_fillMode(Stretch), |
829 | - m_ready(false), |
830 | - m_imageComponent(0), |
831 | - m_imageItem(0) |
832 | -{ |
833 | -} |
834 | - |
835 | -void ApplicationImage::setSource(ApplicationInfo* source) |
836 | -{ |
837 | - if (m_source != source) { |
838 | - if (m_source) |
839 | - disconnect(m_source, &ApplicationInfo::imageQmlChanged, |
840 | - this, &ApplicationImage::updateImage); |
841 | - |
842 | - m_source = source; |
843 | - |
844 | - if (m_source) { |
845 | - connect(m_source, &ApplicationInfo::imageQmlChanged, |
846 | - this, &ApplicationImage::updateImage); |
847 | - } |
848 | - updateImage(); |
849 | - |
850 | - Q_EMIT sourceChanged(); |
851 | - } |
852 | -} |
853 | - |
854 | -void ApplicationImage::setFillMode(FillMode newFillMode) |
855 | -{ |
856 | - if (m_fillMode != newFillMode) { |
857 | - m_fillMode = newFillMode; |
858 | - Q_EMIT fillModeChanged(); |
859 | - } |
860 | -} |
861 | - |
862 | -void ApplicationImage::setReady(bool value) |
863 | -{ |
864 | - if (value != m_ready) { |
865 | - m_ready = value; |
866 | - Q_EMIT readyChanged(); |
867 | - } |
868 | -} |
869 | - |
870 | -void ApplicationImage::destroyImage() |
871 | -{ |
872 | - delete m_imageItem; |
873 | - m_imageItem = 0; |
874 | - delete m_imageComponent; |
875 | - m_imageComponent = 0; |
876 | - m_qmlUsed.clear(); |
877 | - setReady(false); |
878 | -} |
879 | - |
880 | -void ApplicationImage::updateImage() |
881 | -{ |
882 | - if (!m_source || m_source->imageQml().isEmpty()) { |
883 | - destroyImage(); |
884 | - } else if (m_source->imageQml() != m_qmlUsed) { |
885 | - destroyImage(); |
886 | - createImageItem(); |
887 | - } |
888 | -} |
889 | - |
890 | -void ApplicationImage::createImageItem() |
891 | -{ |
892 | - |
893 | - if (!m_imageComponent) |
894 | - createImageComponent(); |
895 | - |
896 | - // only create the windowItem one the component is ready |
897 | - if (!m_imageComponent->isReady()) { |
898 | - connect(m_imageComponent, &QQmlComponent::statusChanged, |
899 | - this, &ApplicationImage::onImageComponentStatusChanged); |
900 | - } else { |
901 | - doCreateImageItem(); |
902 | - } |
903 | - |
904 | -} |
905 | - |
906 | -void ApplicationImage::createImageComponent() |
907 | -{ |
908 | - QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine(); |
909 | - m_imageComponent = new QQmlComponent(engine, this); |
910 | - m_imageComponent->setData(m_source->imageQml().toLatin1(), QUrl()); |
911 | -} |
912 | - |
913 | -void ApplicationImage::doCreateImageItem() |
914 | -{ |
915 | - m_imageItem = qobject_cast<QQuickItem *>(m_imageComponent->create()); |
916 | - m_imageItem->setParentItem(this); |
917 | - setReady(true); |
918 | -} |
919 | - |
920 | -void ApplicationImage::onImageComponentStatusChanged(QQmlComponent::Status status) |
921 | -{ |
922 | - if (status == QQmlComponent::Ready && !m_imageItem) |
923 | - doCreateImageItem(); |
924 | -} |
925 | |
926 | === removed file 'tests/mocks/Unity/Application/ApplicationImage.h' |
927 | --- tests/mocks/Unity/Application/ApplicationImage.h 2013-06-05 22:03:08 +0000 |
928 | +++ tests/mocks/Unity/Application/ApplicationImage.h 1970-01-01 00:00:00 +0000 |
929 | @@ -1,79 +0,0 @@ |
930 | -/* |
931 | - * Copyright (C) 2013 Canonical, Ltd. |
932 | - * |
933 | - * This program is free software; you can redistribute it and/or modify |
934 | - * it under the terms of the GNU General Public License as published by |
935 | - * the Free Software Foundation; version 3. |
936 | - * |
937 | - * This program is distributed in the hope that it will be useful, |
938 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
939 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
940 | - * GNU General Public License for more details. |
941 | - * |
942 | - * You should have received a copy of the GNU General Public License |
943 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
944 | - */ |
945 | - |
946 | -#ifndef APPLICATION_IMAGE_H |
947 | -#define APPLICATION_IMAGE_H |
948 | - |
949 | -#include <QQuickItem> |
950 | - |
951 | -class ApplicationInfo; |
952 | - |
953 | -/* Fake implementation of ApplicationImage |
954 | - |
955 | - That fake implementation is not made in QML just because we can only declare |
956 | - enumerations in C++. We can't even make readonly properties to mimic an enum |
957 | - because properties must begin with a lower case letter. |
958 | -*/ |
959 | -class ApplicationImage : public QQuickItem { |
960 | - Q_OBJECT |
961 | - Q_ENUMS(FillMode) |
962 | - Q_PROPERTY(ApplicationInfo* source READ source WRITE setSource NOTIFY sourceChanged) |
963 | - Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) |
964 | - Q_PROPERTY(bool ready READ ready WRITE setReady NOTIFY readyChanged) |
965 | - |
966 | -public: |
967 | - explicit ApplicationImage(QQuickItem* parent = 0); |
968 | - virtual ~ApplicationImage() {} |
969 | - |
970 | - enum FillMode { Stretch, PreserveAspectCrop }; |
971 | - |
972 | - ApplicationInfo* source() const { return m_source; } |
973 | - void setSource(ApplicationInfo* source); |
974 | - |
975 | - FillMode fillMode() const { return m_fillMode; } |
976 | - void setFillMode(FillMode); |
977 | - |
978 | - void setReady(bool value); |
979 | - bool ready() const { return m_ready; } |
980 | - |
981 | - Q_INVOKABLE void scheduleUpdate() {} |
982 | - Q_INVOKABLE void updateFromCache() {} |
983 | - |
984 | -Q_SIGNALS: |
985 | - void sourceChanged(); |
986 | - void fillModeChanged(); |
987 | - void readyChanged(); |
988 | - |
989 | -private Q_SLOTS: |
990 | - void updateImage(); |
991 | - void onImageComponentStatusChanged(QQmlComponent::Status status); |
992 | - |
993 | -private: |
994 | - void createImageItem(); |
995 | - void createImageComponent(); |
996 | - void doCreateImageItem(); |
997 | - void destroyImage(); |
998 | - |
999 | - ApplicationInfo* m_source; |
1000 | - FillMode m_fillMode; |
1001 | - bool m_ready; |
1002 | - QQmlComponent *m_imageComponent; |
1003 | - QQuickItem* m_imageItem; |
1004 | - // the QML script used to create the current m_imageItem |
1005 | - QString m_qmlUsed; |
1006 | -}; |
1007 | - |
1008 | -#endif // APPLICATION_IMAGE_H |
1009 | |
1010 | === modified file 'tests/mocks/Unity/Application/ApplicationInfo.cpp' |
1011 | --- tests/mocks/Unity/Application/ApplicationInfo.cpp 2014-08-16 16:38:43 +0000 |
1012 | +++ tests/mocks/Unity/Application/ApplicationInfo.cpp 2014-08-25 08:53:17 +0000 |
1013 | @@ -18,6 +18,8 @@ |
1014 | #include "MirSurfaceItem.h" |
1015 | #include "SurfaceManager.h" |
1016 | |
1017 | +#include <paths.h> |
1018 | + |
1019 | #include <QGuiApplication> |
1020 | #include <QQuickItem> |
1021 | #include <QQuickView> |
1022 | @@ -31,10 +33,10 @@ |
1023 | , m_state(Starting) |
1024 | , m_focused(false) |
1025 | , m_fullscreen(false) |
1026 | + , m_surface(0) |
1027 | + , m_manualSurfaceCreation(false) |
1028 | , m_parentItem(0) |
1029 | - , m_surface(0) |
1030 | { |
1031 | - connect(this, &ApplicationInfo::stateChanged, this, &ApplicationInfo::onStateChanged); |
1032 | } |
1033 | |
1034 | ApplicationInfo::ApplicationInfo(QObject *parent) |
1035 | @@ -43,10 +45,10 @@ |
1036 | , m_state(Starting) |
1037 | , m_focused(false) |
1038 | , m_fullscreen(false) |
1039 | + , m_surface(0) |
1040 | + , m_manualSurfaceCreation(false) |
1041 | , m_parentItem(0) |
1042 | - , m_surface(0) |
1043 | { |
1044 | - connect(this, &ApplicationInfo::stateChanged, this, &ApplicationInfo::onStateChanged); |
1045 | } |
1046 | |
1047 | ApplicationInfo::~ApplicationInfo() |
1048 | @@ -58,23 +60,16 @@ |
1049 | } |
1050 | } |
1051 | |
1052 | -void ApplicationInfo::onStateChanged(State state) |
1053 | -{ |
1054 | - if (state == ApplicationInfo::Running) { |
1055 | - QTimer::singleShot(1000, this, SLOT(createSurface())); |
1056 | - } else if (state == ApplicationInfo::Stopped) { |
1057 | - setSurface(nullptr); |
1058 | - } |
1059 | -} |
1060 | - |
1061 | void ApplicationInfo::createSurface() |
1062 | { |
1063 | if (m_surface || state() == ApplicationInfo::Stopped) return; |
1064 | |
1065 | + QUrl screenshotUrl = QString("file://%1").arg(m_screenshotFileName); |
1066 | + |
1067 | setSurface(new MirSurfaceItem(name(), |
1068 | MirSurfaceItem::Normal, |
1069 | fullscreen() ? MirSurfaceItem::Fullscreen : MirSurfaceItem::Maximized, |
1070 | - screenshot())); |
1071 | + screenshotUrl)); |
1072 | } |
1073 | |
1074 | void ApplicationInfo::setSurface(MirSurfaceItem* surface) |
1075 | @@ -152,3 +147,77 @@ |
1076 | return nullptr; |
1077 | return p->m_promptSurfaces[index]; |
1078 | } |
1079 | + |
1080 | +void ApplicationInfo::setIconId(const QString &iconId) |
1081 | +{ |
1082 | + setIcon(QString("file://%1/graphics/applicationIcons/%2@18.png") |
1083 | + .arg(qmlDirectory()) |
1084 | + .arg(iconId)); |
1085 | +} |
1086 | + |
1087 | +void ApplicationInfo::setScreenshotId(const QString &screenshotId) |
1088 | +{ |
1089 | + m_screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png") |
1090 | + .arg(qmlDirectory()) |
1091 | + .arg(screenshotId); |
1092 | +} |
1093 | + |
1094 | +void ApplicationInfo::setName(const QString &value) |
1095 | +{ |
1096 | + if (value != m_name) { |
1097 | + m_name = value; |
1098 | + Q_EMIT nameChanged(value); |
1099 | + } |
1100 | +} |
1101 | + |
1102 | +void ApplicationInfo::setIcon(const QUrl &value) |
1103 | +{ |
1104 | + if (value != m_icon) { |
1105 | + m_icon = value; |
1106 | + Q_EMIT iconChanged(value); |
1107 | + } |
1108 | +} |
1109 | + |
1110 | +void ApplicationInfo::setStage(Stage value) |
1111 | +{ |
1112 | + if (value != m_stage) { |
1113 | + m_stage = value; |
1114 | + Q_EMIT stageChanged(value); |
1115 | + } |
1116 | +} |
1117 | + |
1118 | +void ApplicationInfo::setState(State value) |
1119 | +{ |
1120 | + if (value != m_state) { |
1121 | + m_state = value; |
1122 | + Q_EMIT stateChanged(value); |
1123 | + |
1124 | + if (!m_manualSurfaceCreation && m_state == ApplicationInfo::Running) { |
1125 | + QTimer::singleShot(1000, this, SLOT(createSurface())); |
1126 | + } |
1127 | + } |
1128 | +} |
1129 | + |
1130 | +void ApplicationInfo::setFocused(bool value) |
1131 | +{ |
1132 | + if (value != m_focused) { |
1133 | + m_focused = value; |
1134 | + Q_EMIT focusedChanged(value); |
1135 | + } |
1136 | +} |
1137 | + |
1138 | +void ApplicationInfo::setFullscreen(bool value) |
1139 | +{ |
1140 | + if (value != m_fullscreen) { |
1141 | + m_fullscreen = value; |
1142 | + Q_EMIT fullscreenChanged(value); |
1143 | + } |
1144 | +} |
1145 | + |
1146 | +void ApplicationInfo::setManualSurfaceCreation(bool value) |
1147 | +{ |
1148 | + if (value != m_manualSurfaceCreation) { |
1149 | + m_manualSurfaceCreation = value; |
1150 | + Q_EMIT manualSurfaceCreationChanged(value); |
1151 | + } |
1152 | +} |
1153 | |
1154 | === modified file 'tests/mocks/Unity/Application/ApplicationInfo.h' |
1155 | --- tests/mocks/Unity/Application/ApplicationInfo.h 2014-08-07 17:15:00 +0000 |
1156 | +++ tests/mocks/Unity/Application/ApplicationInfo.h 2014-08-25 08:53:17 +0000 |
1157 | @@ -26,63 +26,52 @@ |
1158 | // unity-api |
1159 | #include <unity/shell/application/ApplicationInfoInterface.h> |
1160 | |
1161 | -// A pretty dumb file. Just a container for properties. |
1162 | -// Implemented in C++ instead of QML just because of the enumerations |
1163 | -// See QTBUG-14861 |
1164 | - |
1165 | using namespace unity::shell::application; |
1166 | |
1167 | class ApplicationInfo : public ApplicationInfoInterface { |
1168 | Q_OBJECT |
1169 | |
1170 | Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged) |
1171 | - Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged) |
1172 | Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged) |
1173 | Q_PROPERTY(QQmlListProperty<MirSurfaceItem> promptSurfaces READ promptSurfaces NOTIFY promptSurfacesChanged DESIGNABLE false) |
1174 | |
1175 | // Only exists in this fake implementation |
1176 | |
1177 | - // QML component used to represent its image/screenhot |
1178 | - Q_PROPERTY(QString imageQml READ imageQml WRITE setImageQml NOTIFY imageQmlChanged) |
1179 | - |
1180 | - // QML component used to represent the application window |
1181 | - Q_PROPERTY(QString windowQml READ windowQml WRITE setWindowQml NOTIFY windowQmlChanged) |
1182 | + // whether the test code will explicitly control the creation of the application surface |
1183 | + Q_PROPERTY(bool manualSurfaceCreation READ manualSurfaceCreation WRITE setManualSurfaceCreation NOTIFY manualSurfaceCreationChanged) |
1184 | |
1185 | public: |
1186 | ApplicationInfo(QObject *parent = NULL); |
1187 | ApplicationInfo(const QString &appId, QObject *parent = NULL); |
1188 | ~ApplicationInfo(); |
1189 | |
1190 | - #define IMPLEMENT_PROPERTY(name, Name, type) \ |
1191 | - public: \ |
1192 | - type name() const { return m_##name; } \ |
1193 | - void set##Name(const type& value) \ |
1194 | - { \ |
1195 | - if (m_##name != value) { \ |
1196 | - m_##name = value; \ |
1197 | - Q_EMIT name##Changed(value); \ |
1198 | - } \ |
1199 | - } \ |
1200 | - Q_SIGNALS: \ |
1201 | - void name##Changed(const type&); \ |
1202 | - private: \ |
1203 | - type m_##name; |
1204 | - |
1205 | - IMPLEMENT_PROPERTY(appId, AppId, QString) |
1206 | - IMPLEMENT_PROPERTY(name, Name, QString) |
1207 | - IMPLEMENT_PROPERTY(comment, Comment, QString) |
1208 | - IMPLEMENT_PROPERTY(icon, Icon, QUrl) |
1209 | - IMPLEMENT_PROPERTY(stage, Stage, Stage) |
1210 | - IMPLEMENT_PROPERTY(state, State, State) |
1211 | - IMPLEMENT_PROPERTY(focused, Focused, bool) |
1212 | - IMPLEMENT_PROPERTY(fullscreen, Fullscreen, bool) |
1213 | - IMPLEMENT_PROPERTY(imageQml, ImageQml, QString) |
1214 | - IMPLEMENT_PROPERTY(windowQml, WindowQml, QString) |
1215 | - IMPLEMENT_PROPERTY(screenshot, Screenshot, QUrl) |
1216 | - |
1217 | - #undef IMPLEMENT_PROPERTY |
1218 | - |
1219 | -public: |
1220 | + void setIconId(const QString &iconId); |
1221 | + void setScreenshotId(const QString &screenshotId); |
1222 | + |
1223 | + void setAppId(const QString &value) { m_appId = value; } |
1224 | + QString appId() const override { return m_appId; } |
1225 | + |
1226 | + void setName(const QString &value); |
1227 | + QString name() const override { return m_name; } |
1228 | + |
1229 | + QString comment() const override { return QString(); } |
1230 | + |
1231 | + QUrl icon() const override { return m_icon; } |
1232 | + |
1233 | + void setStage(Stage value); |
1234 | + Stage stage() const override { return m_stage; } |
1235 | + |
1236 | + Q_INVOKABLE void setState(State value); |
1237 | + State state() const override { return m_state; } |
1238 | + |
1239 | + void setFocused(bool value); |
1240 | + bool focused() const override { return m_focused; } |
1241 | + |
1242 | + QString screenshot() const { return m_screenshotFileName; } |
1243 | + |
1244 | + void setFullscreen(bool value); |
1245 | + bool fullscreen() const { return m_fullscreen; } |
1246 | + |
1247 | void setSurface(MirSurfaceItem* surface); |
1248 | MirSurfaceItem* surface() const { return m_surface; } |
1249 | |
1250 | @@ -92,21 +81,38 @@ |
1251 | QList<MirSurfaceItem*> promptSurfaceList() const; |
1252 | QQmlListProperty<MirSurfaceItem> promptSurfaces(); |
1253 | |
1254 | + bool manualSurfaceCreation() const { return m_manualSurfaceCreation; } |
1255 | + void setManualSurfaceCreation(bool value); |
1256 | + |
1257 | Q_SIGNALS: |
1258 | void surfaceChanged(MirSurfaceItem*); |
1259 | void promptSurfacesChanged(); |
1260 | - |
1261 | -private Q_SLOTS: |
1262 | - void onStateChanged(State state); |
1263 | - |
1264 | - void createSurface(); |
1265 | + void fullscreenChanged(bool value); |
1266 | + void manualSurfaceCreationChanged(bool value); |
1267 | + |
1268 | +public Q_SLOTS: |
1269 | + Q_INVOKABLE void createSurface(); |
1270 | |
1271 | private: |
1272 | static int promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop); |
1273 | static MirSurfaceItem* promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index); |
1274 | + void setIcon(const QUrl &value); |
1275 | + void setScreenshot(const QUrl &value); |
1276 | + |
1277 | + QString m_screenshotFileName; |
1278 | + |
1279 | + QString m_appId; |
1280 | + QString m_name; |
1281 | + QUrl m_icon; |
1282 | + Stage m_stage; |
1283 | + State m_state; |
1284 | + bool m_focused; |
1285 | + bool m_fullscreen; |
1286 | + MirSurfaceItem* m_surface; |
1287 | + |
1288 | + bool m_manualSurfaceCreation; |
1289 | |
1290 | QQuickItem *m_parentItem; |
1291 | - MirSurfaceItem* m_surface; |
1292 | QList<MirSurfaceItem*> m_promptSurfaces; |
1293 | }; |
1294 | |
1295 | |
1296 | === modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp' |
1297 | --- tests/mocks/Unity/Application/ApplicationManager.cpp 2014-08-07 17:15:00 +0000 |
1298 | +++ tests/mocks/Unity/Application/ApplicationManager.cpp 2014-08-25 08:53:17 +0000 |
1299 | @@ -55,14 +55,32 @@ |
1300 | |
1301 | buildListOfAvailableApplications(); |
1302 | |
1303 | + // polling to find out when the toplevel window has been created as there's |
1304 | + // no signal telling us that |
1305 | + connect(&m_windowCreatedTimer, &QTimer::timeout, |
1306 | + this, &ApplicationManager::onWindowCreatedTimerTimeout); |
1307 | + m_windowCreatedTimer.setSingleShot(false); |
1308 | + m_windowCreatedTimer.start(200); |
1309 | +} |
1310 | + |
1311 | +ApplicationManager::~ApplicationManager() |
1312 | +{ |
1313 | +} |
1314 | + |
1315 | +void ApplicationManager::onWindowCreatedTimerTimeout() |
1316 | +{ |
1317 | + if (QGuiApplication::topLevelWindows().count() > 0) { |
1318 | + m_windowCreatedTimer.stop(); |
1319 | + onWindowCreated(); |
1320 | + } |
1321 | +} |
1322 | + |
1323 | +void ApplicationManager::onWindowCreated() |
1324 | +{ |
1325 | startApplication("unity8-dash"); |
1326 | focusApplication("unity8-dash"); |
1327 | } |
1328 | |
1329 | -ApplicationManager::~ApplicationManager() |
1330 | -{ |
1331 | -} |
1332 | - |
1333 | int ApplicationManager::rowCount(const QModelIndex& parent) const { |
1334 | return !parent.isValid() ? m_runningApplications.size() : 0; |
1335 | } |
1336 | @@ -87,8 +105,6 @@ |
1337 | return app->state(); |
1338 | case RoleFocused: |
1339 | return app->focused(); |
1340 | - case RoleScreenshot: |
1341 | - return app->screenshot(); |
1342 | case RoleSurface: |
1343 | return QVariant::fromValue(app->surface()); |
1344 | case RoleFullscreen: |
1345 | @@ -143,6 +159,16 @@ |
1346 | if (!appIndex.isValid()) return; |
1347 | Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleSurface); |
1348 | }); |
1349 | + connect(application, &ApplicationInfo::focusedChanged, this, [application, this]() { |
1350 | + QModelIndex appIndex = findIndex(application); |
1351 | + if (!appIndex.isValid()) return; |
1352 | + Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleFocused); |
1353 | + }); |
1354 | + connect(application, &ApplicationInfo::stateChanged, this, [application, this]() { |
1355 | + QModelIndex appIndex = findIndex(application); |
1356 | + if (!appIndex.isValid()) return; |
1357 | + Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleState); |
1358 | + }); |
1359 | } |
1360 | |
1361 | void ApplicationManager::remove(ApplicationInfo *application) { |
1362 | @@ -155,7 +181,7 @@ |
1363 | Q_EMIT countChanged(); |
1364 | if (isEmpty()) Q_EMIT emptyChanged(isEmpty()); |
1365 | } |
1366 | - disconnect(application, &ApplicationInfo::surfaceChanged, this, 0); |
1367 | + disconnect(application, 0, this, 0); |
1368 | } |
1369 | |
1370 | void ApplicationManager::move(int from, int to) { |
1371 | @@ -198,15 +224,7 @@ |
1372 | const QStringList &arguments) |
1373 | { |
1374 | Q_UNUSED(arguments) |
1375 | - ApplicationInfo *application = 0; |
1376 | - |
1377 | - for (ApplicationInfo *availableApp : m_availableApplications) { |
1378 | - if (availableApp->appId() == appId) { |
1379 | - application = availableApp; |
1380 | - break; |
1381 | - } |
1382 | - } |
1383 | - |
1384 | + ApplicationInfo *application = add(appId); |
1385 | if (!application) |
1386 | return 0; |
1387 | |
1388 | @@ -214,12 +232,28 @@ |
1389 | && application->stage() == ApplicationInfo::SideStage) { |
1390 | application->setStage(ApplicationInfo::MainStage); |
1391 | } |
1392 | - add(application); |
1393 | application->setState(ApplicationInfo::Running); |
1394 | |
1395 | return application; |
1396 | } |
1397 | |
1398 | +ApplicationInfo* ApplicationManager::add(QString appId) |
1399 | +{ |
1400 | + ApplicationInfo *application = 0; |
1401 | + |
1402 | + for (ApplicationInfo *availableApp : m_availableApplications) { |
1403 | + if (availableApp->appId() == appId) { |
1404 | + application = availableApp; |
1405 | + break; |
1406 | + } |
1407 | + } |
1408 | + |
1409 | + if (application) |
1410 | + add(application); |
1411 | + |
1412 | + return application; |
1413 | +} |
1414 | + |
1415 | bool ApplicationManager::stopApplication(const QString &appId) |
1416 | { |
1417 | if (appId == "unity8-dash") { |
1418 | @@ -238,27 +272,6 @@ |
1419 | return true; |
1420 | } |
1421 | |
1422 | -bool ApplicationManager::updateScreenshot(const QString &appId) |
1423 | -{ |
1424 | - int idx = -1; |
1425 | - ApplicationInfo *application = nullptr; |
1426 | - for (int i = 0; i < m_availableApplications.count(); ++i) { |
1427 | - application = m_availableApplications.at(i); |
1428 | - if (application->appId() == appId) { |
1429 | - idx = i; |
1430 | - break; |
1431 | - } |
1432 | - } |
1433 | - |
1434 | - if (idx == -1) { |
1435 | - return false; |
1436 | - } |
1437 | - |
1438 | - QModelIndex appIndex = index(idx); |
1439 | - Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleScreenshot); |
1440 | - return true; |
1441 | -} |
1442 | - |
1443 | QString ApplicationManager::focusedApplicationId() const { |
1444 | for (ApplicationInfo *app : m_runningApplications) { |
1445 | if (app->focused()) { |
1446 | @@ -293,32 +306,18 @@ |
1447 | if (application == nullptr) |
1448 | return false; |
1449 | |
1450 | - if (application->stage() == ApplicationInfo::MainStage) { |
1451 | - // unfocus currently focused mainstage app |
1452 | - for (ApplicationInfo *app : m_runningApplications) { |
1453 | - if (app->focused() && app->stage() == ApplicationInfo::MainStage) { |
1454 | - app->setFocused(false); |
1455 | - app->setState(ApplicationInfo::Suspended); |
1456 | - } |
1457 | - } |
1458 | - |
1459 | - // focus this app |
1460 | - application->setFocused(true); |
1461 | - application->setState(ApplicationInfo::Running); |
1462 | - } else if (application->stage() == ApplicationInfo::SideStage) { |
1463 | - // unfocus currently focused sidestage app |
1464 | - for (ApplicationInfo *app : m_runningApplications) { |
1465 | - if (app->focused() && app->stage() == ApplicationInfo::SideStage) { |
1466 | - app->setFocused(false); |
1467 | - app->setState(ApplicationInfo::Suspended); |
1468 | - } |
1469 | - } |
1470 | - |
1471 | - // focus this app |
1472 | - application->setFocused(true); |
1473 | - application->setState(ApplicationInfo::Running); |
1474 | + // unfocus currently focused app |
1475 | + for (ApplicationInfo *app : m_runningApplications) { |
1476 | + if (app->focused()) { |
1477 | + app->setFocused(false); |
1478 | + app->setState(ApplicationInfo::Suspended); |
1479 | + } |
1480 | } |
1481 | |
1482 | + // focus this app |
1483 | + application->setFocused(true); |
1484 | + application->setState(ApplicationInfo::Running); |
1485 | + |
1486 | // move app to top of stack |
1487 | move(m_runningApplications.indexOf(application), 0); |
1488 | Q_EMIT focusedApplicationIdChanged(); |
1489 | @@ -341,12 +340,6 @@ |
1490 | Q_EMIT focusedApplicationIdChanged(); |
1491 | } |
1492 | |
1493 | -void ApplicationManager::generateQmlStrings(ApplicationInfo *application) |
1494 | -{ |
1495 | - application->setScreenshot(QString("file://%1/Dash/graphics/phone/screenshots/%2@12.png").arg(qmlDirectory()) |
1496 | - .arg(application->icon().toString())); |
1497 | -} |
1498 | - |
1499 | void ApplicationManager::buildListOfAvailableApplications() |
1500 | { |
1501 | ApplicationInfo *application; |
1502 | @@ -354,128 +347,120 @@ |
1503 | application = new ApplicationInfo(this); |
1504 | application->setAppId("unity8-dash"); |
1505 | application->setName("Unity 8 Mock Dash"); |
1506 | - application->setIcon(QUrl("unity8-dash")); |
1507 | + application->setScreenshotId("unity8-dash"); |
1508 | application->setStage(ApplicationInfo::MainStage); |
1509 | - generateQmlStrings(application); |
1510 | m_availableApplications.append(application); |
1511 | |
1512 | application = new ApplicationInfo(this); |
1513 | application->setAppId("dialer-app"); |
1514 | application->setName("Dialer"); |
1515 | - application->setIcon(QUrl("dialer")); |
1516 | + application->setScreenshotId("dialer"); |
1517 | + application->setIconId("dialer-app"); |
1518 | application->setStage(ApplicationInfo::SideStage); |
1519 | - generateQmlStrings(application); |
1520 | m_availableApplications.append(application); |
1521 | |
1522 | application = new ApplicationInfo(this); |
1523 | application->setAppId("camera-app"); |
1524 | application->setName("Camera"); |
1525 | - application->setIcon(QUrl("camera")); |
1526 | + application->setScreenshotId("camera"); |
1527 | + application->setIconId("camera"); |
1528 | application->setFullscreen(true); |
1529 | - generateQmlStrings(application); |
1530 | m_availableApplications.append(application); |
1531 | |
1532 | application = new ApplicationInfo(this); |
1533 | application->setAppId("gallery-app"); |
1534 | application->setName("Gallery"); |
1535 | - application->setIcon(QUrl("gallery")); |
1536 | - generateQmlStrings(application); |
1537 | + application->setScreenshotId("gallery"); |
1538 | + application->setIconId("gallery"); |
1539 | + application->setFullscreen(true); |
1540 | m_availableApplications.append(application); |
1541 | |
1542 | application = new ApplicationInfo(this); |
1543 | application->setAppId("facebook-webapp"); |
1544 | application->setName("Facebook"); |
1545 | - application->setIcon(QUrl("facebook")); |
1546 | + application->setScreenshotId("facebook"); |
1547 | + application->setIconId("facebook"); |
1548 | application->setStage(ApplicationInfo::SideStage); |
1549 | - generateQmlStrings(application); |
1550 | m_availableApplications.append(application); |
1551 | |
1552 | application = new ApplicationInfo(this); |
1553 | application->setAppId("webbrowser-app"); |
1554 | application->setFullscreen(true); |
1555 | application->setName("Browser"); |
1556 | - application->setIcon(QUrl("browser")); |
1557 | - generateQmlStrings(application); |
1558 | + application->setScreenshotId("browser"); |
1559 | + application->setIconId("browser"); |
1560 | m_availableApplications.append(application); |
1561 | |
1562 | application = new ApplicationInfo(this); |
1563 | application->setAppId("twitter-webapp"); |
1564 | application->setName("Twitter"); |
1565 | - application->setIcon(QUrl("twitter")); |
1566 | + application->setScreenshotId("twitter"); |
1567 | + application->setIconId("twitter"); |
1568 | application->setStage(ApplicationInfo::SideStage); |
1569 | - generateQmlStrings(application); |
1570 | + m_availableApplications.append(application); |
1571 | + |
1572 | + application = new ApplicationInfo(this); |
1573 | + application->setAppId("map"); |
1574 | + application->setName("Map"); |
1575 | + application->setIconId("map"); |
1576 | + application->setScreenshotId("map"); |
1577 | m_availableApplications.append(application); |
1578 | |
1579 | application = new ApplicationInfo(this); |
1580 | application->setAppId("gmail-webapp"); |
1581 | application->setName("GMail"); |
1582 | - application->setIcon(QUrl("gmail")); |
1583 | + application->setIconId("gmail"); |
1584 | m_availableApplications.append(application); |
1585 | |
1586 | application = new ApplicationInfo(this); |
1587 | application->setAppId("ubuntu-weather-app"); |
1588 | application->setName("Weather"); |
1589 | - application->setIcon(QUrl("weather")); |
1590 | + application->setIconId("weather"); |
1591 | application->setStage(ApplicationInfo::SideStage); |
1592 | - generateQmlStrings(application); |
1593 | m_availableApplications.append(application); |
1594 | |
1595 | application = new ApplicationInfo(this); |
1596 | application->setAppId("notes-app"); |
1597 | application->setName("Notepad"); |
1598 | - application->setIcon(QUrl("notepad")); |
1599 | + application->setIconId("notepad"); |
1600 | application->setStage(ApplicationInfo::SideStage); |
1601 | m_availableApplications.append(application); |
1602 | |
1603 | application = new ApplicationInfo(this); |
1604 | application->setAppId("calendar-app"); |
1605 | application->setName("Calendar"); |
1606 | - application->setIcon(QUrl("calendar")); |
1607 | + application->setIconId("calendar"); |
1608 | application->setStage(ApplicationInfo::SideStage); |
1609 | m_availableApplications.append(application); |
1610 | |
1611 | application = new ApplicationInfo(this); |
1612 | - application->setAppId("mediaplayer-app"); |
1613 | - application->setName("Media Player"); |
1614 | - application->setIcon(QUrl("mediaplayer-app")); |
1615 | - application->setFullscreen(true); |
1616 | - m_availableApplications.append(application); |
1617 | - |
1618 | - application = new ApplicationInfo(this); |
1619 | application->setAppId("evernote"); |
1620 | application->setName("Evernote"); |
1621 | - application->setIcon(QUrl("evernote")); |
1622 | - m_availableApplications.append(application); |
1623 | - |
1624 | - application = new ApplicationInfo(this); |
1625 | - application->setAppId("map"); |
1626 | - application->setName("Map"); |
1627 | - application->setIcon(QUrl("map")); |
1628 | - generateQmlStrings(application); |
1629 | + application->setIconId("evernote"); |
1630 | m_availableApplications.append(application); |
1631 | |
1632 | application = new ApplicationInfo(this); |
1633 | application->setAppId("pinterest"); |
1634 | application->setName("Pinterest"); |
1635 | - application->setIcon(QUrl("pinterest")); |
1636 | + application->setIconId("pinterest"); |
1637 | m_availableApplications.append(application); |
1638 | |
1639 | application = new ApplicationInfo(this); |
1640 | application->setAppId("soundcloud"); |
1641 | application->setName("SoundCloud"); |
1642 | - application->setIcon(QUrl("soundcloud")); |
1643 | + application->setIconId("soundcloud"); |
1644 | m_availableApplications.append(application); |
1645 | |
1646 | application = new ApplicationInfo(this); |
1647 | application->setAppId("wikipedia"); |
1648 | application->setName("Wikipedia"); |
1649 | - application->setIcon(QUrl("wikipedia")); |
1650 | + application->setIconId("wikipedia"); |
1651 | m_availableApplications.append(application); |
1652 | |
1653 | application = new ApplicationInfo(this); |
1654 | application->setAppId("youtube"); |
1655 | application->setName("YouTube"); |
1656 | - application->setIcon(QUrl("youtube")); |
1657 | + application->setIconId("youtube"); |
1658 | m_availableApplications.append(application); |
1659 | } |
1660 | |
1661 | |
1662 | === modified file 'tests/mocks/Unity/Application/ApplicationManager.h' |
1663 | --- tests/mocks/Unity/Application/ApplicationManager.h 2014-08-07 17:15:00 +0000 |
1664 | +++ tests/mocks/Unity/Application/ApplicationManager.h 2014-08-25 08:53:17 +0000 |
1665 | @@ -20,6 +20,7 @@ |
1666 | #include <QObject> |
1667 | #include <QList> |
1668 | #include <QStringList> |
1669 | +#include <QTimer> |
1670 | #include "ApplicationInfo.h" |
1671 | |
1672 | // unity-api |
1673 | @@ -51,7 +52,7 @@ |
1674 | static ApplicationManager *singleton(); |
1675 | |
1676 | enum MoreRoles { |
1677 | - RoleSurface = RoleScreenshot+1, |
1678 | + RoleSurface = RoleFocused+1, |
1679 | RoleFullscreen, |
1680 | RoleApplication, |
1681 | }; |
1682 | @@ -97,7 +98,6 @@ |
1683 | Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override; |
1684 | Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, ExecFlags flags, const QStringList &arguments = QStringList()); |
1685 | Q_INVOKABLE bool stopApplication(const QString &appId) override; |
1686 | - Q_INVOKABLE bool updateScreenshot(const QString &appId) override; |
1687 | |
1688 | QString focusedApplicationId() const override; |
1689 | bool suspended() const; |
1690 | @@ -105,6 +105,7 @@ |
1691 | |
1692 | // Only for testing |
1693 | Q_INVOKABLE QStringList availableApplications(); |
1694 | + Q_INVOKABLE ApplicationInfo* add(QString appId); |
1695 | |
1696 | QModelIndex findIndex(ApplicationInfo* application); |
1697 | |
1698 | @@ -115,15 +116,18 @@ |
1699 | void focusRequested(const QString &appId); |
1700 | void emptyChanged(bool empty); |
1701 | |
1702 | + private Q_SLOTS: |
1703 | + void onWindowCreatedTimerTimeout(); |
1704 | + |
1705 | private: |
1706 | void add(ApplicationInfo *application); |
1707 | void remove(ApplicationInfo* application); |
1708 | - void showApplicationWindow(ApplicationInfo *application); |
1709 | void buildListOfAvailableApplications(); |
1710 | - void generateQmlStrings(ApplicationInfo *application); |
1711 | + void onWindowCreated(); |
1712 | bool m_suspended; |
1713 | QList<ApplicationInfo*> m_runningApplications; |
1714 | QList<ApplicationInfo*> m_availableApplications; |
1715 | + QTimer m_windowCreatedTimer; |
1716 | |
1717 | static ApplicationManager *the_application_manager; |
1718 | }; |
1719 | |
1720 | === modified file 'tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp' |
1721 | --- tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 2014-07-25 00:10:11 +0000 |
1722 | +++ tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 2014-08-25 08:53:17 +0000 |
1723 | @@ -44,11 +44,9 @@ |
1724 | return QImage(); |
1725 | } |
1726 | |
1727 | - QString filePath = QString("%1/Dash/graphics/phone/screenshots/%2@12.png").arg(qmlDirectory()).arg(app->icon().toString()); |
1728 | - |
1729 | QImage image; |
1730 | - if (!image.load(filePath)) { |
1731 | - qWarning() << "failed loading app image" << filePath; |
1732 | + if (!image.load(app->screenshot())) { |
1733 | + qWarning() << "failed loading app image" << app->screenshot(); |
1734 | } |
1735 | |
1736 | |
1737 | |
1738 | === modified file 'tests/mocks/Unity/Application/CMakeLists.txt' |
1739 | --- tests/mocks/Unity/Application/CMakeLists.txt 2014-07-22 13:24:37 +0000 |
1740 | +++ tests/mocks/Unity/Application/CMakeLists.txt 2014-08-25 08:53:17 +0000 |
1741 | @@ -1,15 +1,13 @@ |
1742 | -pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application) |
1743 | +pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=3) |
1744 | |
1745 | set(FakeUnityApplicationQml_SOURCES |
1746 | plugin.cpp |
1747 | ApplicationDBusAdaptor.cpp |
1748 | ApplicationInfo.cpp |
1749 | - ApplicationImage.cpp |
1750 | ApplicationManager.cpp |
1751 | ApplicationScreenshotProvider.cpp |
1752 | MirSurfaceItem.cpp |
1753 | SurfaceManager.cpp |
1754 | - VirtualKeyboard.cpp |
1755 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h |
1756 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h |
1757 | ) |
1758 | |
1759 | === removed file 'tests/mocks/Unity/Application/InputFilterArea.qml' |
1760 | --- tests/mocks/Unity/Application/InputFilterArea.qml 2013-06-05 22:03:08 +0000 |
1761 | +++ tests/mocks/Unity/Application/InputFilterArea.qml 1970-01-01 00:00:00 +0000 |
1762 | @@ -1,21 +0,0 @@ |
1763 | -/* |
1764 | - * Copyright (C) 2013 Canonical, Ltd. |
1765 | - * |
1766 | - * This program is free software; you can redistribute it and/or modify |
1767 | - * it under the terms of the GNU General Public License as published by |
1768 | - * the Free Software Foundation; version 3. |
1769 | - * |
1770 | - * This program is distributed in the hope that it will be useful, |
1771 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1772 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1773 | - * GNU General Public License for more details. |
1774 | - * |
1775 | - * You should have received a copy of the GNU General Public License |
1776 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1777 | - */ |
1778 | - |
1779 | -import QtQuick 2.0; |
1780 | - |
1781 | -Item { |
1782 | - property bool blockInput: false |
1783 | -} |
1784 | |
1785 | === modified file 'tests/mocks/Unity/Application/MirSurfaceItem.cpp' |
1786 | --- tests/mocks/Unity/Application/MirSurfaceItem.cpp 2014-08-08 09:40:50 +0000 |
1787 | +++ tests/mocks/Unity/Application/MirSurfaceItem.cpp 2014-08-25 08:53:17 +0000 |
1788 | @@ -17,33 +17,67 @@ |
1789 | #include "MirSurfaceItem.h" |
1790 | #include "ApplicationInfo.h" |
1791 | |
1792 | -#include <QPainter> |
1793 | +#include <paths.h> |
1794 | + |
1795 | +#include <QGuiApplication> |
1796 | +#include <QQuickView> |
1797 | +#include <QQmlProperty> |
1798 | #include <QQmlEngine> |
1799 | +#include <QString> |
1800 | + |
1801 | +#include <QDebug> |
1802 | |
1803 | MirSurfaceItem::MirSurfaceItem(const QString& name, |
1804 | MirSurfaceItem::Type type, |
1805 | MirSurfaceItem::State state, |
1806 | const QUrl& screenshot, |
1807 | + const QString &qmlFilePath, |
1808 | QQuickItem *parent) |
1809 | - : QQuickPaintedItem(parent) |
1810 | + : QQuickItem(parent) |
1811 | , m_application(nullptr) |
1812 | , m_name(name) |
1813 | , m_type(type) |
1814 | , m_state(state) |
1815 | - , m_img(screenshot.isLocalFile() ? screenshot.toLocalFile() : screenshot.toString()) |
1816 | , m_parentSurface(nullptr) |
1817 | - , m_haveInputMethod(false) |
1818 | + , m_qmlItem(nullptr) |
1819 | + , m_screenshotUrl(screenshot) |
1820 | { |
1821 | qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name(); |
1822 | |
1823 | QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); |
1824 | |
1825 | - // The virtual keyboard (input method) has a big transparent area so that |
1826 | - // content behind it show through |
1827 | - setFillColor(Qt::transparent); |
1828 | - |
1829 | connect(this, &QQuickItem::focusChanged, |
1830 | this, &MirSurfaceItem::onFocusChanged); |
1831 | + |
1832 | + // The assumptions I make here really should hold. |
1833 | + QQuickView *quickView = |
1834 | + qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]); |
1835 | + |
1836 | + QString qmlComponentFilePath; |
1837 | + if (!qmlFilePath.isEmpty()) { |
1838 | + qmlComponentFilePath.append(qmlFilePath); |
1839 | + } else { |
1840 | + qmlComponentFilePath = QString("%1/Unity/Application/MirSurfaceItem.qml") |
1841 | + .arg(mockPluginsDir()); |
1842 | + } |
1843 | + |
1844 | + m_qmlContentComponent = new QQmlComponent(quickView->engine(), qmlComponentFilePath); |
1845 | + |
1846 | + switch (m_qmlContentComponent->status()) { |
1847 | + case QQmlComponent::Ready: |
1848 | + createQmlContentItem(); |
1849 | + break; |
1850 | + case QQmlComponent::Loading: |
1851 | + connect(m_qmlContentComponent, &QQmlComponent::statusChanged, |
1852 | + this, &MirSurfaceItem::onComponentStatusChanged); |
1853 | + break; |
1854 | + case QQmlComponent::Error: |
1855 | + printComponentErrors(); |
1856 | + qFatal("MirSurfaceItem: failed to create content component."); |
1857 | + break; |
1858 | + default: |
1859 | + qFatal("MirSurfaceItem: Unhandled component status"); |
1860 | + } |
1861 | } |
1862 | |
1863 | MirSurfaceItem::~MirSurfaceItem() |
1864 | @@ -61,10 +95,11 @@ |
1865 | m_application->removeSurface(this); |
1866 | } |
1867 | |
1868 | -void MirSurfaceItem::paint(QPainter * painter) |
1869 | +void MirSurfaceItem::printComponentErrors() |
1870 | { |
1871 | - if (!m_img.isNull()) { |
1872 | - painter->drawImage(contentsBoundingRect(), m_img, QRect(QPoint(0,0), m_img.size())); |
1873 | + QList<QQmlError> errors = m_qmlContentComponent->errors(); |
1874 | + for (int i = 0; i < errors.count(); ++i) { |
1875 | + qDebug() << errors[i]; |
1876 | } |
1877 | } |
1878 | |
1879 | @@ -155,19 +190,24 @@ |
1880 | } |
1881 | |
1882 | |
1883 | -void MirSurfaceItem::touchEvent(QTouchEvent * event) |
1884 | +void MirSurfaceItem::onQmlWantInputMethodChanged() |
1885 | { |
1886 | - if (event->type() == QEvent::TouchBegin && hasFocus()) { |
1887 | + QQmlProperty prop(m_qmlItem, "wantInputMethod"); |
1888 | + bool wantInputMethod = prop.read().toBool(); |
1889 | + |
1890 | + if (hasFocus() && wantInputMethod) { |
1891 | Q_EMIT inputMethodRequested(); |
1892 | - m_haveInputMethod = true; |
1893 | } |
1894 | } |
1895 | |
1896 | void MirSurfaceItem::onFocusChanged() |
1897 | { |
1898 | - if (!hasFocus() && m_haveInputMethod) { |
1899 | + QQmlProperty prop(m_qmlItem, "wantInputMethod"); |
1900 | + bool wantInputMethod = prop.read().toBool(); |
1901 | + |
1902 | + if (!hasFocus() && wantInputMethod) { |
1903 | Q_EMIT inputMethodDismissed(); |
1904 | - m_haveInputMethod = false; |
1905 | + prop.write(QVariant::fromValue(false)); |
1906 | } |
1907 | } |
1908 | |
1909 | @@ -178,3 +218,34 @@ |
1910 | Q_EMIT stateChanged(newState); |
1911 | } |
1912 | } |
1913 | + |
1914 | +void MirSurfaceItem::onComponentStatusChanged(QQmlComponent::Status status) |
1915 | +{ |
1916 | + if (status == QQmlComponent::Ready) { |
1917 | + createQmlContentItem(); |
1918 | + } |
1919 | +} |
1920 | + |
1921 | +void MirSurfaceItem::createQmlContentItem() |
1922 | +{ |
1923 | + qDebug() << "MirSurfaceItem::createQmlContentItem()"; |
1924 | + |
1925 | + m_qmlItem = qobject_cast<QQuickItem*>(m_qmlContentComponent->create()); |
1926 | + m_qmlItem->setParentItem(this); |
1927 | + |
1928 | + setImplicitWidth(m_qmlItem->implicitWidth()); |
1929 | + setImplicitHeight(m_qmlItem->implicitHeight()); |
1930 | + |
1931 | + { |
1932 | + QQmlProperty screenshotSource(m_qmlItem, "screenshotSource"); |
1933 | + screenshotSource.write(QVariant::fromValue(m_screenshotUrl)); |
1934 | + } |
1935 | + |
1936 | + { |
1937 | + QQmlProperty prop(m_qmlItem, "wantInputMethod"); |
1938 | + if (prop.type() == QQmlProperty::Property) { |
1939 | + bool ok = prop.connectNotifySignal(this, SLOT(onQmlWantInputMethodChanged())); |
1940 | + if (!ok) qCritical("MirSurfaceItem: failed to connect to wantInputMethod notify signal"); |
1941 | + } |
1942 | + } |
1943 | +} |
1944 | |
1945 | === modified file 'tests/mocks/Unity/Application/MirSurfaceItem.h' |
1946 | --- tests/mocks/Unity/Application/MirSurfaceItem.h 2014-08-07 17:15:00 +0000 |
1947 | +++ tests/mocks/Unity/Application/MirSurfaceItem.h 2014-08-25 08:53:17 +0000 |
1948 | @@ -17,12 +17,13 @@ |
1949 | #ifndef MIRSURFACEITEM_H |
1950 | #define MIRSURFACEITEM_H |
1951 | |
1952 | -#include <QQuickPaintedItem> |
1953 | -#include <QImage> |
1954 | +#include <QQuickItem> |
1955 | +#include <QQmlComponent> |
1956 | +#include <QUrl> |
1957 | |
1958 | class ApplicationInfo; |
1959 | |
1960 | -class MirSurfaceItem : public QQuickPaintedItem |
1961 | +class MirSurfaceItem : public QQuickItem |
1962 | { |
1963 | Q_OBJECT |
1964 | Q_ENUMS(Type) |
1965 | @@ -59,6 +60,7 @@ |
1966 | Type type, |
1967 | State state, |
1968 | const QUrl& screenshot, |
1969 | + const QString &qmlFilePath = QString(), |
1970 | QQuickItem *parent = 0); |
1971 | ~MirSurfaceItem(); |
1972 | |
1973 | @@ -76,9 +78,6 @@ |
1974 | Q_INVOKABLE void setState(State newState); |
1975 | Q_INVOKABLE void release(); |
1976 | |
1977 | - void paint(QPainter * painter) override; |
1978 | - void touchEvent(QTouchEvent * event) override; |
1979 | - |
1980 | Q_SIGNALS: |
1981 | void typeChanged(Type); |
1982 | void stateChanged(State); |
1983 | @@ -93,9 +92,8 @@ |
1984 | |
1985 | private Q_SLOTS: |
1986 | void onFocusChanged(); |
1987 | - |
1988 | -protected: |
1989 | - const QImage &screenshotImage() { return m_img; } |
1990 | + void onComponentStatusChanged(QQmlComponent::Status status); |
1991 | + void onQmlWantInputMethodChanged(); |
1992 | |
1993 | private: |
1994 | void addChildSurface(MirSurfaceItem* surface); |
1995 | @@ -105,15 +103,20 @@ |
1996 | static int childSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop); |
1997 | static MirSurfaceItem* childSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index); |
1998 | |
1999 | + void createQmlContentItem(); |
2000 | + void printComponentErrors(); |
2001 | + |
2002 | ApplicationInfo* m_application; |
2003 | const QString m_name; |
2004 | const Type m_type; |
2005 | State m_state; |
2006 | - const QImage m_img; |
2007 | |
2008 | MirSurfaceItem* m_parentSurface; |
2009 | QList<MirSurfaceItem*> m_children; |
2010 | - bool m_haveInputMethod; |
2011 | + |
2012 | + QQmlComponent *m_qmlContentComponent; |
2013 | + QQuickItem *m_qmlItem; |
2014 | + QUrl m_screenshotUrl; |
2015 | }; |
2016 | |
2017 | Q_DECLARE_METATYPE(MirSurfaceItem*) |
2018 | |
2019 | === added file 'tests/mocks/Unity/Application/MirSurfaceItem.qml' |
2020 | --- tests/mocks/Unity/Application/MirSurfaceItem.qml 1970-01-01 00:00:00 +0000 |
2021 | +++ tests/mocks/Unity/Application/MirSurfaceItem.qml 2014-08-25 08:53:17 +0000 |
2022 | @@ -0,0 +1,57 @@ |
2023 | +/* |
2024 | + * Copyright 2014 Canonical Ltd. |
2025 | + * |
2026 | + * This program is free software; you can redistribute it and/or modify |
2027 | + * it under the terms of the GNU Lesser General Public License as published by |
2028 | + * the Free Software Foundation; version 3. |
2029 | + * |
2030 | + * This program is distributed in the hope that it will be useful, |
2031 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2032 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2033 | + * GNU Lesser General Public License for more details. |
2034 | + * |
2035 | + * You should have received a copy of the GNU Lesser General Public License |
2036 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2037 | + */ |
2038 | + |
2039 | +import QtQuick 2.0 |
2040 | + |
2041 | +Rectangle { |
2042 | + objectName: "fakeSurfaceQML" |
2043 | + id: root |
2044 | + color: "pink" |
2045 | + |
2046 | + anchors.fill: parent |
2047 | + |
2048 | + implicitWidth: units.gu(40) |
2049 | + implicitHeight: units.gu(70) |
2050 | + |
2051 | + property alias screenshotSource: screenshotImage.source |
2052 | + |
2053 | + property bool wantInputMethod: false |
2054 | + |
2055 | + property int touchPressCount: 0 |
2056 | + property int touchReleaseCount: 0 |
2057 | + |
2058 | + Image { |
2059 | + id: screenshotImage |
2060 | + anchors.fill: parent |
2061 | + fillMode: Image.Stretch |
2062 | + } |
2063 | + |
2064 | + Text { |
2065 | + anchors.fill: parent |
2066 | + text: "SURFACE" |
2067 | + color: "yellow" |
2068 | + font.bold: true |
2069 | + fontSizeMode: Text.Fit |
2070 | + minimumPixelSize: 10; font.pixelSize: 200 |
2071 | + verticalAlignment: Text.AlignVCenter |
2072 | + } |
2073 | + |
2074 | + MultiPointTouchArea { |
2075 | + anchors.fill: parent |
2076 | + onPressed: { root.wantInputMethod = true; root.touchPressCount++; } |
2077 | + onReleased: { root.touchReleaseCount++; } |
2078 | + } |
2079 | +} |
2080 | |
2081 | === removed file 'tests/mocks/Unity/Application/OSKController.qml' |
2082 | --- tests/mocks/Unity/Application/OSKController.qml 2013-09-10 15:06:32 +0000 |
2083 | +++ tests/mocks/Unity/Application/OSKController.qml 1970-01-01 00:00:00 +0000 |
2084 | @@ -1,20 +0,0 @@ |
2085 | -/* |
2086 | - * Copyright (C) 2013 Canonical, Ltd. |
2087 | - * |
2088 | - * This program is free software; you can redistribute it and/or modify |
2089 | - * it under the terms of the GNU General Public License as published by |
2090 | - * the Free Software Foundation; version 3. |
2091 | - * |
2092 | - * This program is distributed in the hope that it will be useful, |
2093 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2094 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2095 | - * GNU General Public License for more details. |
2096 | - * |
2097 | - * You should have received a copy of the GNU General Public License |
2098 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2099 | - */ |
2100 | - |
2101 | -import QtQuick 2.0; |
2102 | - |
2103 | -Item { |
2104 | -} |
2105 | |
2106 | === modified file 'tests/mocks/Unity/Application/SurfaceManager.cpp' |
2107 | --- tests/mocks/Unity/Application/SurfaceManager.cpp 2014-07-24 19:22:20 +0000 |
2108 | +++ tests/mocks/Unity/Application/SurfaceManager.cpp 2014-08-25 08:53:17 +0000 |
2109 | @@ -16,9 +16,8 @@ |
2110 | |
2111 | #include "SurfaceManager.h" |
2112 | |
2113 | +#include <paths.h> |
2114 | #include "MirSurfaceItem.h" |
2115 | -#include "VirtualKeyboard.h" |
2116 | - |
2117 | |
2118 | SurfaceManager *SurfaceManager::the_surface_manager = nullptr; |
2119 | |
2120 | @@ -66,7 +65,19 @@ |
2121 | MirSurfaceItem *SurfaceManager::inputMethodSurface() |
2122 | { |
2123 | if (!m_virtualKeyboard) { |
2124 | - m_virtualKeyboard = new VirtualKeyboard(MirSurfaceItem::Minimized); |
2125 | + |
2126 | + QString screenshotPath = QString("file://%1/Dash/graphics/phone/screenshots/vkb_portrait.png") |
2127 | + .arg(qmlDirectory()); |
2128 | + |
2129 | + QString qmlFilePath = QString("%1/Unity/Application/VirtualKeyboard.qml") |
2130 | + .arg(mockPluginsDir()); |
2131 | + |
2132 | + m_virtualKeyboard = new MirSurfaceItem( |
2133 | + "input-method", |
2134 | + MirSurfaceItem::InputMethod, |
2135 | + MirSurfaceItem::Minimized, |
2136 | + screenshotPath, |
2137 | + qmlFilePath); |
2138 | Q_EMIT surfaceCreated(m_virtualKeyboard); |
2139 | } |
2140 | return m_virtualKeyboard; |
2141 | |
2142 | === modified file 'tests/mocks/Unity/Application/SurfaceManager.h' |
2143 | --- tests/mocks/Unity/Application/SurfaceManager.h 2014-07-24 19:22:20 +0000 |
2144 | +++ tests/mocks/Unity/Application/SurfaceManager.h 2014-08-25 08:53:17 +0000 |
2145 | @@ -20,7 +20,6 @@ |
2146 | #include <QObject> |
2147 | |
2148 | class MirSurfaceItem; |
2149 | -class VirtualKeyboard; |
2150 | |
2151 | class SurfaceManager : public QObject |
2152 | { |
2153 | @@ -48,7 +47,7 @@ |
2154 | |
2155 | private: |
2156 | static SurfaceManager *the_surface_manager; |
2157 | - VirtualKeyboard *m_virtualKeyboard; |
2158 | + MirSurfaceItem *m_virtualKeyboard; |
2159 | }; |
2160 | |
2161 | #endif // SURFACEMANAGER_H |
2162 | |
2163 | === removed file 'tests/mocks/Unity/Application/VirtualKeyboard.cpp' |
2164 | --- tests/mocks/Unity/Application/VirtualKeyboard.cpp 2014-07-22 10:29:25 +0000 |
2165 | +++ tests/mocks/Unity/Application/VirtualKeyboard.cpp 1970-01-01 00:00:00 +0000 |
2166 | @@ -1,55 +0,0 @@ |
2167 | -/* |
2168 | - * Copyright (C) 2014 Canonical, Ltd. |
2169 | - * |
2170 | - * This program is free software; you can redistribute it and/or modify |
2171 | - * it under the terms of the GNU General Public License as published by |
2172 | - * the Free Software Foundation; version 3. |
2173 | - * |
2174 | - * This program is distributed in the hope that it will be useful, |
2175 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2176 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2177 | - * GNU General Public License for more details. |
2178 | - * |
2179 | - * You should have received a copy of the GNU General Public License |
2180 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2181 | - */ |
2182 | - |
2183 | -#include "VirtualKeyboard.h" |
2184 | - |
2185 | -#include <paths.h> |
2186 | - |
2187 | -VirtualKeyboard::VirtualKeyboard(State state, QQuickItem *parent) |
2188 | - : MirSurfaceItem("input-method", |
2189 | - MirSurfaceItem::InputMethod, |
2190 | - state, |
2191 | - QString("file://%1/Dash/graphics/phone/screenshots/vkb_portrait.png").arg(qmlDirectory()), |
2192 | - parent) |
2193 | -{ |
2194 | -} |
2195 | - |
2196 | -void VirtualKeyboard::touchEvent(QTouchEvent *event) |
2197 | -{ |
2198 | - if (event->type() == QEvent::TouchBegin && !hasTouchInsideKeyboard(event)) { |
2199 | - event->ignore(); |
2200 | - } |
2201 | -} |
2202 | - |
2203 | -bool VirtualKeyboard::hasTouchInsideKeyboard(QTouchEvent *event) |
2204 | -{ |
2205 | - const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints(); |
2206 | - for (int i = 0; i < touchPoints.count(); ++i) { |
2207 | - QPoint pos = touchPoints.at(i).pos().toPoint(); |
2208 | - |
2209 | - // Map to image coords |
2210 | - int imageX = (int)( ( ((qreal)pos.x()) / width() ) * ((qreal)screenshotImage().size().width()) ); |
2211 | - int imageY = (int)( ( ((qreal)pos.y()) / height() ) * ((qreal)screenshotImage().size().height()) ); |
2212 | - |
2213 | - QRgb pixelHit = screenshotImage().pixel(imageX, imageY); |
2214 | - |
2215 | - // The keyboard depicted in the image is in its opaque part. |
2216 | - if (qAlpha(pixelHit) != 0) { |
2217 | - return true; |
2218 | - } |
2219 | - } |
2220 | - return false; |
2221 | -} |
2222 | |
2223 | === removed file 'tests/mocks/Unity/Application/VirtualKeyboard.h' |
2224 | --- tests/mocks/Unity/Application/VirtualKeyboard.h 2014-07-22 10:29:25 +0000 |
2225 | +++ tests/mocks/Unity/Application/VirtualKeyboard.h 1970-01-01 00:00:00 +0000 |
2226 | @@ -1,35 +0,0 @@ |
2227 | -/* |
2228 | - * Copyright (C) 2014 Canonical, Ltd. |
2229 | - * |
2230 | - * This program is free software; you can redistribute it and/or modify |
2231 | - * it under the terms of the GNU General Public License as published by |
2232 | - * the Free Software Foundation; version 3. |
2233 | - * |
2234 | - * This program is distributed in the hope that it will be useful, |
2235 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2236 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2237 | - * GNU General Public License for more details. |
2238 | - * |
2239 | - * You should have received a copy of the GNU General Public License |
2240 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2241 | - */ |
2242 | - |
2243 | -#ifndef VIRTUALKEYBOARD_H |
2244 | -#define VIRTUALKEYBOARD_H |
2245 | - |
2246 | -#include "MirSurfaceItem.h" |
2247 | - |
2248 | -class VirtualKeyboard : public MirSurfaceItem |
2249 | -{ |
2250 | - Q_OBJECT |
2251 | -public: |
2252 | - VirtualKeyboard(State state, |
2253 | - QQuickItem *parent = 0); |
2254 | - |
2255 | - void touchEvent(QTouchEvent * event) override; |
2256 | - |
2257 | -private: |
2258 | - bool hasTouchInsideKeyboard(QTouchEvent *event); |
2259 | -}; |
2260 | - |
2261 | -#endif // VIRTUALKEYBOARD_H |
2262 | |
2263 | === added file 'tests/mocks/Unity/Application/VirtualKeyboard.qml' |
2264 | --- tests/mocks/Unity/Application/VirtualKeyboard.qml 1970-01-01 00:00:00 +0000 |
2265 | +++ tests/mocks/Unity/Application/VirtualKeyboard.qml 2014-08-25 08:53:17 +0000 |
2266 | @@ -0,0 +1,40 @@ |
2267 | +/* |
2268 | + * Copyright 2014 Canonical Ltd. |
2269 | + * |
2270 | + * This program is free software; you can redistribute it and/or modify |
2271 | + * it under the terms of the GNU Lesser General Public License as published by |
2272 | + * the Free Software Foundation; version 3. |
2273 | + * |
2274 | + * This program is distributed in the hope that it will be useful, |
2275 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2276 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2277 | + * GNU Lesser General Public License for more details. |
2278 | + * |
2279 | + * You should have received a copy of the GNU Lesser General Public License |
2280 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2281 | + */ |
2282 | + |
2283 | +import QtQuick 2.0 |
2284 | + |
2285 | +Item { |
2286 | + implicitWidth: units.gu(40) |
2287 | + implicitHeight: units.gu(70) |
2288 | + |
2289 | + anchors.fill: parent |
2290 | + |
2291 | + property alias screenshotSource: screenshotImage.source |
2292 | + |
2293 | + property bool landscape: width > height |
2294 | + |
2295 | + Image { |
2296 | + id: screenshotImage |
2297 | + height: landscape ? parent.height * 0.4 : width * 0.6 |
2298 | + anchors.bottom: parent.bottom |
2299 | + anchors.left: parent.left |
2300 | + anchors.right: parent.right |
2301 | + |
2302 | + MultiPointTouchArea { |
2303 | + anchors.fill: parent |
2304 | + } |
2305 | + } |
2306 | +} |
2307 | |
2308 | === modified file 'tests/mocks/Unity/Application/plugin.cpp' |
2309 | --- tests/mocks/Unity/Application/plugin.cpp 2014-07-19 11:52:38 +0000 |
2310 | +++ tests/mocks/Unity/Application/plugin.cpp 2014-08-25 08:53:17 +0000 |
2311 | @@ -16,7 +16,6 @@ |
2312 | |
2313 | #include "plugin.h" |
2314 | #include "ApplicationInfo.h" |
2315 | -#include "ApplicationImage.h" |
2316 | #include "ApplicationManager.h" |
2317 | #include "ApplicationScreenshotProvider.h" |
2318 | #include "MirSurfaceItem.h" |
2319 | @@ -49,8 +48,6 @@ |
2320 | qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo"); |
2321 | |
2322 | qmlRegisterUncreatableType<MirSurfaceItem>(uri, 0, 1, "MirSurfaceItem", "MirSurfaceItem can't be instantiated from QML"); |
2323 | - |
2324 | - qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage"); |
2325 | } |
2326 | |
2327 | void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
2328 | |
2329 | === modified file 'tests/mocks/Unity/Application/qmldir' |
2330 | --- tests/mocks/Unity/Application/qmldir 2014-05-02 22:57:21 +0000 |
2331 | +++ tests/mocks/Unity/Application/qmldir 2014-08-25 08:53:17 +0000 |
2332 | @@ -1,6 +1,3 @@ |
2333 | module Unity.Application |
2334 | plugin FakeUnityApplicationQml |
2335 | typeinfo Application.qmltypes |
2336 | - |
2337 | -InputFilterArea 0.1 InputFilterArea.qml |
2338 | -OSKController 0.1 OSKController.qml |
2339 | |
2340 | === modified file 'tests/plugins/Unity/Launcher/CMakeLists.txt' |
2341 | --- tests/plugins/Unity/Launcher/CMakeLists.txt 2014-05-30 09:22:58 +0000 |
2342 | +++ tests/plugins/Unity/Launcher/CMakeLists.txt 2014-08-25 08:53:17 +0000 |
2343 | @@ -1,6 +1,6 @@ |
2344 | pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt) |
2345 | pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3) |
2346 | -pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=1) |
2347 | +pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=3) |
2348 | |
2349 | include_directories( |
2350 | ${CMAKE_CURRENT_BINARY_DIR} |
2351 | |
2352 | === modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp' |
2353 | --- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2014-07-03 12:03:57 +0000 |
2354 | +++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2014-08-25 08:53:17 +0000 |
2355 | @@ -93,7 +93,6 @@ |
2356 | m_list.takeAt(index)->deleteLater(); |
2357 | endRemoveRows(); |
2358 | } |
2359 | - bool updateScreenshot(const QString &appId) { Q_UNUSED(appId); return true; } |
2360 | bool requestFocusApplication(const QString &appId) { Q_UNUSED(appId); return true; } |
2361 | bool suspended() const { return false; } |
2362 | void setSuspended(bool) {} |
2363 | |
2364 | === modified file 'tests/qmltests/CMakeLists.txt' |
2365 | --- tests/qmltests/CMakeLists.txt 2014-08-20 08:39:09 +0000 |
2366 | +++ tests/qmltests/CMakeLists.txt 2014-08-25 08:53:17 +0000 |
2367 | @@ -76,4 +76,7 @@ |
2368 | # These MenuItemFactory tests need the test/mocks/ to come before plugins/ |
2369 | add_qml_test(Panel/Indicators MenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS}) |
2370 | add_qml_test(Panel/Indicators MessageMenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS}) |
2371 | +add_qml_test(Stages ApplicationWindow ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single") |
2372 | add_qml_test(Stages PhoneStage ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single") |
2373 | +add_qml_test(Stages SpreadDelegate ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single") |
2374 | +add_qml_test(Stages SurfaceContainer ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single") |
2375 | |
2376 | === added file 'tests/qmltests/Stages/tst_ApplicationWindow.qml' |
2377 | --- tests/qmltests/Stages/tst_ApplicationWindow.qml 1970-01-01 00:00:00 +0000 |
2378 | +++ tests/qmltests/Stages/tst_ApplicationWindow.qml 2014-08-25 08:53:17 +0000 |
2379 | @@ -0,0 +1,346 @@ |
2380 | +/* |
2381 | + * Copyright 2014 Canonical Ltd. |
2382 | + * |
2383 | + * This program is free software; you can redistribute it and/or modify |
2384 | + * it under the terms of the GNU General Public License as published by |
2385 | + * the Free Software Foundation; version 3. |
2386 | + * |
2387 | + * This program is distributed in the hope that it will be useful, |
2388 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2389 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2390 | + * GNU General Public License for more details. |
2391 | + * |
2392 | + * You should have received a copy of the GNU General Public License |
2393 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2394 | + */ |
2395 | + |
2396 | +import QtQuick 2.0 |
2397 | +import QtTest 1.0 |
2398 | +import Unity.Test 0.1 as UT |
2399 | +import ".." |
2400 | +import "../../../qml/Stages" |
2401 | +import Ubuntu.Components 0.1 |
2402 | +import Ubuntu.Components.ListItems 1.0 as ListItem |
2403 | +import Unity.Application 0.1 |
2404 | + |
2405 | +Rectangle { |
2406 | + color: "red" |
2407 | + id: root |
2408 | + width: units.gu(70) |
2409 | + height: units.gu(70) |
2410 | + |
2411 | + Component.onCompleted: { |
2412 | + root.fakeApplication = ApplicationManager.add("gallery-app"); |
2413 | + root.fakeApplication.manualSurfaceCreation = true; |
2414 | + root.fakeApplication.setState(ApplicationInfo.Starting); |
2415 | + } |
2416 | + property QtObject fakeApplication: null |
2417 | + |
2418 | + Connections { |
2419 | + target: fakeApplication |
2420 | + onSurfaceChanged: { |
2421 | + surfaceCheckbox.checked = fakeApplication.surface !== null; |
2422 | + } |
2423 | + } |
2424 | + |
2425 | + Component { |
2426 | + id: applicationWindowComponent |
2427 | + ApplicationWindow { |
2428 | + anchors.fill: parent |
2429 | + application: fakeApplication |
2430 | + } |
2431 | + } |
2432 | + Loader { |
2433 | + id: applicationWindowLoader |
2434 | + anchors { |
2435 | + top: parent.top |
2436 | + bottom: parent.bottom |
2437 | + left: parent.left |
2438 | + } |
2439 | + width: units.gu(40) |
2440 | + sourceComponent: applicationWindowComponent |
2441 | + } |
2442 | + |
2443 | + Rectangle { |
2444 | + color: "white" |
2445 | + anchors { |
2446 | + top: parent.top |
2447 | + bottom: parent.bottom |
2448 | + left: applicationWindowLoader.right |
2449 | + right: parent.right |
2450 | + } |
2451 | + |
2452 | + Column { |
2453 | + anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) } |
2454 | + spacing: units.gu(1) |
2455 | + Row { |
2456 | + anchors { left: parent.left; right: parent.right } |
2457 | + CheckBox { |
2458 | + id: surfaceCheckbox; checked: false |
2459 | + onCheckedChanged: { |
2460 | + if (applicationWindowLoader.status !== Loader.Ready) |
2461 | + return; |
2462 | + |
2463 | + if (checked && !fakeApplication.surface) { |
2464 | + fakeApplication.createSurface(); |
2465 | + } else if (!checked && fakeApplication.surface) { |
2466 | + fakeApplication.surface.release(); |
2467 | + } |
2468 | + } |
2469 | + } |
2470 | + Label { text: "Surface" } |
2471 | + } |
2472 | + ListItem.ItemSelector { |
2473 | + id: appStateSelector |
2474 | + anchors { left: parent.left; right: parent.right } |
2475 | + text: "Application state" |
2476 | + model: ["Starting", |
2477 | + "Running", |
2478 | + "Suspended", |
2479 | + "Stopped"] |
2480 | + property int selectedApplicationState: { |
2481 | + if (model[selectedIndex] === "Starting") { |
2482 | + return ApplicationInfo.Starting; |
2483 | + } else if (model[selectedIndex] === "Running") { |
2484 | + return ApplicationInfo.Running; |
2485 | + } else if (model[selectedIndex] === "Suspended") { |
2486 | + return ApplicationInfo.Suspended; |
2487 | + } else { |
2488 | + return ApplicationInfo.Stopped; |
2489 | + } |
2490 | + } |
2491 | + onSelectedApplicationStateChanged: { |
2492 | + // state is a read-only property, thus we have to call the setter function |
2493 | + fakeApplication.setState(selectedApplicationState); |
2494 | + } |
2495 | + } |
2496 | + } |
2497 | + } |
2498 | + |
2499 | + UT.UnityTestCase { |
2500 | + id: testCase |
2501 | + name: "ApplicationWindow" |
2502 | + when: windowShown |
2503 | + |
2504 | + // just to make them shorter |
2505 | + property int appStarting: ApplicationInfo.Starting |
2506 | + property int appRunning: ApplicationInfo.Running |
2507 | + property int appSuspended: ApplicationInfo.Suspended |
2508 | + property int appStopped: ApplicationInfo.Stopped |
2509 | + |
2510 | + function setApplicationState(appState) { |
2511 | + switch (appState) { |
2512 | + case appStarting: |
2513 | + appStateSelector.selectedIndex = 0; |
2514 | + break; |
2515 | + case appRunning: |
2516 | + appStateSelector.selectedIndex = 1; |
2517 | + break; |
2518 | + case appSuspended: |
2519 | + appStateSelector.selectedIndex = 2; |
2520 | + break; |
2521 | + case appStopped: |
2522 | + appStateSelector.selectedIndex = 3; |
2523 | + break; |
2524 | + } |
2525 | + } |
2526 | + |
2527 | + // holds some of the internal ApplicationWindow objects we probe during the tests |
2528 | + property var stateGroup: null |
2529 | + |
2530 | + function findInterestingApplicationWindowChildren() { |
2531 | + stateGroup = findInvisibleChild(applicationWindowLoader.item, "applicationWindowStateGroup"); |
2532 | + verify(stateGroup); |
2533 | + } |
2534 | + |
2535 | + function forgetApplicationWindowChildren() { |
2536 | + stateGroup = null; |
2537 | + } |
2538 | + |
2539 | + // wait until any transition animation has finished |
2540 | + function waitUntilTransitionsEnd() { |
2541 | + var transitions = stateGroup.transitions; |
2542 | + for (var i = 0; i < transitions.length; ++i) { |
2543 | + var transition = transitions[i]; |
2544 | + tryCompare(transition, "running", false, 2000); |
2545 | + } |
2546 | + } |
2547 | + |
2548 | + function init() { |
2549 | + findInterestingApplicationWindowChildren(); |
2550 | + } |
2551 | + |
2552 | + function cleanup() { |
2553 | + forgetApplicationWindowChildren(); |
2554 | + |
2555 | + // reload our test subject to get it in a fresh state once again |
2556 | + applicationWindowLoader.active = false; |
2557 | + |
2558 | + appStateSelector.selectedIndex = 0; |
2559 | + surfaceCheckbox.checked = false; |
2560 | + |
2561 | + if (fakeApplication.surface) |
2562 | + fakeApplication.surface.release(); |
2563 | + |
2564 | + applicationWindowLoader.active = true; |
2565 | + } |
2566 | + |
2567 | + function test_showSplashUntilAppFullyInit_data() { |
2568 | + return [ |
2569 | + {tag: "state=Running then create surface", swapInitOrder: false}, |
2570 | + |
2571 | + {tag: "create surface then state=Running", swapInitOrder: true}, |
2572 | + ] |
2573 | + } |
2574 | + |
2575 | + function test_showSplashUntilAppFullyInit() { |
2576 | + verify(stateGroup.state === "splashScreen"); |
2577 | + |
2578 | + if (data.swapInitOrder) { |
2579 | + surfaceCheckbox.checked = true; |
2580 | + } else { |
2581 | + setApplicationState(appRunning); |
2582 | + } |
2583 | + |
2584 | + verify(stateGroup.state === "splashScreen"); |
2585 | + |
2586 | + if (data.swapInitOrder) { |
2587 | + setApplicationState(appRunning); |
2588 | + } else { |
2589 | + surfaceCheckbox.checked = true; |
2590 | + } |
2591 | + |
2592 | + tryCompare(stateGroup, "state", "surface"); |
2593 | + } |
2594 | + |
2595 | + function test_suspendedAppShowsSurface() { |
2596 | + surfaceCheckbox.checked = true; |
2597 | + setApplicationState(appRunning); |
2598 | + |
2599 | + tryCompare(stateGroup, "state", "surface"); |
2600 | + |
2601 | + waitUntilTransitionsEnd(); |
2602 | + |
2603 | + setApplicationState(appSuspended); |
2604 | + |
2605 | + verify(stateGroup.state === "surface"); |
2606 | + waitUntilTransitionsEnd(); |
2607 | + } |
2608 | + |
2609 | + function test_killedAppShowsScreenshot() { |
2610 | + surfaceCheckbox.checked = true; |
2611 | + setApplicationState(appRunning); |
2612 | + tryCompare(stateGroup, "state", "surface"); |
2613 | + |
2614 | + setApplicationState(appSuspended); |
2615 | + |
2616 | + verify(stateGroup.state === "surface"); |
2617 | + verify(fakeApplication.surface !== null); |
2618 | + |
2619 | + // kill it! |
2620 | + setApplicationState(appStopped); |
2621 | + |
2622 | + tryCompare(stateGroup, "state", "screenshot"); |
2623 | + tryCompare(fakeApplication, "surface", null); |
2624 | + } |
2625 | + |
2626 | + function test_restartApp() { |
2627 | + var screenshotImage = findChild(applicationWindowLoader.item, "screenshotImage"); |
2628 | + |
2629 | + surfaceCheckbox.checked = true; |
2630 | + setApplicationState(appRunning); |
2631 | + tryCompare(stateGroup, "state", "surface"); |
2632 | + waitUntilTransitionsEnd(); |
2633 | + |
2634 | + setApplicationState(appSuspended); |
2635 | + |
2636 | + // kill it |
2637 | + setApplicationState(appStopped); |
2638 | + |
2639 | + tryCompare(stateGroup, "state", "screenshot"); |
2640 | + waitUntilTransitionsEnd(); |
2641 | + tryCompare(fakeApplication, "surface", null); |
2642 | + |
2643 | + // and restart it |
2644 | + setApplicationState(appStarting); |
2645 | + |
2646 | + waitUntilTransitionsEnd(); |
2647 | + verify(stateGroup.state === "screenshot"); |
2648 | + verify(fakeApplication.surface === null); |
2649 | + |
2650 | + setApplicationState(appRunning); |
2651 | + |
2652 | + waitUntilTransitionsEnd(); |
2653 | + verify(stateGroup.state === "screenshot"); |
2654 | + |
2655 | + surfaceCheckbox.checked = true; |
2656 | + |
2657 | + tryCompare(stateGroup, "state", "surface"); |
2658 | + tryCompare(screenshotImage, "status", Image.Null); |
2659 | + } |
2660 | + |
2661 | + function test_appCrashed() { |
2662 | + surfaceCheckbox.checked = true; |
2663 | + setApplicationState(appRunning); |
2664 | + tryCompare(stateGroup, "state", "surface"); |
2665 | + waitUntilTransitionsEnd(); |
2666 | + |
2667 | + // oh, it crashed... |
2668 | + setApplicationState(appStopped); |
2669 | + |
2670 | + tryCompare(stateGroup, "state", "screenshot"); |
2671 | + tryCompare(fakeApplication, "surface", null); |
2672 | + } |
2673 | + |
2674 | + function test_keepSurfaceWhileInvisible() { |
2675 | + surfaceCheckbox.checked = true; |
2676 | + setApplicationState(appRunning); |
2677 | + tryCompare(stateGroup, "state", "surface"); |
2678 | + waitUntilTransitionsEnd(); |
2679 | + verify(fakeApplication.surface !== null); |
2680 | + |
2681 | + applicationWindowLoader.item.visible = false; |
2682 | + |
2683 | + waitUntilTransitionsEnd(); |
2684 | + verify(stateGroup.state === "surface"); |
2685 | + verify(fakeApplication.surface !== null); |
2686 | + |
2687 | + applicationWindowLoader.item.visible = true; |
2688 | + |
2689 | + waitUntilTransitionsEnd(); |
2690 | + verify(stateGroup.state === "surface"); |
2691 | + verify(fakeApplication.surface !== null); |
2692 | + } |
2693 | + |
2694 | + function test_touchesReachSurfaceWhenItsShown() { |
2695 | + setApplicationState(appRunning); |
2696 | + surfaceCheckbox.checked = true; |
2697 | + |
2698 | + tryCompare(stateGroup, "state", "surface"); |
2699 | + |
2700 | + waitUntilTransitionsEnd(); |
2701 | + |
2702 | + // Because doing stuff in C++ is a PITA we keep the counter in the interal qml impl. |
2703 | + var fakeSurface = findChild(fakeApplication.surface, "fakeSurfaceQML"); |
2704 | + fakeSurface.touchPressCount = 0; |
2705 | + fakeSurface.touchReleaseCount = 0; |
2706 | + |
2707 | + tap(applicationWindowLoader.item, |
2708 | + applicationWindowLoader.item.width / 2, applicationWindowLoader.item.height / 2); |
2709 | + |
2710 | + verify(fakeSurface.touchPressCount === 1); |
2711 | + verify(fakeSurface.touchReleaseCount === 1); |
2712 | + } |
2713 | + |
2714 | + function test_showNothingOnSuddenSurfaceLoss() { |
2715 | + surfaceCheckbox.checked = true; |
2716 | + setApplicationState(appRunning); |
2717 | + tryCompare(stateGroup, "state", "surface"); |
2718 | + waitUntilTransitionsEnd(); |
2719 | + |
2720 | + surfaceCheckbox.checked = false; |
2721 | + |
2722 | + verify(stateGroup.state === "void"); |
2723 | + } |
2724 | + } |
2725 | +} |
2726 | |
2727 | === modified file 'tests/qmltests/Stages/tst_PhoneStage.qml' |
2728 | --- tests/qmltests/Stages/tst_PhoneStage.qml 2014-07-25 00:01:00 +0000 |
2729 | +++ tests/qmltests/Stages/tst_PhoneStage.qml 2014-08-25 08:53:17 +0000 |
2730 | @@ -26,14 +26,11 @@ |
2731 | width: units.gu(70) |
2732 | height: units.gu(70) |
2733 | |
2734 | - Rectangle { |
2735 | - |
2736 | - } |
2737 | - |
2738 | PhoneStage { |
2739 | id: phoneStage |
2740 | anchors { fill: parent; rightMargin: units.gu(30) } |
2741 | dragAreaWidth: units.gu(2) |
2742 | + maximizedAppTopMargin: units.gu(3) + units.dp(2) |
2743 | } |
2744 | |
2745 | Binding { |
2746 | @@ -46,6 +43,7 @@ |
2747 | anchors { fill: parent; leftMargin: phoneStage.width } |
2748 | |
2749 | Column { |
2750 | + id: buttons |
2751 | anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) } |
2752 | spacing: units.gu(1) |
2753 | Button { |
2754 | @@ -57,9 +55,33 @@ |
2755 | } |
2756 | Button { |
2757 | anchors { left: parent.left; right: parent.right } |
2758 | - text: "Remove App" |
2759 | - onClicked: { |
2760 | - ApplicationManager.stopApplication(ApplicationManager.get(0).appId) |
2761 | + text: "Remove Selected" |
2762 | + onClicked: { |
2763 | + ApplicationManager.stopApplication(ApplicationManager.get(appList.selectedAppIndex).appId); |
2764 | + } |
2765 | + } |
2766 | + Button { |
2767 | + anchors { left: parent.left; right: parent.right } |
2768 | + text: "Stop Selected" |
2769 | + onClicked: { |
2770 | + ApplicationManager.get(appList.selectedAppIndex).setState(ApplicationInfo.Stopped); |
2771 | + } |
2772 | + } |
2773 | + } |
2774 | + ListView { |
2775 | + id: appList |
2776 | + property int selectedAppIndex |
2777 | + anchors { left: parent.left; right: parent.right; top: buttons.bottom; bottom: parent.bottom } |
2778 | + boundsBehavior: Flickable.StopAtBounds |
2779 | + model: ApplicationManager |
2780 | + delegate: Rectangle { |
2781 | + anchors { left: parent.left; right: parent.right } |
2782 | + height: units.gu(2) |
2783 | + color: appList.selectedAppIndex === model.index ? "red" : "white" |
2784 | + Text { anchors.fill: parent; text: model.appId } |
2785 | + MouseArea { |
2786 | + anchors.fill: parent |
2787 | + onPressed: { appList.selectedAppIndex = model.index; } |
2788 | } |
2789 | } |
2790 | } |
2791 | @@ -84,7 +106,9 @@ |
2792 | function goToSpread() { |
2793 | var spreadView = findChild(phoneStage, "spreadView"); |
2794 | |
2795 | - var startX = phoneStage.width; |
2796 | + // Keep it inside the PhoneStage otherwise the controls on the right side will |
2797 | + // capture the press thus the "- 2" on startX. |
2798 | + var startX = phoneStage.width - 2; |
2799 | var startY = phoneStage.height / 2; |
2800 | var endY = startY; |
2801 | var endX = units.gu(2); |
2802 | @@ -132,7 +156,9 @@ |
2803 | |
2804 | var spreadView = findChild(phoneStage, "spreadView"); |
2805 | |
2806 | - var startX = phoneStage.width; |
2807 | + // Keep it inside the PhoneStage otherwise the controls on the right side will |
2808 | + // capture the press thus the "- 2" on startX. |
2809 | + var startX = phoneStage.width - 2; |
2810 | var startY = phoneStage.height / 2; |
2811 | var endY = startY; |
2812 | var endX = spreadView.width - (spreadView.width * spreadView[data.positionMarker]) - data.offset; |
2813 | |
2814 | === added file 'tests/qmltests/Stages/tst_SpreadDelegate.qml' |
2815 | --- tests/qmltests/Stages/tst_SpreadDelegate.qml 1970-01-01 00:00:00 +0000 |
2816 | +++ tests/qmltests/Stages/tst_SpreadDelegate.qml 2014-08-25 08:53:17 +0000 |
2817 | @@ -0,0 +1,167 @@ |
2818 | +/* |
2819 | + * Copyright 2014 Canonical Ltd. |
2820 | + * |
2821 | + * This program is free software; you can redistribute it and/or modify |
2822 | + * it under the terms of the GNU General Public License as published by |
2823 | + * the Free Software Foundation; version 3. |
2824 | + * |
2825 | + * This program is distributed in the hope that it will be useful, |
2826 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2827 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2828 | + * GNU General Public License for more details. |
2829 | + * |
2830 | + * You should have received a copy of the GNU General Public License |
2831 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2832 | + */ |
2833 | + |
2834 | +import QtQuick 2.0 |
2835 | +import QtTest 1.0 |
2836 | +import Unity.Test 0.1 as UT |
2837 | +import ".." |
2838 | +import "../../../qml/Stages" |
2839 | +import Ubuntu.Components 0.1 |
2840 | +import Ubuntu.Components.ListItems 1.0 as ListItem |
2841 | +import Unity.Application 0.1 |
2842 | + |
2843 | +Rectangle { |
2844 | + color: "red" |
2845 | + id: root |
2846 | + width: units.gu(70) |
2847 | + height: units.gu(70) |
2848 | + |
2849 | + Component.onCompleted: { |
2850 | + root.fakeApplication = ApplicationManager.startApplication("gallery-app"); |
2851 | + } |
2852 | + property QtObject fakeApplication: null |
2853 | + |
2854 | + Component { |
2855 | + id: spreadDelegateComponent |
2856 | + SpreadDelegate { |
2857 | + anchors.fill: parent |
2858 | + swipeToCloseEnabled: swipeToCloseCheckbox.checked |
2859 | + closeable: closeableCheckbox.checked |
2860 | + application: fakeApplication |
2861 | + } |
2862 | + } |
2863 | + Loader { |
2864 | + id: spreadDelegateLoader |
2865 | + anchors { |
2866 | + top: parent.top |
2867 | + bottom: parent.bottom |
2868 | + left: parent.left |
2869 | + } |
2870 | + width: units.gu(40) |
2871 | + sourceComponent: spreadDelegateComponent |
2872 | + } |
2873 | + |
2874 | + Rectangle { |
2875 | + color: "white" |
2876 | + anchors { |
2877 | + top: parent.top |
2878 | + bottom: parent.bottom |
2879 | + left: spreadDelegateLoader.right |
2880 | + right: parent.right |
2881 | + } |
2882 | + |
2883 | + Column { |
2884 | + anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) } |
2885 | + spacing: units.gu(1) |
2886 | + Row { |
2887 | + anchors { left: parent.left; right: parent.right } |
2888 | + CheckBox { id: swipeToCloseCheckbox; checked: false; } |
2889 | + Label { text: "swipeToCloseEnabled" } |
2890 | + } |
2891 | + Row { |
2892 | + anchors { left: parent.left; right: parent.right } |
2893 | + CheckBox { id: closeableCheckbox; checked: false } |
2894 | + Label { text: "closeable" } |
2895 | + } |
2896 | + } |
2897 | + } |
2898 | + |
2899 | + UT.UnityTestCase { |
2900 | + id: testCase |
2901 | + name: "SpreadDelegate" |
2902 | + when: windowShown |
2903 | + |
2904 | + SignalSpy { |
2905 | + id: spyClosedSignal |
2906 | + target: spreadDelegateLoader.item |
2907 | + signalName: "closed" |
2908 | + } |
2909 | + |
2910 | + property var dragArea |
2911 | + |
2912 | + function init() { |
2913 | + dragArea = findInvisibleChild(spreadDelegateLoader.item, "dragArea"); |
2914 | + dragArea.__dateTime = fakeDateTime; |
2915 | + } |
2916 | + |
2917 | + function cleanup() { |
2918 | + // reload our test subject to get it in a fresh state once again |
2919 | + spreadDelegateLoader.active = false; |
2920 | + spreadDelegateLoader.active = true; |
2921 | + |
2922 | + spyClosedSignal.clear(); |
2923 | + } |
2924 | + |
2925 | + function test_swipeToClose_data() { |
2926 | + return [ |
2927 | + {tag: "swipeToClose=true closeable=true -> appWindow moves away", |
2928 | + swipeToClose: true, closeable: true }, |
2929 | + |
2930 | + {tag: "swipeToClose=true closeable=alse -> appWindow bounces back", |
2931 | + swipeToClose: true, closeable: false }, |
2932 | + |
2933 | + {tag: "swipeToClose=false -> appWindow stays put", |
2934 | + swipeToClose: false, closeable: true }, |
2935 | + ] |
2936 | + } |
2937 | + |
2938 | + function test_swipeToClose(data) { |
2939 | + var appWindowWithShadow = findChild(spreadDelegateLoader.item, "appWindowWithShadow"); |
2940 | + |
2941 | + verify(appWindowWithShadow.y === 0); |
2942 | + |
2943 | + swipeToCloseCheckbox.checked = data.swipeToClose; |
2944 | + closeableCheckbox.checked = data.closeable; |
2945 | + |
2946 | + var dragDistance = spreadDelegateLoader.item.height / 2; |
2947 | + var touchX = spreadDelegateLoader.item.width / 2; |
2948 | + var fromY = spreadDelegateLoader.item.height / 2; |
2949 | + var toY = fromY - dragDistance; |
2950 | + touchFlick(spreadDelegateLoader.item, |
2951 | + touchX /* fromX */, fromY, touchX /* toX */, toY, |
2952 | + true /* beginTouch */, false /* endTouch */, dragArea.minSpeedToClose * 1.1 /* speed */); |
2953 | + |
2954 | + |
2955 | + if (data.swipeToClose) { |
2956 | + verify(appWindowWithShadow.y < 0); |
2957 | + verify(Math.abs(Math.abs(appWindowWithShadow.y) - dragDistance) < units.gu(1)); |
2958 | + |
2959 | + touchRelease(spreadDelegateLoader.item, touchX, toY - units.gu(1)); |
2960 | + |
2961 | + waitForCloseAnimationToFinish(); |
2962 | + |
2963 | + if (data.closeable) { |
2964 | + verify(spyClosedSignal.count === 1); |
2965 | + } else { |
2966 | + verify(spyClosedSignal.count === 0); |
2967 | + tryCompare(appWindowWithShadow, "y", 0); |
2968 | + } |
2969 | + |
2970 | + } else { |
2971 | + verify(appWindowWithShadow.y === 0); |
2972 | + |
2973 | + touchRelease(spreadDelegateLoader.item, touchX, toY); |
2974 | + } |
2975 | + } |
2976 | + |
2977 | + function waitForCloseAnimationToFinish() { |
2978 | + var closeAnimation = findInvisibleChild(spreadDelegateLoader.item, "closeAnimation"); |
2979 | + wait(closeAnimation.duration * 1.5); |
2980 | + tryCompare(closeAnimation, "running", false); |
2981 | + } |
2982 | + |
2983 | + } |
2984 | +} |
2985 | |
2986 | === added file 'tests/qmltests/Stages/tst_SurfaceContainer.qml' |
2987 | --- tests/qmltests/Stages/tst_SurfaceContainer.qml 1970-01-01 00:00:00 +0000 |
2988 | +++ tests/qmltests/Stages/tst_SurfaceContainer.qml 2014-08-25 08:53:17 +0000 |
2989 | @@ -0,0 +1,154 @@ |
2990 | +/* |
2991 | + * Copyright 2014 Canonical Ltd. |
2992 | + * |
2993 | + * This program is free software; you can redistribute it and/or modify |
2994 | + * it under the terms of the GNU General Public License as published by |
2995 | + * the Free Software Foundation; version 3. |
2996 | + * |
2997 | + * This program is distributed in the hope that it will be useful, |
2998 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2999 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3000 | + * GNU General Public License for more details. |
3001 | + * |
3002 | + * You should have received a copy of the GNU General Public License |
3003 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3004 | + */ |
3005 | + |
3006 | +import QtQuick 2.0 |
3007 | +import QtTest 1.0 |
3008 | +import Unity.Test 0.1 as UT |
3009 | +import ".." |
3010 | +import "../../../qml/Stages" |
3011 | +import Ubuntu.Components 0.1 |
3012 | +import Unity.Application 0.1 |
3013 | + |
3014 | +Rectangle { |
3015 | + color: "black" |
3016 | + id: root |
3017 | + width: units.gu(70) |
3018 | + height: units.gu(70) |
3019 | + |
3020 | + Component { |
3021 | + id: fakeSurfaceComponent |
3022 | + Rectangle { |
3023 | + color: "green" |
3024 | + |
3025 | + Rectangle { |
3026 | + color: "blue" |
3027 | + anchors.fill: parent |
3028 | + anchors.margins: units.gu(2) |
3029 | + Text { |
3030 | + anchors.fill: parent |
3031 | + text: "Surface" |
3032 | + color: "green" |
3033 | + font.bold: true |
3034 | + fontSizeMode: Text.Fit |
3035 | + minimumPixelSize: 10; font.pixelSize: 200 |
3036 | + verticalAlignment: Text.AlignVCenter |
3037 | + } |
3038 | + } |
3039 | + |
3040 | + width: units.gu(1) |
3041 | + height: units.gu(1) |
3042 | + |
3043 | + property int type: MirSurfaceItem.Normal |
3044 | + property int state: MirSurfaceItem.Restored |
3045 | + property string name: "Fake Surface" |
3046 | + property Item parentSurface: null |
3047 | + property list<Item> childSurfaces |
3048 | + function release() {} |
3049 | + signal removed(); |
3050 | + } |
3051 | + } |
3052 | + |
3053 | + Item { |
3054 | + id: tempSurfaceHolder |
3055 | + } |
3056 | + |
3057 | + Component { |
3058 | + id: surfaceContainerComponent |
3059 | + SurfaceContainer { |
3060 | + anchors.fill: parent |
3061 | + } |
3062 | + } |
3063 | + Loader { |
3064 | + id: surfaceContainerLoader |
3065 | + anchors { |
3066 | + top: parent.top |
3067 | + topMargin: fullscreenCheckbox.checked ? 0 : units.gu(3) + units.dp(2) |
3068 | + bottom: parent.bottom |
3069 | + left: parent.left |
3070 | + } |
3071 | + width: units.gu(40) |
3072 | + sourceComponent: surfaceContainerComponent |
3073 | + } |
3074 | + |
3075 | + Rectangle { |
3076 | + color: "white" |
3077 | + anchors { |
3078 | + top: parent.top |
3079 | + bottom: parent.bottom |
3080 | + left: surfaceContainerLoader.right |
3081 | + right: parent.right |
3082 | + } |
3083 | + |
3084 | + Column { |
3085 | + anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) } |
3086 | + spacing: units.gu(1) |
3087 | + Row { |
3088 | + anchors { left: parent.left; right: parent.right } |
3089 | + CheckBox { |
3090 | + id: surfaceCheckbox; checked: false; |
3091 | + onCheckedChanged: { |
3092 | + if (surfaceContainerLoader.status !== Loader.Ready) |
3093 | + return; |
3094 | + |
3095 | + if (checked) { |
3096 | + var fakeSurface = fakeSurfaceComponent.createObject(tempSurfaceHolder); |
3097 | + surfaceContainerLoader.item.surface = fakeSurface; |
3098 | + } else { |
3099 | + var fakeSurface = surfaceContainerLoader.item.surface; |
3100 | + surfaceContainerLoader.item.surface = null; |
3101 | + fakeSurface.parent = null; |
3102 | + fakeSurface.destroy(); |
3103 | + } |
3104 | + } |
3105 | + } |
3106 | + Label { text: "surface" } |
3107 | + } |
3108 | + Row { |
3109 | + anchors { left: parent.left; right: parent.right } |
3110 | + CheckBox {id: fullscreenCheckbox; checked: true; } |
3111 | + Label { text: "fullscreen" } |
3112 | + } |
3113 | + } |
3114 | + } |
3115 | + |
3116 | + UT.UnityTestCase { |
3117 | + id: testCase |
3118 | + name: "SurfaceContainer" |
3119 | + when: windowShown |
3120 | + |
3121 | + function cleanup() { |
3122 | + // reload our test subject to get it in a fresh state once again |
3123 | + surfaceContainerLoader.active = false; |
3124 | + surfaceCheckbox.checked = false; |
3125 | + surfaceContainerLoader.active = true; |
3126 | + } |
3127 | + |
3128 | + /* |
3129 | + Add a first surface. Then remove it. Then add a second surface. |
3130 | + That second surface should be properly sized. |
3131 | + |
3132 | + Regression test for https://bugs.launchpad.net/ubuntu/+source/qtmir/+bug/1359819 |
3133 | + */ |
3134 | + function test_resetSurfaceGetsProperlySized() { |
3135 | + surfaceCheckbox.checked = true; |
3136 | + surfaceCheckbox.checked = false; |
3137 | + surfaceCheckbox.checked = true; |
3138 | + var fakeSurface = surfaceContainerLoader.item.surface; |
3139 | + compare(fakeSurface.width, surfaceContainerLoader.item.width); |
3140 | + compare(fakeSurface.height, surfaceContainerLoader.item.height); |
3141 | + } |
3142 | + } |
3143 | +} |
3144 | |
3145 | === modified file 'tests/qmltests/tst_Shell.qml' |
3146 | --- tests/qmltests/tst_Shell.qml 2014-08-21 14:46:12 +0000 |
3147 | +++ tests/qmltests/tst_Shell.qml 2014-08-25 08:53:17 +0000 |
3148 | @@ -416,11 +416,11 @@ |
3149 | compare(panel.fullscreenMode, false); |
3150 | ApplicationManager.startApplication("camera-app"); |
3151 | tryCompare(panel, "fullscreenMode", true); |
3152 | - ApplicationManager.startApplication("gallery-app"); |
3153 | + ApplicationManager.startApplication("dialer-app"); |
3154 | tryCompare(panel, "fullscreenMode", false); |
3155 | ApplicationManager.requestFocusApplication("camera-app"); |
3156 | tryCompare(panel, "fullscreenMode", true); |
3157 | - ApplicationManager.requestFocusApplication("gallery-app"); |
3158 | + ApplicationManager.requestFocusApplication("dialer-app"); |
3159 | tryCompare(panel, "fullscreenMode", false); |
3160 | } |
3161 | |
3162 | |
3163 | === modified file 'tests/utils/modules/Unity/Test/UnityTestCase.qml' |
3164 | --- tests/utils/modules/Unity/Test/UnityTestCase.qml 2014-06-23 16:40:11 +0000 |
3165 | +++ tests/utils/modules/Unity/Test/UnityTestCase.qml 2014-08-25 08:53:17 +0000 |
3166 | @@ -312,12 +312,15 @@ |
3167 | } |
3168 | |
3169 | function tap(item, x, y) { |
3170 | + var root = fetchRootItem(item) |
3171 | + var rootPoint = item.mapToItem(root, x, y) |
3172 | + |
3173 | var event = touchEvent() |
3174 | - event.press(0 /* touchId */, x, y) |
3175 | + event.press(0 /* touchId */, rootPoint.x, rootPoint.y) |
3176 | event.commit() |
3177 | |
3178 | event = touchEvent() |
3179 | - event.release(0 /* touchId */, x, y) |
3180 | + event.release(0 /* touchId */, rootPoint.x, rootPoint.y) |
3181 | event.commit() |
3182 | } |
3183 |
FAILED: Continuous integration, rev:1136 jenkins. qa.ubuntu. com/job/ unity8- ci/3834/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- utopic- touch/3245/ console jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- utopic/ 836/console jenkins. qa.ubuntu. com/job/ unity8- utopic- amd64-ci/ 928/console jenkins. qa.ubuntu. com/job/ unity8- utopic- armhf-ci/ 928/console jenkins. qa.ubuntu. com/job/ unity8- utopic- i386-ci/ 928/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/4490/ console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/3834/ rebuild
http://