Merge lp:~zsombi/ubuntu-ui-toolkit/asyncPageCreation into lp:ubuntu-ui-toolkit/staging

Proposed by Zsombor Egri
Status: Merged
Approved by: Cris Dywan
Approved revision: 1627
Merged at revision: 1624
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/asyncPageCreation
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 505 lines (+343/-13)
8 files modified
documentation/ubuntu-ui-toolkit-common.qdocconf (+1/-1)
examples/ubuntu-ui-toolkit-gallery/ubuntu-ui-toolkit-gallery.qml (+1/-2)
src/Ubuntu/Components/1.3/AdaptivePageLayout.qml (+81/-7)
src/Ubuntu/Components/1.3/PageWrapper.qml (+25/-2)
src/Ubuntu/Components/1.3/PageWrapperUtils.js (+167/-0)
src/Ubuntu/Components/ComponentModule.pro (+1/-0)
tests/unit_x11/tst_components/tst_adaptivepagelayout.qml (+61/-0)
tests/unit_x11/tst_components/tst_multicolumnheader.qml (+6/-1)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/asyncPageCreation
Reviewer Review Type Date Requested Status
Cris Dywan Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+269509@code.launchpad.net

Commit message

Turn AdaptivePageLayout page creation to be asynchronous.

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

tests/unit_x11/tst_components/tst_multicolumnheader.qml and tests/unit_x11/tst_components/tst_pagestack.new_header.qml need adapting so they don't immediately check the header.

The fake incubator looks pretty straightforward. Can we link to the upstream docs¹, though? And point out that it's equivalent to using incubateObject or a Loader, which may even get people to use it in their own code.

¹ http://doc.qt.io/qt-5/qml-qtqml-component.html#incubateObject-method

review: Needs Fixing
Revision history for this message
Zsombor Egri (zsombi) wrote :

> tests/unit_x11/tst_components/tst_multicolumnheader.qml and
> tests/unit_x11/tst_components/tst_pagestack.new_header.qml need adapting so
> they don't immediately check the header.

Actually PageStack should behave like did before, loading pages synchronously. We should mark the PageStack deprecated, and instruct people to move away from it from 1.3 onwards. So the only test needed to be adjusted is the tst_multicolumnheader, but the incubation had to be fixed to work synchronously when not used from AdaptivePageLayout.

>
> The fake incubator looks pretty straightforward. Can we link to the upstream
> docs¹, though? And point out that it's equivalent to using incubateObject or a
> Loader, which may even get people to use it in their own code.
>
> ¹ http://doc.qt.io/qt-5/qml-qtqml-component.html#incubateObject-method

I did that, however would be nicer if we could link to the d.u.c link. But d.u.c is broken, seems not all Qt docs are taken from qt.io.

1623. By Zsombor Egri

adapt multicolumn test to async page loading

1624. By Zsombor Egri

fix async loading to be triggered only when PageWrapper synchronous is not set to avoid breaking PageStack behavior; toolkit gallery title not being set fixed; adapt multicolumnheader test to async loading

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

I prefer not to touch 1.2, so that would mean we don't edit 1.2/PageWrapperUtils.js, but create a copy in 1.3/PageWrapperUtils.js that we edit.

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

> I prefer not to touch 1.2, so that would mean we don't edit
> 1.2/PageWrapperUtils.js, but create a copy in 1.3/PageWrapperUtils.js that we
> edit.

It's internal.. but I agree for consistency it makes sense.

1625. By Zsombor Egri

copy PageWrapperUtils.js to 1.3 and have the changes there only.

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

documentation fix

1627. By Zsombor Egri

staging merge

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

Let's get it landed!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'documentation/ubuntu-ui-toolkit-common.qdocconf'
2--- documentation/ubuntu-ui-toolkit-common.qdocconf 2015-07-24 18:00:54 +0000
3+++ documentation/ubuntu-ui-toolkit-common.qdocconf 2015-09-01 12:00:47 +0000
4@@ -26,7 +26,7 @@
5 sources.fileextensions = "*.qml *.qdoc *.cpp *.js"
6 headers.fileextensions = "*.h"
7 # exclude qml files that have the component documented in a separate qdoc file
8-excludefiles = $BLD/../src/Ubuntu/Components/MainView.qml
9+excludefiles += $BLD/../src/Ubuntu/Components/1.3/PageWrapperUtils.js
10 outputdir = $BLD/html
11 outputformats = HTML
12 version = 1.2
13
14=== modified file 'examples/ubuntu-ui-toolkit-gallery/ubuntu-ui-toolkit-gallery.qml'
15--- examples/ubuntu-ui-toolkit-gallery/ubuntu-ui-toolkit-gallery.qml 2015-08-14 10:11:58 +0000
16+++ examples/ubuntu-ui-toolkit-gallery/ubuntu-ui-toolkit-gallery.qml 2015-09-01 12:00:47 +0000
17@@ -96,9 +96,8 @@
18 selected: index === widgetList.currentIndex
19 onClicked: {
20 var source = Qt.resolvedUrl(model.source);
21- var newPage = layout.addPageToNextColumn(mainPage, source);
22+ layout.addPageToNextColumn(mainPage, source, {title: model.label});
23
24- newPage.title = model.label;
25 widgetList.currentIndex = index;
26 }
27 }
28
29=== modified file 'src/Ubuntu/Components/1.3/AdaptivePageLayout.qml'
30--- src/Ubuntu/Components/1.3/AdaptivePageLayout.qml 2015-08-27 20:27:45 +0000
31+++ src/Ubuntu/Components/1.3/AdaptivePageLayout.qml 2015-09-01 12:00:47 +0000
32@@ -83,6 +83,12 @@
33 }
34 \endqml
35
36+ \note Observe the use of the \c Page::pageStack property in the example above.
37+ The same property is used to share the AdaptivePageLayout instance the Page is
38+ used in, therefore the same page can be used in a PageStack or in an AdaptivePageLayout.
39+ However implementations must make sure the desired PageStack or AdaptivePageLayout
40+ function exists in the instance before using it.
41+
42 AdaptivePageLayout supports adaptive column handling. When the number of columns changes at
43 runtime the pages are automatically rearranged.
44
45@@ -196,12 +202,72 @@
46 property list<PageColumnsLayout> layouts
47
48 /*!
49- \qmlmethod Item addPageToCurrentColumn(Item sourcePage, var page[, var properties])
50+ \qmlmethod object addPageToCurrentColumn(Item sourcePage, var page[, var properties])
51 Adds a \c page to the column the \c sourcePage resides in and removes all pages
52 from the higher columns. \c page can be a Component or a file.
53- \c properties is a JSON object containing properties
54- to be set when page is created. \c sourcePage must be active. Returns the
55- instance of the page created.
56+ \c properties is a JSON object containing properties to be set when page
57+ is created. \c sourcePage must be active.
58+
59+ The function creates the new page asynchronously if the new \c page to be
60+ added is a Component or a QML document. In this case the function returns
61+ an incubator which can be used to track the page creation.For more about
62+ incubation in QML and creating components asynchronously, see
63+ \l {http://doc.qt.io/qt-5/qml-qtqml-component.html#incubateObject-method}
64+ {Component.incubateObject()}.
65+ The following example removes an element from the list model whenever the
66+ page opened in the second column is closed. Note, the example must be run
67+ on desktop or on a device with at least 90 grid units screen width.
68+ \qml
69+ import QtQuick 2.4
70+ import Ubuntu.Components 1.3
71+
72+ MainView {
73+ width: units.gu(90)
74+ height: units.gu(70)
75+
76+ Component {
77+ id: page2Component
78+ Page {
79+ title: "Second Page"
80+ Button {
81+ text: "Close me"
82+ onClicked: pageStack.removePages(pageStack.primaryPage);
83+ }
84+ }
85+ }
86+
87+ AdaptivePageLayout {
88+ id: pageLayout
89+ anchors.fill: parent
90+ primaryPage: Page {
91+ title: "Primary Page"
92+ ListView {
93+ id: listView
94+ anchors.fill: parent
95+ model: 10
96+ delegate: ListItem {
97+ Label { text: modelData }
98+ onClicked: {
99+ var incubator = pageLayout.addPageToNextColumn(pageLayout.primaryPage, page2Component);
100+ if (incubator && incubator.status == Component.Loading) {
101+ incubator.onStatusChanged = function(status) {
102+ if (status == Component.Ready) {
103+ // connect page's destruction to decrement model
104+ incubator.object.Component.destruction.connect(function() {
105+ listView.model--;
106+ });
107+ }
108+ }
109+ }
110+ }
111+ }
112+ }
113+ }
114+ }
115+ }
116+ \endqml
117+
118+ \sa {http://doc.qt.io/qt-5/qml-qtqml-component.html#incubateObject-method}{Component.incubateObject}
119 */
120 function addPageToCurrentColumn(sourcePage, page, properties) {
121 var nextColumn = d.columnForPage(sourcePage) + 1;
122@@ -221,6 +287,7 @@
123 holds \c sourcePage) and all following columns, and then add \c page to the next column.
124 If \c sourcePage is located in the
125 rightmost column, the new page will be pushed to the same column as \c sourcePage.
126+ The return value is the same as in \l addPageToCurrentColumn case.
127 */
128 function addPageToNextColumn(sourcePage, page, properties) {
129 var nextColumn = d.columnForPage(sourcePage) + 1;
130@@ -304,7 +371,7 @@
131
132 function createWrapper(page, properties) {
133 var wrapperComponent = Qt.createComponent("PageWrapper.qml");
134- var wrapperObject = wrapperComponent.createObject(hiddenPages);
135+ var wrapperObject = wrapperComponent.createObject(hiddenPages, {synchronous: false});
136 wrapperObject.pageStack = layout;
137 wrapperObject.properties = properties;
138 // set reference last because it will trigger creation of the object
139@@ -320,7 +387,14 @@
140 // replace page holder's child
141 var holder = body.children[targetColumn];
142 holder.detachCurrentPage();
143- holder.attachPage(pageWrapper)
144+ if ((pageWrapper.incubator && pageWrapper.incubator.status == Component.Ready) || pageWrapper.object) {
145+ holder.attachPage(pageWrapper);
146+ } else {
147+ // asynchronous, connect to page load completion and attach when page is available
148+ pageWrapper.pageLoaded.connect(function () {
149+ holder.attachPage(pageWrapper);
150+ });
151+ }
152 }
153
154 function getWrapper(page) {
155@@ -378,7 +452,7 @@
156 newWrapper.parentPage = sourcePage;
157 newWrapper.column = column;
158 d.addWrappedPage(newWrapper);
159- return newWrapper.object;
160+ return newWrapper.incubator;
161 }
162
163 // update the page for the specified column
164
165=== modified file 'src/Ubuntu/Components/1.3/PageWrapper.qml'
166--- src/Ubuntu/Components/1.3/PageWrapper.qml 2015-06-15 07:45:34 +0000
167+++ src/Ubuntu/Components/1.3/PageWrapper.qml 2015-09-01 12:00:47 +0000
168@@ -15,7 +15,7 @@
169 */
170
171 import QtQuick 2.4
172-import "../1.2/PageWrapperUtils.js" as Utils
173+import "PageWrapperUtils.js" as Utils
174
175 /*!
176 \internal
177@@ -66,6 +66,22 @@
178 property Item pageHolder
179
180 /*!
181+ Instructs to load the page synchronously or not. Used by AdaptivePageLayout.
182+ True by default to keep PageStack integrity.
183+ */
184+ property bool synchronous: true
185+
186+ /*!
187+ Incubator for the asynchronous page creation
188+ */
189+ property var incubator: null
190+
191+ /*!
192+ Signal emitted when incubator completes page loading.
193+ */
194+ signal pageLoaded()
195+
196+ /*!
197 Returns true if the current PageWrapper is a child of the given page
198 */
199 function childOf(page) {
200@@ -114,7 +130,14 @@
201 if (pageWrapper.object) pageWrapper.object = null;
202 Utils.initPage(pageWrapper);
203 if (pageWrapper.active && reference) {
204- Utils.activate(pageWrapper);
205+ if ((pageWrapper.incubator && pageWrapper.incubator.status == Component.Ready) || pageWrapper.object) {
206+ Utils.activate(pageWrapper);
207+ } else {
208+ // asynchronous, connect page activation
209+ pageLoaded.connect(function () {
210+ Utils.activate(pageWrapper);
211+ });
212+ }
213 }
214 }
215
216
217=== added file 'src/Ubuntu/Components/1.3/PageWrapperUtils.js'
218--- src/Ubuntu/Components/1.3/PageWrapperUtils.js 1970-01-01 00:00:00 +0000
219+++ src/Ubuntu/Components/1.3/PageWrapperUtils.js 2015-09-01 12:00:47 +0000
220@@ -0,0 +1,167 @@
221+/*
222+ * Copyright 2015 Canonical Ltd.
223+ *
224+ * This program is free software; you can redistribute it and/or modify
225+ * it under the terms of the GNU Lesser General Public License as published by
226+ * the Free Software Foundation; version 3.
227+ *
228+ * This program is distributed in the hope that it will be useful,
229+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
230+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
231+ * GNU Lesser General Public License for more details.
232+ *
233+ * You should have received a copy of the GNU Lesser General Public License
234+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
235+ */
236+
237+//.pragma library // FIXME: cannot refer to Component.Error if I use this.
238+// FIXME: ideally we would make this a stateless library, but that breaks applications
239+// that rely on accessing context variables in pages that were pushed on a PageStack
240+// by url (PageStack.push("FileName.qml")) because of a Qt bug:
241+// https://bugreports.qt-project.org/browse/QTBUG-31347
242+
243+/*!
244+ \internal
245+ Incubator wrapper object. Used when page is loaded asynchronously.
246+ */
247+
248+function Incubator(pageWrapper, pageComponent) {
249+ // private variable for QmlIncubatorObject
250+ var incubator = null;
251+
252+ // public API
253+ this.status = Component.Ready;
254+ this.object = null;
255+ this.onStatusChanged = null;
256+ this.forceCompletion = function () {
257+ if (incubator) {
258+ incubator.forceCompletion();
259+ }
260+ }
261+
262+ // internal function to catch status changes
263+ function incubatorStatusChanged(status) {
264+ // update wrapper incubator fields
265+ pageWrapper.incubator.status = status;
266+ pageWrapper.incubator.object = pageWrapper.object = incubator.object;
267+
268+ // emit pageWrapper's pageLoaded signal to complete page activation and loading
269+ if (status === Component.Ready) {
270+ pageWrapper.pageLoaded();
271+ }
272+
273+ // forward state change to the user
274+ if (pageWrapper.incubator.onStatusChanged) {
275+ // call onStatusChanged
276+ pageWrapper.incubator.onStatusChanged(status);
277+ }
278+
279+ // cleanup of ready or error
280+ if (status !== Component.Loading) {
281+ pageWrapper.incubator = null;
282+ incubator = null;
283+ }
284+ }
285+
286+ if (pageWrapper.properties) {
287+ incubator = pageComponent.incubateObject(pageWrapper, pageWrapper.properties);
288+ } else {
289+ incubator = pageComponent.incubateObject(pageWrapper);
290+ }
291+
292+ this.status = incubator.status;
293+ if (incubator.status != Component.Ready) {
294+ incubator.onStatusChanged = incubatorStatusChanged;
295+ } else {
296+ incubatorStatusChanged(incubator.status);
297+ }
298+}
299+
300+/*******************************************************
301+ *
302+ */
303+/*!
304+ \internal
305+ Initialize pageWrapper.object.
306+ */
307+function initPage(pageWrapper) {
308+ var pageComponent;
309+
310+ if (pageWrapper.reference.createObject) {
311+ // page reference is a component
312+ pageComponent = pageWrapper.reference;
313+ } else if (typeof pageWrapper.reference == "string") {
314+ // page reference is a string (url)
315+ pageComponent = Qt.createComponent(pageWrapper.reference);
316+ }
317+
318+ // PageWrapper can override the synchronous loading
319+ var synchronous = pageWrapper.hasOwnProperty("synchronous") ? pageWrapper.synchronous : true;
320+
321+ if (pageComponent) {
322+ if (pageComponent.status === Component.Error) {
323+ throw new Error("Error while loading page: " + pageComponent.errorString());
324+ } else {
325+ // create the object
326+ pageWrapper.incubator = new Incubator(pageWrapper, pageComponent);
327+ if (synchronous) {
328+ pageWrapper.incubator.forceCompletion();
329+ }
330+ pageWrapper.canDestroy = true;
331+ }
332+ } else {
333+ // page reference is an object
334+ pageWrapper.object = pageWrapper.reference;
335+ pageWrapper.object.parent = pageWrapper;
336+ pageWrapper.canDestroy = false;
337+
338+ // copy the properties to the page object
339+ for (var prop in pageWrapper.properties) {
340+ if (pageWrapper.properties.hasOwnProperty(prop)) {
341+ pageWrapper.object[prop] = pageWrapper.properties[prop];
342+ }
343+ }
344+ }
345+
346+ return pageWrapper.object;
347+}
348+
349+/*!
350+ \internal
351+ Create the page object if needed, and make the page object visible.
352+ */
353+function activate(pageWrapper) {
354+ if (!pageWrapper.object) {
355+ initPage(pageWrapper);
356+ }
357+
358+ // Having the same page pushed multiple times on a stack changes
359+ // the parent of the page object. Change it back here.
360+ pageWrapper.object.parent = pageWrapper;
361+
362+ // Some page objects are invisible initially. Make visible.
363+
364+ pageWrapper.object.visible = true;
365+ pageWrapper.active = true;
366+}
367+
368+/*!
369+ \internal
370+ Hide page object.
371+ */
372+function deactivate(pageWrapper) {
373+ pageWrapper.active = false;
374+}
375+
376+/*!
377+ \internal
378+ Destroy the page object if pageWrapper.canDestroy is true.
379+ Do nothing if pageWrapper.canDestroy is false.
380+ */
381+function destroyObject(pageWrapper) {
382+ if (pageWrapper.canDestroy) {
383+ pageWrapper.object.destroy();
384+ pageWrapper.object = null;
385+ pageWrapper.canDestroy = false;
386+ }
387+}
388
389=== modified file 'src/Ubuntu/Components/ComponentModule.pro'
390--- src/Ubuntu/Components/ComponentModule.pro 2015-08-24 16:02:50 +0000
391+++ src/Ubuntu/Components/ComponentModule.pro 2015-09-01 12:00:47 +0000
392@@ -110,6 +110,7 @@
393 1.3/PageTreeNode.qml \
394 1.3/pageUtils.js \
395 1.3/PageWrapper.qml \
396+ 1.3/PageWrapperUtils.js \
397 1.3/Panel.qml \
398 1.3/ProgressBar.qml \
399 1.3/PullToRefresh.qml \
400
401=== modified file 'tests/unit_x11/tst_components/tst_adaptivepagelayout.qml'
402--- tests/unit_x11/tst_components/tst_adaptivepagelayout.qml 2015-08-11 08:30:57 +0000
403+++ tests/unit_x11/tst_components/tst_adaptivepagelayout.qml 2015-09-01 12:00:47 +0000
404@@ -69,9 +69,25 @@
405 id: defaults
406 }
407
408+ Component {
409+ id: pageComponent
410+ Page {
411+ title: "DynamicPage"
412+ }
413+ }
414+
415 UbuntuTestCase {
416+ id: testCase
417 when: windowShown
418
419+ signal pageLoaded()
420+
421+ SignalSpy {
422+ id: loadedSpy
423+ target: testCase
424+ signalName: "pageLoaded"
425+ }
426+
427 function resize_single_column() {
428 layout.width = units.gu(40);
429 }
430@@ -82,6 +98,11 @@
431 }
432
433 function cleanup() {
434+ page1.title = "Page1";
435+ page2.title = "Page2";
436+ page3.title = "Page3";
437+ page4.title = "Page4";
438+ loadedSpy.clear();
439 resize_multiple_columns();
440 layout.removePages(page1);
441 }
442@@ -185,5 +206,45 @@
443 layout.removePages(page3);
444 compare(page2.visible, true, "Adding page to current column pruned that column.");
445 }
446+
447+ function test_add_page_to_current_data() {
448+ return [
449+ {tag: "Synchronously to current column", func: "addPageToCurrentColumn", page: page2, params: {}, sync: true},
450+ {tag: "Synchronously to current column, with params", func: "addPageToCurrentColumn", page: page2, params: {title: "Altered title"}, sync: true},
451+ {tag: "Synchronously to next column", func: "addPageToNextColumn", page: page2, params: {}, sync: true},
452+ {tag: "Synchronously to next column, with params", func: "addPageToNextColumn", page: page2, params: {title: "Altered title"}, sync: true},
453+ {tag: "Asynchronously to current column", func: "addPageToCurrentColumn", page: pageComponent, params: {}, sync: false},
454+ {tag: "Asynchronously to current column, with params", func: "addPageToCurrentColumn", page: pageComponent, params: {title: "Altered title"}, sync: false},
455+ {tag: "Asynchronously to next column", func: "addPageToNextColumn", page: pageComponent, params: {}, sync: false},
456+ {tag: "Asynchronously to next column, with params", func: "addPageToNextColumn", page: pageComponent, params: {title: "Altered title"}, sync: false},
457+ ]
458+ }
459+ function test_add_page_to_current(data) {
460+ var incubator = layout[data.func](layout.primaryPage, data.page, data.params);
461+ compare((incubator == null), data.sync);
462+ if (incubator) {
463+ compare(incubator.status, Component.Loading, "The incubator status is not Component.Loading, but " + incubator.status);
464+ // for cleanup, we must wait till the page is added, so we can do proper cleanup
465+ incubator.onStatusChanged = function (status) {
466+ // test params
467+ for (var param in data.params) {
468+ compare(incubator.object[param], data.params[param], "parameter '" + param + "' values do not match");
469+ }
470+ testCase.pageLoaded();
471+ layout.removePages(layout.primaryPage);
472+ }
473+ // make sure we wait enough to let additional tests to complete
474+ loadedSpy.wait(1500);
475+ }
476+ }
477+
478+ function test_asynchronous_page_loading_incubator_forcecompletion() {
479+ var incubator = layout.addPageToCurrentColumn(layout.primaryPage, pageComponent);
480+ verify(incubator, "Page added synchronously!");
481+ compare(incubator.status, Component.Loading, "Incubator in different state");
482+ incubator.forceCompletion();
483+ compare(incubator.status, Component.Ready, "Incubator not completed");
484+ verify(incubator.object, "Page object not set");
485+ }
486 }
487 }
488
489=== modified file 'tests/unit_x11/tst_components/tst_multicolumnheader.qml'
490--- tests/unit_x11/tst_components/tst_multicolumnheader.qml 2015-08-27 21:11:36 +0000
491+++ tests/unit_x11/tst_components/tst_multicolumnheader.qml 2015-09-01 12:00:47 +0000
492@@ -240,7 +240,12 @@
493 }
494
495 function test_header_title_for_external_page() {
496- layout.addPageToNextColumn(rootPage, Qt.resolvedUrl("MyExternalPage.qml"));
497+ var incubator = layout.addPageToNextColumn(rootPage, Qt.resolvedUrl("MyExternalPage.qml"));
498+ var pageLoaded = false;
499+ incubator.onStatusChanged = function (status) {
500+ pageLoaded = (incubator.object != null);
501+ }
502+ tryCompareFunction(function() {return pageLoaded}, true, 1000);
503 var n = root.columns === 2 ? 1 : 0
504 compare(get_header(n).config.title, "Page from QML file",
505 "Adding external Page does not update the header title.");

Subscribers

People subscribed via source and target branches