diff options
Diffstat (limited to 'tests/auto/qml')
-rw-r--r-- | tests/auto/qml/qqmlinstantiator/data/removeDuringModelChange.qml | 10 | ||||
-rw-r--r-- | tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp | 89 |
2 files changed, 99 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmlinstantiator/data/removeDuringModelChange.qml b/tests/auto/qml/qqmlinstantiator/data/removeDuringModelChange.qml new file mode 100644 index 0000000000..079e376549 --- /dev/null +++ b/tests/auto/qml/qqmlinstantiator/data/removeDuringModelChange.qml @@ -0,0 +1,10 @@ +import QtQuick 2.15 +import QtQml.Models 2.15 + +Instantiator { + delegate: QtObject { + function deactivate() { + model.active = false; + } + } +} diff --git a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp index 1097c65f02..f6d2752889 100644 --- a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp +++ b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include <qtest.h> #include <QSignalSpy> +#include <QSortFilterProxyModel> #include <QDebug> #include <QtQml/qqmlengine.h> @@ -28,6 +29,7 @@ private slots: void activeModelChangeInteraction(); void intModelChange(); void createAndRemove(); + void removeDuringModelChange(); void asynchronous_data(); void asynchronous(); @@ -306,6 +308,93 @@ void tst_qqmlinstantiator::boundDelegateComponent() QCOMPARE(b->objectAt(2)->objectName(), QStringLiteral("root3")); } +class SingleBoolItemModel : public QAbstractListModel +{ + Q_OBJECT + +public: + SingleBoolItemModel(QObject *parent = nullptr) : QAbstractListModel(parent) {} + + int rowCount(const QModelIndex &parent = QModelIndex()) const override + { + if (parent.isValid()) + return 0; + return 1; + } + + QVariant data(const QModelIndex &index, int role) const override + { + if (index.parent().isValid() || index.row() != 0 || index.column() != 0 + || role != Qt::UserRole) + return QVariant(); + + return m_active; + } + + bool setData(const QModelIndex &index, const QVariant &value, + int role) override { + if (index.parent().isValid() || index.row() != 0 || index.column() != 0 + || role != Qt::UserRole || m_active == value.toBool()) + return false; + + m_active = value.toBool(); + Q_EMIT dataChanged(index, index, QList<int>{Qt::UserRole}); + return true; + } + + QHash<int, QByteArray> roleNames() const override + { + return { {Qt::UserRole, "active"} }; + } + +private: + bool m_active = true; +}; + +class FilterBoolRoleProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + FilterBoolRoleProxyModel(QObject *parent = nullptr) + : QSortFilterProxyModel(parent) {} + + bool filterAcceptsRow(int source_row, + const QModelIndex &source_parent) const override + { + return sourceModel()->index(source_row, 0, source_parent).data(Qt::UserRole).toBool(); + } +}; + +void tst_qqmlinstantiator::removeDuringModelChange() +{ + SingleBoolItemModel model; + + FilterBoolRoleProxyModel proxyModel; + proxyModel.setSourceModel(&model); + proxyModel.setFilterRole(Qt::UserRole); + QCOMPARE(proxyModel.rowCount(), 1); + + QQmlEngine engine; + const QUrl url(testFileUrl("removeDuringModelChange.qml")); + QQmlComponent component(&engine, url); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + + QScopedPointer<QObject> o(component.create()); + QVERIFY2(!o.isNull(), qPrintable(component.errorString())); + + QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator *>(o.data()); + + instantiator->setModel(QVariant::fromValue(&proxyModel)); + + QSignalSpy removedSpy(instantiator, &QQmlInstantiator::objectRemoved); + QMetaObject::invokeMethod(instantiator->object(), "deactivate"); + + // We should still be alive at this point. + QCOMPARE(removedSpy.size(), 1); + QCOMPARE(proxyModel.rowCount(), 0); +} + QTEST_MAIN(tst_qqmlinstantiator) #include "tst_qqmlinstantiator.moc" |