diff options
author | Robert Griebl <robert.griebl@pelagicore.com> | 2015-06-17 16:38:47 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2015-06-23 17:31:51 +0000 |
commit | 1b4f94c8fe0452cc053907fea2ad8be3930df8ce (patch) | |
tree | 3c65361cdeb08ce764979b8e35604f4a84c8f909 | |
parent | fcbefee383ccff2a6485acc120631123e30b41dd (diff) |
Force completion of asynchronously loaded components.
[ChangeLog][QtQuick][QQmlComponent] Synchronously complete the loading of a
Asynchronous QQmlComponent, if a PreferSynchronous QQmlComponent is created
for the same url (given that this url does support synchronous loading).
Change-Id: I3291d0569a69bac2aeb4815f1068a426ef2707ef
Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
-rw-r--r-- | src/qml/qml/ftw/qqmlthread.cpp | 27 | ||||
-rw-r--r-- | src/qml/qml/ftw/qqmlthread_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 14 | ||||
-rw-r--r-- | tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp | 30 |
4 files changed, 73 insertions, 0 deletions
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp index 4addcd9e58..62f6f76a7e 100644 --- a/src/qml/qml/ftw/qqmlthread.cpp +++ b/src/qml/qml/ftw/qqmlthread.cpp @@ -377,4 +377,31 @@ void QQmlThread::internalPostMethodToMain(Message *message) d->unlock(); } +void QQmlThread::waitForNextMessage() +{ + Q_ASSERT(!isThisThread()); + d->lock(); + Q_ASSERT(d->m_mainThreadWaiting == false); + + d->m_mainThreadWaiting = true; + + if (d->mainSync || !d->threadList.isEmpty()) { + if (d->mainSync) { + QQmlThread::Message *message = d->mainSync; + unlock(); + message->call(this); + delete message; + lock(); + d->mainSync = 0; + wakeOne(); + } else { + d->wait(); + } + } + + d->m_mainThreadWaiting = false; + d->unlock(); +} + + QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qqmlthread_p.h b/src/qml/qml/ftw/qqmlthread_p.h index 86d7d2cf19..73658536ac 100644 --- a/src/qml/qml/ftw/qqmlthread_p.h +++ b/src/qml/qml/ftw/qqmlthread_p.h @@ -108,6 +108,8 @@ public: template<typename T, typename T2, class V, class V2, class O> inline void postMethodToMain(void (O::*Member)(V, V2), const T &, const T2 &); + void waitForNextMessage(); + protected: virtual void startupThread(); virtual void shutdownThread(); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index e860b8e0fa..408f17ffde 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1612,6 +1612,20 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode) } else { QQmlTypeLoader::load(typeData, mode); } + } else if ((mode == PreferSynchronous) && QQmlFile::isSynchronous(url)) { + // this was started Asynchronous, but we need to force Synchronous + // completion now (if at all possible with this type of URL). + + if (!m_thread->isThisThread()) { + // this only works when called directly from the UI thread, but not + // when recursively called on the QML thread via resolveTypes() + + while (!typeData->isCompleteOrError()) { + unlock(); + m_thread->waitForNextMessage(); + lock(); + } + } } typeData->addref(); diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index bb159d5931..4c1f827915 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -110,6 +110,7 @@ private slots: void qmlCreateParentReference(); void async(); void asyncHierarchy(); + void asyncForceSync(); void componentUrlCanonicalization(); void onDestructionLookup(); void onDestructionCount(); @@ -371,6 +372,35 @@ void tst_qqmlcomponent::asyncHierarchy() delete root; } +void tst_qqmlcomponent::asyncForceSync() +{ + { + // 1) make sure that HTTP URLs cannot be completed synchronously + TestHTTPServer server; + QVERIFY2(server.listen(), qPrintable(server.errorString())); + server.serveDirectory(dataDirectory()); + + // ensure that the item hierarchy is compiled correctly. + QQmlComponent component(&engine); + component.loadUrl(server.url("/TestComponent.2.qml"), QQmlComponent::Asynchronous); + QCOMPARE(component.status(), QQmlComponent::Loading); + QQmlComponent component2(&engine, server.url("/TestComponent.2.qml"), QQmlComponent::PreferSynchronous); + QCOMPARE(component2.status(), QQmlComponent::Loading); + } + { + // 2) make sure that file:// URL can be completed synchronously + + // ensure that the item hierarchy is compiled correctly. + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("/TestComponent.2.qml"), QQmlComponent::Asynchronous); + QCOMPARE(component.status(), QQmlComponent::Loading); + QQmlComponent component2(&engine, testFileUrl("/TestComponent.2.qml"), QQmlComponent::PreferSynchronous); + QCOMPARE(component2.status(), QQmlComponent::Ready); + QCOMPARE(component.status(), QQmlComponent::Loading); + QTRY_COMPARE_WITH_TIMEOUT(component.status(), QQmlComponent::Ready, 0); + } +} + void tst_qqmlcomponent::componentUrlCanonicalization() { // ensure that url canonicalization succeeds so that type information |