diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2019-05-16 10:10:30 +0200 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2019-10-09 18:58:18 +0200 |
commit | 2d9cf3ef0fc09254b1a63ab04b86d9beb52e71bc (patch) | |
tree | 2a4a09fc481336b193677b7e58fc995aeda41681 | |
parent | d522746afa394960bef225ba08080d8364b69a7e (diff) |
When a DelegateModel delegate changes, refill the view
It looked a bit odd that the DelegateModel delegate property was not a
notifying property. Adding the delegateChanged signal makes it easier
to update the view when this happens. The previous approach of removing
all delegates and adding all new ones resulted in the view losing its
currentIndex and often scrolling to a different place. It's also nice
to reduce the number of d-> indirections by adding the
QQuickItemViewPrivate::applyDelegateChange() function, so that we just
need one indirection to call it, and then it updates all the internal
stuff in one place.
Done-with: Frederik Gladhorn
Done-with: Joni Poikelin
Fixes: QTBUG-63477
Change-Id: I2d17fd11ff4a2fcb20968a7182dd2c403abb715a
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
-rw-r--r-- | src/qmlmodels/qqmldelegatemodel.cpp | 9 | ||||
-rw-r--r-- | src/qmlmodels/qqmldelegatemodel_p.h | 3 | ||||
-rw-r--r-- | src/quick/items/qquickitemview.cpp | 38 | ||||
-rw-r--r-- | src/quick/items/qquickitemview_p_p.h | 2 | ||||
-rw-r--r-- | tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp | 40 |
5 files changed, 73 insertions, 19 deletions
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index e7868517cd..65c99d9bc0 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -454,7 +454,8 @@ void QQmlDelegateModel::setDelegate(QQmlComponent *delegate) } if (d->m_delegate == delegate) return; - bool wasValid = d->m_delegate != nullptr; + if (d->m_complete) + _q_itemsRemoved(0, d->m_count); d->m_delegate.setObject(delegate, this); d->m_delegateValidated = false; if (d->m_delegateChooser) @@ -470,7 +471,11 @@ void QQmlDelegateModel::setDelegate(QQmlComponent *delegate) [d](){ d->delegateChanged(); }); } } - d->delegateChanged(d->m_delegate, wasValid); + if (d->m_complete) { + _q_itemsInserted(0, d->adaptorModelCount()); + d->requestMoreIfNecessary(); + } + emit delegateChanged(); } /*! diff --git a/src/qmlmodels/qqmldelegatemodel_p.h b/src/qmlmodels/qqmldelegatemodel_p.h index 21eaef02e0..9e846ccc3e 100644 --- a/src/qmlmodels/qqmldelegatemodel_p.h +++ b/src/qmlmodels/qqmldelegatemodel_p.h @@ -77,7 +77,7 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, p Q_DECLARE_PRIVATE(QQmlDelegateModel) Q_PROPERTY(QVariant model READ model WRITE setModel) - Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate) + Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup) Q_PROPERTY(QQmlDelegateModelGroup *items READ items CONSTANT) //TODO : worth renaming? Q_PROPERTY(QQmlDelegateModelGroup *persistedItems READ persistedItems CONSTANT) @@ -136,6 +136,7 @@ Q_SIGNALS: void filterGroupChanged(); void defaultGroupsChanged(); void rootIndexChanged(); + void delegateChanged(); private Q_SLOTS: void _q_itemsChanged(int index, int count, const QVector<int> &roles); diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index bbfbf6244c..e1af65c986 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -247,6 +247,8 @@ void QQuickItemView::setModel(const QVariant &m) connect(d->model, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(modelUpdated(QQmlChangeSet,bool))); + if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) + QObjectPrivate::connect(dataModel, &QQmlDelegateModel::delegateChanged, d, &QQuickItemViewPrivate::applyDelegateChange); emit countChanged(); } emit modelChanged(); @@ -277,22 +279,8 @@ void QQuickItemView::setDelegate(QQmlComponent *delegate) if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) { int oldCount = dataModel->count(); dataModel->setDelegate(delegate); - if (isComponentComplete()) { - d->releaseVisibleItems(); - d->releaseItem(d->currentItem); - d->currentItem = nullptr; - d->updateSectionCriteria(); - d->refill(); - d->moveReason = QQuickItemViewPrivate::SetIndex; - d->updateCurrent(d->currentIndex); - if (d->highlight && d->currentItem) { - if (d->autoHighlight) - d->resetHighlightPosition(); - d->updateTrackedItem(); - } - d->moveReason = QQuickItemViewPrivate::Other; - d->updateViewport(); - } + if (isComponentComplete()) + d->applyDelegateChange(); if (oldCount != dataModel->count()) emit countChanged(); } @@ -1089,6 +1077,24 @@ qreal QQuickItemViewPrivate::calculatedMaxExtent() const return maxExtent; } +void QQuickItemViewPrivate::applyDelegateChange() +{ + releaseVisibleItems(); + releaseItem(currentItem); + currentItem = nullptr; + updateSectionCriteria(); + refill(); + moveReason = QQuickItemViewPrivate::SetIndex; + updateCurrent(currentIndex); + if (highlight && currentItem) { + if (autoHighlight) + resetHighlightPosition(); + updateTrackedItem(); + } + moveReason = QQuickItemViewPrivate::Other; + updateViewport(); +} + // for debugging only void QQuickItemViewPrivate::checkVisible() const { diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index ef674f0fc7..860cf5fa20 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -191,6 +191,8 @@ public: qreal calculatedMinExtent() const; qreal calculatedMaxExtent() const; + void applyDelegateChange(); + void applyPendingChanges(); bool applyModelChanges(ChangeResult *insertionResult, ChangeResult *removalResult); bool applyRemovalChange(const QQmlChangeSet::Change &removal, ChangeResult *changeResult, int *removedCount); diff --git a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp index 32008f675a..fe56cad018 100644 --- a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp +++ b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp @@ -432,6 +432,7 @@ private slots: void asynchronousCancel(); void invalidContext(); void externalManagedModel(); + void delegateModelChangeDelegate(); private: template <int N> void groups_verify( @@ -4302,6 +4303,45 @@ void tst_qquickvisualdatamodel::externalManagedModel() QTRY_VERIFY(!object->property("running").toBool()); } +void tst_qquickvisualdatamodel::delegateModelChangeDelegate() +{ + // Verify that QTBUG-63477 is fixed. + // Changing the delegate would not update existing items. + QQmlEngine engine; + QScopedPointer<QQmlContext> context(new QQmlContext(engine.rootContext())); + + QQmlComponent c(&engine); + c.setData("import QtQml.Models 2.2\nDelegateModel {}\n", QUrl()); + QCOMPARE(c.status(), QQmlComponent::Ready); + + QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(c.create(context.data())); + QVERIFY(visualModel); + visualModel->setModel(QVariant(3)); + + QQmlComponent first(&engine); + first.setData("import QtQuick 2.0\nItem { objectName: \"old\" }\n", QUrl()); + QCOMPARE(first.status(), QQmlComponent::Ready); + + // Without delegate, claim to have an item count of 0 + QCOMPARE(visualModel->count(), 0); + + visualModel->setDelegate(&first); + // The first delegate has been set, verify we get it + QObject* old = visualModel->object(0, QQmlIncubator::Synchronous); + QVERIFY(old); + QCOMPARE(visualModel->object(0, QQmlIncubator::Synchronous)->objectName(), QStringLiteral("old")); + QCOMPARE(visualModel->count(), 3); + + QQmlComponent second(&engine); + second.setData("import QtQuick 2.0\nItem { objectName: \"new\" }\n", QUrl()); + QCOMPARE(second.status(), QQmlComponent::Ready); + + visualModel->setDelegate(&second); + // After changing the delegate, expect the existing item to have the new delegate + QCOMPARE(visualModel->object(0, QQmlIncubator::Synchronous)->objectName(), QStringLiteral("new")); + QCOMPARE(visualModel->count(), 3); +} + QTEST_MAIN(tst_qquickvisualdatamodel) #include "tst_qquickvisualdatamodel.moc" |