diff options
-rw-r--r-- | src/quick/items/qquickloader.cpp | 12 | ||||
-rw-r--r-- | tests/auto/quick/qquickloader/data/bindings.qml | 71 | ||||
-rw-r--r-- | tests/auto/quick/qquickloader/data/parentErrors.qml | 47 | ||||
-rw-r--r-- | tests/auto/quick/qquickloader/tst_qquickloader.cpp | 67 |
4 files changed, 197 insertions, 0 deletions
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index 27afe5a5db..27b8d32707 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -96,6 +96,12 @@ void QQuickLoaderPrivate::clear() delete itemContext; itemContext = 0; + // Prevent any bindings from running while waiting for deletion. Without + // this we may get transient errors from use of 'parent', for example. + QQmlContext *context = qmlContext(object); + if (context) + QQmlContextData::get(context)->invalidate(); + if (loadingFromSource && component) { // disconnect since we deleteLater QObject::disconnect(component, SIGNAL(statusChanged(QQmlComponent::Status)), @@ -351,6 +357,12 @@ void QQuickLoader::setActive(bool newVal) d->itemContext = 0; } + // Prevent any bindings from running while waiting for deletion. Without + // this we may get transient errors from use of 'parent', for example. + QQmlContext *context = qmlContext(d->object); + if (context) + QQmlContextData::get(context)->invalidate(); + if (d->item) { QQuickItemPrivate *p = QQuickItemPrivate::get(d->item); p->removeItemChangeListener(d, watchedChanges); diff --git a/tests/auto/quick/qquickloader/data/bindings.qml b/tests/auto/quick/qquickloader/data/bindings.qml new file mode 100644 index 0000000000..e0eae2a3e5 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/bindings.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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 + +Item { + id: root + + property alias game: theGame + property alias loader: theLoader + + Item { + id: theGame + + property bool isReady: false + + onStateChanged: { + if (state == "invalid") { + // The Loader's active property is bound to isReady, so none of its bindings + // should be updated when isReady becomes false + isReady = false; + + player.destroy(); + player = null; + } else if (state == "running") { + player = Qt.createQmlObject("import QtQuick 2.0; Item { property color color: 'black' }", root); + + isReady = true; + } + } + + property Item player + } + + Loader { + id: theLoader + active: theGame.isReady + sourceComponent: Rectangle { + width: 400 + height: 400 + color: game.player.color + + property var game: theGame + } + } +} diff --git a/tests/auto/quick/qquickloader/data/parentErrors.qml b/tests/auto/quick/qquickloader/data/parentErrors.qml new file mode 100644 index 0000000000..36607e7f05 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/parentErrors.qml @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** 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 + anchors.fill: parent + } + + property Component component: Rectangle { + width: parent.width + height: parent.height + color: "pink" + } +} diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index c70b4c85e7..e557b592ee 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -114,11 +114,17 @@ private slots: void QTBUG_30183(); void sourceComponentGarbageCollection(); + + void bindings(); + void parentErrors(); }; +Q_DECLARE_METATYPE(QList<QQmlError>) + tst_QQuickLoader::tst_QQuickLoader() { qmlRegisterType<SlowComponent>("LoaderTest", 1, 0, "SlowComponent"); + qRegisterMetaType<QList<QQmlError>>(); } void tst_QQuickLoader::sourceOrComponent() @@ -1174,6 +1180,67 @@ void tst_QQuickLoader::sourceComponentGarbageCollection() QCOMPARE(spy.count(), 1); } +// QTBUG-51995 +void tst_QQuickLoader::bindings() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("bindings.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QQuickItem *game = object->property("game").value<QQuickItem*>(); + QVERIFY(game); + + QQuickLoader *loader = object->property("loader").value<QQuickLoader*>(); + QVERIFY(loader); + + QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QQmlError>))); + + // Causes the Loader to become active + game->setState(QLatin1String("running")); + QTRY_VERIFY(loader->item()); + + // Causes the Loader to become inactive - should not cause binding errors + game->setState(QLatin1String("invalid")); + QTRY_VERIFY(!loader->item()); + + QString failureMessage; + if (!warningsSpy.isEmpty()) { + QDebug stream(&failureMessage); + stream << warningsSpy.first().first().value<QList<QQmlError>>(); + } + QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage)); +} + +// QTBUG-47321 +void tst_QQuickLoader::parentErrors() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("parentErrors.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->item()); + + // Clear the loader's component; should not cause binding errors + loader->setSourceComponent(nullptr); + QTRY_VERIFY(!loader->item()); + + QString failureMessage; + if (!warningsSpy.isEmpty()) { + QDebug stream(&failureMessage); + stream << warningsSpy.first().first().value<QList<QQmlError>>(); + } + QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage)); +} + QTEST_MAIN(tst_QQuickLoader) #include "tst_qquickloader.moc" |