diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index b960c88a99..1499626c99 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -367,8 +367,8 @@ void QQmlDelegateModelPrivate::connectToAbstractItemModel() q, QQmlDelegateModel, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector))); qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), q, QQmlDelegateModel, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); - qmlobject_connect(aim, QAbstractItemModel, SIGNAL(modelReset()), - q, QQmlDelegateModel, SLOT(_q_modelReset())); + + QObject::connect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset); qmlobject_connect(aim, QAbstractItemModel, SIGNAL(layoutChanged(QList,QAbstractItemModel::LayoutChangeHint)), q, QQmlDelegateModel, SLOT(_q_layoutChanged(QList,QAbstractItemModel::LayoutChangeHint))); } @@ -397,8 +397,7 @@ void QQmlDelegateModelPrivate::disconnectFromAbstractItemModel() q, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector))); QObject::disconnect(aim, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), q, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); - QObject::disconnect(aim, SIGNAL(modelReset()), - q, SLOT(_q_modelReset())); + QObject::disconnect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset); QObject::disconnect(aim, SIGNAL(layoutChanged(QList,QAbstractItemModel::LayoutChangeHint)), q, SLOT(_q_layoutChanged(QList,QAbstractItemModel::LayoutChangeHint))); } @@ -1840,7 +1839,29 @@ void QQmlDelegateModelPrivate::emitChanges() } } -void QQmlDelegateModel::_q_modelReset() +void QQmlDelegateModel::_q_modelAboutToBeReset() +{ + auto aim = static_cast(sender()); + auto oldRoleNames = aim->roleNames(); + // this relies on the fact that modelAboutToBeReset must be followed + // by a modelReset signal before any further modelAboutToBeReset can occur + QObject::connect(aim, &QAbstractItemModel::modelReset, this, [&, oldRoleNames](){ + auto aim = static_cast(sender()); + if (oldRoleNames == aim->roleNames()) { + // if the rolenames stayed the same (most common case), then we don't have + // to throw away all the setup that we did + handleModelReset(); + } else { + // If they did change, we give up and just start from scratch via setMode + setModel(QVariant::fromValue(model())); + // but we still have to call handleModelReset, otherwise views will + // not refresh + handleModelReset(); + } + }, Qt::SingleShotConnection); +} + +void QQmlDelegateModel::handleModelReset() { Q_D(QQmlDelegateModel); if (!d->m_delegate) @@ -2005,7 +2026,7 @@ void QQmlDelegateModel::_q_layoutChanged(const QList &par // Ignored } else { // We don't know what's going on, so reset the model - _q_modelReset(); + handleModelReset(); } } diff --git a/src/qmlmodels/qqmldelegatemodel_p.h b/src/qmlmodels/qqmldelegatemodel_p.h index bfb5b6d38a..cd62573635 100644 --- a/src/qmlmodels/qqmldelegatemodel_p.h +++ b/src/qmlmodels/qqmldelegatemodel_p.h @@ -114,7 +114,7 @@ private Q_SLOTS: void _q_itemsInserted(int index, int count); void _q_itemsRemoved(int index, int count); void _q_itemsMoved(int from, int to, int count); - void _q_modelReset(); + void _q_modelAboutToBeReset(); void _q_rowsInserted(const QModelIndex &,int,int); void _q_columnsInserted(const QModelIndex &, int, int); void _q_columnsRemoved(const QModelIndex &, int, int); @@ -126,6 +126,7 @@ private Q_SLOTS: void _q_layoutChanged(const QList&, QAbstractItemModel::LayoutChangeHint); private: + void handleModelReset(); bool isDescendantOf(const QPersistentModelIndex &desc, const QList &parents) const; Q_DISABLE_COPY(QQmlDelegateModel) diff --git a/tests/auto/qml/qqmldelegatemodel/data/resetModelData.qml b/tests/auto/qml/qqmldelegatemodel/data/resetModelData.qml new file mode 100644 index 0000000000..1fe6168c79 --- /dev/null +++ b/tests/auto/qml/qqmldelegatemodel/data/resetModelData.qml @@ -0,0 +1,16 @@ +import QtQuick + +ListView { + id: root + anchors.fill: parent + property bool success: (currentItem?.mydata ?? 0) === 42 + height: 300 + width: 200 + + delegate: Rectangle { + required property var model + implicitWidth: 100 + implicitHeight: 50 + property var mydata: model?.foo ?? model.bar + } +} diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp index ca66ddb618..0ac12cd337 100644 --- a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp +++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ public: tst_QQmlDelegateModel(); private slots: + void resettingRolesRespected(); void valueWithoutCallingObjectFirst_data(); void valueWithoutCallingObjectFirst(); void qtbug_86017(); @@ -85,6 +87,61 @@ tst_QQmlDelegateModel::tst_QQmlDelegateModel() qmlRegisterType("Test", 1, 0, "AbstractItemModel"); } +class TableModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + int rowCount(const QModelIndex & = QModelIndex()) const override + { + return 1; + } + + int columnCount(const QModelIndex & = QModelIndex()) const override + { + return 1; + } + + QVariant data(const QModelIndex &index, int role) const override + { + switch (role) { + case 0: + return QString("foo: %1, %2").arg(index.column()).arg(index.row()); + case 1: + return 42; + default: + break; + } + + return QVariant(); + } + + Q_INVOKABLE void change() { beginResetModel(); toggle = !toggle; endResetModel(); } + + QHash roleNames() const override + { + if (toggle) + return { {0, "foo"} }; + else + return { {1, "bar"} }; + } + + bool toggle = true; +}; + +void tst_QQmlDelegateModel::resettingRolesRespected() +{ + auto model = std::make_unique(); + QQmlApplicationEngine engine; + engine.setInitialProperties({ {"model", QVariant::fromValue(model.get()) }} ); + engine.load(testFileUrl("resetModelData.qml")); + QTRY_VERIFY(!engine.rootObjects().isEmpty()); + QObject *root = engine.rootObjects().constFirst(); + QVERIFY(!root->property("success").toBool()); + model->change(); + QTRY_VERIFY(root->property("success").toBool()); +} + void tst_QQmlDelegateModel::valueWithoutCallingObjectFirst_data() { QTest::addColumn("qmlFileUrl");