Merge lp:~tpeeters/ubuntu-ui-toolkit/headlock into lp:ubuntu-ui-toolkit/staging

Proposed by Tim Peeters
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1483
Merged at revision: 1463
Proposed branch: lp:~tpeeters/ubuntu-ui-toolkit/headlock
Merge into: lp:ubuntu-ui-toolkit/staging
Prerequisite: lp:~tpeeters/ubuntu-ui-toolkit/waitForHeaderAnimation
Diff against target: 1300 lines (+680/-256)
16 files modified
components.api (+5/-1)
modules/Ubuntu/Components/AppHeader.qml (+103/-15)
modules/Ubuntu/Components/MainView.qml (+2/-1)
modules/Ubuntu/Components/MainView12.qml (+9/-4)
modules/Ubuntu/Components/Page10.qml (+1/-1)
modules/Ubuntu/Components/Page11.qml (+5/-3)
modules/Ubuntu/Components/PageHeadConfiguration.qdoc (+202/-0)
modules/Ubuntu/Components/PageHeadConfiguration11.qml (+3/-155)
modules/Ubuntu/Components/PageHeadConfiguration13.qml (+30/-0)
modules/Ubuntu/Components/Tabs.qml (+4/-1)
modules/Ubuntu/Components/qmldir (+2/-1)
modules/Ubuntu/Test/UbuntuTestCase.qml (+3/-4)
tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_header.py (+4/-1)
tests/resources/header/lockedToolbar.deprecated.qml (+0/-52)
tests/unit_x11/tst_components/tst_header_visible.qml (+288/-0)
tests/unit_x11/tst_components/tst_page13.qml (+19/-17)
To merge this branch: bzr merge lp:~tpeeters/ubuntu-ui-toolkit/headlock
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Zsombor Egri Approve
Review via email: mp+253845@code.launchpad.net

Commit message

Add visible and locked properties to Page.head.

Description of the change

To post a comment you must log in.
1478. By Tim Peeters

clean

1479. By Tim Peeters

use waitForHeaderAnimation(mainView) in tst_page13.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)
1480. By Tim Peeters

merge staging

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

merge staging

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

update components.api

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

Loosk good

review: Approve
1483. By Tim Peeters

merge waitForHeaderAnimation prerequisite branch

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) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'components.api'
2--- components.api 2015-04-02 11:17:02 +0000
3+++ components.api 2015-04-02 11:17:02 +0000
4@@ -246,7 +246,7 @@
5 property Flickable flickable
6 property list<Action> actions
7 Page 1.1
8-Page10
9+Toolkit10.Page
10 readonly property PageHeadConfiguration head
11 Page 1.3
12 PageTreeNode
13@@ -261,6 +261,10 @@
14 property string preset
15 readonly property PageHeadSections sections
16 property color foregroundColor
17+PageHeadConfiguration 1.3
18+Toolkit12.PageHeadConfiguration
19+ property bool locked
20+ property bool visible
21 PageHeadSections 1.1
22 QtObject
23 property bool enabled
24
25=== modified file 'modules/Ubuntu/Components/AppHeader.qml'
26--- modules/Ubuntu/Components/AppHeader.qml 2015-04-02 11:17:02 +0000
27+++ modules/Ubuntu/Components/AppHeader.qml 2015-04-02 11:17:02 +0000
28@@ -1,5 +1,5 @@
29 /*
30- * Copyright 2013-2014 Canonical Ltd.
31+ * Copyright 2013-2015 Canonical Ltd.
32 *
33 * This program is free software; you can redistribute it and/or modify
34 * it under the terms of the GNU Lesser General Public License as published by
35@@ -60,7 +60,8 @@
36 internal.movementEnded();
37 }
38
39- visible: title || contents || tabsModel
40+ // with PageHeadConfiguration 1.2, always be visible.
41+ visible: title || contents || tabsModel || internal.newConfig
42 onVisibleChanged: {
43 internal.checkFlickableMargins();
44 }
45@@ -69,6 +70,9 @@
46 Show the header
47 */
48 function show() {
49+ if (internal.newConfig) {
50+ header.config.visible = true;
51+ }
52 header.y = 0;
53 }
54
55@@ -76,7 +80,10 @@
56 Hide the header
57 */
58 function hide() {
59- header.y = - header.height;
60+ if (internal.newConfig) {
61+ header.config.visible = false;
62+ }
63+ header.y = -header.height;
64 }
65
66 /*!
67@@ -84,7 +91,10 @@
68 */
69 property string title: ""
70 onTitleChanged: {
71- header.show();
72+ // deprecated for new versions of PageHeadConfiguration
73+ if (!internal.newConfig) {
74+ header.show();
75+ }
76 }
77
78 /*!
79@@ -93,7 +103,10 @@
80 */
81 property Item contents: null
82 onContentsChanged: {
83- header.show();
84+ // deprecated for new versions of PageHeadConfiguration
85+ if (!internal.newConfig) {
86+ header.show();
87+ }
88 }
89
90 /*!
91@@ -152,9 +165,10 @@
92 */
93 property Flickable flickable: null
94 onFlickableChanged: {
95- internal.checkFlickableMargins();
96 internal.connectFlickable();
97- header.show();
98+ if (!internal.newConfig || !header.config.locked) {
99+ header.show();
100+ }
101 }
102
103 /*!
104@@ -164,12 +178,68 @@
105
106 /*!
107 Configuration of the header.
108+ FIXME: Must be of type PageHeadConfiguration. Setting that as the property type
109+ however will use the latest version (1.3) and a Page that uses an older
110+ version (1.1) will no longer work.
111 */
112- property PageHeadConfiguration config: null
113+ property Object config: null
114+ onConfigChanged: {
115+ // set internal.newConfig because when we rely on the binding,
116+ // the value of newConfig may be updated after executing the code below.
117+ internal.newConfig = config && config.hasOwnProperty("visible") &&
118+ config.hasOwnProperty("locked");
119+ internal.connectFlickable();
120+
121+ if (internal.newConfig && header.config.locked &&!header.config.visible) {
122+ header.hide();
123+ } else {
124+ header.show();
125+ }
126+ }
127+ Connections {
128+ target: header.config
129+ ignoreUnknownSignals: true // PageHeadConfiguration <1.2 lacks the signals below
130+ onVisibleChanged: {
131+ if (header.config.visible) {
132+ header.show();
133+ } else {
134+ header.hide();
135+ }
136+ internal.checkFlickableMargins();
137+ }
138+ onLockedChanged: {
139+ internal.connectFlickable();
140+ if (!header.config.locked) {
141+ internal.movementEnded();
142+ }
143+ }
144+ }
145+
146+ /*!
147+ The header is not fully opened or fully closed.
148+
149+ This property is true if the header is animating towards a fully
150+ opened or fully closed state, or if the header is moving due to user
151+ interaction with the flickable.
152+
153+ The value of moving is always false when using an old version of
154+ PageHeadConfiguration (which does not have the visible property).
155+
156+ Used in tst_header_locked_visible.qml.
157+ */
158+ readonly property bool moving: internal.newConfig &&
159+ ((config.visible && header.y !== 0) ||
160+ (!config.visible && header.y !== -header.height))
161
162 QtObject {
163 id: internal
164
165+ // This property is updated in header.onConfigChanged to ensure it
166+ // is updated before other functions are called in onConfigChanged.
167+ property bool newConfig: header.config &&
168+ header.config.hasOwnProperty("locked") &&
169+ header.config.hasOwnProperty("visible")
170+
171 /*!
172 Track the y-position inside the flickable.
173 */
174@@ -184,20 +254,26 @@
175 Disconnect previous flickable, and connect the new one.
176 */
177 function connectFlickable() {
178+ // Finish the current header movement in case the current
179+ // flickable is disconnected while scrolling:
180+ internal.movementEnded();
181+
182 if (previousFlickable) {
183 previousFlickable.contentYChanged.disconnect(internal.scrollContents);
184 previousFlickable.movementEnded.disconnect(internal.movementEnded);
185 previousFlickable.interactiveChanged.disconnect(internal.interactiveChanged);
186+ previousFlickable = null;
187 }
188- if (flickable) {
189+ if (flickable && !(internal.newConfig && header.config.locked)) {
190 // Connect flicking to movements of the header
191 previousContentY = flickable.contentY;
192 flickable.contentYChanged.connect(internal.scrollContents);
193 flickable.movementEnded.connect(internal.movementEnded);
194 flickable.interactiveChanged.connect(internal.interactiveChanged);
195 flickable.contentHeightChanged.connect(internal.contentHeightChanged);
196+ previousFlickable = flickable;
197 }
198- previousFlickable = flickable;
199+ internal.checkFlickableMargins();
200 }
201
202 /*!
203@@ -217,9 +293,14 @@
204 Fully show or hide the header, depending on its current y.
205 */
206 function movementEnded() {
207- if (flickable && flickable.contentY < 0) header.show();
208- else if (header.y < -header.height/2) header.hide();
209- else header.show();
210+ if (!(internal.newConfig && header.config.locked)) {
211+ if ( (flickable && flickable.contentY < 0) ||
212+ (header.y > -header.height/2)) {
213+ header.show();
214+ } else {
215+ header.hide();
216+ }
217+ }
218 }
219
220 /*
221@@ -242,13 +323,20 @@
222 */
223 function checkFlickableMargins() {
224 if (header.flickable) {
225- var headerHeight = header.visible ? header.height : 0
226+ var headerHeight = 0;
227+ if (header.visible && !(internal.newConfig &&
228+ header.config.locked &&
229+ !header.config.visible)) {
230+ headerHeight = header.height;
231+ }
232+
233 if (flickable.topMargin !== headerHeight) {
234+ var oldContentY = flickable.contentY;
235 var previousHeaderHeight = flickable.topMargin;
236 flickable.topMargin = headerHeight;
237 // push down contents when header grows,
238 // pull up contents when header shrinks.
239- flickable.contentY -= headerHeight - previousHeaderHeight;
240+ flickable.contentY = oldContentY - headerHeight + previousHeaderHeight;
241 }
242 }
243 }
244
245=== modified file 'modules/Ubuntu/Components/MainView.qml'
246--- modules/Ubuntu/Components/MainView.qml 2015-03-03 13:47:48 +0000
247+++ modules/Ubuntu/Components/MainView.qml 2015-04-02 11:17:02 +0000
248@@ -125,6 +125,7 @@
249 AppHeader {
250 // This objectName is used in the MainView autopilot custom proxy object
251 // in order to select the application header.
252+ // Also used in tst_header_locked_visible.qml.
253 objectName: "MainView_Header"
254 id: headerItem
255 property real bottomY: headerItem.y + headerItem.height
256@@ -136,7 +137,7 @@
257 flickable: internal.activePage ? internal.activePage.flickable : null
258 pageStack: internal.activePage ? internal.activePage.pageStack : null
259
260- PageHeadConfiguration {
261+ Toolkit.PageHeadConfiguration {
262 id: headerConfig
263 // for backwards compatibility with deprecated tools property
264 actions: internal.activePage ?
265
266=== modified file 'modules/Ubuntu/Components/MainView12.qml'
267--- modules/Ubuntu/Components/MainView12.qml 2015-04-02 11:17:02 +0000
268+++ modules/Ubuntu/Components/MainView12.qml 2015-04-02 11:17:02 +0000
269@@ -69,6 +69,7 @@
270 AppHeader {
271 // This objectName is used in the MainView autopilot custom proxy object
272 // in order to select the application header.
273+ // Also used in tst_header_locked_visible.qml.
274 objectName: "MainView_Header"
275 id: headerItem
276 property real bottomY: headerItem.y + headerItem.height
277@@ -84,7 +85,7 @@
278 internal.activePage.hasOwnProperty("__customHeaderContents") ?
279 internal.activePage.__customHeaderContents : null
280
281- PageHeadConfiguration {
282+ Toolkit.PageHeadConfiguration {
283 id: defaultConfig
284 // Used when there is no active Page, or a Page 1.0 is used which
285 // does not have a PageHeadConfiguration.
286@@ -115,9 +116,13 @@
287 target: Qt.application
288 onActiveChanged: {
289 if (Qt.application.active) {
290- headerItem.animate = false;
291- headerItem.show();
292- headerItem.animate = true;
293+ if (!(headerItem.config &&
294+ headerItem.config.hasOwnProperty("locked") &&
295+ headerItem.locked)) {
296+ headerItem.animate = false;
297+ headerItem.show();
298+ headerItem.animate = true;
299+ }
300 }
301 }
302 }
303
304=== modified file 'modules/Ubuntu/Components/Page10.qml'
305--- modules/Ubuntu/Components/Page10.qml 2015-04-02 11:17:02 +0000
306+++ modules/Ubuntu/Components/Page10.qml 2015-04-02 11:17:02 +0000
307@@ -15,7 +15,7 @@
308 */
309
310 import QtQuick 2.4
311-import Ubuntu.Components 1.2 as Toolkit
312+import Ubuntu.Components 1.0 as Toolkit
313 import "pageUtils.js" as Utils
314
315 /*!
316
317=== modified file 'modules/Ubuntu/Components/Page11.qml'
318--- modules/Ubuntu/Components/Page11.qml 2015-03-03 12:53:42 +0000
319+++ modules/Ubuntu/Components/Page11.qml 2015-04-02 11:17:02 +0000
320@@ -15,16 +15,18 @@
321 */
322
323 import QtQuick 2.4
324+import Ubuntu.Components 1.0 as Toolkit10
325+import Ubuntu.Components 1.1 as Toolkit11
326
327 /*! \internal */
328 // Documentation in Page.qdoc
329-Page10 {
330+Toolkit10.Page {
331 id: page
332 /*!
333 \qmlproperty PageHeadConfiguration head
334 */
335 readonly property alias head: headerConfig
336- PageHeadConfiguration {
337+ Toolkit11.PageHeadConfiguration {
338 id: headerConfig
339 }
340
341@@ -32,7 +34,7 @@
342 print("Page.tools is a deprecated property. Please use Page.head instead.");
343 }
344
345- Object {
346+ Toolkit11.Object {
347 id: internal
348
349 // Note: The bindings below need to check whether headerConfig.contents
350
351=== added file 'modules/Ubuntu/Components/PageHeadConfiguration.qdoc'
352--- modules/Ubuntu/Components/PageHeadConfiguration.qdoc 1970-01-01 00:00:00 +0000
353+++ modules/Ubuntu/Components/PageHeadConfiguration.qdoc 2015-04-02 11:17:02 +0000
354@@ -0,0 +1,202 @@
355+/*
356+ * Copyright 2014-2015 Canonical Ltd.
357+ *
358+ * This program is free software; you can redistribute it and/or modify
359+ * it under the terms of the GNU Lesser General Public License as published by
360+ * the Free Software Foundation; version 3.
361+ *
362+ * This program is distributed in the hope that it will be useful,
363+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
364+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
365+ * GNU Lesser General Public License for more details.
366+ *
367+ * You should have received a copy of the GNU Lesser General Public License
368+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
369+ */
370+
371+/*!
372+ \qmltype PageHeadConfiguration
373+ \inqmlmodule Ubuntu.Components 1.1
374+ \ingroup ubuntu
375+ \since Ubuntu.Components 1.1
376+ \brief Page.head is used to configure the header for a \l Page.
377+
378+ For examples how to use Page.head, see \l Page.
379+ */
380+
381+/*!
382+ List of actions to show in the header.
383+
384+ Example:
385+ \qml
386+ Page {
387+ title: "Custom header actions"
388+ head.actions: [
389+ Action {
390+ iconName: "save"
391+ text: i18n.tr("Save")
392+ },
393+ Action {
394+ iconName: "add"
395+ text: i18n.tr("Add")
396+ }
397+ ]
398+ }
399+ \endqml
400+ \qmlproperty list<Action> PageHeadConfiguration::actions
401+ */
402+
403+/*!
404+ \qmlproperty Action PageHeadConfiguration::backAction
405+ Overrides the default \l PageStack back button and the
406+ \l Tabs drawer button in the header.
407+
408+ Example:
409+ \qml
410+ Page {
411+ title: "Back Action Page"
412+ head.backAction: Action {
413+ iconName: "close"
414+ onTriggered: {
415+ console.log("Run custom back action")
416+ }
417+ }
418+ }
419+ \endqml
420+ */
421+
422+/*!
423+ \qmlproperty Item PageHeadConfiguration::contents
424+ Set this property to show this Item in the header instead of
425+ the title. Use a \l TextField here for implementing search in header.
426+
427+ The parent of this Item will be binded while the \l Page is active.
428+ The header contents will automatically be anchored to the left and
429+ vertically centered inside the header.
430+
431+ Example:
432+ \qml
433+ Page {
434+ title: "Invisible title"
435+ head.contents: Rectangle {
436+ color: UbuntuColors.orange
437+ height: units.gu(5)
438+ width: parent ? parent.width - units.gu(2) : undefined
439+ }
440+ }
441+ \endqml
442+
443+ See \l PageHeadState for an example that shows how search mode can
444+ be implemented.
445+ */
446+
447+// FIXME: The example below can be much simplified using PageHeadState
448+// when bug #1345775 has been fixed.
449+/*!
450+ \qmlproperty string PageHeadConfiguration::preset
451+ Choose a preset for the header visuals and behavior.
452+ The default is an empty string "".
453+ By setting this to "select", title will be hidden and
454+ actions will be represented by icons with a label.
455+
456+ Example:
457+ \qml
458+ import QtQuick 2.4
459+ import Ubuntu.Components 1.2
460+
461+ MainView {
462+ id: mainView
463+ width: units.gu(40)
464+ height: units.gu(50)
465+
466+ Page {
467+ id: page
468+ title: "Demo"
469+
470+ state: "default"
471+ states: [
472+ PageHeadState {
473+ name: "default"
474+ head: page.head
475+ actions: [
476+ Action {
477+ iconName: "contact"
478+ text: "Contact"
479+ }
480+ ]
481+ },
482+ State {
483+ id: selectState
484+ name: "select"
485+
486+ property Action leaveSelect: Action {
487+ iconName: "back"
488+ text: "Back"
489+ onTriggered: page.state = "default"
490+ }
491+ property list<Action> actions: [
492+ Action {
493+ iconName: "select"
494+ text: "Select All"
495+ },
496+ Action {
497+ iconName: "delete"
498+ text: "Delete"
499+ }
500+ ]
501+ PropertyChanges {
502+ target: page.head
503+ backAction: selectState.leaveSelect
504+ actions: selectState.actions
505+ preset: "select"
506+ }
507+ }
508+ ]
509+
510+ Label {
511+ anchors.centerIn: parent
512+ text: "Use back button to leave selection mode."
513+ visible: page.state == "select"
514+ }
515+
516+ Button {
517+ anchors.centerIn: parent
518+ onClicked: page.state = "select"
519+ visible: page.state != "select"
520+ text: "selection mode"
521+ }
522+ }
523+ }
524+ \endqml
525+ */
526+
527+/*!
528+ \qmlproperty PageHeadSections PageHeadConfiguration::sections
529+ Defines the sections in the page header divider.
530+ */
531+
532+/*!
533+ \qmlproperty color PageHeadConfiguration::foregroundColor
534+ The color of the text and icons.
535+ */
536+
537+/*!
538+ \qmlproperty bool PageHeadConfiguration::locked
539+ \since 1.2
540+ When the \l Page is active, the locked property controls the behavior
541+ of the header. A locked header stays visible or invisible, depending
542+ on the value of the \l visible property. An unlocked header automatically
543+ shows and hides if the \l Page has a flickable in which the user
544+ scrolls up or down.
545+ Default value: false
546+ */
547+
548+/*!
549+ \qmlproperty bool PageHeadConfiguration::visible
550+ \since 1.2
551+ Update the value of the visible property to show or hide the header.
552+ This works both when the header is \l locked and unlocked. An unlocked
553+ header can also become visible or hidden when the user scrolls the
554+ active \l Page's flickable. The value of the visible property will be
555+ updated at the end of the showing/hiding animation of the header.
556+ */
557
558=== renamed file 'modules/Ubuntu/Components/PageHeadConfiguration.qml' => 'modules/Ubuntu/Components/PageHeadConfiguration11.qml'
559--- modules/Ubuntu/Components/PageHeadConfiguration.qml 2015-03-03 13:47:48 +0000
560+++ modules/Ubuntu/Components/PageHeadConfiguration11.qml 2015-04-02 11:17:02 +0000
561@@ -15,92 +15,24 @@
562 */
563
564 import QtQuick 2.4
565-import Ubuntu.Components 1.2
566+import Ubuntu.Components 1.1
567
568 /*!
569- \qmltype PageHeadConfiguration
570- \inqmlmodule Ubuntu.Components 1.1
571- \ingroup ubuntu
572- \since Ubuntu.Components 1.1
573- \brief Page.head is used to configure the header for a \l Page.
574-
575- For examples how to use Page.head, see \l Page.
576+ \internal
577+ Documented in PageHeadConfiguration.qdoc
578 */
579 Object {
580 // To be used inside a Page only.
581 id: headerConfig
582
583- /*!
584- List of actions to show in the header.
585-
586- Example:
587- \qml
588- Page {
589- title: "Custom header actions"
590- head.actions: [
591- Action {
592- iconName: "save"
593- text: i18n.tr("Save")
594- },
595- Action {
596- iconName: "add"
597- text: i18n.tr("Add")
598- }
599- ]
600- }
601- \endqml
602- */
603 property list<Action> actions
604-
605- /*!
606- Overrides the default \l PageStack back button and the
607- \l Tabs drawer button in the header.
608-
609- Example:
610- \qml
611- Page {
612- title: "Back Action Page"
613- head.backAction: Action {
614- iconName: "close"
615- onTriggered: {
616- console.log("Run custom back action")
617- }
618- }
619- }
620- \endqml
621- */
622 property Action backAction: null
623-
624- /*!
625- Set this property to show this Item in the header instead of
626- the title. Use a \l TextField here for implementing search in header.
627-
628- The parent of this Item will be binded while the \l Page is active.
629- The header contents will automatically be anchored to the left and
630- vertically centered inside the header.
631-
632- Example:
633- \qml
634- Page {
635- title: "Invisible title"
636- head.contents: Rectangle {
637- color: UbuntuColors.orange
638- height: units.gu(5)
639- width: parent ? parent.width - units.gu(2) : undefined
640- }
641- }
642- \endqml
643-
644- See \l PageHeadState for an example that shows how search mode can
645- be implemented.
646- */
647 property Item contents: null
648
649 QtObject {
650 id: internal
651 property Item oldContents: null
652 }
653-
654 onContentsChanged: {
655 if (internal.oldContents) {
656 // FIX: bug #1341814 and #1400297
657@@ -111,97 +43,13 @@
658 internal.oldContents = contents;
659 }
660
661- // FIXME: The example below can be much simplified using PageHeadState
662- // when bug #1345775 has been fixed.
663- /*!
664- Choose a preset for the header visuals and behavior.
665- The default is an empty string "".
666- By setting this to "select", title will be hidden and
667- actions will be represented by icons with a label.
668-
669- Example:
670- \qml
671- import QtQuick 2.4
672- import Ubuntu.Components 1.2
673-
674- MainView {
675- id: mainView
676- width: units.gu(40)
677- height: units.gu(50)
678-
679- Page {
680- id: page
681- title: "Demo"
682-
683- state: "default"
684- states: [
685- PageHeadState {
686- name: "default"
687- head: page.head
688- actions: [
689- Action {
690- iconName: "contact"
691- text: "Contact"
692- }
693- ]
694- },
695- State {
696- id: selectState
697- name: "select"
698-
699- property Action leaveSelect: Action {
700- iconName: "back"
701- text: "Back"
702- onTriggered: page.state = "default"
703- }
704- property list<Action> actions: [
705- Action {
706- iconName: "select"
707- text: "Select All"
708- },
709- Action {
710- iconName: "delete"
711- text: "Delete"
712- }
713- ]
714- PropertyChanges {
715- target: page.head
716- backAction: selectState.leaveSelect
717- actions: selectState.actions
718- preset: "select"
719- }
720- }
721- ]
722-
723- Label {
724- anchors.centerIn: parent
725- text: "Use back button to leave selection mode."
726- visible: page.state == "select"
727- }
728-
729- Button {
730- anchors.centerIn: parent
731- onClicked: page.state = "select"
732- visible: page.state != "select"
733- text: "selection mode"
734- }
735- }
736- }
737- \endqml
738- */
739 property string preset: ""
740-
741 /*!
742 \qmlproperty PageHeadSections sections
743- Defines the sections in the page header divider.
744 */
745 readonly property alias sections: headSections
746 PageHeadSections {
747 id: headSections
748 }
749-
750- /*!
751- The color of the text and icons.
752- */
753 property color foregroundColor: Theme.palette.selected.backgroundText
754 }
755
756=== added file 'modules/Ubuntu/Components/PageHeadConfiguration13.qml'
757--- modules/Ubuntu/Components/PageHeadConfiguration13.qml 1970-01-01 00:00:00 +0000
758+++ modules/Ubuntu/Components/PageHeadConfiguration13.qml 2015-04-02 11:17:02 +0000
759@@ -0,0 +1,30 @@
760+/*
761+ * Copyright 2015 Canonical Ltd.
762+ *
763+ * This program is free software; you can redistribute it and/or modify
764+ * it under the terms of the GNU Lesser General Public License as published by
765+ * the Free Software Foundation; version 3.
766+ *
767+ * This program is distributed in the hope that it will be useful,
768+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
769+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
770+ * GNU Lesser General Public License for more details.
771+ *
772+ * You should have received a copy of the GNU Lesser General Public License
773+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
774+ */
775+
776+import Ubuntu.Components 1.2 as Toolkit12
777+
778+/*!
779+ \internal
780+ documented in PageHeadConfiguration.qdoc
781+ */
782+Toolkit12.PageHeadConfiguration {
783+ id: headerConfig
784+
785+ property bool locked: false
786+
787+ // auto-updated by AppHeader, but may be set by the developer
788+ property bool visible
789+}
790
791=== modified file 'modules/Ubuntu/Components/Tabs.qml'
792--- modules/Ubuntu/Components/Tabs.qml 2015-03-05 09:35:06 +0000
793+++ modules/Ubuntu/Components/Tabs.qml 2015-04-02 11:17:02 +0000
794@@ -310,7 +310,10 @@
795 if (tabBar && tabBar.__styleInstance && tabBar.__styleInstance.hasOwnProperty("sync")) {
796 tabBar.__styleInstance.sync();
797 }
798- if (tabs.active && internal.header) {
799+ if ((tabs.active && internal.header) &&
800+ !(internal.header.config &&
801+ internal.header.config.hasOwnProperty("locked") &&
802+ internal.header.config.locked)) {
803 internal.header.show();
804 }
805 // deprecated, however use it till we remove it completely
806
807=== modified file 'modules/Ubuntu/Components/qmldir'
808--- modules/Ubuntu/Components/qmldir 2015-04-02 11:17:02 +0000
809+++ modules/Ubuntu/Components/qmldir 2015-04-02 11:17:02 +0000
810@@ -98,7 +98,7 @@
811 UbuntuListView 1.1 UbuntuListView11.qml
812 internal PageBase Page10.qml
813 Page 1.1 Page11.qml
814-PageHeadConfiguration 1.1 PageHeadConfiguration.qml
815+PageHeadConfiguration 1.1 PageHeadConfiguration11.qml
816 PageHeadSections 1.1 PageHeadSections.qml
817 PageHeadState 1.1 PageHeadState.qml
818 Icon 1.1 Icon11.qml
819@@ -114,3 +114,4 @@
820
821 #version 1.3
822 Page 1.3 Page13.qml
823+PageHeadConfiguration 1.3 PageHeadConfiguration13.qml
824
825=== modified file 'modules/Ubuntu/Test/UbuntuTestCase.qml'
826--- modules/Ubuntu/Test/UbuntuTestCase.qml 2015-04-02 11:17:02 +0000
827+++ modules/Ubuntu/Test/UbuntuTestCase.qml 2015-04-02 11:17:02 +0000
828@@ -115,10 +115,10 @@
829 var iy = 0;
830
831 for (var step=0; step < steps; step++) {
832- if (ix < abs_dx) {
833+ if (Math.abs(ix) < abs_dx) {
834 ix += step_dx;
835 }
836- if (iy < abs_dy) {
837+ if (Math.abs(iy) < abs_dy) {
838 iy += step_dy;
839 }
840 mouseMove(item, x + ix, y + iy, stepdelay);
841@@ -253,7 +253,6 @@
842 // Wait for animation of the style inside the header (when pushing/popping):
843 tryCompareFunction(function(){ return headerStyle.animating }, false);
844 // Wait for the header to finish showing/hiding:
845- // FIXME: Uncomment this in the following MR that adds the header.moving property.
846- //tryCompareFunction(function(){ return header.moving }, false);
847+ tryCompareFunction(function(){ return header.moving }, false);
848 }
849 }
850
851=== modified file 'tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_header.py'
852--- tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_header.py 2015-03-04 21:57:25 +0000
853+++ tests/autopilot/ubuntuuitoolkit/_custom_proxy_objects/_header.py 2015-04-02 11:17:02 +0000
854@@ -1,6 +1,6 @@
855 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
856 #
857-# Copyright (C) 2012, 2013, 2014 Canonical Ltd.
858+# Copyright (C) 2012-2015 Canonical Ltd.
859 #
860 # This program is free software; you can redistribute it and/or modify
861 # it under the terms of the GNU Lesser General Public License as published by
862@@ -64,6 +64,9 @@
863 # so no need to wait.
864 return
865
866+ # Wait showing/hiding animation of the header.
867+ self.moving.wait_for(False)
868+
869 @autopilot_logging.log_action(logger.info)
870 def switch_to_section_by_index(self, index):
871 """Select a section in the header divider
872
873=== removed file 'tests/resources/header/lockedToolbar.deprecated.qml'
874--- tests/resources/header/lockedToolbar.deprecated.qml 2015-03-06 12:42:00 +0000
875+++ tests/resources/header/lockedToolbar.deprecated.qml 1970-01-01 00:00:00 +0000
876@@ -1,52 +0,0 @@
877-/*
878- * Copyright (C) 2014 Canonical Ltd.
879- *
880- * This program is free software; you can redistribute it and/or modify
881- * it under the terms of the GNU Lesser General Public License as published by
882- * the Free Software Foundation; version 3.
883- *
884- * This program is distributed in the hope that it will be useful,
885- * but WITHOUT ANY WARRANTY; without even the implied warranty of
886- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
887- * GNU Lesser General Public License for more details.
888- *
889- * You should have received a copy of the GNU Lesser General Public License
890- * along with this program. If not, see <http://www.gnu.org/licenses/>.
891- */
892-
893-import QtQuick 2.0
894-import Ubuntu.Components 1.1
895-
896-MainView {
897- width: units.gu(50)
898- height: units.gu(80)
899- id: mainView
900-
901- Page {
902- id: page
903- title: "test page"
904- Label {
905- anchors.centerIn: parent
906- text: "testing the toolbar"
907- }
908- tools: ToolbarItems {
909- id: toolbarItems
910- ToolbarButton {
911- text: "action1"
912- }
913- }
914- }
915-
916- ToolbarItems {
917- id: lockedTools
918- ToolbarButton {
919- text: "locked"
920- }
921- locked: true
922- opened: true
923- }
924-
925- Component.onCompleted: {
926- page.tools = lockedTools;
927- }
928-}
929
930=== added file 'tests/unit_x11/tst_components/tst_header_visible.qml'
931--- tests/unit_x11/tst_components/tst_header_visible.qml 1970-01-01 00:00:00 +0000
932+++ tests/unit_x11/tst_components/tst_header_visible.qml 2015-04-02 11:17:02 +0000
933@@ -0,0 +1,288 @@
934+/*
935+ * Copyright (C) 2015 Canonical Ltd.
936+ *
937+ * This program is free software; you can redistribute it and/or modify
938+ * it under the terms of the GNU Lesser General Public License as published by
939+ * the Free Software Foundation; version 3.
940+ *
941+ * This program is distributed in the hope that it will be useful,
942+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
943+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
944+ * GNU Lesser General Public License for more details.
945+ *
946+ * You should have received a copy of the GNU Lesser General Public License
947+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
948+ */
949+
950+import QtQuick 2.4
951+import Ubuntu.Components 1.3
952+import Ubuntu.Test 1.0
953+
954+Item {
955+ width: units.gu(50)
956+ height: units.gu(70)
957+
958+ MainView {
959+ id: mainView
960+ width: units.gu(50)
961+ height: units.gu(70)
962+
963+ PageStack {
964+ id: stack
965+ Component.onCompleted: stack.push(page)
966+
967+ Page {
968+ id: page
969+ title: "Auto-hide"
970+ head {
971+ locked: lockedSwitch.checked
972+ onVisibleChanged: {
973+ visibleSwitch.checked = page.head.visible
974+ }
975+ }
976+ Flickable {
977+ id: flickable
978+ anchors.fill: parent
979+ contentHeight: units.gu(200)
980+ Rectangle {
981+ color: "green"
982+ opacity: 0.3
983+ anchors {
984+ left: parent.left
985+ right: parent.right
986+ top: parent.top
987+ }
988+ height: 1
989+ }
990+
991+ Grid {
992+ id: switchGrid
993+ columns: 2
994+ spacing: units.gu(1)
995+ anchors {
996+ top: parent.top
997+ left: parent.left
998+ leftMargin: units.gu(5)
999+ topMargin: units.gu(15)
1000+ }
1001+ Switch {
1002+ id: lockedSwitch
1003+ checked: false
1004+ }
1005+ Label {
1006+ text: "header locked"
1007+ }
1008+ Switch {
1009+ id: visibleSwitch
1010+ checked: page.head.visible
1011+ onClicked: page.head.visible = checked
1012+ }
1013+ Label {
1014+ text: "header visible"
1015+ }
1016+ }
1017+ Label {
1018+ id: label
1019+ anchors {
1020+ horizontalCenter: parent.horizontalCenter
1021+ top: switchGrid.bottom
1022+ topMargin: units.gu(15)
1023+ }
1024+ text: "Flick me"
1025+ }
1026+ Button {
1027+ anchors {
1028+ horizontalCenter: parent.horizontalCenter
1029+ top: label.bottom
1030+ topMargin: units.gu(5)
1031+ }
1032+ text: "Click me"
1033+ onTriggered: stack.push(otherPage)
1034+ }
1035+ }
1036+ }
1037+ Page {
1038+ id: otherPage
1039+ title: "On stack"
1040+ visible: false
1041+
1042+ Label {
1043+ anchors.centerIn: parent
1044+ text: "Stacked"
1045+ }
1046+ }
1047+ Page {
1048+ id: titleLessPage
1049+ visible: false
1050+ }
1051+ }
1052+ }
1053+
1054+ UbuntuTestCase {
1055+ name: "HeaderLockedVisible"
1056+ when: windowShown
1057+ id: testCase
1058+
1059+ property var header
1060+ function initTestCase() {
1061+ testCase.header = findChild(mainView, "MainView_Header");
1062+ }
1063+
1064+ function init() {
1065+ page.head.visible = true;
1066+ page.head.locked = false;
1067+ otherPage.head.visible = true;
1068+ otherPage.head.locked = false;
1069+ wait_for_visible(true, "Header is not visible initially.");
1070+ compare(stack.currentPage, page, "Wrong Page on PageStack initially.");
1071+ compare(page.head.locked, false, "Header is not locked initially.");
1072+ }
1073+
1074+ function scroll(dy) {
1075+ var p = centerOf(mainView);
1076+ // Use mouseWheel to scroll because mouseDrag is very unreliable
1077+ // and does not properly handle negative values for dy.
1078+ mouseWheel(mainView, p.x, p.y, 0, 2*dy);
1079+ }
1080+
1081+ function scroll_down() {
1082+ scroll(-header.height);
1083+ }
1084+
1085+ function scroll_up() {
1086+ scroll(header.height);
1087+ }
1088+
1089+ function wait_for_visible(visible, errorMessage) {
1090+ waitForHeaderAnimation(mainView);
1091+ compare(stack.currentPage.head.visible, visible, errorMessage);
1092+ var mismatchMessage = " Page.head.visible does not match header visibility.";
1093+ if (visible) {
1094+ compare(header.y, 0, errorMessage + mismatchMessage);
1095+ } else {
1096+ compare(header.y, -header.height, errorMessage + mismatchMessage);
1097+ }
1098+ }
1099+
1100+ function test_set_visible_to_hide_and_show() {
1101+ page.head.visible = false;
1102+ wait_for_visible(false, "Cannot hide unlocked header by setting visible to false.");
1103+ page.head.visible = true;
1104+ wait_for_visible(true, "Cannot show unlocked header by setting visible to true.");
1105+
1106+ page.head.locked = true;
1107+ page.head.visible = false;
1108+ wait_for_visible(false, "Cannot hide locked header by setting visible to false.");
1109+ page.head.visible = true;
1110+ wait_for_visible(true, "Cannot show locked header by setting visible to true.");
1111+ }
1112+
1113+ function test_scroll_when_unlocked_updates_visible() {
1114+ scroll_down();
1115+ wait_for_visible(false, "Scrolling down does not hide header.");
1116+ scroll_up();
1117+ wait_for_visible(true, "Scrolling up does not show header.");
1118+ }
1119+
1120+ function test_scroll_when_locked_does_not_update_visible() {
1121+ // Note that with a locked header, scrolling up and down does not
1122+ // cause the header to move, so the wait_for_visible() calls below
1123+ // will return almost instantly.
1124+ page.head.locked = true;
1125+ scroll_down();
1126+ wait_for_visible(true, "Scrolling down hides locked header.");
1127+ scroll_up();
1128+ wait_for_visible(true, "Scrolling up hides locked header.");
1129+
1130+ page.head.visible = false;
1131+ waitForHeaderAnimation(mainView);
1132+ scroll_down();
1133+ wait_for_visible(false, "Scrolling down shows locked header.");
1134+ scroll_up();
1135+ wait_for_visible(false, "Scrolling up shows locked header.");
1136+ }
1137+
1138+ function test_locking_updates_visible() {
1139+ // locked = false, visible = true.
1140+ page.head.locked = true;
1141+ wait_for_visible(true, "Locking hides header.");
1142+ page.head.locked = false;
1143+ wait_for_visible(true, "Unlocking hides header.");
1144+
1145+ page.head.locked = true;
1146+ page.head.visible = false;
1147+ waitForHeaderAnimation(mainView);
1148+ // When the flickable is scrolled to the top, unlocking the header must show
1149+ // the header because you cannot scroll more up to reveal it:
1150+ page.head.locked = false;
1151+ wait_for_visible(true, "Unlocking header when flickable is at Y beginning "+
1152+ "does not show header.");
1153+
1154+ scroll_down();
1155+ wait_for_visible(false, "Scrolling down does not hide header.");
1156+ page.head.locked = true;
1157+ wait_for_visible(false, "Locking shows header.");
1158+ // When flickable is scrolled down, unlocking header does not show header
1159+ // because the user can scroll up to reveal it:
1160+ page.head.locked = false;
1161+ wait_for_visible(false, "Unlocking shows header when flickable is not at " +
1162+ "Y beginning.");
1163+ }
1164+
1165+ function test_activate_page_shows_header() {
1166+ page.head.visible = false;
1167+ waitForHeaderAnimation(mainView);
1168+
1169+ // Header becomes visible when new Page becomes active:
1170+ stack.push(otherPage);
1171+ wait_for_visible(true, "Pushing page on stack does not show header.");
1172+
1173+ // Header becomes visible when Page with previously hidden header
1174+ // becomes active:
1175+ stack.pop();
1176+ wait_for_visible(true, "Activating unlocked Page does not make header visible.");
1177+ }
1178+
1179+ function test_activate_hides_locked_hidden_header() {
1180+ otherPage.head.locked = true;
1181+ otherPage.head.visible = false;
1182+
1183+ stack.push(otherPage);
1184+ wait_for_visible(false, "Pushing Page with locked hidden header shows header.");
1185+ compare(otherPage.head.locked, true, "Pushing Page unlocks header.");
1186+ compare(page.head.locked, false, "Pushing Page locks previous header.");
1187+
1188+ stack.pop();
1189+ wait_for_visible(true, "Popping to a Page with unlocked header does not show header.");
1190+ compare(otherPage.head.locked, true, "Popping Page unlocks previous header.");
1191+ compare(page.head.locked, false, "Popping Page locks header.");
1192+ }
1193+
1194+ function test_hidden_locked_header_stays_hidden() {
1195+ page.head.locked = true;
1196+ page.head.visible = false;
1197+ waitForHeaderAnimation(mainView);
1198+ stack.push(otherPage);
1199+ waitForHeaderAnimation(mainView);
1200+ stack.pop();
1201+ wait_for_visible(false, "Popping to a Page with locked hidden header shows header.");
1202+ }
1203+
1204+ function test_page_with_no_title_on_pagestack_has_back_button_bug1402054() {
1205+ page.head.visible = false;
1206+ waitForHeaderAnimation(mainView);
1207+ stack.push(titleLessPage);
1208+ wait_for_visible(true, "Page with no title hides the header.");
1209+
1210+ var backButton = findChild(testCase.header, "backButton");
1211+ verify(null !== backButton, "Header has no back button.");
1212+ compare(backButton.visible, true, "Page with no title hides the back button.");
1213+
1214+ var center = centerOf(backButton);
1215+ mouseClick(backButton, center.x, center.y);
1216+ waitForHeaderAnimation(mainView);
1217+ compare(stack.depth, 1, "Clicking back button of page with no title does not "+
1218+ "pop the page from the PageStack.");
1219+ }
1220+ }
1221+}
1222
1223=== modified file 'tests/unit_x11/tst_components/tst_page13.qml'
1224--- tests/unit_x11/tst_components/tst_page13.qml 2015-04-02 11:17:02 +0000
1225+++ tests/unit_x11/tst_components/tst_page13.qml 2015-04-02 11:17:02 +0000
1226@@ -1,5 +1,5 @@
1227 /*
1228- * Copyright 2012-2015 Canonical Ltd.
1229+ * Copyright 2015 Canonical Ltd.
1230 *
1231 * This program is free software; you can redistribute it and/or modify
1232 * it under the terms of the GNU Lesser General Public License as published by
1233@@ -15,7 +15,7 @@
1234 */
1235
1236 import QtQuick 2.4
1237-import QtTest 1.0
1238+import Ubuntu.Test 1.0
1239 import Ubuntu.Components 1.3
1240
1241 Item {
1242@@ -49,11 +49,12 @@
1243 }
1244 }
1245
1246- TestCase {
1247+ UbuntuTestCase {
1248+ id: testCase
1249 name: "Page13API"
1250 when: windowShown
1251
1252- function initTestCase() {
1253+ function init() {
1254 compare(page.title, "", "Page title is set by default.");
1255 compare(page.active, true, "Page is inactive by default.");
1256 compare(page.pageStack, null, "Page has a PageStack by default.");
1257@@ -94,29 +95,30 @@
1258 }
1259
1260 function test_flickableY_bug1201452() {
1261- var pageTitle = "Hello bug!";
1262- page.title = pageTitle;
1263- var header = page.__propagated.header;
1264-
1265- var headerHeight = header.height
1266+ var header = findChild(mainView, "MainView_Header");
1267+ var headerHeight = header.height;
1268 var flickableY = 150;
1269 page.flickable.contentY = flickableY;
1270 compare(page.flickable.contentY, flickableY,
1271 "Flickable.contentY could not be set.");
1272 compare(page.flickable.topMargin, headerHeight,
1273 "topMargin of the flickable does not equal header height.");
1274- page.title = "";
1275-
1276- // FIXME: Update the checks below when new API is added
1277- // for showing and hiding the header.
1278- compare(header.visible, false, "Header is not hidden when title is unset.");
1279+
1280+ page.head.locked = true;
1281+ page.head.visible = false;
1282+ waitForHeaderAnimation(mainView);
1283+
1284 compare(page.flickable.topMargin, 0,
1285- "topMargin is not 0 when header is hidden.");
1286+ "topMargin is not 0 when header is locked hidden.");
1287 compare(page.flickable.contentY, flickableY + headerHeight,
1288 "contentY was not updated properly when header was hidden.");
1289- page.title = pageTitle;
1290+
1291+ page.head.locked.locked = false;
1292+ page.head.visible = true;
1293+ waitForHeaderAnimation(mainView);
1294+
1295 compare(page.flickable.contentY, flickableY,
1296- "Making header visible changes flickable.contentY");
1297+ "Hiding and showing header changes flickable.contentY.");
1298 compare(page.flickable.topMargin, headerHeight,
1299 "topMargin was not updated when header became visible.");
1300 }

Subscribers

People subscribed via source and target branches