Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/orientationManual into lp:ubuntu-ui-toolkit/staging

Proposed by Cris Dywan
Status: Rejected
Rejected by: Cris Dywan
Proposed branch: lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/orientationManual
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 664 lines (+304/-37)
19 files modified
modules/Ubuntu/Components/1.3/MainView.qml (+1/-0)
modules/Ubuntu/Components/1.3/MainViewBase.qml (+19/-0)
modules/Ubuntu/Components/1.3/OrientationHelper.qml (+3/-9)
modules/Ubuntu/Components/1.3/TextCursor.qml (+10/-1)
modules/Ubuntu/Components/Popups/1.2/popupUtils.js (+1/-1)
modules/Ubuntu/Components/Popups/1.3/PopupBase.qml (+6/-7)
modules/Ubuntu/Components/plugin/plugin.cpp (+0/-7)
modules/Ubuntu/Components/plugin/ucapplication.cpp (+41/-1)
modules/Ubuntu/Components/plugin/ucapplication.h (+5/-0)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_mainview.py (+13/-0)
tests/autopilot/ubuntuuitoolkit/tests/components/test_popover.py (+44/-0)
tests/autopilot/ubuntuuitoolkit/tests/components/test_popover.qml (+56/-5)
tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.header.qml (+1/-1)
tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.py (+26/-0)
tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textarea.qml (+3/-1)
tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textfield.qml (+11/-3)
tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textfield_custom.qml (+3/-1)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_main_view.orientation.qml (+29/-0)
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_main_view.py (+32/-0)
To merge this branch: bzr merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/orientationManual
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Leo Arias (community) Approve
Tim Peeters Approve
Zsombor Egri Pending
Review via email: mp+254753@code.launchpad.net

This proposal supersedes a proposal from 2015-03-09.

Commit message

Allow manual orientation changes through OrientationHelper.orientation

Description of the change

Autopilot tests for orientation issues in both text input and popovers/ dialogs:
env APP_ID=uitl LANGUAGE=en ./run_tests.sh ubuntuuitoolkit.tests.components.test_textinput.InsertModeTextInputTestCase.test_rotate_portrait -v
env APP_ID=uitl LANGUAGE=en ./run_tests.sh ubuntuuitoolkit.tests.components.test_popover.PopoverOpenTestCase.test_popover_rotate_portrait -v

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

If someone would be setting OrientationHelper.orientationAngle, that will break because it became read-only here.

Revision history for this message
Tim Peeters (tpeeters) wrote :

22 + // Functions to allow Autopilot to handle orientation
23 + objectName: "MainViewBaseStyledItem"
24 + function setOrientation(newOrientation) {
25 + if (newOrientation == 'Landscape')
26 + UbuntuApplication.orientation = Qt.LandscapeOrientation
27 + else if (newOrientation == 'Portrait')
28 + UbuntuApplication.orientation = Qt.PortraitOrientation
29 + else
30 + UbuntuApplication.orientation = newOrientation
31 + }
32 + function getOrientation() {
33 + return UbuntuApplication.orientation
34 + }

Could this be implemented in autopilot without adding the JS functions here? Ca we get to the UbuntuApplication in AP?

Revision history for this message
Tim Peeters (tpeeters) wrote :

46 - property int orientationAngle: automaticOrientation ? Screen.angleBetween(Screen.primaryOrientation, Screen.orientation) : 0
47 + readonly property int orientationAngle: automaticOrientation
48 + ? Screen.angleBetween(Screen.primaryOrientation, UbuntuApplication.orientation)
49 + : 0

This breaks API. Perhaps we should split up OrientationHelper in an 1.0 version an 1.3 version.

Was there any use case for setting the value previously? And did you check that apps don't set the orientationAngle?

review: Needs Fixing
Revision history for this message
Tim Peeters (tpeeters) wrote :

53 - onOrientationAngleChanged: { automaticOrientation ? stableOrientationAngleTimer.restart() : d.tryUpdateState(); }
54 + onOrientationAngleChanged: automaticOrientation ? stableOrientationAngleTimer.restart()
55 + : d.tryUpdateState();

why did you remove the { }?

Personally I would use the old-fashioned if-then-else ;) but that's a matter of taste I guess.

Revision history for this message
Tim Peeters (tpeeters) wrote :

63 - /*
64 - The attached property Screen.orientation is only valid inside Item or
65 - derived components. Inside Object it evaluates to 0 with no error.
66 - Also be aware that some apps eg. webbrowser-app set window.contentOrientation
67 - and thus can hide failure to update it from this code.
68 - See http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-window2-screen.html
69 - */

(why) is this comment no longer valid?

The link would require an update though.

Revision history for this message
Tim Peeters (tpeeters) wrote :

nevermind that^ comment. Got it.

> 63 - /*
> 64 - The attached property Screen.orientation is only valid inside
> Item or
> 65 - derived components. Inside Object it evaluates to 0 with no
> error.
> 66 - Also be aware that some apps eg. webbrowser-app set
> window.contentOrientation
> 67 - and thus can hide failure to update it from this code.
> 68 - See http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-
> window2-screen.html
> 69 - */
>
> (why) is this comment no longer valid?
>
> The link would require an update though.

Revision history for this message
Tim Peeters (tpeeters) wrote :

107 - automaticOrientation: stateWrapper.rootItem && stateWrapper.rootItem.automaticOrientation ?
108 - stateWrapper.rootItem.automaticOrientation : false
109 + rotation: stateWrapper.automaticOrientation
110 + ? Screen.angleBetween(Screen.primaryOrientation, UbuntuApplication.orientation) : 0
111 anchorToKeyboard: true
112
113 LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft
114 @@ -180,6 +179,7 @@
115 Item {
116 id: stateWrapper
117 property Item rootItem: QuickUtils.rootItem(popupBase)
118 + property bool automaticOrientation: rootItem && rootItem.automaticOrientation ? rootItem.automaticOrientation : false

This change doesn't really make it prettier. Does the automaticOrientation have anything to do with the stateWrapper, or is it only a convenient internal place where you can put the property?

Revision history for this message
Tim Peeters (tpeeters) wrote :

130 - parent: QuickUtils.rootItem(handler.main)
131 + // Parent to the contentsItem to be able to inherit rotation
132 + parent: {
133 + var mainView = QuickUtils.rootItem(handler.main);
134 + // Check in case the root isn't a MainView
135 + return mainView.contentsItem ? mainView.contentsItem[0] : mainView;
136 + }

Can you add a comment explaining what you expect to be mainView.contentsItem[0]? It seems that can be anything that the developer added inside the MainView.

review: Needs Fixing
Revision history for this message
Tim Peeters (tpeeters) wrote :

201 +/*!
202 + * \qmlproperty Qt.ScreenOrientation Application::orientation
203 + * \internal
204 + * The current orientation of the application - can be overridden manually for testing.
205 + */

Why is the component name here Application and not UbuntuApplication? (same question would apply to Applcation::applicationName documentation)?

And why is it internal? Don't we want this to be documented? (again, same question for applicationName).

Revision history for this message
Tim Peeters (tpeeters) wrote :

214 +void UCApplication::setOrientation(Qt::ScreenOrientation orientation) {
215 + if (m_orientation == -1) {
216 + // we're now in manual override mode
217 + disconnect(QGuiApplication::primaryScreen(), &QScreen::orientationChanged,
218 + this, &UCApplication::orientationChanged);
219 + }
220 +
221 + if (m_orientation != orientation) {
222 + m_orientation = orientation;
223 + Q_EMIT orientationChanged(orientation);
224 + }
225 +}

You want to re-connect when the orientation is set to -1. Also, document that you can set it to -1 to make it follow the Qt value.

Revision history for this message
Tim Peeters (tpeeters) wrote :

276 + def _set_orientation(self, orientation):
277 + self.select_single(
278 + objectName='MainViewBaseStyledItem').slots.setOrientation(
279 + orientation)
280 + # Short delay to ensure introspection is uptodate
281 + time.sleep(1)
282 +
283 + @property
284 + def _orientation(self):
285 + return self.select_single(
286 + objectName='MainViewBaseStyledItem').orientation

Since we are using _orientation outside of the CPOs themselves (in tests/components), perhaps we should expose it properly? So no _-prefix?

Also, we should also test the property in tests/custom_proxy_objects/test_mainview.py.

review: Needs Fixing
Revision history for this message
Tim Peeters (tpeeters) wrote :

281 + time.sleep(1)

When changing orientation, there can be an animation going on because of the orientation change. It is better to have a proper wait for that (similar to waitForAnimation() in _header.py)?

Revision history for this message
Tim Peeters (tpeeters) wrote :

324 + # Give rendering a chance to finish
325 + time.sleep(2)

Here you would call the proper waitForOrientationChange() function that I suggested above.

Anyway I think if you physically rotate a device, the rotation animation is more than 2ms.

Revision history for this message
Tim Peeters (tpeeters) wrote :

311 + scenarios = [
312 + ('Popover', dict(button='button', popover='popover')),
313 + ('Small dialog', dict(button='button_small', popover='dialog_small')),
314 + ('Huge dialog', dict(button='button_huge', popover='dialog_huge')),
315 + ]

I prefer buttonName, popoverName etc to name the variables, to make the code that follows more clear (the first time I read popover = self.main_view.select_single(objectName=self.popover), I got confused).

review: Needs Fixing
Revision history for this message
Tim Peeters (tpeeters) wrote :

 + def _rotate(self, orientation):

I don't know if there is a policy on this, but I noticed that in the other python component tests, we don't prefix functions with _.

Revision history for this message
Tim Peeters (tpeeters) wrote :

330 + def test_popover_rotate_landscape(self):
331 + self._rotate('Landscape')
332 +
333 + def test_popover_rotate_portrait(self):
334 + self._rotate('Portrait')

Minor detail: test_rotate_to_landscape() and test_rotate_to_portrait() have my preference. You already are inside a popover testcase. And adding _to makes the function read like a proper sentence.

Revision history for this message
Tim Peeters (tpeeters) wrote :

304 +class PopoverOpenTestCase(tests.QMLFileAppTestCase):

you are not testing opening of a Popover, but its rotation.

review: Needs Fixing
Revision history for this message
Tim Peeters (tpeeters) wrote :

440 + def _rotate(self, orientation):

other functions (like select_cursor() in the same class) don't use the _ prefix.

454 + def test_rotate_landscape(self):
455 + self._rotate('Landscape')
456 +
457 + def test_rotate_portrait(self):
458 + self._rotate('Portrait')
459

same as above, I would prefer test_rotate_to_landscape etc.

Revision history for this message
Tim Peeters (tpeeters) wrote :

> env APP_ID=uitl LANGUAGE=en ./run_tests.sh >ubuntuuitoolkit.tests.components.test_textinput.InsertModeTextInputTestCase.test_rotate_portrait -v

This works on my desktop without the APP_ID. Is that because I'm on desktop?
Where does the uitl id come from? Is that something common for all our tests?

Revision history for this message
Cris Dywan (kalikiana) wrote :

> 201 +/*!
> 202 + * \qmlproperty Qt.ScreenOrientation Application::orientation
> 203 + * \internal
> 204 + * The current orientation of the application - can be overridden
> manually for testing.
> 205 + */
>
> Why is the component name here Application and not UbuntuApplication? (same
> question would apply to Applcation::applicationName documentation)?
>
> And why is it internal? Don't we want this to be documented? (again, same
> question for applicationName).

That whole object is internal API that exists for things we can't implement in QML.

Revision history for this message
Cris Dywan (kalikiana) wrote :

> 214 +void UCApplication::setOrientation(Qt::ScreenOrientation orientation)
> {
> 215 + if (m_orientation == -1) {
> 216 + // we're now in manual override mode
> 217 + disconnect(QGuiApplication::primaryScreen(),
> &QScreen::orientationChanged,
> 218 + this, &UCApplication::orientationChanged);
> 219 + }
> 220 +
> 221 + if (m_orientation != orientation) {
> 222 + m_orientation = orientation;
> 223 + Q_EMIT orientationChanged(orientation);
> 224 + }
> 225 +}
>
> You want to re-connect when the orientation is set to -1. Also, document that
> you can set it to -1 to make it follow the Qt value.

I don't see a use case for that. As the documentation says you can override it for testing, and if you do that it makes no sense to go back to physical orientation.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote :

> > env APP_ID=uitl LANGUAGE=en ./run_tests.sh >ubuntuuitoolkit.tests.components
> .test_textinput.InsertModeTextInputTestCase.test_rotate_portrait -v
>
>
> This works on my desktop without the APP_ID. Is that because I'm on desktop?
> Where does the uitl id come from? Is that something common for all our tests?

I use it to get rid of some of the error spam which you get despite the fact that it is indeed neither required nor usually set on the desktop.

Revision history for this message
Cris Dywan (kalikiana) wrote :

> 324 + # Give rendering a chance to finish
> 325 + time.sleep(2)
>
> Here you would call the proper waitForOrientationChange() function that I
> suggested above.
>
> Anyway I think if you physically rotate a device, the rotation animation is
> more than 2ms.

I added a rotating.wait_for. But it's not apparently enough for AP to update its coordinate space when the animation is in fact finished. So I left a sleep(1), not sure what else I could check for here. The one for the cursor is in fact unnecessary, though, so I removed it.

Revision history for this message
Cris Dywan (kalikiana) wrote :

I addressed all the naming suggestions, made the set_orientation function public and added a test for it. Note there's no actual way to verify rotation and as such absent from the cpo test because one of the orientations is always a no-op depending on the primary orientation and the real tests don't need to be aware of it… after having written this I actually convinced myself that this isn't acceptable… I'll have to look into a way to address this.

Revision history for this message
Leo Arias (elopio) wrote :

I left some comments.

Revision history for this message
Tim Peeters (tpeeters) wrote :

9 + // Function provided here because Autopilot can't change property

Is the function that you refer to getOrientation(), which you removed in a later commit?

Revision history for this message
Tim Peeters (tpeeters) wrote :

264 + def set_orientation(self, orientation):
265 + self.select_single(
266 + objectName='MainViewBaseStyledItem').slots.setOrientation(
267 + orientation)
268 + self.select_single('OrientationHelper').rotating.wait_for(False)
269 + # Short delay to ensure introspection is uptodate
270 + time.sleep(1)

I wonder if the problem here is that when you do the wait_for, perhaps the value of the property was not updated to be True yet? In that case it is better to add the sleep(1) before the wait_for.

Revision history for this message
Tim Peeters (tpeeters) wrote :

In two occasions, you use select_single('OrientationHelper').

I think it is better to use an objectName for selecting the OrientationHelper. In the past we had problems some times (with versioning or custom subclasses of components) when using the type.

Revision history for this message
Tim Peeters (tpeeters) wrote :

118 + do {
119 + orientationHelper = orientationHelper.parent;
120 + } while (orientationHelper && !orientationHelper.automaticOrientation && orientationHelper != null);

isn't orientationHelper != null already implied by orientationHelper? Anyway it would be weird to put the != null in the end.

Also, if you are looking for orientationHelper, you should be checking orientationHelper.hasOwnProperty("automaticOrientation"), not the value of automaticOrientation.

review: Needs Fixing
Revision history for this message
Cris Dywan (kalikiana) wrote :

> 9 + // Function provided here because Autopilot can't change
> property
>
> Is the function that you refer to getOrientation(), which you removed in a
> later commit?

There still is a function right below the comment…

Revision history for this message
Tim Peeters (tpeeters) wrote :

looks good!

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Leo Arias (elopio) wrote :

<elopio> kalikiana: FOLLOW_SCREAM_ORIENTATION
<elopio> is it really scream?
<kalikiana> erm
<kalikiana> well, timp asked me to fix the typo in SCREEM…
<kalikiana> ^_^'
<kalikiana> brainfart…
<elopio> other than that, lgt.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

Found 1 license problems:
tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_main_view.orientation.qml UNKNOWN *No copyright*

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1193. By Cris Dywan

Only test non-default orientation for clear results

Otherwise some properties may not change if nothing did rotate.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1194. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

1195. By Cris Dywan

Take Component-based popover rootItem from the caller

1196. By Cris Dywan

FakeCursor parent should fallback to toplevel

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1197. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1198. By Cris Dywan

Put back accidentally removed "import os"

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1199. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1200. By Cris Dywan

Empty commit

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1201. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1202. By Cris Dywan

Update components.api

1203. By Cris Dywan

Undo accidental changes

1204. By Cris Dywan

Move all orientation tests to 1.3

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1205. By Cris Dywan

Revert bogus components.api changes

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1206. By Cris Dywan

Normalize rotation angle in tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1207. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

1208. By Cris Dywan

Use Popups 1.3 in test_popover.qml

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1209. By Cris Dywan

Assert focus after tapping TextField in popover tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1210. By Cris Dywan

Anchor Column in test_textinput.textfield.qml to the top

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1211. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1212. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1213. By Cris Dywan

Use Eventually and wait_ instead of time.sleep

1214. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1215. By Cris Dywan

Make flake8 happy once again

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1216. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Unmerged revisions

1216. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

1215. By Cris Dywan

Make flake8 happy once again

1214. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

1213. By Cris Dywan

Use Eventually and wait_ instead of time.sleep

1212. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

1211. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

1210. By Cris Dywan

Anchor Column in test_textinput.textfield.qml to the top

1209. By Cris Dywan

Assert focus after tapping TextField in popover tests

1208. By Cris Dywan

Use Popups 1.3 in test_popover.qml

1207. By Cris Dywan

Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/staging

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'modules/Ubuntu/Components/1.3/MainView.qml'
2--- modules/Ubuntu/Components/1.3/MainView.qml 2015-05-11 12:50:00 +0000
3+++ modules/Ubuntu/Components/1.3/MainView.qml 2015-06-18 17:57:10 +0000
4@@ -33,6 +33,7 @@
5 default property alias contentsItem: contents.data
6 OrientationHelper {
7 id: canvas
8+ objectName: 'canvas'
9
10 automaticOrientation: false
11 anchorToKeyboard: mainView.anchorToKeyboard
12
13=== modified file 'modules/Ubuntu/Components/1.3/MainViewBase.qml'
14--- modules/Ubuntu/Components/1.3/MainViewBase.qml 2015-05-21 10:50:35 +0000
15+++ modules/Ubuntu/Components/1.3/MainViewBase.qml 2015-06-18 17:57:10 +0000
16@@ -64,6 +64,25 @@
17 mainView.theme.name = "Ubuntu.Components.Themes.%1".arg(autoThemeName);
18 }
19 }
20+
21+ // Function provided here because Autopilot can't change property
22+ // Also UbuntuApplication is not accessible via introspection
23+ objectName: "MainViewBaseStyledItem"
24+ function setOrientation(newOrientation) {
25+ // Rotation can only happen if it was enabled; prevent false positives
26+ if (!mainView.automaticOrientation)
27+ return;
28+ if (newOrientation == 'landscape')
29+ UbuntuApplication.orientation = Qt.LandscapeOrientation;
30+ else if (newOrientation == 'portrait')
31+ UbuntuApplication.orientation = Qt.PortraitOrientation;
32+ }
33+ property string orientation: {
34+ if (UbuntuApplication.orientation == Qt.LandscapeOrientation)
35+ return 'landscape';
36+ else if (UbuntuApplication.orientation == Qt.PortraitOrientation)
37+ return 'portrait';
38+ }
39 }
40
41 active: true
42
43=== modified file 'modules/Ubuntu/Components/1.3/OrientationHelper.qml'
44--- modules/Ubuntu/Components/1.3/OrientationHelper.qml 2015-04-25 08:54:58 +0000
45+++ modules/Ubuntu/Components/1.3/OrientationHelper.qml 2015-06-18 17:57:10 +0000
46@@ -83,7 +83,7 @@
47
48 Calculates the current orientation angle.
49 */
50- property int orientationAngle: automaticOrientation ? Screen.angleBetween(Screen.primaryOrientation, Screen.orientation) : 0
51+ property int orientationAngle: automaticOrientation ? Screen.angleBetween(Screen.primaryOrientation, UbuntuApplication.orientation) : 0
52 // Screen.primaryOrientation and Screen.orientation can change one right after the other,
53 // causing orientationAngle to momentarily change. To avoid responding to such
54 // intermediate states, wait for its value to stabilize before rotating to it.
55@@ -102,15 +102,9 @@
56 width: parent ? (d.flipDimensions ? d.availableParentHeight : parent.width) : 0
57 height: parent ? (d.flipDimensions ? parent.width : d.availableParentHeight) : 0
58
59- /*
60- The attached property Screen.orientation is only valid inside Item or
61- derived components. Inside Object it evaluates to 0 with no error.
62- Also be aware that some apps eg. webbrowser-app set window.contentOrientation
63- and thus can hide failure to update it from this code.
64- See http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick-window2-screen.html
65- */
66 Item {
67 id: d
68+ objectName: 'd'
69
70 property real availableParentHeight: {
71 if (!orientationHelper.parent)
72@@ -138,7 +132,7 @@
73 */
74 function applyOrientation() {
75 if (windowActive && window)
76- window.contentOrientation = Screen.orientation
77+ window.contentOrientation = UbuntuApplication.orientation
78 }
79
80 onWindowActiveChanged: {
81
82=== modified file 'modules/Ubuntu/Components/1.3/TextCursor.qml'
83--- modules/Ubuntu/Components/1.3/TextCursor.qml 2015-06-10 17:23:51 +0000
84+++ modules/Ubuntu/Components/1.3/TextCursor.qml 2015-06-18 17:57:10 +0000
85@@ -295,7 +295,16 @@
86 Item {
87 id: fakeCursor
88 objectName: positionProperty + "FakeCursor"
89- parent: QuickUtils.rootItem(handler.main)
90+ // Parent to OrientationHelper to inherit rotation
91+ parent: {
92+ var orientationHelper = handler.main;
93+ do {
94+ if (!orientationHelper.parent)
95+ break;
96+ orientationHelper = orientationHelper.parent;
97+ } while (orientationHelper && !orientationHelper.hasOwnProperty('automaticOrientation'));
98+ return orientationHelper;
99+ }
100 width: cursorItem.width
101 height: cursorItem.height
102 Component.onCompleted: caret.parent = fakeCursor
103
104=== modified file 'modules/Ubuntu/Components/Popups/1.2/popupUtils.js'
105--- modules/Ubuntu/Components/Popups/1.2/popupUtils.js 2015-04-30 08:32:44 +0000
106+++ modules/Ubuntu/Components/Popups/1.2/popupUtils.js 2015-06-18 17:57:10 +0000
107@@ -31,7 +31,7 @@
108 if (popup.createObject) {
109 // popup is a component and can create an object
110 popupComponent = popup;
111- rootObject = QuickUtils.rootItem(popup);
112+ rootObject = (caller !== undefined) ? QuickUtils.rootItem(caller) : QuickUtils.rootItem(null);
113 } else if (typeof popup === "string") {
114 popupComponent = Qt.createComponent(popup);
115 rootObject = (caller !== undefined) ? QuickUtils.rootItem(caller) : QuickUtils.rootItem(null);
116
117=== modified file 'modules/Ubuntu/Components/Popups/1.3/PopupBase.qml'
118--- modules/Ubuntu/Components/Popups/1.3/PopupBase.qml 2015-04-29 08:55:31 +0000
119+++ modules/Ubuntu/Components/Popups/1.3/PopupBase.qml 2015-06-18 17:57:10 +0000
120@@ -15,6 +15,7 @@
121 */
122
123 import QtQuick 2.4
124+import QtQuick.Window 2.0
125 import Ubuntu.Components 1.3
126
127 /*!
128@@ -47,14 +48,12 @@
129 */
130 property PropertyAnimation fadingAnimation: PropertyAnimation{duration: 0}
131
132- // without specifying width and height below, some width calculations go wrong in Sheet.
133- // I guess popupBase.width is not correctly set initially
134- width: parent ? parent.width : undefined
135- height: parent ? parent.height : undefined
136-
137+ // No need for transitioning, take rotation directly
138+ automaticOrientation: false
139+ transitionEnabled: false
140 // copy value of automaticOrientation from root object (typically a MainView)
141- automaticOrientation: stateWrapper.rootItem && stateWrapper.rootItem.automaticOrientation ?
142- stateWrapper.rootItem.automaticOrientation : false
143+ rotation: stateWrapper.rootItem && stateWrapper.rootItem.automaticOrientation
144+ ? Screen.angleBetween(Screen.primaryOrientation, UbuntuApplication.orientation) : 0
145 anchorToKeyboard: true
146
147 LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft
148
149=== modified file 'modules/Ubuntu/Components/plugin/plugin.cpp'
150--- modules/Ubuntu/Components/plugin/plugin.cpp 2015-05-26 17:54:51 +0000
151+++ modules/Ubuntu/Components/plugin/plugin.cpp 2015-06-18 17:57:10 +0000
152@@ -272,12 +272,5 @@
153 // register icon provider
154 engine->addImageProvider(QLatin1String("theme"), new UnityThemeIconProvider);
155
156- // Necessary for Screen.orientation (from import QtQuick.Window 2.0) to work
157- QGuiApplication::primaryScreen()->setOrientationUpdateMask(
158- Qt::PortraitOrientation |
159- Qt::LandscapeOrientation |
160- Qt::InvertedPortraitOrientation |
161- Qt::InvertedLandscapeOrientation);
162-
163 registerWindowContextProperty();
164 }
165
166=== modified file 'modules/Ubuntu/Components/plugin/ucapplication.cpp'
167--- modules/Ubuntu/Components/plugin/ucapplication.cpp 2014-10-02 10:14:51 +0000
168+++ modules/Ubuntu/Components/plugin/ucapplication.cpp 2015-06-18 17:57:10 +0000
169@@ -19,10 +19,15 @@
170 #include "ucapplication.h"
171
172 #include <QtCore/QCoreApplication>
173+#include <QtGui/QGuiApplication>
174+#include <QWindow>
175 #include <QDebug>
176 #include <QtQml/QQmlContext>
177 #include <QtQml/QQmlEngine>
178 #include <QtCore/QStandardPaths>
179+#include <QScreen>
180+
181+const int FOLLOW_SCREEN_ORIENTATION = -1;
182
183 /*!
184 * \qmltype UbuntuApplication
185@@ -33,11 +38,20 @@
186 *
187 * UbuntuApplication is a context property in QML.
188 */
189-UCApplication::UCApplication(QObject* parent) : QObject(parent), m_context(0)
190+UCApplication::UCApplication(QObject* parent) : QObject(parent), m_context(0), m_orientation(FOLLOW_SCREEN_ORIENTATION)
191 {
192 // Make sure we receive application name changes from C++ modules
193 connect(QCoreApplication::instance(), &QCoreApplication::applicationNameChanged,
194 this, &UCApplication::applicationNameChanged);
195+
196+ // Follow primary screen orientation changes
197+ QGuiApplication::primaryScreen()->setOrientationUpdateMask(
198+ Qt::PortraitOrientation |
199+ Qt::LandscapeOrientation |
200+ Qt::InvertedPortraitOrientation |
201+ Qt::InvertedLandscapeOrientation);
202+ connect(QGuiApplication::primaryScreen(), &QScreen::orientationChanged,
203+ this, &UCApplication::orientationChanged);
204 }
205
206 void UCApplication::setContext(QQmlContext* context) {
207@@ -73,3 +87,29 @@
208 QCoreApplication::setOrganizationDomain(applicationName);
209 }
210
211+/*!
212+ * \qmlproperty Qt.ScreenOrientation Application::orientation
213+ * \internal
214+ * The current orientation of the application - can be overridden manually for testing.
215+ */
216+Qt::ScreenOrientation UCApplication::orientation() {
217+ if (m_orientation == FOLLOW_SCREEN_ORIENTATION) {
218+ return QGuiApplication::primaryScreen()->orientation();
219+ } else {
220+ return static_cast<Qt::ScreenOrientation>(m_orientation);
221+ }
222+}
223+
224+void UCApplication::setOrientation(Qt::ScreenOrientation orientation) {
225+ if (m_orientation == FOLLOW_SCREEN_ORIENTATION) {
226+ // we're now in manual override mode
227+ disconnect(QGuiApplication::primaryScreen(), &QScreen::orientationChanged,
228+ this, &UCApplication::orientationChanged);
229+ }
230+
231+ if (m_orientation != orientation) {
232+ m_orientation = orientation;
233+ Q_EMIT orientationChanged(orientation);
234+ }
235+}
236+
237
238=== modified file 'modules/Ubuntu/Components/plugin/ucapplication.h'
239--- modules/Ubuntu/Components/plugin/ucapplication.h 2013-10-18 08:56:39 +0000
240+++ modules/Ubuntu/Components/plugin/ucapplication.h 2015-06-18 17:57:10 +0000
241@@ -28,6 +28,7 @@
242 {
243 Q_OBJECT
244 Q_PROPERTY(QString applicationName READ applicationName WRITE setApplicationName NOTIFY applicationNameChanged)
245+ Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged)
246
247 private:
248 Q_DISABLE_COPY(UCApplication)
249@@ -42,16 +43,20 @@
250
251 // getter
252 QString applicationName();
253+ Qt::ScreenOrientation orientation();
254
255 // setter
256 void setContext(QQmlContext* context);
257 void setApplicationName(const QString& applicationName);
258+ void setOrientation(Qt::ScreenOrientation orientation);
259
260 private:
261 QQmlContext* m_context;
262+ int m_orientation;
263
264 Q_SIGNALS:
265 void applicationNameChanged();
266+ void orientationChanged(Qt::ScreenOrientation orientation);
267 };
268
269 #endif // UBUNTU_COMPONENTS_I18N_H
270
271=== modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_mainview.py'
272--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_mainview.py 2015-04-14 21:02:06 +0000
273+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_mainview.py 2015-06-18 17:57:10 +0000
274@@ -56,6 +56,19 @@
275
276 return False
277
278+ def set_orientation(self, orientation):
279+ self.select_single(
280+ objectName='MainViewBaseStyledItem').slots.setOrientation(
281+ orientation)
282+ orientationHelper = self.select_single(objectName='canvas')
283+ orientationHelper.select_single(
284+ objectName='d').flipDimensions.wait_for(True)
285+
286+ @property
287+ def orientation(self):
288+ return self.select_single(
289+ objectName='MainViewBaseStyledItem').orientation
290+
291 def get_header(self):
292 """Return the AppHeader custom proxy object of the MainView."""
293 try:
294
295=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/components/test_popover.py'
296--- tests/autopilot/ubuntuuitoolkit/tests/components/test_popover.py 2015-04-14 21:02:06 +0000
297+++ tests/autopilot/ubuntuuitoolkit/tests/components/test_popover.py 2015-06-18 17:57:10 +0000
298@@ -18,9 +18,53 @@
299
300 import os
301
302+from autopilot.matchers import Eventually
303+from testtools.matchers import Equals
304 from ubuntuuitoolkit import tests
305
306
307+class PopoverRotateTestCase(tests.QMLFileAppTestCase):
308+
309+ path = os.path.abspath(__file__)
310+ dir_path = os.path.dirname(path)
311+ test_qml_file_path = os.path.join(
312+ dir_path, 'test_popover.qml')
313+
314+ scenarios = [
315+ ('Popover', dict(buttonName='button', popoverName='popover')),
316+ ('Small dialog', dict(buttonName='button_small',
317+ popoverName='dialog_small')),
318+ ('Huge dialog', dict(buttonName='button_huge',
319+ popoverName='dialog_huge')),
320+ ]
321+
322+ def setUp(self):
323+ super(PopoverRotateTestCase, self).setUp()
324+
325+ def rotate(self, orientation):
326+ self.main_view.set_orientation(orientation)
327+ self.assertThat(self.main_view.orientation,
328+ Eventually(Equals(orientation)))
329+
330+ def open_popover(self):
331+ button = self.main_view.select_single(objectName=self.buttonName)
332+ self.pointing_device.click_object(button)
333+
334+ def assert_popover_orientation(self):
335+ popover = self.main_view.wait_select_single(
336+ objectName=self.popoverName)
337+ self.assertEqual(popover.rotation, self.main_view.select_single(
338+ 'OrientationHelper').rotation)
339+
340+ def test_rotate(self):
341+ if self.main_view.orientation == 'portrait':
342+ self.rotate('landscape')
343+ else:
344+ self.rotate('portrait')
345+ self.open_popover()
346+ self.assert_popover_orientation()
347+
348+
349 class DialogScrollTestCase(tests.QMLFileAppTestCase):
350
351 path = os.path.abspath(__file__)
352
353=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/components/test_popover.qml'
354--- tests/autopilot/ubuntuuitoolkit/tests/components/test_popover.qml 2015-03-03 13:20:06 +0000
355+++ tests/autopilot/ubuntuuitoolkit/tests/components/test_popover.qml 2015-06-18 17:57:10 +0000
356@@ -15,18 +15,30 @@
357 */
358
359 import QtQuick 2.0
360-import Ubuntu.Components 1.1
361-import Ubuntu.Components.Popups 1.0
362+import Ubuntu.Components 1.3
363+import Ubuntu.Components.Popups 1.3
364+import Ubuntu.Test 1.0
365
366 MainView {
367- width: units.gu(48)
368- height: units.gu(60)
369+ id: root
370+ width: units.gu(60)
371+ height: units.gu(40)
372 objectName: "mainView"
373
374+ automaticOrientation: true
375+
376 Page {
377 title: "Popover"
378
379 Column {
380+ anchors.top: parent.top
381+ anchors.bottom: parent.bottom
382+
383+ Button {
384+ objectName: "button"
385+ text: "Pop over"
386+ onClicked: PopupUtils.open(popoverComponent)
387+ }
388 Button {
389 objectName: "button_small"
390 text: "Small"
391@@ -37,15 +49,54 @@
392 text: "Huge"
393 onClicked: PopupUtils.open(hugeDialogComponent)
394 }
395+ Button {
396+ text: "Landscape"
397+ onClicked: UbuntuApplication.orientation = Qt.LandscapeOrientation;
398+ }
399+ Button {
400+ text: "Portrait"
401+ onClicked: UbuntuApplication.orientation = Qt.PortraitOrientation;
402+ }
403+ }
404+
405+ Component {
406+ id: popoverComponent
407+ Popover {
408+ objectName: "popover"
409+ Column {
410+ Button {
411+ text: "Just a button"
412+ onClicked: {
413+ if (UbuntuApplication.orientation === Qt.LandscapeOrientation) {
414+ UbuntuApplication.orientation = Qt.PortraitOrientation;
415+ } else {
416+ UbuntuApplication.orientation = Qt.LandscapeOrientation
417+ }
418+ }
419+ }
420+ }
421+ }
422 }
423
424 Component {
425 id: smallDialogComponent
426 Dialog {
427+ id: smallDialog
428 objectName: "dialog_small"
429- Column {
430+ Row {
431 Button {
432 text: "Just a button"
433+ onClicked: {
434+ if (UbuntuApplication.orientation === Qt.LandscapeOrientation) {
435+ UbuntuApplication.orientation = Qt.PortraitOrientation;
436+ } else {
437+ UbuntuApplication.orientation = Qt.LandscapeOrientation
438+ }
439+ }
440+ }
441+ Button {
442+ text: "close"
443+ onClicked: PopupUtils.close(smallDialog)
444 }
445 }
446 }
447
448=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.header.qml'
449--- tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.header.qml 2015-05-29 17:35:52 +0000
450+++ tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.header.qml 2015-06-18 17:57:10 +0000
451@@ -15,7 +15,7 @@
452 */
453
454 import QtQuick 2.0
455-import Ubuntu.Components 1.2
456+import Ubuntu.Components 1.3
457
458 MainView {
459 id: root
460
461=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.py'
462--- tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.py 2015-06-03 15:09:52 +0000
463+++ tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.py 2015-06-18 17:57:10 +0000
464@@ -174,6 +174,32 @@
465 self.assertTrue(popover.globalRect.y > 0,
466 '%s <= 0' % popover.globalRect.y)
467
468+ def rotate(self, orientation):
469+ self.main_view.set_orientation(orientation)
470+
471+ def open_context_menu(self):
472+ self.pointing_device.click_object(self.textfield)
473+ cursor = self.select_cursor('cursorPosition')
474+ self.pointing_device.click_object(cursor)
475+
476+ def assert_context_menu_orientation(self):
477+ popover = self.main_view.get_text_input_context_menu(
478+ 'text_input_contextmenu')
479+ self.assertEqual(popover.rotation, self.main_view.select_single(
480+ 'OrientationHelper').rotation)
481+
482+ def test_rotate(self):
483+ # https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1443358
484+ if self.test_qml_file_path != self.textfield_qml_file_path:
485+ self.skipTest('FIXME: Header behavior breaks some rotation cases')
486+
487+ if self.main_view.orientation == 'portrait':
488+ self.rotate('landscape')
489+ else:
490+ self.rotate('portrait')
491+ self.open_context_menu()
492+ self.assert_context_menu_orientation()
493+
494 def test_header_undisturbed_by_text_handlers(self):
495 # Verify that handlers aren't accidentally placed at absolute 0/0
496 self.pointing_device.click_object(self.textfield)
497
498=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textarea.qml'
499--- tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textarea.qml 2015-03-10 16:29:24 +0000
500+++ tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textarea.qml 2015-06-18 17:57:10 +0000
501@@ -15,13 +15,15 @@
502 */
503
504 import QtQuick 2.0
505-import Ubuntu.Components 1.2
506+import Ubuntu.Components 1.3
507
508 MainView {
509 width: units.gu(48)
510 height: units.gu(60)
511 objectName: "mainView"
512
513+ automaticOrientation: true
514+
515 Page {
516 title: "Textarea"
517 head.backAction: Action {
518
519=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textfield.qml'
520--- tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textfield.qml 2015-03-10 16:29:24 +0000
521+++ tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textfield.qml 2015-06-18 17:57:10 +0000
522@@ -15,13 +15,15 @@
523 */
524
525 import QtQuick 2.0
526-import Ubuntu.Components 1.2
527+import Ubuntu.Components 1.3
528
529 MainView {
530- width: units.gu(48)
531- height: units.gu(60)
532+ width: units.gu(60)
533+ height: units.gu(40)
534 objectName: "mainView"
535
536+ automaticOrientation: true
537+
538 Page {
539 title: "Textfield"
540 head.backAction: Action {
541@@ -31,11 +33,17 @@
542 }
543
544 Column {
545+ anchors.top: parent.top
546+ spacing: units.gu(2)
547+
548 TextField {
549 objectName: "textfield"
550 placeholderText: "Type here"
551 width: units.gu(35)
552 }
553+ Label {
554+ text: i18n.tr("Text fields are awesome")
555+ }
556 }
557 }
558 }
559
560=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textfield_custom.qml'
561--- tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textfield_custom.qml 2015-03-10 16:29:24 +0000
562+++ tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.textfield_custom.qml 2015-06-18 17:57:10 +0000
563@@ -15,7 +15,7 @@
564 */
565
566 import QtQuick 2.0
567-import Ubuntu.Components 1.2
568+import Ubuntu.Components 1.3
569 import Ubuntu.Components.Themes.Ambiance 1.1
570
571 MainView {
572@@ -23,6 +23,8 @@
573 height: units.gu(60)
574 objectName: "mainView"
575
576+ automaticOrientation: true
577+
578 Page {
579 title: "Textfield"
580 head.backAction: Action {
581
582=== added file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_main_view.orientation.qml'
583--- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_main_view.orientation.qml 1970-01-01 00:00:00 +0000
584+++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_main_view.orientation.qml 2015-06-18 17:57:10 +0000
585@@ -0,0 +1,29 @@
586+/*
587+ * Copyright 2015 Canonical Ltd.
588+ *
589+ * This program is free software; you can redistribute it and/or modify
590+ * it under the terms of the GNU Lesser General Public License as published by
591+ * the Free Software Foundation; version 3.
592+ *
593+ * This program is distributed in the hope that it will be useful,
594+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
595+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
596+ * GNU Lesser General Public License for more details.
597+ *
598+ * You should have received a copy of the GNU Lesser General Public License
599+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
600+ */
601+
602+import QtQuick 2.3
603+import Ubuntu.Components 1.3
604+
605+MainView {
606+ width: units.gu(48)
607+ height: units.gu(60)
608+ objectName: "mainView"
609+ automaticOrientation: true
610+
611+ Page {
612+ title: i18n.tr('Orientation')
613+ }
614+}
615
616=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_main_view.py'
617--- tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_main_view.py 2015-04-14 21:02:06 +0000
618+++ tests/autopilot/ubuntuuitoolkit/tests/custom_proxy_objects/test_main_view.py 2015-06-18 17:57:10 +0000
619@@ -15,6 +15,7 @@
620 # along with this program. If not, see <http://www.gnu.org/licenses/>.
621
622 from unittest import mock
623+import os
624
625 import ubuntuuitoolkit
626 from ubuntuuitoolkit import tests
627@@ -75,6 +76,37 @@
628 str(error), 'The MainView has no Tabs.')
629
630
631+class MainViewOrientationTestCase(tests.QMLFileAppTestCase):
632+
633+ path = os.path.abspath(__file__)
634+ dir_path = os.path.dirname(path)
635+ test_qml_file_path = os.path.join(
636+ dir_path, 'test_main_view.orientation.qml')
637+
638+ def test_set_orientation(self):
639+ if self.main_view.orientation == 'portrait':
640+ self.rotate('landscape')
641+ self.assert_main_view_orientation('landscape')
642+ else:
643+ self.rotate('portrait')
644+ self.assert_main_view_orientation('portrait')
645+
646+ def rotate(self, orientation):
647+ self.main_view.set_orientation(orientation)
648+
649+ def normalizedAngle(self, angle):
650+ # Same orientation maps to different angles on different devices
651+ if angle in [-90, 270]:
652+ return 90
653+ return angle
654+
655+ def assert_main_view_orientation(self, orientation):
656+ helper = self.main_view.select_single('OrientationHelper')
657+ self.assertEqual(self.normalizedAngle(helper.rotation),
658+ self.normalizedAngle(helper.orientationAngle))
659+ self.assertEqual(self.main_view.orientation, orientation)
660+
661+
662 class MainView12TestCase(tests.QMLStringAppTestCase):
663
664 test_qml = ("""

Subscribers

People subscribed via source and target branches