diff options
author | Ulf Hermann <[email protected]> | 2025-09-11 14:01:58 +0200 |
---|---|---|
committer | Ulf Hermann <[email protected]> | 2025-09-15 20:07:59 +0200 |
commit | a5ad373e6e19909a814a813daafd8402cf5153bd (patch) | |
tree | b9760ad7dc05940564f9de4fb165416f7e12a030 | |
parent | 7105eb6d0d46949e235d213cfe77dda95f16c6c5 (diff) |
QQuickTableView: Expose internal model changes via the model property
If the delegate changes the model, those changes need to be visible in
the "model" property of the view. To this end, use
QQmlTableInstanceModel's model variant instead of the assigned one once
it has been synchronized.
The inner change signaling from the delegates to the view will be
added in a separate change.
Pick-to: 6.10
Task-number: QTBUG-139941
Change-Id: I1296fa2c886dad063b6b39defef56cb7faf1e943
Reviewed-by: Sami Shalayel <[email protected]>
-rw-r--r-- | src/qmlmodels/qqmltableinstancemodel.cpp | 19 | ||||
-rw-r--r-- | src/qmlmodels/qqmltableinstancemodel_p.h | 4 | ||||
-rw-r--r-- | src/quick/items/qquicktableview.cpp | 18 | ||||
-rw-r--r-- | src/quick/items/qquicktableview_p_p.h | 1 | ||||
-rw-r--r-- | tests/auto/quick/qquicktableview/data/delegateModelAccess.qml | 13 | ||||
-rw-r--r-- | tests/auto/quick/qquicktableview/tst_qquicktableview.cpp | 20 |
6 files changed, 71 insertions, 4 deletions
diff --git a/src/qmlmodels/qqmltableinstancemodel.cpp b/src/qmlmodels/qqmltableinstancemodel.cpp index 77564e3fe7..d07808ffe5 100644 --- a/src/qmlmodels/qqmltableinstancemodel.cpp +++ b/src/qmlmodels/qqmltableinstancemodel.cpp @@ -452,7 +452,7 @@ QVariant QQmlTableInstanceModel::model() const return m_adaptorModel.model(); } -void QQmlTableInstanceModel::setModel(const QVariant &model) +void QQmlTableInstanceModel::forceSetModel(const QVariant &model) { // Pooled items are still accessible/alive for the application, and // needs to stay in sync with the model. So we need to drain the pool @@ -469,6 +469,16 @@ void QQmlTableInstanceModel::setModel(const QVariant &model) } } +void QQmlTableInstanceModel::setModel(const QVariant &model) +{ + if (m_adaptorModel.model() == model) + return; + + forceSetModel(model); + + emit modelChanged(); +} + void QQmlTableInstanceModel::dataChangedCallback(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles) { // This function is called when model data has changed. In that case, we tell the adaptor model @@ -494,8 +504,11 @@ void QQmlTableInstanceModel::modelAboutToBeResetCallback() auto const aim = abstractItemModel(); auto oldRoleNames = aim->roleNames(); QObject::connect(aim, &QAbstractItemModel::modelReset, this, [this, aim, oldRoleNames](){ - if (oldRoleNames != aim->roleNames()) - setModel(model()); + if (oldRoleNames != aim->roleNames()) { + // We refresh the model, but without sending any signals. The actual model object + // stays the same after all. + forceSetModel(model()); + } }, Qt::SingleShotConnection); } diff --git a/src/qmlmodels/qqmltableinstancemodel_p.h b/src/qmlmodels/qqmltableinstancemodel_p.h index eabb0e2067..bf2309dcff 100644 --- a/src/qmlmodels/qqmltableinstancemodel_p.h +++ b/src/qmlmodels/qqmltableinstancemodel_p.h @@ -102,6 +102,9 @@ public: QQmlDelegateModelItem *getModelItem(int index); +signals: + void modelChanged(); + private: enum DestructionMode { Deferred, @@ -129,6 +132,7 @@ private: void dataChangedCallback(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles); void modelAboutToBeResetCallback(); + void forceSetModel(const QVariant &model); static bool isDoneIncubating(QQmlDelegateModelItem *modelItem); static void deleteModelItemLater(QQmlDelegateModelItem *modelItem); diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp index 6c8ace80e6..56e5819080 100644 --- a/src/quick/items/qquicktableview.cpp +++ b/src/quick/items/qquicktableview.cpp @@ -4573,12 +4573,17 @@ void QQuickTableViewPrivate::syncDelegateModelAccess() QVariant QQuickTableViewPrivate::modelImpl() const { - return assignedModel; + if (needsModelSynchronization) + return assignedModel; + if (tableModel) + return tableModel->model(); + return QVariant::fromValue(model); } void QQuickTableViewPrivate::setModelImpl(const QVariant &newModel) { assignedModel = newModel; + needsModelSynchronization = true; scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All); emit q_func()->modelChanged(); } @@ -4612,6 +4617,7 @@ void QQuickTableViewPrivate::syncModel() tableModel->setModel(assignedModel); } + needsModelSynchronization = false; connectToModel(); } @@ -4748,6 +4754,11 @@ void QQuickTableViewPrivate::connectToModel() } else { QObjectPrivate::connect(model, &QQmlInstanceModel::modelUpdated, this, &QQuickTableViewPrivate::modelUpdated); } + + if (tableModel) { + QObject::connect(tableModel, &QQmlTableInstanceModel::modelChanged, + q, &QQuickTableView::modelChanged); + } } void QQuickTableViewPrivate::disconnectFromModel() @@ -4774,6 +4785,11 @@ void QQuickTableViewPrivate::disconnectFromModel() } else { QObjectPrivate::disconnect(model, &QQmlInstanceModel::modelUpdated, this, &QQuickTableViewPrivate::modelUpdated); } + + if (tableModel) { + QObject::disconnect(tableModel, &QQmlTableInstanceModel::modelChanged, + q, &QQuickTableView::modelChanged); + } } void QQuickTableViewPrivate::modelUpdated(const QQmlChangeSet &changeSet, bool reset) diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h index 3db877e4a3..4cdd94f3d3 100644 --- a/src/quick/items/qquicktableview_p_p.h +++ b/src/quick/items/qquicktableview_p_p.h @@ -427,6 +427,7 @@ public: QItemSelectionModel::SelectionFlag selectionFlag = QItemSelectionModel::NoUpdate; std::function<void(CallBackFlag)> selectableCallbackFunction; bool inSelectionModelUpdate = false; + bool needsModelSynchronization = false; int assignedPositionViewAtRowAfterRebuild = 0; int assignedPositionViewAtColumnAfterRebuild = 0; diff --git a/tests/auto/quick/qquicktableview/data/delegateModelAccess.qml b/tests/auto/quick/qquicktableview/data/delegateModelAccess.qml index 21e67bb5d3..5652d986ee 100644 --- a/tests/auto/quick/qquicktableview/data/delegateModelAccess.qml +++ b/tests/auto/quick/qquicktableview/data/delegateModelAccess.qml @@ -68,6 +68,19 @@ Item { property int y: 12 } + function aAt0() : real { + switch (modelIndex) { + case Model.Singular: + case Model.List: + return model.get(0).a + case Model.Array: + return model[0].a + case Model.Object: + return model.a + } + return -1; + } + property int modelIndex: Model.None property int delegateIndex: Delegate.None diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index 6205b92acf..7a04a6ab7d 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -8382,6 +8382,18 @@ void tst_QQuickTableView::delegateModelAccess() ? access != QQmlDelegateModel::ReadOnly : access == QQmlDelegateModel::ReadWrite; + const bool writeShouldPropagate = + + // If we've explicitly asked for the model to be written, it is + (access == QQmlDelegateModel::ReadWrite) || + + // If it's a QAIM or an object, it's implicitly written + (modelKind != Model::Kind::Array) || + + // When writing through the model object from a typed delegate, + // (like with DelegateModel). + (access == QQmlDelegateModel::Qt5ReadWrite && delegateKind == Delegate::Typed); + double expected = 11; QCOMPARE(delegate->property("immediateX").toDouble(), expected); @@ -8394,6 +8406,10 @@ void tst_QQuickTableView::delegateModelAccess() QCOMPARE(delegate->property("immediateX").toDouble(), expected); QCOMPARE(delegate->property("modelX").toDouble(), expected); + double aAt0 = -1; + QMetaObject::invokeMethod(tableView, "aAt0", Q_RETURN_ARG(double, aAt0)); + QCOMPARE(aAt0, writeShouldPropagate ? expected : 11); + if (immediateWritable) expected = 1; @@ -8404,6 +8420,10 @@ void tst_QQuickTableView::delegateModelAccess() delegateKind == Delegate::Untyped ? expected : 1); QCOMPARE(delegate->property("modelX").toDouble(), expected); + + aAt0 = -1; + QMetaObject::invokeMethod(tableView, "aAt0", Q_RETURN_ARG(double, aAt0)); + QCOMPARE(aAt0, writeShouldPropagate ? expected : 11); } void tst_QQuickTableView::checkVisualRowColumnAfterReorder() |