aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <[email protected]>2025-09-12 13:41:21 +0200
committerUlf Hermann <[email protected]>2025-09-15 20:08:03 +0200
commitc66fb45c886781c8af85e15c8e8af7305ab38fed (patch)
treeeea51d1cfecac41d135df9067c63b9a4d395eb32
parenta5ad373e6e19909a814a813daafd8402cf5153bd (diff)
QmlModels: Signal list model changes also via QQmlTableInstanceModel
Allow QQmlDelegateModelItemMetaType to store any QQmlInstanceModel, but also store the kind of model we're dealing with so that we can quickly produce a QQmlDelegateModel or a QQmlTableInstanceModel when necessary. This allows us to send the modelChanged() signal. We do not expect to perform the same trickery that QQmlDelegateModel and QQmlTableInstanceModel do more often. Therefore this solution does not need to scale beyond those. Pick-to: 6.10 Task-number: QTBUG-139941 Change-Id: Id6d2a8ae5f96b755a776eb354e6ae291314dbf7b Reviewed-by: Sami Shalayel <[email protected]>
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp86
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p_p.h25
-rw-r--r--src/qmlmodels/qqmldmlistaccessordata.cpp3
-rw-r--r--src/qmlmodels/qqmltableinstancemodel.cpp4
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp21
5 files changed, 103 insertions, 36 deletions
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index 51c875465e..032a7b71f9 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -16,6 +16,7 @@
#include <private/qqmlcomponent_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlpropertytopropertybinding_p.h>
+#include <private/qqmltableinstancemodel_p.h>
#include <private/qquickpackage_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4objectiterator_p.h>
@@ -2250,11 +2251,34 @@ QQmlDelegateModelItemMetaType::QQmlDelegateModelItemMetaType(
: model(model)
, v4Engine(engine)
, groupNames(groupNames)
+ , modelKind(ModelKind::DelegateModel)
+{
+}
+
+QQmlDelegateModelItemMetaType::QQmlDelegateModelItemMetaType(
+ QV4::ExecutionEngine *engine, QQmlTableInstanceModel *model)
+ : model(model)
+ , v4Engine(engine)
+ , modelKind(ModelKind::TableInstanceModel)
{
}
QQmlDelegateModelItemMetaType::~QQmlDelegateModelItemMetaType() = default;
+void QQmlDelegateModelItemMetaType::emitModelChanged() const
+{
+ switch (modelKind) {
+ case ModelKind::InstanceModel:
+ break;
+ case ModelKind::DelegateModel:
+ emit static_cast<QQmlDelegateModel *>(model.data())->modelChanged();
+ break;
+ case ModelKind::TableInstanceModel:
+ emit static_cast<QQmlTableInstanceModel *>(model.data())->modelChanged();
+ break;
+ }
+}
+
void QQmlDelegateModelItemMetaType::initializeAttachedMetaObject()
{
QMetaObjectBuilder builder;
@@ -2417,10 +2441,11 @@ QV4::ReturnedValue QQmlDelegateModelItem::set_groups(const QV4::FunctionObject *
if (!argc)
THROW_TYPE_ERROR();
- if (!o->d()->item->metaType->model)
+ QQmlDelegateModel *delegateModel = o->d()->item->metaType->delegateModel();
+ if (!delegateModel)
RETURN_UNDEFINED();
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->d()->item->metaType->model);
+ QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(delegateModel);
const int groupFlags = model->m_cacheMetaType->parseGroups(argv[0]);
const int cacheIndex = model->m_cache.indexOf(o->d()->item);
Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
@@ -2435,16 +2460,16 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_member(QQmlDelegateModelItem *this
QV4::ReturnedValue QQmlDelegateModelItem::set_member(QQmlDelegateModelItem *cacheItem, uint flag, const QV4::Value &arg)
{
- if (!cacheItem->metaType->model)
- return QV4::Encode::undefined();
-
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(cacheItem->metaType->model);
-
bool member = arg.toBoolean();
uint groupFlag = (1 << flag);
if (member == ((cacheItem->groups & groupFlag) != 0))
return QV4::Encode::undefined();
+ QQmlDelegateModel *delegateModel = cacheItem->metaType->delegateModel();
+ if (!delegateModel)
+ return QV4::Encode::undefined();
+
+ QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(delegateModel);
const int cacheIndex = model->m_cache.indexOf(cacheItem);
Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
if (member)
@@ -2510,8 +2535,8 @@ QQmlDelegateModelItem::~QQmlDelegateModelItem()
Q_ASSERT(!object);
if (incubationTask) {
- if (metaType->model)
- QQmlDelegateModelPrivate::get(metaType->model)->releaseIncubator(incubationTask);
+ if (QQmlDelegateModel *delegateModel = metaType->delegateModel())
+ QQmlDelegateModelPrivate::get(delegateModel)->releaseIncubator(incubationTask);
else
delete incubationTask;
}
@@ -2523,10 +2548,9 @@ void QQmlDelegateModelItem::dispose()
if (isReferenced())
return;
- if (metaType->model) {
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(metaType->model);
- model->removeCacheItem(this);
- }
+ if (QQmlDelegateModel *delegateModel = metaType->delegateModel())
+ QQmlDelegateModelPrivate::get(delegateModel)->removeCacheItem(this);
+
delete this;
}
@@ -2607,9 +2631,8 @@ QQmlDelegateModelItem *QQmlDelegateModelItem::dataForObject(QObject *object)
int QQmlDelegateModelItem::groupIndex(Compositor::Group group)
{
- if (QQmlDelegateModelPrivate * const model = metaType->model
- ? QQmlDelegateModelPrivate::get(metaType->model)
- : nullptr) {
+ if (QQmlDelegateModel *delegateModel = metaType->delegateModel()) {
+ QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(delegateModel);
return model->m_compositor.find(Compositor::Cache, model->m_cache.indexOf(this)).index[group];
}
return -1;
@@ -2656,9 +2679,10 @@ int QQmlDelegateModelAttachedMetaObject::metaCall(QObject *object, QMetaObject::
}
} else if (call == QMetaObject::WriteProperty) {
if (_id >= memberPropertyOffset) {
- if (!metaType->model)
+ QQmlDelegateModel *delegateModel = metaType->delegateModel();
+ if (!delegateModel)
return -1;
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(metaType->model);
+ QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(delegateModel);
Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
const int groupFlag = 1 << group;
const bool member = attached->m_cacheItem->groups & groupFlag;
@@ -2714,8 +2738,8 @@ void QQmlDelegateModelAttached::resetCurrentIndex()
if (QQDMIncubationTask *incubationTask = m_cacheItem->incubationTask) {
for (qsizetype i = 1, end = metaType->groupCount(); i <= end; ++i)
m_currentIndex[i] = incubationTask->index[i];
- } else {
- QQmlDelegateModelPrivate * const model = QQmlDelegateModelPrivate::get(m_cacheItem->metaType->model);
+ } else if (QQmlDelegateModel *delegateModel = metaType->delegateModel()) {
+ QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(delegateModel);
Compositor::iterator it = model->m_compositor.find(
Compositor::Cache, model->m_cache.indexOf(m_cacheItem));
for (qsizetype i = 1, end = metaType->groupCount(); i <= end; ++i)
@@ -2745,9 +2769,14 @@ int QQmlDelegateModelAttached::persistedItemsIndex() const
void QQmlDelegateModelAttached::setInGroup(QQmlListCompositor::Group group, bool inGroup)
{
- if (!(m_cacheItem && m_cacheItem->metaType && m_cacheItem->metaType->model))
+ if (!m_cacheItem)
+ return;
+
+ QQmlDelegateModel *delegateModel = m_cacheItem->metaType->delegateModel();
+ if (!delegateModel)
return;
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_cacheItem->metaType->model);
+
+ QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(delegateModel);
const uint groupFlag = (1 << group);
if (inGroup == bool(m_cacheItem->groups & groupFlag))
return;
@@ -2791,7 +2820,7 @@ int QQmlDelegateModelAttached::itemsIndex() const
QQmlDelegateModel *QQmlDelegateModelAttached::model() const
{
- return m_cacheItem ? m_cacheItem->metaType->model : nullptr;
+ return m_cacheItem ? m_cacheItem->metaType->delegateModel() : nullptr;
}
/*!
@@ -2821,8 +2850,11 @@ void QQmlDelegateModelAttached::setGroups(const QStringList &groups)
if (!m_cacheItem)
return;
- QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_cacheItem->metaType->model);
+ QQmlDelegateModel *delegateModel = m_cacheItem->metaType->delegateModel();
+ if (!delegateModel)
+ return;
+ QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(delegateModel);
const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
@@ -3177,10 +3209,8 @@ bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::Value &value, int *ind
if (object) {
QQmlDelegateModelItem * const cacheItem = object->d()->item;
- if (QQmlDelegateModelPrivate *model = cacheItem->metaType->model
- ? QQmlDelegateModelPrivate::get(cacheItem->metaType->model)
- : nullptr) {
- *index = model->m_cache.indexOf(cacheItem);
+ if (QQmlDelegateModel *delegateModel = cacheItem->metaType->delegateModel()) {
+ *index = QQmlDelegateModelPrivate::get(delegateModel)->m_cache.indexOf(cacheItem);
*group = Compositor::Cache;
return true;
}
diff --git a/src/qmlmodels/qqmldelegatemodel_p_p.h b/src/qmlmodels/qqmldelegatemodel_p_p.h
index 367504d7fc..1eff54162a 100644
--- a/src/qmlmodels/qqmldelegatemodel_p_p.h
+++ b/src/qmlmodels/qqmldelegatemodel_p_p.h
@@ -37,12 +37,22 @@ typedef QQmlListCompositor Compositor;
class QQmlDelegateModelAttachedMetaObject;
class QQmlAbstractDelegateComponent;
+class QQmlTableInstanceModel;
class Q_QMLMODELS_EXPORT QQmlDelegateModelItemMetaType final
: public QQmlRefCounted<QQmlDelegateModelItemMetaType>
{
public:
- QQmlDelegateModelItemMetaType(QV4::ExecutionEngine *engine, QQmlDelegateModel *model, const QStringList &groupNames);
+ enum class ModelKind : quint8 {
+ InstanceModel,
+ DelegateModel,
+ TableInstanceModel,
+ };
+
+ QQmlDelegateModelItemMetaType(
+ QV4::ExecutionEngine *engine, QQmlDelegateModel *model, const QStringList &groupNames);
+ QQmlDelegateModelItemMetaType(
+ QV4::ExecutionEngine *engine, QQmlTableInstanceModel *model);
~QQmlDelegateModelItemMetaType();
void initializeAttachedMetaObject();
@@ -51,12 +61,23 @@ public:
int parseGroups(const QStringList &groupNames) const;
int parseGroups(const QV4::Value &groupNames) const;
- QPointer<QQmlDelegateModel> model;
+ QQmlDelegateModel *delegateModel() const
+ {
+ return modelKind == ModelKind::DelegateModel
+ ? static_cast<QQmlDelegateModel *>(model.get())
+ : nullptr;
+ }
+
qsizetype groupCount() const { return groupNames.size(); }
+
+ void emitModelChanged() const;
+
+ QPointer<QQmlInstanceModel> model;
QV4::ExecutionEngine * const v4Engine;
QQmlRefPointer<QQmlDelegateModelAttachedMetaObject> attachedMetaObject;
const QStringList groupNames;
QV4::PersistentValue modelItemProto;
+ ModelKind modelKind = ModelKind::InstanceModel;
};
class QQmlAdaptorModel;
diff --git a/src/qmlmodels/qqmldmlistaccessordata.cpp b/src/qmlmodels/qqmldmlistaccessordata.cpp
index 99e1612f80..4eedb8b772 100644
--- a/src/qmlmodels/qqmldmlistaccessordata.cpp
+++ b/src/qmlmodels/qqmldmlistaccessordata.cpp
@@ -99,8 +99,7 @@ int VDMListDelegateDataType::metaCall(
accessor->cachedDataClean = false;
} else {
model->list.set(accessor->index, data);
- if (QQmlDelegateModel *delegateModel = accessor->metaType->model)
- emit delegateModel->modelChanged();
+ accessor->metaType->emitModelChanged();
}
QMetaObject::activate(accessor, this, id - propertyOffset, nullptr);
emit accessor->modelDataChanged();
diff --git a/src/qmlmodels/qqmltableinstancemodel.cpp b/src/qmlmodels/qqmltableinstancemodel.cpp
index d07808ffe5..c19bcf3138 100644
--- a/src/qmlmodels/qqmltableinstancemodel.cpp
+++ b/src/qmlmodels/qqmltableinstancemodel.cpp
@@ -36,8 +36,8 @@ void QQmlTableInstanceModel::deleteModelItemLater(QQmlDelegateModelItem *modelIt
QQmlTableInstanceModel::QQmlTableInstanceModel(QQmlContext *qmlContext, QObject *parent)
: QQmlInstanceModel(*(new QObjectPrivate()), parent)
, m_qmlContext(qmlContext)
- , m_metaType(new QQmlDelegateModelItemMetaType(m_qmlContext->engine()->handle(), nullptr, QStringList()),
- QQmlRefPointer<QQmlDelegateModelItemMetaType>::Adopt)
+ , m_metaType(QQml::makeRefPointer<QQmlDelegateModelItemMetaType>(
+ m_qmlContext->engine()->handle(), this))
{
}
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 7a04a6ab7d..b80aaba10c 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -8355,6 +8355,8 @@ void tst_QQuickTableView::delegateModelAccess()
const QUrl url = testFileUrl("delegateModelAccess.qml");
LOAD_TABLEVIEW("delegateModelAccess.qml");
+ QSignalSpy modelChangedSpy(tableView, &QQuickTableView::modelChanged);
+
if (delegateKind == Delegate::Untyped && modelKind == Model::Array)
QSKIP("Properties of objects in arrays are not exposed as context properties");
@@ -8394,24 +8396,38 @@ void tst_QQuickTableView::delegateModelAccess()
// (like with DelegateModel).
(access == QQmlDelegateModel::Qt5ReadWrite && delegateKind == Delegate::Typed);
+ // Only the array is actually updated itself. The other models are pointers
+ const bool writeShouldSignal = modelKind == Model::Kind::Array;
+
double expected = 11;
+ // Initial setting of the model, signals one update
+ int expectedModelUpdates = 1;
+ QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
+
QCOMPARE(delegate->property("immediateX").toDouble(), expected);
QCOMPARE(delegate->property("modelX").toDouble(), expected);
- if (modelWritable)
+ if (modelWritable) {
expected = 3;
+ if (writeShouldSignal)
+ ++expectedModelUpdates;
+ }
QMetaObject::invokeMethod(delegate, "writeThroughModel");
QCOMPARE(delegate->property("immediateX").toDouble(), expected);
QCOMPARE(delegate->property("modelX").toDouble(), expected);
+ QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
double aAt0 = -1;
QMetaObject::invokeMethod(tableView, "aAt0", Q_RETURN_ARG(double, aAt0));
QCOMPARE(aAt0, writeShouldPropagate ? expected : 11);
- if (immediateWritable)
+ if (immediateWritable) {
expected = 1;
+ if (writeShouldSignal)
+ ++expectedModelUpdates;
+ }
QMetaObject::invokeMethod(delegate, "writeImmediate");
@@ -8420,6 +8436,7 @@ void tst_QQuickTableView::delegateModelAccess()
delegateKind == Delegate::Untyped ? expected : 1);
QCOMPARE(delegate->property("modelX").toDouble(), expected);
+ QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
aAt0 = -1;
QMetaObject::invokeMethod(tableView, "aAt0", Q_RETURN_ARG(double, aAt0));