Merge lp:~zsombi/ubuntu-ui-toolkit/aplReplacePrimaryPage into lp:ubuntu-ui-toolkit/staging
- aplReplacePrimaryPage
- Merge into staging
Status: | Merged |
---|---|
Approved by: | Cris Dywan |
Approved revision: | 1668 |
Merged at revision: | 1673 |
Proposed branch: | lp:~zsombi/ubuntu-ui-toolkit/aplReplacePrimaryPage |
Merge into: | lp:ubuntu-ui-toolkit/staging |
Prerequisite: | lp:~zsombi/ubuntu-ui-toolkit/aplPrimaryPageAsync |
Diff against target: |
466 lines (+179/-138) 2 files modified
src/Ubuntu/Components/1.3/AdaptivePageLayout.qml (+52/-30) tests/unit_x11/tst_components/tst_adaptivepagelayout.qml (+127/-108) |
To merge this branch: | bzr merge lp:~zsombi/ubuntu-ui-toolkit/aplReplacePrimaryPage |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cris Dywan | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Review via email: mp+272868@code.launchpad.net |
Commit message
Make primaryPage and primaryPageSource replaceable after component completion.
Description of the change
Make primaryPage and primaryPageSource replaceable after component completion.
PS Jenkins bot (ps-jenkins) wrote : | # |
- 1666. By Zsombor Egri
-
documentation fixed
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1666
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : | # |
+ The property can only hold a Page instance. When changed runtime (not by the
...changed at runtime...
+ be cerated asynchronously and the instance will be reported through
...be created asynchronously...
+ if (source === null) {
+ if (source === undefined) {
These conditionals are hard to make sense of for me even after checking the two places the function can be called from. I'm thinking it might make more sense to dissolve the function so it's easier to understand given there is very little code to be shared.
+ function findPageFromLay
How about making this objectName only? That'd be more consistent and there's no chance of killing time by retroactively investigating localization-
Also, may be worth adding to UbuntuTestCase?
Zsombor Egri (zsombi) wrote : | # |
> + The property can only hold a Page instance. When changed runtime (not by the
>
> ...changed at runtime...
>
> + be cerated asynchronously and the instance will be reported through
>
> ...be created asynchronously...
>
> + if (source === null) {
> + if (source === undefined) {
>
> These conditionals are hard to make sense of for me even after checking the
> two places the function can be called from. I'm thinking it might make more
> sense to dissolve the function so it's easier to understand given there is
> very little code to be shared.
>
> + function findPageFromLay
>
> How about making this objectName only? That'd be more consistent and there's
> no chance of killing time by retroactively investigating localization-
> failures because of labels.
Yep, makes sense.
> Also, may be worth adding to UbuntuTestCase?
Well... should we have APL specific function in UbuntuTestCase? The function itself looks in the body of the APL and not in the APL children itself. Pages can be added as child to APL (which are then forwarded to the internal hiddenPages) so we are not interested of those...
- 1667. By Zsombor Egri
-
review comments applied
- 1668. By Zsombor Egri
-
findPageFromLay
outWithProperty renamed into findPageFromLayout
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1668
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Cris Dywan (kalikiana) wrote : | # |
Thanks for the update!
Preview Diff
1 | === modified file 'src/Ubuntu/Components/1.3/AdaptivePageLayout.qml' |
2 | --- src/Ubuntu/Components/1.3/AdaptivePageLayout.qml 2015-09-30 09:46:03 +0000 |
3 | +++ src/Ubuntu/Components/1.3/AdaptivePageLayout.qml 2015-10-02 05:22:37 +0000 |
4 | @@ -42,13 +42,11 @@ |
5 | add the page to the leftmost column of the view. |
6 | |
7 | The primary page, the very first page must be specified either through the |
8 | - \l primaryPage or \l primaryPageSource properties. The properties cannot be |
9 | - changed after component completion. \l primaryPage can only hold a Page instance, |
10 | - \l primaryPageSource can either be a Component or a url to a document defining |
11 | - a Page. This page cannot be removed from the view. \l primaryPageSource has |
12 | - precedence over \l primaryPage and will create the Page asynchronously. The |
13 | - page instance will be reported through \l primaryPage property and will replace |
14 | - any previous value set to that property. |
15 | + \l primaryPage or \l primaryPageSource properties. \l primaryPage can only |
16 | + hold a Page instance, \l primaryPageSource can either be a Component or a |
17 | + url to a document defining a Page. \l primaryPageSource has precedence over |
18 | + \l primaryPage, and when set it will report the loaded Page through \l primaryPage |
19 | + property, and will replace any value set into that property. |
20 | |
21 | \qml |
22 | import QtQuick 2.4 |
23 | @@ -188,17 +186,18 @@ |
24 | /*! |
25 | The property holds the first Page which will be added to the view. If the |
26 | view has more than one column, the page will be added to the leftmost column. |
27 | - The property can hold only a Page instance. The property cannot be changed after |
28 | - component completion. |
29 | + The property can only hold a Page instance. When changed runtime (not by the |
30 | + AdaptivePageLayout component itself), the \l primaryPageSource property |
31 | + will be reset. |
32 | */ |
33 | property Page primaryPage |
34 | |
35 | /*! |
36 | The property specifies the source of the primaryPage in case the primary |
37 | page is created from a Component or loaded from an external document. It |
38 | - has precedence over \l primaryPage and cannot be changed after component |
39 | - completion. The page specified in this way will be cerated asynchronously |
40 | - and the instance will be reported through \l primaryPage property. |
41 | + has precedence over \l primaryPage. The page specified in this way will |
42 | + be cerated asynchronously and the instance will be reported through |
43 | + \l primaryPage property. |
44 | */ |
45 | property var primaryPageSource |
46 | |
47 | @@ -322,12 +321,7 @@ |
48 | pages will be removed. |
49 | */ |
50 | function removePages(page) { |
51 | - var nodeToRemove = d.getWrapper(page); |
52 | - var removedNodes = d.tree.chop(nodeToRemove, page != layout.primaryPage); |
53 | - for (var i = removedNodes.length-1; i >= 0; i--) { |
54 | - var node = removedNodes[i]; |
55 | - d.updatePageForColumn(node.column); |
56 | - } |
57 | + d.removeAllPages(page, page != layout.primaryPage); |
58 | } |
59 | |
60 | /* |
61 | @@ -345,26 +339,34 @@ |
62 | d.createPrimaryPage(primaryPageSource); |
63 | } else if (primaryPage) { |
64 | d.createPrimaryPage(primaryPage); |
65 | - } else { |
66 | - console.warn("No primary page set. No pages can be added without a primary page."); |
67 | } |
68 | d.completed = true; |
69 | } |
70 | onPrimaryPageChanged: { |
71 | - if (d.completed && !d.internalUpdate) { |
72 | - console.warn("Cannot change primaryPage after completion."); |
73 | - d.internalPropertyUpdate("primaryPage", d.lastPrimaryPage); |
74 | + if (!d.completed || d.internalUpdate) { |
75 | return; |
76 | } |
77 | - d.lastPrimaryPage = primaryPage; |
78 | + // reset the primaryPageSource |
79 | + d.internalPropertyUpdate("primaryPageSource", undefined); |
80 | + // clear the layout |
81 | + d.purgeLayout(); |
82 | + // add the new page if valid |
83 | + if (primaryPage !== null) { |
84 | + d.createPrimaryPage(primaryPage); |
85 | + } |
86 | } |
87 | onPrimaryPageSourceChanged: { |
88 | - if (d.completed && !d.internalUpdate) { |
89 | - console.warn("Cannot change primaryPageSource after completion."); |
90 | - d.internalPropertyUpdate("primaryPageSource", d.lastPrimaryPageSource); |
91 | + if (!d.completed || d.internalUpdate) { |
92 | return; |
93 | } |
94 | - d.lastPrimaryPageSource = primaryPageSource; |
95 | + // remove all pages first |
96 | + d.purgeLayout(); |
97 | + // create the new primary page if a valid component is specified |
98 | + if (primaryPageSource) { |
99 | + d.createPrimaryPage(primaryPageSource); |
100 | + } else { |
101 | + d.internalPropertyUpdate("primaryPage", null); |
102 | + } |
103 | } |
104 | |
105 | onLayoutsChanged: { |
106 | @@ -389,8 +391,7 @@ |
107 | (activeLayout ? activeLayout.data.length : 1) |
108 | property PageColumnsLayout activeLayout: null |
109 | property list<PageColumnsLayout> prevLayouts |
110 | - property Page lastPrimaryPage |
111 | - property var lastPrimaryPageSource |
112 | + property Page prevPrimaryPage |
113 | |
114 | /*! internal */ |
115 | onColumnsChanged: { |
116 | @@ -416,10 +417,20 @@ |
117 | wrapper.incubator.onStatusChanged = function (status) { |
118 | if (status == Component.Ready) { |
119 | internalPropertyUpdate("primaryPage", wrapper.incubator.object); |
120 | + prevPrimaryPage = wrapper.incubator.object; |
121 | } |
122 | } |
123 | } else { |
124 | finalizeAddingPage(wrapper); |
125 | + prevPrimaryPage = wrapper.object; |
126 | + } |
127 | + } |
128 | + |
129 | + // remove all pages, including primaryPage |
130 | + function purgeLayout() { |
131 | + if (prevPrimaryPage) { |
132 | + removeAllPages(prevPrimaryPage, true); |
133 | + prevPrimaryPage = null; |
134 | } |
135 | } |
136 | |
137 | @@ -514,6 +525,17 @@ |
138 | return newWrapper.incubator; |
139 | } |
140 | |
141 | + // removes all pages from the layout, and may include the page itself |
142 | + function removeAllPages(page, inclusive) { |
143 | + inclusive = typeof inclusive !== 'undefined' ? inclusive : true; |
144 | + var nodeToRemove = d.getWrapper(page); |
145 | + var removedNodes = d.tree.chop(nodeToRemove, inclusive); |
146 | + for (var i = removedNodes.length-1; i >= 0; i--) { |
147 | + var node = removedNodes[i]; |
148 | + updatePageForColumn(node.column); |
149 | + } |
150 | + } |
151 | + |
152 | // update the page for the specified column |
153 | function updatePageForColumn(column) { |
154 | var effectiveColumn = MathUtils.clamp(column, 0, d.columns - 1); |
155 | |
156 | === modified file 'tests/unit_x11/tst_components/tst_adaptivepagelayout.qml' |
157 | --- tests/unit_x11/tst_components/tst_adaptivepagelayout.qml 2015-09-29 10:37:46 +0000 |
158 | +++ tests/unit_x11/tst_components/tst_adaptivepagelayout.qml 2015-10-02 05:22:37 +0000 |
159 | @@ -27,83 +27,79 @@ |
160 | // 2 on desktop, 1 on phone. |
161 | property int columns: width >= units.gu(80) ? 2 : 1 |
162 | |
163 | - AdaptivePageLayout { |
164 | - id: layout |
165 | - width: parent.width |
166 | - height: parent.height |
167 | - |
168 | - primaryPage: page1 |
169 | - |
170 | - Page { |
171 | - id: page1 |
172 | - title: "Page1" |
173 | - |
174 | - Column { |
175 | - anchors.centerIn: parent |
176 | - width: childrenRect.width |
177 | - Button { |
178 | - text: "Page 2 left" |
179 | - onTriggered: layout.addPageToCurrentColumn(page1, page2) |
180 | - } |
181 | - Button { |
182 | - text: "Page 3 right" |
183 | - onTriggered: layout.addPageToNextColumn(page1, page3); |
184 | - } |
185 | - } |
186 | - } |
187 | - Page { |
188 | - id: page2 |
189 | - title: "Page2" |
190 | - } |
191 | - Page { |
192 | - id: page3 |
193 | - title: "Page3" |
194 | - } |
195 | - Page { |
196 | - id: page4 |
197 | - title: "Page4" |
198 | - } |
199 | - } |
200 | - |
201 | - AdaptivePageLayout { |
202 | - id: defaults |
203 | + Column { |
204 | + anchors.fill: parent |
205 | + AdaptivePageLayout { |
206 | + id: layout |
207 | + width: parent.width |
208 | + height: parent.height / 2 |
209 | + |
210 | + primaryPage: page1 |
211 | + |
212 | + Page { |
213 | + id: page1 |
214 | + objectName: title |
215 | + title: "Page1" |
216 | + |
217 | + Column { |
218 | + anchors.centerIn: parent |
219 | + width: childrenRect.width |
220 | + Button { |
221 | + text: "Page 2 left" |
222 | + onTriggered: layout.addPageToCurrentColumn(page1, page2) |
223 | + } |
224 | + Button { |
225 | + text: "Page 3 right" |
226 | + onTriggered: layout.addPageToNextColumn(page1, page3); |
227 | + } |
228 | + } |
229 | + } |
230 | + Page { |
231 | + id: page2 |
232 | + objectName: title |
233 | + title: "Page2" |
234 | + } |
235 | + Page { |
236 | + id: page3 |
237 | + objectName: title |
238 | + title: "Page3" |
239 | + } |
240 | + Page { |
241 | + id: page4 |
242 | + objectName: title |
243 | + title: "Page4" |
244 | + } |
245 | + } |
246 | + AdaptivePageLayout { |
247 | + id: defaults |
248 | + width: parent.width |
249 | + height: parent.height / 2 |
250 | + Page { |
251 | + id: otherPage1 |
252 | + objectName: title |
253 | + title: "Page1" |
254 | + } |
255 | + Page { |
256 | + id: otherPage2 |
257 | + objectName: title |
258 | + title: "Page2" |
259 | + } |
260 | + Page { |
261 | + id: otherPage3 |
262 | + objectName: title |
263 | + title: "Page3" |
264 | + } |
265 | + } |
266 | } |
267 | |
268 | Component { |
269 | id: pageComponent |
270 | Page { |
271 | + objectName: title |
272 | title: "DynamicPage" |
273 | } |
274 | } |
275 | |
276 | - Component { |
277 | - id: aplComponent |
278 | - AdaptivePageLayout { |
279 | - width: units.gu(40) |
280 | - height: units.gu(50) |
281 | - primaryPageSource: pageComponent |
282 | - } |
283 | - } |
284 | - |
285 | - Component { |
286 | - id: aplDocument |
287 | - AdaptivePageLayout { |
288 | - width: units.gu(40) |
289 | - height: units.gu(50) |
290 | - primaryPageSource: Qt.resolvedUrl("MyExternalPage.qml") |
291 | - } |
292 | - } |
293 | - |
294 | - Component { |
295 | - id: aplPrecedence |
296 | - AdaptivePageLayout { |
297 | - width: units.gu(40) |
298 | - height: units.gu(50) |
299 | - primaryPage: page1 |
300 | - primaryPageSource: Qt.resolvedUrl("MyExternalPage.qml") |
301 | - } |
302 | - } |
303 | - |
304 | UbuntuTestCase { |
305 | id: testCase |
306 | when: windowShown |
307 | @@ -115,6 +111,10 @@ |
308 | target: testCase |
309 | signalName: "pageLoaded" |
310 | } |
311 | + SignalSpy { |
312 | + id: primaryPageSpy |
313 | + signalName: "primaryPageChanged" |
314 | + } |
315 | |
316 | function resize_single_column() { |
317 | layout.width = units.gu(40); |
318 | @@ -135,29 +135,38 @@ |
319 | return apl.__d.getWrapper(page); |
320 | } |
321 | |
322 | + function findPageFromLayout(apl, objectName) { |
323 | + var body = findChild(apl, "body"); |
324 | + verify(body); |
325 | + return findChild(body, objectName); |
326 | + } |
327 | + |
328 | function cleanup() { |
329 | page1.title = "Page1"; |
330 | page2.title = "Page2"; |
331 | page3.title = "Page3"; |
332 | page4.title = "Page4"; |
333 | loadedSpy.clear(); |
334 | + primaryPageSpy.clear(); |
335 | + primaryPageSpy.target = null; |
336 | resize_multiple_columns(); |
337 | - layout.removePages(page1); |
338 | + layout.removePages(layout.primaryPage); |
339 | + defaults.primaryPage = null; |
340 | + wait(200); |
341 | } |
342 | |
343 | function initTestCase() { |
344 | compare(defaults.primaryPage, null, "primaryPage not null by default"); |
345 | compare(defaults.primaryPageSource, undefined, "primaryPageSource not set by default"); |
346 | compare(defaults.layouts.length, 0, "no layouts by default"); |
347 | - compare(defaults.columns, 1, "1 column as default"); |
348 | + compare(defaults.columns, columns, columns + " column(s) as default"); |
349 | } |
350 | |
351 | function test_change_primaryPage() { |
352 | - // this prints the warning but still changes the primary page, |
353 | - // so the test must be executed last not to mess up the other tests. |
354 | - ignoreWarning("Cannot change primaryPage after completion."); |
355 | - layout.primaryPage = page3; |
356 | - verify(layout.primaryPage != page3, "primaryPage value was changed"); |
357 | + defaults.primaryPage = otherPage1; |
358 | + defaults.addPageToCurrentColumn(defaults.primaryPage, otherPage2); |
359 | + defaults.primaryPage = otherPage3; |
360 | + verify(!findPageFromLayout(defaults, "Page2"), "Page2 still in the view!"); |
361 | } |
362 | |
363 | function test_add_page_when_source_page_not_in_stack() { |
364 | @@ -333,10 +342,10 @@ |
365 | } |
366 | |
367 | var testPage = testHolder.pageWrapper.object; |
368 | - var prevPageActive = false |
369 | + var prevPageActive = false; |
370 | var incubator = data.nextColumn |
371 | ? layout.addPageToNextColumn(data.sourcePage, data.page) |
372 | - : layout.addPageToCurrentColumn(data.sourcePage, data.page);; |
373 | + : layout.addPageToCurrentColumn(data.sourcePage, data.page); |
374 | verify(incubator); |
375 | compare(testHolder.pageWrapper.object, testPage); |
376 | incubator.onStatusChanged = function (status) { |
377 | @@ -351,48 +360,58 @@ |
378 | |
379 | function test_primaryPageSource_bug1499179_data() { |
380 | return [ |
381 | - {tag: "Component", test: aplComponent}, |
382 | - {tag: "Document", test: aplDocument}, |
383 | + {tag: "Component", test: pageComponent}, |
384 | + {tag: "Document", test: Qt.resolvedUrl("MyExternalPage.qml")}, |
385 | ]; |
386 | } |
387 | function test_primaryPageSource_bug1499179(data) { |
388 | - var apl = data.test.createObject(root); |
389 | - verify(apl); |
390 | - tryCompareFunction(function () { return apl.primaryPage != null }, true, 1500); |
391 | - apl.visible = false; |
392 | - apl = null; |
393 | + primaryPageSpy.target = defaults; |
394 | + defaults.primaryPageSource = data.test; |
395 | + primaryPageSpy.wait(); |
396 | } |
397 | |
398 | - function test_primaryPageSource_not_set_twice_data() { |
399 | + function test_change_primaryPageSource_data() { |
400 | return [ |
401 | - {tag: "Component", test: aplComponent, nextValue: null}, |
402 | - {tag: "Document", test: aplDocument, nextValue: null}, |
403 | + {tag: "Component", test: pageComponent, nextValue: Qt.resolvedUrl("MyExternalPage.qml")}, |
404 | + {tag: "Document", test: Qt.resolvedUrl("MyExternalPage.qml"), nextValue: pageComponent}, |
405 | ]; |
406 | } |
407 | - function test_primaryPageSource_not_set_twice(data) { |
408 | - var apl = data.test.createObject(root); |
409 | - verify(apl); |
410 | - tryCompareFunction(function () { return apl.primaryPage != null }, true, 1500); |
411 | - ignoreWarning("Cannot change primaryPageSource after completion."); |
412 | - apl.primaryPageSource = data.nextValue; |
413 | - verify(apl.primaryPageSource != data.nextValue, "property value changed!"); |
414 | - apl.visible = false; |
415 | - apl = null; |
416 | - } |
417 | - |
418 | - SignalSpy { |
419 | - id: primaryPageSpy |
420 | - signalName: "primaryPageChanged" |
421 | + function test_change_primaryPageSource(data) { |
422 | + primaryPageSpy.target = defaults; |
423 | + verify(defaults.primaryPage == null); |
424 | + verify(defaults.primaryPageSource == undefined); |
425 | + defaults.primaryPageSource = data.test; |
426 | + primaryPageSpy.wait(400); |
427 | + // add some pages |
428 | + defaults.addPageToCurrentColumn(defaults.primaryPage, otherPage2); |
429 | + // then replace the primaryPageSource |
430 | + primaryPageSpy.clear(); |
431 | + defaults.primaryPageSource = data.nextValue; |
432 | + primaryPageSpy.wait(400); |
433 | + // look after page2 |
434 | + verify(!findPageFromLayout(defaults, "Page2"), "Page2 still in the view!"); |
435 | } |
436 | |
437 | function test_primaryPageSource_precedence_over_primaryPage() { |
438 | - var apl = aplPrecedence.createObject(root); |
439 | - primaryPageSpy.target = apl; |
440 | - verify(apl); |
441 | - primaryPageSpy.wait(); |
442 | - verify(apl.primaryPage.title != page1.title, "primaryPage has not been overloaded by primaryPageSource"); |
443 | - apl.visible = false; |
444 | - apl = null; |
445 | + primaryPageSpy.target = defaults; |
446 | + defaults.primaryPage = otherPage1; |
447 | + primaryPageSpy.wait(400); |
448 | + // now set a value to primaryPageSource |
449 | + primaryPageSpy.clear(); |
450 | + defaults.primaryPageSource = pageComponent; |
451 | + primaryPageSpy.wait(400); |
452 | + } |
453 | + |
454 | + function test_primaryPage_change_clears_primaryPageSource() { |
455 | + primaryPageSpy.target = defaults; |
456 | + defaults.primaryPageSource = pageComponent; |
457 | + primaryPageSpy.wait(400); |
458 | + compare(defaults.primaryPage.title, "DynamicPage", "DynamicPage not set as primaryPage"); |
459 | + // now set a value to primaryPage |
460 | + primaryPageSpy.clear(); |
461 | + defaults.primaryPage = otherPage1; |
462 | + primaryPageSpy.wait(400); |
463 | + compare(defaults.primaryPageSource, undefined, "primaryPageSource must be cleared"); |
464 | } |
465 | } |
466 | } |
FAILED: Continuous integration, rev:1665 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/2334/ jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-amd64- ci/1062/ console jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-armhf- ci/1064/ console jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-i386- ci/1061/ console
http://
Executed test runs:
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/2334/ rebuild
http://