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

Proposed by Zsombor Egri
Status: Superseded
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/bottomEdgePreloadsContent
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 990 lines (+771/-4)
19 files modified
examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml (+1/-0)
src/Ubuntu/Components/plugin/ucbottomedge.cpp (+58/-0)
src/Ubuntu/Components/plugin/ucbottomedge.h (+7/-0)
src/Ubuntu/Components/plugin/ucbottomedge_p.h (+9/-0)
src/Ubuntu/Test/plugin/uctestcase.cpp (+13/-0)
src/Ubuntu/Test/plugin/uctestcase.h (+1/-0)
src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro (+4/-2)
src/Ubuntu/UbuntuToolkit/asyncloader.cpp (+214/-0)
src/Ubuntu/UbuntuToolkit/asyncloader.h (+71/-0)
tests/unit/plugin_dependency.pri (+1/-0)
tests/unit/test-include.pri (+1/-1)
tests/unit_x11/tst_asyncloader/Document.qml (+31/-0)
tests/unit_x11/tst_asyncloader/FaultyDocument.qml (+20/-0)
tests/unit_x11/tst_asyncloader/HeavyDocument.qml (+31/-0)
tests/unit_x11/tst_asyncloader/TestApp.qml (+30/-0)
tests/unit_x11/tst_asyncloader/tst_asyncloader.cpp (+265/-0)
tests/unit_x11/tst_asyncloader/tst_asyncloader.pro (+11/-0)
tests/unit_x11/tst_bottomedge/tst_bottomedge.cpp (+1/-0)
tests/unit_x11/unit_x11.pro (+2/-1)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/bottomEdgePreloadsContent
Reviewer Review Type Date Requested Status
Ubuntu SDK team Pending
Review via email: mp+285756@code.launchpad.net

Commit message

BorromEdge.preloadContent

To post a comment you must log in.
1845. By Zsombor Egri

remove original asyncloader

1846. By Zsombor Egri

prereq merge

1847. By Zsombor Egri

prereq sync

1848. By Zsombor Egri

adjust AsyncLoader changes

1849. By Zsombor Egri

API updated

1850. By Zsombor Egri

remove enum

1851. By Zsombor Egri

make things nicer and unified

1852. By Zsombor Egri

use BottomEdge context when creating the content

1853. By Zsombor Egri

tests added, content handling fixed

1854. By Zsombor Egri

adjust tests with deprecation warning so those are not shown anymore

1855. By Zsombor Egri

prereq sync

1856. By Zsombor Egri

reshape gallery page

1857. By Zsombor Egri

prereq sync

1858. By Zsombor Egri

prereq sync

1859. By Zsombor Egri

turn off logs

1860. By Zsombor Egri

prereq sync

1861. By Zsombor Egri

prereq sync

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml'
2--- examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml 2016-01-13 16:07:58 +0000
3+++ examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml 2016-02-19 14:39:50 +0000
4@@ -119,6 +119,7 @@
5 flickable: page.flickable
6 }
7 contentComponent: bottomEdgeContent
8+ preloadContent: true
9
10 onCommitCompleted: {
11 if (contentToLayout.checked && contentToLayout.enabled) {
12
13=== modified file 'src/Ubuntu/Components/plugin/ucbottomedge.cpp'
14--- src/Ubuntu/Components/plugin/ucbottomedge.cpp 2016-01-25 12:23:03 +0000
15+++ src/Ubuntu/Components/plugin/ucbottomedge.cpp 2016-02-19 14:39:50 +0000
16@@ -37,6 +37,8 @@
17 #include "private/ucswipearea_p.h"
18 #include <QtQuick/private/qquickanimation_p.h>
19
20+using namespace UbuntuToolkit;
21+
22 Q_LOGGING_CATEGORY(ucBottomEdge, "ubuntu.components.BottomEdge", QtMsgType::QtWarningMsg)
23
24 #define LOG qCDebug(ucBottomEdge) << "[BottomEdge]"
25@@ -47,6 +49,7 @@
26 , hint(new UCBottomEdgeHint)
27 , contentComponent(Q_NULLPTR)
28 , bottomPanel(Q_NULLPTR)
29+ , loader(Q_NULLPTR)
30 , previousDistance(0.0)
31 , dragProgress(0.)
32 , status(UCBottomEdge::Hidden)
33@@ -54,6 +57,7 @@
34 , dragDirection(UCBottomEdge::Undefined)
35 , defaultRegionsReset(false)
36 , mousePressed(false)
37+ , preloadContent(false)
38 {
39 }
40
41@@ -1082,4 +1086,58 @@
42 return d->activeRegion;
43 }
44
45+/*!
46+ * \qmlproperty bool BottomEdge::preloadContent
47+ * If set, all the contents set in the component and in regions will be loaded
48+ * in the background, so it will be available before it is revealed.
49+ */
50+bool UCBottomEdge::preloadContent() const
51+{
52+ return d_func()->preloadContent;
53+}
54+void UCBottomEdge::setPreloadContent(bool value)
55+{
56+ Q_D(UCBottomEdge);
57+ if (d->preloadContent == value) {
58+ return;
59+ }
60+ d->preloadContent = value;
61+ if (!d->preloadContent) {
62+ d->loader->reset();
63+ } else {
64+ d->preload();
65+ }
66+
67+ // TODO: instruct regions to preload
68+ Q_EMIT preloadContentChanged();
69+}
70+
71+void UCBottomEdgePrivate::preload()
72+{
73+ if (!preloadContent) {
74+ return;
75+ }
76+ Q_Q(UCBottomEdge);
77+ if (!loader) {
78+ loader = new AsyncLoader(q);
79+ QObject::connect(loader, SIGNAL(statusChanged(QQmlIncubator::Status,QObject*)),
80+ q, SLOT(onLoaderStatusChanged(QQmlIncubator::Status,QObject*)));
81+ }
82+ // component has priority over the URL!
83+ if (contentComponent) {
84+ loader->load(contentComponent, new QQmlContext(qmlContext(q)));
85+ } else if (contentUrl.isValid()) {
86+ loader->load(qmlEngine(q), contentUrl, new QQmlContext(qmlContext(q)));
87+ }
88+}
89+
90+void UCBottomEdgePrivate::onLoaderStatusChanged(QQmlIncubator::Status status, QObject *object)
91+{
92+ qDebug() << status << object;
93+ if (status == QQmlIncubator::Ready && object) {
94+ object->setParent(bottomPanel->m_panel);
95+ qobject_cast<QQuickItem*>(object)->setParentItem(bottomPanel->m_panel);
96+ }
97+}
98+
99 #include "moc_ucbottomedge.cpp"
100
101=== modified file 'src/Ubuntu/Components/plugin/ucbottomedge.h'
102--- src/Ubuntu/Components/plugin/ucbottomedge.h 2015-12-11 12:10:54 +0000
103+++ src/Ubuntu/Components/plugin/ucbottomedge.h 2016-02-19 14:39:50 +0000
104@@ -42,6 +42,7 @@
105 Q_PROPERTY(QQuickItem* contentItem READ contentItem NOTIFY contentItemChanged FINAL)
106 Q_PROPERTY(QQmlListProperty<UCBottomEdgeRegion> regions READ regions NOTIFY regionsChanged FINAL)
107 Q_PROPERTY(UCBottomEdgeRegion* activeRegion READ activeRegion NOTIFY activeRegionChanged FINAL)
108+ Q_PROPERTY(bool preloadContent READ preloadContent WRITE setPreloadContent NOTIFY preloadContentChanged FINAL DESIGNABLE false)
109
110 // overloaded data property to catch regions
111 Q_PRIVATE_PROPERTY(UCBottomEdge::d_func(), QQmlListProperty<QObject> data READ data DESIGNABLE false)
112@@ -73,6 +74,8 @@
113 void setFillWindow(bool fill);
114 QQmlListProperty<UCBottomEdgeRegion> regions();
115 UCBottomEdgeRegion *activeRegion();
116+ bool preloadContent() const;
117+ void setPreloadContent(bool value);
118
119 Q_SIGNALS:
120 void dragProgressChanged(qreal dragProgress);
121@@ -83,6 +86,7 @@
122 void contentItemChanged();
123 void regionsChanged();
124 void activeRegionChanged(UCBottomEdgeRegion *activeRegion);
125+ void preloadContentChanged();
126
127 void commitStarted();
128 void commitCompleted();
129@@ -109,6 +113,9 @@
130
131 Q_DECLARE_PRIVATE(UCBottomEdge)
132
133+private:
134+ Q_PRIVATE_SLOT(d_func(), void onLoaderStatusChanged(QQmlIncubator::Status status, QObject *object))
135+
136 friend class tst_BottomEdge;
137 };
138 Q_DECLARE_METATYPE(UCBottomEdge::Status)
139
140=== modified file 'src/Ubuntu/Components/plugin/ucbottomedge_p.h'
141--- src/Ubuntu/Components/plugin/ucbottomedge_p.h 2015-12-21 17:49:59 +0000
142+++ src/Ubuntu/Components/plugin/ucbottomedge_p.h 2016-02-19 14:39:50 +0000
143@@ -23,6 +23,10 @@
144 #include "ucstyleditembase_p.h"
145 #include "ucaction.h"
146
147+#include <AsyncLoader>
148+
149+using namespace UbuntuToolkit;
150+
151 class UCBottomEdgeStyle;
152 class UCBottomEdgePrivate : public UCStyledItemBasePrivate, protected QQuickItemChangeListener
153 {
154@@ -70,6 +74,9 @@
155 void itemChildAdded(QQuickItem *item, QQuickItem *child);
156 void itemChildRemoved(QQuickItem *item, QQuickItem *child);
157
158+ void preload();
159+ void onLoaderStatusChanged(QQmlIncubator::Status status, QObject *object);
160+
161 // members
162 QUrl contentUrl;
163 QList<UCBottomEdgeRegion*> regions;
164@@ -77,6 +84,7 @@
165 UCBottomEdgeHint *hint;
166 QQmlComponent *contentComponent;
167 UCBottomEdgeStyle *bottomPanel;
168+ UbuntuToolkit::AsyncLoader *loader;
169
170 qreal previousDistance;
171 qreal dragProgress;
172@@ -93,6 +101,7 @@
173
174 bool defaultRegionsReset:1;
175 bool mousePressed:1;
176+ bool preloadContent:1;
177
178 // status management
179 void setOperationStatus(OperationStatus s);
180
181=== modified file 'src/Ubuntu/Test/plugin/uctestcase.cpp'
182--- src/Ubuntu/Test/plugin/uctestcase.cpp 2016-01-25 17:12:56 +0000
183+++ src/Ubuntu/Test/plugin/uctestcase.cpp 2016-02-19 14:39:50 +0000
184@@ -76,3 +76,16 @@
185 QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
186 }
187 }
188+
189+/*!
190+ * Same as previous but without column number
191+ */
192+void UbuntuTestCase::ignoreWarning(const QString& fileName, uint line,
193+ const QString& message, uint occurences)
194+{
195+ for (uint i = 0; i < occurences; i++) {
196+ QString url(QUrl::fromLocalFile(QFileInfo(fileName).absoluteFilePath()).toEncoded());
197+ QString warning(QString("%1:%2 %3").arg(url).arg(line).arg(message));
198+ QTest::ignoreMessage(QtWarningMsg, warning.toUtf8());
199+ }
200+}
201
202=== modified file 'src/Ubuntu/Test/plugin/uctestcase.h'
203--- src/Ubuntu/Test/plugin/uctestcase.h 2016-01-25 17:12:56 +0000
204+++ src/Ubuntu/Test/plugin/uctestcase.h 2016-02-19 14:39:50 +0000
205@@ -54,6 +54,7 @@
206 }
207
208 static void ignoreWarning(const QString& fileName, uint line, uint column, const QString& message, uint occurences=1);
209+ static void ignoreWarning(const QString& fileName, uint line, const QString& message, uint occurences=1);
210
211 static inline void waitForSignal(QSignalSpy *spy, int timeout = 5000)
212 {
213
214=== modified file 'src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro'
215--- src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro 2016-02-11 17:19:48 +0000
216+++ src/Ubuntu/UbuntuToolkit/UbuntuToolkit.pro 2016-02-19 14:39:50 +0000
217@@ -15,8 +15,10 @@
218 HEADERS += \
219 colorutils.h \
220 ubuntutoolkitglobal.h \
221- tree.h
222+ tree.h \
223+ asyncloader.h
224
225 SOURCES += \
226 colorutils.cpp \
227- tree.cpp
228+ tree.cpp \
229+ asyncloader.cpp
230
231=== added file 'src/Ubuntu/UbuntuToolkit/asyncloader.cpp'
232--- src/Ubuntu/UbuntuToolkit/asyncloader.cpp 1970-01-01 00:00:00 +0000
233+++ src/Ubuntu/UbuntuToolkit/asyncloader.cpp 2016-02-19 14:39:50 +0000
234@@ -0,0 +1,214 @@
235+/*
236+ * Copyright 2016 Canonical Ltd.
237+ *
238+ * This program is free software; you can redistribute it and/or modify
239+ * it under the terms of the GNU Lesser General Public License as published by
240+ * the Free Software Foundation; version 3.
241+ *
242+ * This program is distributed in the hope that it will be useful,
243+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
244+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
245+ * GNU Lesser General Public License for more details.
246+ *
247+ * You should have received a copy of the GNU Lesser General Public License
248+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
249+ */
250+
251+#include <asyncloader.h>
252+
253+#include <QtQml/QQmlContext>
254+#include <QtQml/QQmlComponent>
255+#include <QtQuick/QQuickItem>
256+
257+namespace UbuntuToolkit {
258+
259+AsyncLoader::AsyncLoader(QObject *parent)
260+ : QObject(parent)
261+ , QQmlIncubator(Asynchronous)
262+ , m_component(nullptr)
263+ , m_context(nullptr)
264+ , m_ownComponent(false)
265+{
266+}
267+
268+AsyncLoader::~AsyncLoader()
269+{
270+ reset();
271+}
272+
273+// incubator methods
274+void AsyncLoader::setInitialState(QObject *object)
275+{
276+ emitStatus(Initializing, object);
277+}
278+
279+AsyncLoader::LoadingStatus incubatorToLoadingStatus(QQmlIncubator::Status status)
280+{
281+ switch (status) {
282+ case QQmlIncubator::Null: return AsyncLoader::Null;
283+ case QQmlIncubator::Ready: return AsyncLoader::Ready;
284+ case QQmlIncubator::Loading: return AsyncLoader::Loading;
285+ case QQmlIncubator::Error: return AsyncLoader::Error;
286+ }
287+ // unlikely to be reached, but must satisfy compiler
288+ return AsyncLoader::Null;
289+}
290+
291+void AsyncLoader::statusChanged(Status status)
292+{
293+ if (status == QQmlIncubator::Error) {
294+ QList<QQmlError> e = errors();
295+ for (int i = 0; i < e.size(); i++) {
296+ // remove quotes and any leading/trailing whitespace
297+ qWarning().noquote() << e[0].toString().trimmed();
298+ }
299+ }
300+ if (status != QQmlIncubator::Loading) {
301+ detachComponent();
302+ }
303+ // we should emit the status change only after we do the cleanup
304+ emitStatus(incubatorToLoadingStatus(status));
305+}
306+
307+// procected methods
308+void AsyncLoader::emitStatus(LoadingStatus status, QObject *object)
309+{
310+ if (m_status == status) {
311+ return;
312+ }
313+
314+ m_status = status;
315+ if (!object) {
316+ object = this->object();
317+ }
318+ Q_EMIT loadingStatus(m_status, object);
319+}
320+
321+void AsyncLoader::detachComponent()
322+{
323+ if (!m_component) {
324+ return;
325+ }
326+
327+ disconnect(m_component, &QQmlComponent::statusChanged,
328+ this, &AsyncLoader::onComponentStatusChanged);
329+ if (m_ownComponent) {
330+ m_component->deleteLater();
331+ }
332+ m_component = nullptr;
333+ m_ownComponent = false;
334+}
335+
336+void AsyncLoader::onComponentStatusChanged(QQmlComponent::Status status)
337+{
338+ if (status == QQmlComponent::Error) {
339+ QString error = m_component->errorString();
340+ // remove quotes and any leading/trailing whitespace
341+ qWarning().noquote() << error.trimmed();
342+ detachComponent();
343+ emitStatus(Error);
344+ return;
345+ }
346+ if (status == QQmlComponent::Ready) {
347+ m_component->create(*this, m_context);
348+ }
349+}
350+
351+/*!
352+ * \brief AsyncLoader::load
353+ * \param url
354+ * \param context
355+ * \return bool
356+ * The method initiates the loading of a given \e url within a specific \e context.
357+ * Returns true on success.
358+ * \note If the loading is initiated while there is a previous loading in place,
359+ * you must make sure you delete the object from the previous loading before you
360+ * trigger the new load.
361+ */
362+bool AsyncLoader::load(const QUrl &url, QQmlContext *context)
363+{
364+ if (!reset()) {
365+ return false;
366+ }
367+ if (url.isEmpty() || !url.isValid() || !context) {
368+ emitStatus(Ready);
369+ return true;
370+ }
371+ m_ownComponent = true;
372+ return load(new QQmlComponent(context->engine(), url, QQmlComponent::Asynchronous), context);
373+}
374+
375+/*!
376+ * \brief AsyncLoader::load
377+ * \param component
378+ * \param context
379+ * \return bool
380+ * The method initiates the loading of a \e component within the given \e context.
381+ * Returns true on success.
382+ * \note If the loading is initiated while there is a previous loading in place,
383+ * you must make sure you delete the object from the previous loading before you
384+ * trigger the new load.
385+ */
386+bool AsyncLoader::load(QQmlComponent *component, QQmlContext *context)
387+{
388+ if (!reset()) {
389+ return false;
390+ }
391+ if (!component || !context) {
392+ emitStatus(Ready);
393+ return true;
394+ }
395+ m_component = component;
396+ m_context = context;
397+ if (m_component->isLoading()) {
398+ emitStatus(Compiling);
399+ connect(m_component, &QQmlComponent::statusChanged,
400+ this, &AsyncLoader::onComponentStatusChanged, Qt::DirectConnection);
401+ } else {
402+ onComponentStatusChanged(m_component->status());
403+ }
404+ return true;
405+}
406+
407+/*!
408+ * \brief AsyncLoader::reset
409+ * \return bool
410+ * Clears the incubator and emits loadingStatus() signal with \c Reset status.
411+ * The loader can be reset only if the status passed \c Loading. Returns true
412+ * if the reset was successful, or when the loader status is \c Ready or
413+ * \c Error.
414+ */
415+bool AsyncLoader::reset()
416+{
417+ if (m_status < Loading) {
418+ return false;
419+ }
420+ if (m_status >= Ready) {
421+ return true;
422+ }
423+ clear();
424+ // make sure the listeners are getting the reset so they can delete the object
425+ emitStatus(Reset);
426+ return true;
427+}
428+
429+/*!
430+ * \brief AsyncLoader::status
431+ * \return LoadingStatus
432+ * Returns the status of the loader.
433+ */
434+AsyncLoader::LoadingStatus AsyncLoader::status()
435+{
436+ return m_status;
437+}
438+
439+/*!
440+ * \brief AsyncLoader::forceCompletion
441+ * Forces loading completion.
442+ */
443+void AsyncLoader::forceCompletion()
444+{
445+ QQmlIncubator::forceCompletion();
446+}
447+
448+} // namespace UbuntuToolkit
449
450=== added file 'src/Ubuntu/UbuntuToolkit/asyncloader.h'
451--- src/Ubuntu/UbuntuToolkit/asyncloader.h 1970-01-01 00:00:00 +0000
452+++ src/Ubuntu/UbuntuToolkit/asyncloader.h 2016-02-19 14:39:50 +0000
453@@ -0,0 +1,71 @@
454+/*
455+ * Copyright 2016 Canonical Ltd.
456+ *
457+ * This program is free software; you can redistribute it and/or modify
458+ * it under the terms of the GNU Lesser General Public License as published by
459+ * the Free Software Foundation; version 3.
460+ *
461+ * This program is distributed in the hope that it will be useful,
462+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
463+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
464+ * GNU Lesser General Public License for more details.
465+ *
466+ * You should have received a copy of the GNU Lesser General Public License
467+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
468+ */
469+
470+#ifndef ASYNCLOADER_H
471+#define ASYNCLOADER_H
472+
473+#include <QtQml/QQmlIncubator>
474+#include <QtQml/QQmlComponent>
475+#include <ubuntutoolkitglobal.h>
476+
477+class QQuickItem;
478+class QQmlContext;
479+
480+namespace UbuntuToolkit {
481+
482+class UBUNTUTOOLKIT_EXPORT AsyncLoader : public QObject, protected QQmlIncubator
483+{
484+ Q_OBJECT
485+public:
486+ enum LoadingStatus {
487+ Null,
488+ Compiling,
489+ Loading,
490+ Initializing,
491+ Ready,
492+ Error,
493+ Reset
494+ };
495+
496+ explicit AsyncLoader(QObject *parent = 0);
497+ ~AsyncLoader();
498+
499+ bool load(const QUrl &url, QQmlContext *context);
500+ bool load(QQmlComponent *component, QQmlContext *context);
501+ bool reset();
502+ LoadingStatus status();
503+ void forceCompletion();
504+
505+Q_SIGNALS:
506+ void loadingStatus(LoadingStatus status, QObject *object);
507+
508+protected:
509+ void setInitialState(QObject *object) override;
510+ void statusChanged(Status status) override;
511+
512+ void emitStatus(LoadingStatus status, QObject *object = 0);
513+ void onComponentStatusChanged(QQmlComponent::Status status);
514+ void detachComponent();
515+
516+ QQmlComponent *m_component = nullptr;
517+ QQmlContext *m_context = nullptr;
518+ LoadingStatus m_status = Ready;
519+ bool m_ownComponent = false;
520+};
521+
522+} // namespace UbuntuToolkit
523+
524+#endif // ASYNCLOADER_H
525
526=== modified file 'tests/unit/plugin_dependency.pri'
527--- tests/unit/plugin_dependency.pri 2015-12-21 12:18:50 +0000
528+++ tests/unit/plugin_dependency.pri 2016-02-19 14:39:50 +0000
529@@ -9,6 +9,7 @@
530 LIBS += -L$$PLUGIN_BLD/Components -lUbuntuComponents
531 LIBS += -L$$PLUGIN_BLD/Test -lUbuntuTest
532 LIBS += -L$${ROOT_BUILD_DIR}/lib -lUbuntuGestures
533+#LIBS += -L$${ROOT_BUILD_DIR}/lib -lUbuntuToolkit
534 DEFINES += QUICK_TEST_SOURCE_DIR=\"\\\"$$_PRO_FILE_PWD_\\\"\"
535 QMAKE_CXXFLAGS += -Werror
536
537
538=== modified file 'tests/unit/test-include.pri'
539--- tests/unit/test-include.pri 2014-11-25 09:58:33 +0000
540+++ tests/unit/test-include.pri 2016-02-19 14:39:50 +0000
541@@ -3,6 +3,6 @@
542
543 TEMPLATE = app
544 QT += testlib qml quick
545-CONFIG += no_keywords
546+CONFIG += no_keywords c++11
547
548
549
550=== added directory 'tests/unit_x11/tst_asyncloader'
551=== added file 'tests/unit_x11/tst_asyncloader/Document.qml'
552--- tests/unit_x11/tst_asyncloader/Document.qml 1970-01-01 00:00:00 +0000
553+++ tests/unit_x11/tst_asyncloader/Document.qml 2016-02-19 14:39:50 +0000
554@@ -0,0 +1,31 @@
555+/*
556+ * Copyright 2016 Canonical Ltd.
557+ *
558+ * This program is free software; you can redistribute it and/or modify
559+ * it under the terms of the GNU Lesser General Public License as published by
560+ * the Free Software Foundation; version 3.
561+ *
562+ * This program is distributed in the hope that it will be useful,
563+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
564+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
565+ * GNU Lesser General Public License for more details.
566+ *
567+ * You should have received a copy of the GNU Lesser General Public License
568+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
569+ *
570+ */
571+
572+import QtQuick 2.4
573+import Ubuntu.Components 1.3
574+
575+Column {
576+ anchors.fill: parent
577+ spacing: 1
578+ Repeater {
579+ model: 500
580+ TextField {
581+ width: parent.width
582+ }
583+ }
584+}
585+
586
587=== added file 'tests/unit_x11/tst_asyncloader/FaultyDocument.qml'
588--- tests/unit_x11/tst_asyncloader/FaultyDocument.qml 1970-01-01 00:00:00 +0000
589+++ tests/unit_x11/tst_asyncloader/FaultyDocument.qml 2016-02-19 14:39:50 +0000
590@@ -0,0 +1,20 @@
591+/*
592+ * Copyright 2016 Canonical Ltd.
593+ *
594+ * This program is free software; you can redistribute it and/or modify
595+ * it under the terms of the GNU Lesser General Public License as published by
596+ * the Free Software Foundation; version 3.
597+ *
598+ * This program is distributed in the hope that it will be useful,
599+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
600+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
601+ * GNU Lesser General Public License for more details.
602+ *
603+ * You should have received a copy of the GNU Lesser General Public License
604+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
605+ *
606+ */
607+
608+import QtQuick 2.4
609+
610+Label {}
611
612=== added file 'tests/unit_x11/tst_asyncloader/HeavyDocument.qml'
613--- tests/unit_x11/tst_asyncloader/HeavyDocument.qml 1970-01-01 00:00:00 +0000
614+++ tests/unit_x11/tst_asyncloader/HeavyDocument.qml 2016-02-19 14:39:50 +0000
615@@ -0,0 +1,31 @@
616+/*
617+ * Copyright 2016 Canonical Ltd.
618+ *
619+ * This program is free software; you can redistribute it and/or modify
620+ * it under the terms of the GNU Lesser General Public License as published by
621+ * the Free Software Foundation; version 3.
622+ *
623+ * This program is distributed in the hope that it will be useful,
624+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
625+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
626+ * GNU Lesser General Public License for more details.
627+ *
628+ * You should have received a copy of the GNU Lesser General Public License
629+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
630+ *
631+ */
632+
633+import QtQuick 2.4
634+import Ubuntu.Components 1.3
635+
636+Column {
637+ anchors.fill: parent
638+ spacing: units.dp(1)
639+ Repeater {
640+ model: 500
641+ TextField {
642+ width: parent.width
643+ }
644+ }
645+}
646+
647
648=== added file 'tests/unit_x11/tst_asyncloader/TestApp.qml'
649--- tests/unit_x11/tst_asyncloader/TestApp.qml 1970-01-01 00:00:00 +0000
650+++ tests/unit_x11/tst_asyncloader/TestApp.qml 2016-02-19 14:39:50 +0000
651@@ -0,0 +1,30 @@
652+/*
653+ * Copyright 2016 Canonical Ltd.
654+ *
655+ * This program is free software; you can redistribute it and/or modify
656+ * it under the terms of the GNU Lesser General Public License as published by
657+ * the Free Software Foundation; version 3.
658+ *
659+ * This program is distributed in the hope that it will be useful,
660+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
661+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
662+ * GNU Lesser General Public License for more details.
663+ *
664+ * You should have received a copy of the GNU Lesser General Public License
665+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
666+ *
667+ */
668+
669+import QtQuick 2.4
670+//import Ubuntu.Components 1.3
671+
672+//MainView {
673+// width: units.gu(40)
674+// height: units.gu(71)
675+
676+// applicationName: "Document"
677+//}
678+
679+Item {
680+
681+}
682
683=== added file 'tests/unit_x11/tst_asyncloader/tst_asyncloader.cpp'
684--- tests/unit_x11/tst_asyncloader/tst_asyncloader.cpp 1970-01-01 00:00:00 +0000
685+++ tests/unit_x11/tst_asyncloader/tst_asyncloader.cpp 2016-02-19 14:39:50 +0000
686@@ -0,0 +1,265 @@
687+/*
688+ * Copyright 2016 Canonical Ltd.
689+ *
690+ * This program is free software; you can redistribute it and/or modify
691+ * it under the terms of the GNU Lesser General Public License as published by
692+ * the Free Software Foundation; version 3.
693+ *
694+ * This program is distributed in the hope that it will be useful,
695+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
696+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
697+ * GNU Lesser General Public License for more details.
698+ *
699+ * You should have received a copy of the GNU Lesser General Public License
700+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
701+ *
702+ */
703+
704+#include <QtTest/QtTest>
705+#include "uctestcase.h"
706+#include "uctestextras.h"
707+#include <AsyncLoader>
708+#include <functional>
709+#include <QtQml/QQmlEngine>
710+
711+class LoaderSpy : public QObject
712+{
713+ Q_OBJECT
714+public:
715+ UbuntuToolkit::AsyncLoader *m_loader;
716+ QScopedPointer<QObject> m_object;
717+ bool m_done = false;
718+ bool m_error = false;
719+ QList<UbuntuToolkit::AsyncLoader::LoadingStatus> m_statusList;
720+public:
721+ LoaderSpy(UbuntuToolkit::AsyncLoader *loader)
722+ : QObject(0)
723+ , m_loader(loader)
724+ {
725+ connect(loader, &UbuntuToolkit::AsyncLoader::loadingStatus,
726+ this, &LoaderSpy::onLoadingStatusChanged);
727+ }
728+
729+protected Q_SLOTS:
730+ virtual void onLoadingStatusChanged(UbuntuToolkit::AsyncLoader::LoadingStatus status, QObject *object)
731+ {
732+ m_statusList << status;
733+ if (status == UbuntuToolkit::AsyncLoader::Ready) {
734+ m_done = true;
735+ m_object.reset(object);
736+ }
737+ if (status == UbuntuToolkit::AsyncLoader::Error) {
738+ m_error = true;
739+ }
740+ }
741+};
742+
743+class ResetLoaderSpy : public LoaderSpy
744+{
745+ Q_OBJECT
746+public:
747+ bool m_reset = false;
748+public:
749+ ResetLoaderSpy(UbuntuToolkit::AsyncLoader *loader)
750+ : LoaderSpy(loader)
751+ {
752+ }
753+
754+ void onLoadingStatusChanged(UbuntuToolkit::AsyncLoader::LoadingStatus status, QObject *object) override
755+ {
756+ if (status == UbuntuToolkit::AsyncLoader::Loading) {
757+ m_loader->reset();
758+ m_reset = true;
759+ }
760+ LoaderSpy::onLoadingStatusChanged(status, object);
761+ }
762+};
763+
764+class SecondLoaderSpy : public LoaderSpy
765+{
766+ Q_OBJECT
767+public:
768+ bool m_loadResult = false;
769+public:
770+ SecondLoaderSpy(UbuntuToolkit::AsyncLoader *loader, UbuntuToolkit::AsyncLoader::LoadingStatus loadAt,
771+ const QUrl &url, QQmlContext *context)
772+ : LoaderSpy(loader)
773+ , m_loadAt(loadAt)
774+ , m_url(url)
775+ , m_context(context)
776+ {
777+ }
778+
779+ void onLoadingStatusChanged(UbuntuToolkit::AsyncLoader::LoadingStatus status, QObject *object) override
780+ {
781+ if (status == (UbuntuToolkit::AsyncLoader::LoadingStatus)m_loadAt) {
782+ m_loadAt = -1;
783+ delete object;
784+ object = nullptr;
785+ m_loadResult = m_loader->load(m_url, m_context);
786+ }
787+ LoaderSpy::onLoadingStatusChanged(status, object);
788+ }
789+
790+private:
791+ int m_loadAt;
792+ QUrl m_url;
793+ QQmlContext *m_context;
794+};
795+
796+/********************************************************************
797+ * Test
798+ ********************************************************************/
799+class tst_AsyncLoader : public QObject
800+{
801+ Q_OBJECT
802+private Q_SLOTS:
803+
804+ void test_load_data()
805+ {
806+ QTest::addColumn<bool>("loadAsDocument");
807+ QTest::addColumn<QString>("document");
808+ QTest::addColumn<int>("mode");
809+ QTest::addColumn< QList<int> >("statuses");
810+
811+ QTest::newRow("document") << true << "Document.qml" << (int)QQmlComponent::Asynchronous
812+ << (QList<int>()
813+ << UbuntuToolkit::AsyncLoader::Compiling
814+ << UbuntuToolkit::AsyncLoader::Loading
815+ << UbuntuToolkit::AsyncLoader::Initializing
816+ << UbuntuToolkit::AsyncLoader::Ready
817+ );
818+ QTest::newRow("component, asynchronous") << false << "Document.qml" << (int)QQmlComponent::Asynchronous
819+ << (QList<int>()
820+ << UbuntuToolkit::AsyncLoader::Compiling
821+ << UbuntuToolkit::AsyncLoader::Loading
822+ << UbuntuToolkit::AsyncLoader::Initializing
823+ << UbuntuToolkit::AsyncLoader::Ready
824+ );
825+ QTest::newRow("component, synchronous") << false << "Document.qml" << (int)QQmlComponent::PreferSynchronous
826+ << (QList<int>()
827+ << UbuntuToolkit::AsyncLoader::Loading
828+ << UbuntuToolkit::AsyncLoader::Initializing
829+ << UbuntuToolkit::AsyncLoader::Ready
830+ );
831+ }
832+ void test_load()
833+ {
834+ QFETCH(bool, loadAsDocument);
835+ QFETCH(QString, document);
836+ QFETCH(int, mode);
837+ QFETCH(QList<int>, statuses);
838+
839+ QScopedPointer<UbuntuTestCase> view(new UbuntuTestCase("TestApp.qml"));
840+ UbuntuToolkit::AsyncLoader loader;
841+ LoaderSpy spy(&loader);
842+ QScopedPointer<QQmlComponent> component;
843+
844+ if (loadAsDocument) {
845+ loader.load(QUrl::fromLocalFile(document), view->rootContext());
846+ } else {
847+ // create a component
848+ component.reset(new QQmlComponent(view->engine(), QUrl::fromLocalFile(document), (QQmlComponent::CompilationMode)mode));
849+ loader.load(component.data(), view->rootContext());
850+ }
851+ QTRY_VERIFY_WITH_TIMEOUT(spy.m_object != nullptr, 2000);
852+ // check the statuses
853+ QCOMPARE(spy.m_statusList.length(), statuses.length());
854+ for (int i = 0; i < spy.m_statusList.length(); i++) {
855+ QVERIFY2((int)spy.m_statusList[i] == statuses[i], (QString(" Status at index %1 differs").arg(i)).toLocal8Bit().constData());
856+ }
857+ }
858+
859+ void test_load_with_error()
860+ {
861+ QUrl document = QUrl::fromLocalFile("FaultyDocument.qml");
862+ UbuntuTestCase::ignoreWarning("FaultyDocument.qml", 20, "Label is not a type");
863+ QScopedPointer<UbuntuTestCase> view(new UbuntuTestCase("TestApp.qml"));
864+ UbuntuToolkit::AsyncLoader loader;
865+ LoaderSpy spy(&loader);
866+ loader.load(document, view->rootContext());
867+ QTRY_VERIFY_WITH_TIMEOUT(spy.m_error == true, 2000);
868+ }
869+
870+ void test_load_and_cancel_data()
871+ {
872+ QTest::addColumn<bool>("loadAsDocument");
873+ QTest::addColumn<QString>("document");
874+ QTest::addColumn<int>("mode");
875+
876+ QTest::newRow("document") << true << "HeavyDocument.qml" << (int)QQmlComponent::Asynchronous;
877+ QTest::newRow("component, asynchronous") << false << "HeavyDocument.qml" << (int)QQmlComponent::Asynchronous;
878+ QTest::newRow("component, synchronous") << false << "HeavyDocument.qml" << (int)QQmlComponent::PreferSynchronous;
879+ }
880+ void test_load_and_cancel()
881+ {
882+ QFETCH(bool, loadAsDocument);
883+ QFETCH(QString, document);
884+ QFETCH(int, mode);
885+
886+ QScopedPointer<UbuntuTestCase> view(new UbuntuTestCase("TestApp.qml"));
887+ UbuntuToolkit::AsyncLoader loader;
888+ ResetLoaderSpy spy(&loader);
889+ QScopedPointer<QQmlComponent> component;
890+
891+ if (loadAsDocument) {
892+ loader.load(QUrl::fromLocalFile(document), view->rootContext());
893+ } else {
894+ // create a component
895+ component.reset(new QQmlComponent(view->engine(), QUrl::fromLocalFile(document), (QQmlComponent::CompilationMode)mode));
896+ loader.load(component.data(), view->rootContext());
897+ }
898+ if (loader.status() < UbuntuToolkit::AsyncLoader::Loading) {
899+ // cannot reset yet!
900+ QVERIFY(!loader.reset());
901+ }
902+ QTRY_VERIFY_WITH_TIMEOUT(spy.m_reset, 2000);
903+ }
904+
905+ void test_second_load_scenarios_data()
906+ {
907+ QTest::addColumn<QString> ("doc1");
908+ QTest::addColumn<QString> ("doc2");
909+ QTest::addColumn<int> ("when");
910+ QTest::addColumn<bool> ("success");
911+
912+ QTest::newRow("status = Compiling")
913+ << "Document.qml" << "HeavyDocument.qml"
914+ << (int)UbuntuToolkit::AsyncLoader::Compiling << false;
915+ QTest::newRow("status = Loading")
916+ << "Document.qml" << "HeavyDocument.qml"
917+ << (int)UbuntuToolkit::AsyncLoader::Loading << true;
918+ QTest::newRow("status = Initializing")
919+ << "Document.qml" << "HeavyDocument.qml"
920+ << (int)UbuntuToolkit::AsyncLoader::Initializing << true;
921+ QTest::newRow("status = Ready")
922+ << "Document.qml" << "HeavyDocument.qml"
923+ << (int)UbuntuToolkit::AsyncLoader::Ready << true;
924+ QTest::newRow("status = Error")
925+ << "FaultyDocument.qml" << "HeavyDocument.qml"
926+ << (int)UbuntuToolkit::AsyncLoader::Error << true;
927+ }
928+ void test_second_load_scenarios()
929+ {
930+ QFETCH(QString, doc1);
931+ QFETCH(QString, doc2);
932+ QFETCH(int, when);
933+ QFETCH(bool, success);
934+
935+ QScopedPointer<UbuntuTestCase> view(new UbuntuTestCase("TestApp.qml"));
936+ UbuntuToolkit::AsyncLoader loader;
937+ if (when == (int)UbuntuToolkit::AsyncLoader::Error) {
938+ UbuntuTestCase::ignoreWarning("FaultyDocument.qml", 20, "Label is not a type");
939+ }
940+
941+ SecondLoaderSpy spy(&loader, (UbuntuToolkit::AsyncLoader::LoadingStatus)when, QUrl::fromLocalFile(doc2), view->rootContext());
942+ // load the first document
943+ QVERIFY(loader.load(QUrl::fromLocalFile(doc1), view->rootContext()));
944+ QTRY_VERIFY_WITH_TIMEOUT(spy.m_object != nullptr, 4000);
945+ QCOMPARE(spy.m_loadResult, success);
946+ }
947+};
948+
949+QTEST_MAIN(tst_AsyncLoader)
950+
951+#include "tst_asyncloader.moc"
952
953=== added file 'tests/unit_x11/tst_asyncloader/tst_asyncloader.pro'
954--- tests/unit_x11/tst_asyncloader/tst_asyncloader.pro 1970-01-01 00:00:00 +0000
955+++ tests/unit_x11/tst_asyncloader/tst_asyncloader.pro 2016-02-19 14:39:50 +0000
956@@ -0,0 +1,11 @@
957+include(../test-include.pri)
958+QT += core-private qml-private quick-private gui-private UbuntuToolkit
959+
960+SOURCES += \
961+ tst_asyncloader.cpp
962+
963+DISTFILES += \
964+ Document.qml \
965+ TestApp.qml \
966+ HeavyDocument.qml \
967+ FaultyDocument.qml
968
969=== modified file 'tests/unit_x11/tst_bottomedge/tst_bottomedge.cpp'
970--- tests/unit_x11/tst_bottomedge/tst_bottomedge.cpp 2016-02-10 10:57:20 +0000
971+++ tests/unit_x11/tst_bottomedge/tst_bottomedge.cpp 2016-02-19 14:39:50 +0000
972@@ -137,6 +137,7 @@
973 QCOMPARE(test->regionAt("testItem", 0)->m_from, 0.33);
974 QCOMPARE(test->regionAt("testItem", 0)->m_to, 1.0);
975 QVERIFY(!test->testItem()->activeRegion());
976+ QVERIFY(!test->testItem()->preloadContent());
977 }
978
979 void test_height_moves_when_reparented()
980
981=== modified file 'tests/unit_x11/unit_x11.pro'
982--- tests/unit_x11/unit_x11.pro 2015-11-23 16:12:16 +0000
983+++ tests/unit_x11/unit_x11.pro 2016-02-19 14:39:50 +0000
984@@ -17,4 +17,5 @@
985 tst_subtheming \
986 tst_swipearea \
987 tst_touchregistry \
988- tst_bottomedge
989+ tst_bottomedge \
990+ tst_asyncloader

Subscribers

People subscribed via source and target branches