Merge lp:~tpeeters/ubuntu-ui-toolkit/headlock into lp:ubuntu-ui-toolkit/staging
- headlock
- Merge into staging
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 | ||||||||
Related bugs: |
|
||||||||
Related blueprints: |
Additional new header features
(Undefined)
|
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
Add visible and locked properties to Page.head.
This MR has two pre-requisites that must land first:
1 - https:/
2 - https:/
- 1478. By Tim Peeters
-
clean
- 1479. By Tim Peeters
-
use waitForHeaderAn
imation( mainView) in tst_page13.qml
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1479
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1480. By Tim Peeters
-
merge staging
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1480
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1481. By Tim Peeters
-
merge staging
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1481
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 1482. By Tim Peeters
-
update components.api
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1482
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1483. By Tim Peeters
-
merge waitForHeaderAn
imation prerequisite branch
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1483
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
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 | } |
FAILED: Continuous integration, rev:1477 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/1584/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 1922/console jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-amd64- ci/311/ console jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-armhf- ci/314/ console jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-i386- ci/311/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 1920/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/1584/ rebuild
http://