aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqmlcontext.cpp8
-rw-r--r--src/qml/qml/qqmlcontext_p.h1
-rw-r--r--src/quick/items/qquickloader.cpp4
-rw-r--r--tests/auto/quick/qquickloader/data/rootContext.qml55
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp61
5 files changed, 127 insertions, 2 deletions
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 6e43bc735f..5dd3278b4c 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -593,6 +593,14 @@ void QQmlContextData::invalidate()
parent = nullptr;
}
+void QQmlContextData::clearContextRecursively()
+{
+ clearContext();
+
+ for (auto ctxIt = childContexts; ctxIt; ctxIt = ctxIt->nextChild)
+ ctxIt->clearContextRecursively();
+}
+
void QQmlContextData::clearContext()
{
emitDestruction();
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index ff36d6c9a8..5dfee48848 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -115,6 +115,7 @@ public:
QQmlContextData(QQmlContext *);
void emitDestruction();
void clearContext();
+ void clearContextRecursively();
void invalidate();
inline bool isValid() const {
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 34f30e81a3..6960e16bd9 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -102,7 +102,7 @@ void QQuickLoaderPrivate::clear()
// this we may get transient errors from use of 'parent', for example.
QQmlContext *context = qmlContext(object);
if (context)
- QQmlContextData::get(context)->invalidate();
+ QQmlContextData::get(context)->clearContextRecursively();
if (loadingFromSource && component) {
// disconnect since we deleteLater
@@ -363,7 +363,7 @@ void QQuickLoader::setActive(bool newVal)
// this we may get transient errors from use of 'parent', for example.
QQmlContext *context = qmlContext(d->object);
if (context)
- QQmlContextData::get(context)->invalidate();
+ QQmlContextData::get(context)->clearContextRecursively();
if (d->item) {
QQuickItemPrivate *p = QQuickItemPrivate::get(d->item);
diff --git a/tests/auto/quick/qquickloader/data/rootContext.qml b/tests/auto/quick/qquickloader/data/rootContext.qml
new file mode 100644
index 0000000000..277db43d57
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/rootContext.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the manual tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 360
+ height: 360
+
+ property alias loader: loader
+
+ Loader {
+ id: loader
+ }
+
+ property Component component: Item {
+ property bool trigger: false
+ onTriggerChanged: {
+ objectInRootContext.doIt() // make sure we can resolve objectInRootContext
+ loader.active = false
+ objectInRootContext.doIt() // make sure we can STILL resolve objectInRootContext
+ anotherProperty = true // see if we can trigger subsequent signal handlers (we shouldn't)
+ }
+ property bool anotherProperty: false
+ onAnotherPropertyChanged: {
+ // this should never be executed
+ objectInRootContext.doIt()
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index 30fc52f95a..7a176661e8 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -29,6 +29,7 @@
#include <QSignalSpy>
+#include <QtQml/QQmlContext>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlincubator.h>
@@ -123,6 +124,8 @@ private slots:
void bindings();
void parentErrors();
+
+ void rootContext();
};
Q_DECLARE_METATYPE(QList<QQmlError>)
@@ -1327,6 +1330,64 @@ void tst_QQuickLoader::parentErrors()
QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage));
}
+class ObjectInRootContext: public QObject
+{
+ Q_OBJECT
+
+public:
+ int didIt = 0;
+
+public slots:
+ void doIt() {
+ didIt += 1;
+ }
+};
+
+void tst_QQuickLoader::rootContext()
+{
+ QQmlEngine engine;
+ ObjectInRootContext objectInRootContext;
+ engine.rootContext()->setContextProperty("objectInRootContext", &objectInRootContext);
+
+ QQmlComponent component(&engine, testFileUrl("rootContext.qml"));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QQuickLoader *loader = object->property("loader").value<QQuickLoader*>();
+ QVERIFY(loader);
+
+ QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QQmlError>)));
+
+ // Give the loader a component
+ loader->setSourceComponent(object->property("component").value<QQmlComponent*>());
+ QTRY_VERIFY(loader->active());
+ QTRY_VERIFY(loader->item());
+
+ QString failureMessage;
+ if (!warningsSpy.isEmpty()) {
+ QDebug stream(&failureMessage);
+ stream << warningsSpy.first().first().value<QList<QQmlError>>();
+ }
+ QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage));
+ QCOMPARE(objectInRootContext.didIt, 0);
+
+ // Deactivate the loader, which deletes the item.
+ // Check that a) there are no errors, and b) the objectInRootContext can still be resolved even
+ // after deactivating the loader. If it cannot, a ReferenceError for objectInRootContext is
+ // generated (and the 'doIt' counter in objectInRootContext will be 1 for the call before
+ // the deactivation).
+ loader->item()->setProperty("trigger", true);
+ QTRY_VERIFY(!loader->active());
+ QTRY_VERIFY(!loader->item());
+
+ if (!warningsSpy.isEmpty()) {
+ QDebug stream(&failureMessage);
+ stream << warningsSpy.first().first().value<QList<QQmlError>>();
+ }
+ QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage));
+ QCOMPARE(objectInRootContext.didIt, 2);
+}
+
QTEST_MAIN(tst_QQuickLoader)
#include "tst_qquickloader.moc"