aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlmodels')
-rw-r--r--src/qmlmodels/CMakeLists.txt10
-rw-r--r--src/qmlmodels/doc/qtqmlmodels.qdocconf2
-rw-r--r--src/qmlmodels/doc/snippets/delegatemodel/delegatemodel.qml4
-rw-r--r--src/qmlmodels/doc/snippets/delegatemodel/delegatemodel_rootindex/view.qml4
-rw-r--r--src/qmlmodels/doc/snippets/delegatemodel/delegatemodelgroup.qml4
-rw-r--r--src/qmlmodels/doc/snippets/package/Delegate.qml2
-rw-r--r--src/qmlmodels/doc/snippets/package/view.qml4
-rw-r--r--src/qmlmodels/doc/snippets/qml/listmodel/WorkerScript.qml43
-rw-r--r--src/qmlmodels/doc/snippets/qml/listmodel/dataloader.mjs13
-rw-r--r--src/qmlmodels/doc/snippets/qml/listmodel/listelements.qml2
-rw-r--r--src/qmlmodels/doc/snippets/qml/listmodel/listmodel-modify.qml2
-rw-r--r--src/qmlmodels/doc/snippets/qml/listmodel/listmodel-nested.qml2
-rw-r--r--src/qmlmodels/doc/snippets/qml/listmodel/listmodel-simple.qml2
-rw-r--r--src/qmlmodels/doc/snippets/qml/listmodel/listmodel.qml2
-rw-r--r--src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-complex.qml6
-rw-r--r--src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-delegatechooser.qml6
-rw-r--r--src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-simpledelegate.qml6
-rw-r--r--src/qmlmodels/doc/src/qtqmlmodel.qdoc2
-rw-r--r--src/qmlmodels/qqmlabstractdelegatecomponent_p.h3
-rw-r--r--src/qmlmodels/qqmladaptormodel.cpp963
-rw-r--r--src/qmlmodels/qqmladaptormodel_p.h8
-rw-r--r--src/qmlmodels/qqmladaptormodelenginedata.cpp24
-rw-r--r--src/qmlmodels/qqmladaptormodelenginedata_p.h68
-rw-r--r--src/qmlmodels/qqmlchangeset.cpp4
-rw-r--r--src/qmlmodels/qqmlchangeset_p.h9
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp307
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p.h41
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p_p.h19
-rw-r--r--src/qmlmodels/qqmldmabstractitemmodeldata.cpp253
-rw-r--r--src/qmlmodels/qqmldmabstractitemmodeldata_p.h339
-rw-r--r--src/qmlmodels/qqmldmlistaccessordata.cpp157
-rw-r--r--src/qmlmodels/qqmldmlistaccessordata_p.h293
-rw-r--r--src/qmlmodels/qqmldmobjectdata.cpp18
-rw-r--r--src/qmlmodels/qqmldmobjectdata_p.h247
-rw-r--r--src/qmlmodels/qqmlinstantiator.cpp38
-rw-r--r--src/qmlmodels/qqmlinstantiator_p.h2
-rw-r--r--src/qmlmodels/qqmlinstantiator_p_p.h5
-rw-r--r--src/qmlmodels/qqmlitemmodels.qdoc7
-rw-r--r--src/qmlmodels/qqmllistaccessor.cpp146
-rw-r--r--src/qmlmodels/qqmllistaccessor_p.h1
-rw-r--r--src/qmlmodels/qqmllistmodel.cpp62
-rw-r--r--src/qmlmodels/qqmllistmodel_p.h11
-rw-r--r--src/qmlmodels/qqmllistmodel_p_p.h17
-rw-r--r--src/qmlmodels/qqmllistmodelworkeragent.cpp6
-rw-r--r--src/qmlmodels/qqmllistmodelworkeragent_p.h12
-rw-r--r--src/qmlmodels/qqmlmodelindexvaluetype_p.h12
-rw-r--r--src/qmlmodels/qqmlobjectmodel_p.h9
-rw-r--r--src/qmlmodels/qqmltableinstancemodel.cpp23
-rw-r--r--src/qmlmodels/qqmltableinstancemodel_p.h5
-rw-r--r--src/qmlmodels/qqmltreemodeltotablemodel.cpp115
-rw-r--r--src/qmlmodels/qqmltreemodeltotablemodel_p_p.h12
-rw-r--r--src/qmlmodels/qquickpackage.cpp4
-rw-r--r--src/qmlmodels/qquickpackage_p.h6
-rw-r--r--src/qmlmodels/qtqmlmodelsglobal_p.h2
54 files changed, 2094 insertions, 1270 deletions
diff --git a/src/qmlmodels/CMakeLists.txt b/src/qmlmodels/CMakeLists.txt
index b3875a8091..510143bb74 100644
--- a/src/qmlmodels/CMakeLists.txt
+++ b/src/qmlmodels/CMakeLists.txt
@@ -12,7 +12,7 @@ qt_internal_add_qml_module(QmlModels
PLUGIN_TARGET modelsplugin
CLASS_NAME QtQmlModelsPlugin
DEPENDENCIES
- QtQml.Base/auto
+ QML/1.0
SOURCES
qqmlchangeset.cpp qqmlchangeset_p.h
qqmlmodelsmodule.cpp qqmlmodelsmodule_p.h
@@ -30,9 +30,7 @@ qt_internal_add_qml_module(QmlModels
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
Qt::QmlPrivate
- GENERATE_CPP_EXPORTS
- GENERATE_PRIVATE_CPP_EXPORTS
-)
+ )
qt_internal_extend_target(QmlModels CONDITION QT_FEATURE_qml_itemmodel
SOURCES
@@ -63,8 +61,12 @@ qt_internal_extend_target(QmlModels CONDITION QT_FEATURE_qml_delegate_model
SOURCES
qqmlabstractdelegatecomponent.cpp qqmlabstractdelegatecomponent_p.h
qqmladaptormodel.cpp qqmladaptormodel_p.h
+ qqmladaptormodelenginedata.cpp qqmladaptormodelenginedata_p.h
qqmldelegatemodel.cpp qqmldelegatemodel_p.h
qqmldelegatemodel_p_p.h
+ qqmldmabstractitemmodeldata.cpp qqmldmabstractitemmodeldata_p.h
+ qqmldmlistaccessordata.cpp qqmldmlistaccessordata_p.h
+ qqmldmobjectdata.cpp qqmldmobjectdata_p.h
qqmllistaccessor.cpp qqmllistaccessor_p.h
qqmllistcompositor.cpp qqmllistcompositor_p.h
qquickpackage.cpp qquickpackage_p.h
diff --git a/src/qmlmodels/doc/qtqmlmodels.qdocconf b/src/qmlmodels/doc/qtqmlmodels.qdocconf
index 35910b7c71..5c9c04a85a 100644
--- a/src/qmlmodels/doc/qtqmlmodels.qdocconf
+++ b/src/qmlmodels/doc/qtqmlmodels.qdocconf
@@ -35,5 +35,5 @@ navigation.qmltypespage = "Qt Qml Models QML Types"
# suppress qdoc warnings for \instantiates entries
spurious += "C\\+\\+ class .*\\\\instantiates .*"
-# Fail the documentation build if there are more warnings than the limit
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/qmlmodels/doc/snippets/delegatemodel/delegatemodel.qml b/src/qmlmodels/doc/snippets/delegatemodel/delegatemodel.qml
index a2f12d5567..51bba64534 100644
--- a/src/qmlmodels/doc/snippets/delegatemodel/delegatemodel.qml
+++ b/src/qmlmodels/doc/snippets/delegatemodel/delegatemodel.qml
@@ -1,8 +1,8 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
-import QtQml.Models 2.2
+import QtQuick
+import QtQml.Models
Rectangle {
width: 200; height: 100
diff --git a/src/qmlmodels/doc/snippets/delegatemodel/delegatemodel_rootindex/view.qml b/src/qmlmodels/doc/snippets/delegatemodel/delegatemodel_rootindex/view.qml
index b124bb7b2a..01abaf1909 100644
--- a/src/qmlmodels/doc/snippets/delegatemodel/delegatemodel_rootindex/view.qml
+++ b/src/qmlmodels/doc/snippets/delegatemodel/delegatemodel_rootindex/view.qml
@@ -1,8 +1,8 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
-import QtQml.Models 2.2
+import QtQuick
+import QtQml.Models
ListView {
id: view
diff --git a/src/qmlmodels/doc/snippets/delegatemodel/delegatemodelgroup.qml b/src/qmlmodels/doc/snippets/delegatemodel/delegatemodelgroup.qml
index 0325d7f7f3..1f55f0d193 100644
--- a/src/qmlmodels/doc/snippets/delegatemodel/delegatemodelgroup.qml
+++ b/src/qmlmodels/doc/snippets/delegatemodel/delegatemodelgroup.qml
@@ -1,8 +1,8 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
-import QtQml.Models 2.2
+import QtQuick
+import QtQml.Models
Rectangle {
width: 200; height: 100
diff --git a/src/qmlmodels/doc/snippets/package/Delegate.qml b/src/qmlmodels/doc/snippets/package/Delegate.qml
index 48edb90125..d671c15b26 100644
--- a/src/qmlmodels/doc/snippets/package/Delegate.qml
+++ b/src/qmlmodels/doc/snippets/package/Delegate.qml
@@ -1,7 +1,7 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
//! [0]
Package {
diff --git a/src/qmlmodels/doc/snippets/package/view.qml b/src/qmlmodels/doc/snippets/package/view.qml
index e0c43dad55..4df31a8498 100644
--- a/src/qmlmodels/doc/snippets/package/view.qml
+++ b/src/qmlmodels/doc/snippets/package/view.qml
@@ -1,8 +1,8 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
-import QtQml.Models 2.1
+import QtQuick
+import QtQml.Models
Rectangle {
id: root
diff --git a/src/qmlmodels/doc/snippets/qml/listmodel/WorkerScript.qml b/src/qmlmodels/doc/snippets/qml/listmodel/WorkerScript.qml
new file mode 100644
index 0000000000..4799878375
--- /dev/null
+++ b/src/qmlmodels/doc/snippets/qml/listmodel/WorkerScript.qml
@@ -0,0 +1,43 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Rectangle {
+ color: "white"
+ width: 200
+ height: 300
+
+ ListView {
+ anchors.fill: parent
+ model: listModel
+ delegate: Component {
+ Text {
+ required property string time
+ text: time
+ }
+ }
+
+ ListModel { id: listModel }
+
+ WorkerScript {
+ id: worker
+ source: "dataloader.mjs"
+ }
+
+// ![0]
+ Timer {
+ id: timer
+ interval: 2000; repeat: true
+ running: true
+ triggeredOnStart: true
+
+ onTriggered: {
+ var msg = {'action': 'appendCurrentTime', 'model': listModel};
+ worker.sendMessage(msg);
+ }
+ }
+// ![0]
+ }
+}
+
diff --git a/src/qmlmodels/doc/snippets/qml/listmodel/dataloader.mjs b/src/qmlmodels/doc/snippets/qml/listmodel/dataloader.mjs
new file mode 100644
index 0000000000..eed1bca6f1
--- /dev/null
+++ b/src/qmlmodels/doc/snippets/qml/listmodel/dataloader.mjs
@@ -0,0 +1,13 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+// ![0]
+WorkerScript.onMessage = function(msg) {
+ if (msg.action == 'appendCurrentTime') {
+ var data = {'time': new Date().toTimeString()};
+ msg.model.append(data);
+ msg.model.sync(); // updates the changes to the list
+ }
+}
+// ![0]
+
diff --git a/src/qmlmodels/doc/snippets/qml/listmodel/listelements.qml b/src/qmlmodels/doc/snippets/qml/listmodel/listelements.qml
index bab4aec6a2..e2a1525534 100644
--- a/src/qmlmodels/doc/snippets/qml/listmodel/listelements.qml
+++ b/src/qmlmodels/doc/snippets/qml/listmodel/listelements.qml
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [document]
-import QtQuick 2.0
+import QtQuick
Item {
width: 200; height: 250
diff --git a/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-modify.qml b/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-modify.qml
index 3178abfcfd..99d6a3adc7 100644
--- a/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-modify.qml
+++ b/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-modify.qml
@@ -1,6 +1,6 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
Rectangle {
width: 200; height: 200
diff --git a/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-nested.qml b/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-nested.qml
index 15a5fc858f..8018f7b69f 100644
--- a/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-nested.qml
+++ b/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-nested.qml
@@ -1,6 +1,6 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick 2.0
+import QtQuick
Rectangle {
width: 200; height: 200
diff --git a/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-simple.qml b/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-simple.qml
index 2640a38f13..8ba0a6d182 100644
--- a/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-simple.qml
+++ b/src/qmlmodels/doc/snippets/qml/listmodel/listmodel-simple.qml
@@ -1,7 +1,7 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
Rectangle {
width: 200; height: 200
diff --git a/src/qmlmodels/doc/snippets/qml/listmodel/listmodel.qml b/src/qmlmodels/doc/snippets/qml/listmodel/listmodel.qml
index 05deec06b6..3eefc4b9a5 100644
--- a/src/qmlmodels/doc/snippets/qml/listmodel/listmodel.qml
+++ b/src/qmlmodels/doc/snippets/qml/listmodel/listmodel.qml
@@ -1,7 +1,7 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![0]
-import QtQuick 2.0
+import QtQuick
ListModel {
id: fruitModel
diff --git a/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-complex.qml b/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-complex.qml
index ab44bf5696..70ce56f599 100644
--- a/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-complex.qml
+++ b/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-complex.qml
@@ -2,9 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![file]
-import QtQuick 2.12
-import QtQuick.Window 2.12
-import Qt.labs.qmlmodels 1.0
+import QtQuick
+import QtQuick.Window
+import Qt.labs.qmlmodels
Window {
width: 400
diff --git a/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-delegatechooser.qml b/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-delegatechooser.qml
index 45c6f1818d..5241317c4d 100644
--- a/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-delegatechooser.qml
+++ b/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-delegatechooser.qml
@@ -2,9 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![file]
-import QtQuick 2.12
-import QtQuick.Controls 2.5
-import Qt.labs.qmlmodels 1.0
+import QtQuick
+import QtQuick.Controls
+import Qt.labs.qmlmodels
ApplicationWindow {
width: 400
diff --git a/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-simpledelegate.qml b/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-simpledelegate.qml
index e00ae6bfc0..0c9622c440 100644
--- a/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-simpledelegate.qml
+++ b/src/qmlmodels/doc/snippets/qml/tablemodel/fruit-example-simpledelegate.qml
@@ -2,9 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//![file]
-import QtQuick 2.12
-import QtQuick.Window 2.12
-import Qt.labs.qmlmodels 1.0
+import QtQuick
+import QtQuick.Window
+import Qt.labs.qmlmodels
Window {
width: 400
diff --git a/src/qmlmodels/doc/src/qtqmlmodel.qdoc b/src/qmlmodels/doc/src/qtqmlmodel.qdoc
index 321b3fd57b..f75530e93c 100644
--- a/src/qmlmodels/doc/src/qtqmlmodel.qdoc
+++ b/src/qmlmodels/doc/src/qtqmlmodel.qdoc
@@ -17,7 +17,7 @@
\endqml
\note QtQml.Models module started at version 2.1 to match the version
- of the parent module, \l{Qt QML}.
+ of the parent module, \l{Qt Qml}.
In addition, Qt.labs.qmlmodels provides experimental QML types for models.
To use these experimental types, import the module with the following line:
diff --git a/src/qmlmodels/qqmlabstractdelegatecomponent_p.h b/src/qmlmodels/qqmlabstractdelegatecomponent_p.h
index 91339616f7..ae4811dd9c 100644
--- a/src/qmlmodels/qqmlabstractdelegatecomponent_p.h
+++ b/src/qmlmodels/qqmlabstractdelegatecomponent_p.h
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE
// TODO: consider making QQmlAbstractDelegateComponent public API
class QQmlAdaptorModel;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlAbstractDelegateComponent : public QQmlComponent
+class Q_QMLMODELS_EXPORT QQmlAbstractDelegateComponent : public QQmlComponent
{
Q_OBJECT
QML_NAMED_ELEMENT(AbstractDelegateComponent)
@@ -37,6 +37,7 @@ public:
~QQmlAbstractDelegateComponent() override;
virtual QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = 0) const = 0;
+ virtual QString role() const = 0;
Q_SIGNALS:
void delegateChanged();
diff --git a/src/qmlmodels/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp
index dd08f91c61..f72a5e6b16 100644
--- a/src/qmlmodels/qqmladaptormodel.cpp
+++ b/src/qmlmodels/qqmladaptormodel.cpp
@@ -3,949 +3,19 @@
#include "qqmladaptormodel_p.h"
-#include <private/qqmldelegatemodel_p_p.h>
-#include <private/qmetaobjectbuilder_p.h>
-#include <private/qqmlproperty_p.h>
-
-#include <private/qv4value_p.h>
-#include <private/qv4functionobject_p.h>
+#include <private/qqmldmabstractitemmodeldata_p.h>
+#include <private/qqmldmlistaccessordata_p.h>
+#include <private/qqmldmobjectdata_p.h>
QT_BEGIN_NAMESPACE
-class QQmlAdaptorModelEngineData : public QV4::ExecutionEngine::Deletable
-{
-public:
- QQmlAdaptorModelEngineData(QV4::ExecutionEngine *v4);
- ~QQmlAdaptorModelEngineData();
-
- QV4::ExecutionEngine *v4;
- QV4::PersistentValue listItemProto;
-};
-
-V4_DEFINE_EXTENSION(QQmlAdaptorModelEngineData, engineData)
-
-static QV4::ReturnedValue get_index(const QV4::FunctionObject *f, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(f);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object")));
-
- RETURN_RESULT(QV4::Encode(o->d()->item->index));
-}
-
-template <typename T, typename M> static void setModelDataType(QMetaObjectBuilder *builder, M *metaType)
-{
- builder->setFlags(MetaObjectFlag::DynamicMetaObject);
- builder->setClassName(T::staticMetaObject.className());
- builder->setSuperClass(&T::staticMetaObject);
- metaType->propertyOffset = T::staticMetaObject.propertyCount();
- metaType->signalOffset = T::staticMetaObject.methodCount();
-}
-
-static void addProperty(QMetaObjectBuilder *builder, int propertyId, const QByteArray &propertyName, const QByteArray &propertyType)
-{
- builder->addSignal("__" + QByteArray::number(propertyId) + "()");
- QMetaPropertyBuilder property = builder->addProperty(
- propertyName, propertyType, propertyId);
- property.setWritable(true);
-}
-
-class VDMModelDelegateDataType;
-
-class QQmlDMCachedModelData : public QQmlDelegateModelItem
-{
-public:
- QQmlDMCachedModelData(
- const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
- VDMModelDelegateDataType *dataType,
- int index, int row, int column);
-
- int metaCall(QMetaObject::Call call, int id, void **arguments);
-
- virtual QVariant value(int role) const = 0;
- virtual void setValue(int role, const QVariant &value) = 0;
-
- void setValue(const QString &role, const QVariant &value) override;
- bool resolveIndex(const QQmlAdaptorModel &model, int idx) override;
-
- static QV4::ReturnedValue get_property(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
- static QV4::ReturnedValue set_property(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
-
- VDMModelDelegateDataType *type;
- QVector<QVariant> cachedData;
-};
-
-class VDMModelDelegateDataType
- : public QQmlRefCount
- , public QQmlAdaptorModel::Accessors
- , public QAbstractDynamicMetaObject
-{
-public:
- VDMModelDelegateDataType(QQmlAdaptorModel *model)
- : model(model)
- , propertyOffset(0)
- , signalOffset(0)
- , hasModelData(false)
- {
- }
-
- bool notify(
- const QQmlAdaptorModel &,
- const QList<QQmlDelegateModelItem *> &items,
- int index,
- int count,
- const QVector<int> &roles) const override
- {
- bool changed = roles.isEmpty() && !watchedRoles.isEmpty();
- if (!changed && !watchedRoles.isEmpty() && watchedRoleIds.isEmpty()) {
- QList<int> roleIds;
- for (const QByteArray &r : watchedRoles) {
- QHash<QByteArray, int>::const_iterator it = roleNames.find(r);
- if (it != roleNames.end())
- roleIds << it.value();
- }
- const_cast<VDMModelDelegateDataType *>(this)->watchedRoleIds = roleIds;
- }
-
- QVector<int> signalIndexes;
- for (int i = 0; i < roles.size(); ++i) {
- const int role = roles.at(i);
- if (!changed && watchedRoleIds.contains(role))
- changed = true;
-
- int propertyId = propertyRoles.indexOf(role);
- if (propertyId != -1)
- signalIndexes.append(propertyId + signalOffset);
- }
- if (roles.isEmpty()) {
- const int propertyRolesCount = propertyRoles.size();
- signalIndexes.reserve(propertyRolesCount);
- for (int propertyId = 0; propertyId < propertyRolesCount; ++propertyId)
- signalIndexes.append(propertyId + signalOffset);
- }
-
- QVarLengthArray<QQmlGuard<QQmlDelegateModelItem>> guardedItems;
- for (const auto item : items)
- guardedItems.append(item);
-
- for (const auto &item : std::as_const(guardedItems)) {
- if (item.isNull())
- continue;
-
- const int idx = item->modelIndex();
- if (idx >= index && idx < index + count) {
- for (int i = 0; i < signalIndexes.size(); ++i)
- QMetaObject::activate(item, signalIndexes.at(i), nullptr);
- }
- }
- return changed;
- }
-
- void replaceWatchedRoles(
- QQmlAdaptorModel &,
- const QList<QByteArray> &oldRoles,
- const QList<QByteArray> &newRoles) const override
- {
- VDMModelDelegateDataType *dataType = const_cast<VDMModelDelegateDataType *>(this);
-
- dataType->watchedRoleIds.clear();
- for (const QByteArray &oldRole : oldRoles)
- dataType->watchedRoles.removeOne(oldRole);
- dataType->watchedRoles += newRoles;
- }
-
- static QV4::ReturnedValue get_hasModelChildren(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
- {
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object")));
-
- const QQmlAdaptorModel *const model = static_cast<QQmlDMCachedModelData *>(o->d()->item)->type->model;
- if (o->d()->item->index >= 0) {
- if (const QAbstractItemModel *const aim = model->aim())
- RETURN_RESULT(QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex))));
- }
- RETURN_RESULT(QV4::Encode(false));
- }
-
-
- void initializeConstructor(QQmlAdaptorModelEngineData *const data)
- {
- QV4::ExecutionEngine *v4 = data->v4;
- QV4::Scope scope(v4);
- QV4::ScopedObject proto(scope, v4->newObject());
- proto->defineAccessorProperty(QStringLiteral("index"), get_index, nullptr);
- proto->defineAccessorProperty(QStringLiteral("hasModelChildren"), get_hasModelChildren, nullptr);
- QV4::ScopedProperty p(scope);
-
- typedef QHash<QByteArray, int>::const_iterator iterator;
- for (iterator it = roleNames.constBegin(), end = roleNames.constEnd(); it != end; ++it) {
- const int propertyId = propertyRoles.indexOf(it.value());
- const QByteArray &propertyName = it.key();
-
- QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
- QV4::ExecutionContext *global = v4->rootContext();
- QV4::ScopedFunctionObject g(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::get_property));
- QV4::ScopedFunctionObject s(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::set_property));
- p->setGetter(g);
- p->setSetter(s);
- proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
- }
- prototype.set(v4, proto);
- }
-
- // QAbstractDynamicMetaObject
-
- void objectDestroyed(QObject *) override
- {
- release();
- }
-
- int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) override
- {
- return static_cast<QQmlDMCachedModelData *>(object)->metaCall(call, id, arguments);
- }
-
- QV4::PersistentValue prototype;
- QList<int> propertyRoles;
- QList<int> watchedRoleIds;
- QList<QByteArray> watchedRoles;
- QHash<QByteArray, int> roleNames;
- QQmlAdaptorModel *model;
- int propertyOffset;
- int signalOffset;
- bool hasModelData;
-};
-
-QQmlDMCachedModelData::QQmlDMCachedModelData(
- const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
- VDMModelDelegateDataType *dataType, int index, int row, int column)
- : QQmlDelegateModelItem(metaType, dataType, index, row, column)
- , type(dataType)
-{
- if (index == -1)
- cachedData.resize(type->hasModelData ? 1 : type->propertyRoles.size());
-
- QObjectPrivate::get(this)->metaObject = type;
-
- type->addref();
-}
-
-int QQmlDMCachedModelData::metaCall(QMetaObject::Call call, int id, void **arguments)
-{
- if (call == QMetaObject::ReadProperty && id >= type->propertyOffset) {
- const int propertyIndex = id - type->propertyOffset;
- if (index == -1) {
- if (!cachedData.isEmpty()) {
- *static_cast<QVariant *>(arguments[0]) = cachedData.at(
- type->hasModelData ? 0 : propertyIndex);
- }
- } else if (*type->model) {
- *static_cast<QVariant *>(arguments[0]) = value(type->propertyRoles.at(propertyIndex));
- }
- return -1;
- } else if (call == QMetaObject::WriteProperty && id >= type->propertyOffset) {
- const int propertyIndex = id - type->propertyOffset;
- if (index == -1) {
- const QMetaObject *meta = metaObject();
- if (cachedData.size() > 1) {
- cachedData[propertyIndex] = *static_cast<QVariant *>(arguments[0]);
- QMetaObject::activate(this, meta, propertyIndex, nullptr);
- } else if (cachedData.size() == 1) {
- cachedData[0] = *static_cast<QVariant *>(arguments[0]);
- QMetaObject::activate(this, meta, 0, nullptr);
- QMetaObject::activate(this, meta, 1, nullptr);
- }
- } else if (*type->model) {
- setValue(type->propertyRoles.at(propertyIndex), *static_cast<QVariant *>(arguments[0]));
- }
- return -1;
- } else {
- return qt_metacall(call, id, arguments);
- }
-}
-
-void QQmlDMCachedModelData::setValue(const QString &role, const QVariant &value)
-{
- QHash<QByteArray, int>::iterator it = type->roleNames.find(role.toUtf8());
- if (it != type->roleNames.end()) {
- for (int i = 0; i < type->propertyRoles.size(); ++i) {
- if (type->propertyRoles.at(i) == *it) {
- cachedData[i] = value;
- return;
- }
- }
- }
-}
-
-bool QQmlDMCachedModelData::resolveIndex(const QQmlAdaptorModel &adaptorModel, int idx)
-{
- if (index == -1) {
- Q_ASSERT(idx >= 0);
- cachedData.clear();
- setModelIndex(idx, adaptorModel.rowAt(idx), adaptorModel.columnAt(idx));
- const QMetaObject *meta = metaObject();
- const int propertyCount = type->propertyRoles.size();
- for (int i = 0; i < propertyCount; ++i)
- QMetaObject::activate(this, meta, i, nullptr);
- return true;
- } else {
- return false;
- }
-}
-
-QV4::ReturnedValue QQmlDMCachedModelData::get_property(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- uint propertyId = static_cast<const QV4::IndexedBuiltinFunction *>(b)->d()->index;
-
- QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item);
- if (o->d()->item->index == -1) {
- if (!modelData->cachedData.isEmpty()) {
- return scope.engine->fromVariant(
- modelData->cachedData.at(modelData->type->hasModelData ? 0 : propertyId));
- }
- } else if (*modelData->type->model) {
- return scope.engine->fromVariant(
- modelData->value(modelData->type->propertyRoles.at(propertyId)));
- }
- return QV4::Encode::undefined();
-}
-
-QV4::ReturnedValue QQmlDMCachedModelData::set_property(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
-{
- QV4::Scope scope(b);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
- if (!o)
- return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
- if (!argc)
- return scope.engine->throwTypeError();
-
- uint propertyId = static_cast<const QV4::IndexedBuiltinFunction *>(b)->d()->index;
-
- if (o->d()->item->index == -1) {
- QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item);
- if (!modelData->cachedData.isEmpty()) {
- if (modelData->cachedData.size() > 1) {
- modelData->cachedData[propertyId]
- = QV4::ExecutionEngine::toVariant(argv[0], QMetaType {});
- QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), propertyId, nullptr);
- } else if (modelData->cachedData.size() == 1) {
- modelData->cachedData[0] = QV4::ExecutionEngine::toVariant(argv[0], QMetaType {});
- QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 0, nullptr);
- QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 1, nullptr);
- }
- }
- }
- return QV4::Encode::undefined();
-}
-
-//-----------------------------------------------------------------
-// QAbstractItemModel
-//-----------------------------------------------------------------
-
-class QQmlDMAbstractItemModelData : public QQmlDMCachedModelData
-{
- Q_OBJECT
- Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT)
-
-public:
- QQmlDMAbstractItemModelData(
- const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
- VDMModelDelegateDataType *dataType,
- int index, int row, int column)
- : QQmlDMCachedModelData(metaType, dataType, index, row, column)
- {
- }
-
- bool hasModelChildren() const
- {
- if (index >= 0) {
- if (const QAbstractItemModel *const model = type->model->aim())
- return model->hasChildren(model->index(row, column, type->model->rootIndex));
- }
- return false;
- }
-
- QVariant value(int role) const override
- {
- if (const QAbstractItemModel *aim = type->model->aim())
- return aim->index(row, column, type->model->rootIndex).data(role);
- return QVariant();
- }
-
- void setValue(int role, const QVariant &value) override
- {
- if (QAbstractItemModel *aim = type->model->aim())
- aim->setData(aim->index(row, column, type->model->rootIndex), value, role);
- }
-
- QV4::ReturnedValue get() override
- {
- if (type->prototype.isUndefined()) {
- QQmlAdaptorModelEngineData * const data = engineData(v4);
- type->initializeConstructor(data);
- }
- QV4::Scope scope(v4);
- QV4::ScopedObject proto(scope, type->prototype.value());
- QV4::ScopedObject o(scope, proto->engine()->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
- o->setPrototypeOf(proto);
- ++scriptRef;
- return o.asReturnedValue();
- }
-};
-
-class VDMAbstractItemModelDataType : public VDMModelDelegateDataType
-{
-public:
- VDMAbstractItemModelDataType(QQmlAdaptorModel *model)
- : VDMModelDelegateDataType(model)
- {
- }
-
- int rowCount(const QQmlAdaptorModel &model) const override
- {
- if (const QAbstractItemModel *aim = model.aim())
- return aim->rowCount(model.rootIndex);
- return 0;
- }
-
- int columnCount(const QQmlAdaptorModel &model) const override
- {
- if (const QAbstractItemModel *aim = model.aim())
- return aim->columnCount(model.rootIndex);
- return 0;
- }
-
- void cleanup(QQmlAdaptorModel &) const override
- {
- release();
- }
-
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
- {
- if (!metaObject) {
- VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
- dataType->initializeMetaType(model);
- }
-
- if (const QAbstractItemModel *aim = model.aim()) {
- QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8());
- if (it != roleNames.end()) {
- return aim->index(model.rowAt(index), model.columnAt(index),
- model.rootIndex).data(*it);
- } else if (role == QLatin1String("hasModelChildren")) {
- return QVariant(aim->hasChildren(aim->index(model.rowAt(index),
- model.columnAt(index),
- model.rootIndex)));
- }
- }
- return QVariant();
- }
-
- QVariant parentModelIndex(const QQmlAdaptorModel &model) const override
- {
- if (const QAbstractItemModel *aim = model.aim())
- return QVariant::fromValue(aim->parent(model.rootIndex));
- return QVariant();
- }
-
- QVariant modelIndex(const QQmlAdaptorModel &model, int index) const override
- {
- if (const QAbstractItemModel *aim = model.aim())
- return QVariant::fromValue(aim->index(model.rowAt(index), model.columnAt(index),
- model.rootIndex));
- return QVariant();
- }
-
- bool canFetchMore(const QQmlAdaptorModel &model) const override
- {
- if (const QAbstractItemModel *aim = model.aim())
- return aim->canFetchMore(model.rootIndex);
- return false;
- }
-
- void fetchMore(QQmlAdaptorModel &model) const override
- {
- if (QAbstractItemModel *aim = model.aim())
- aim->fetchMore(model.rootIndex);
- }
-
- QQmlDelegateModelItem *createItem(
- QQmlAdaptorModel &model,
- const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
- int index, int row, int column) const override
- {
- VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
- if (!metaObject)
- dataType->initializeMetaType(model);
- return new QQmlDMAbstractItemModelData(metaType, dataType, index, row, column);
- }
-
- void initializeMetaType(const QQmlAdaptorModel &model)
- {
- QMetaObjectBuilder builder;
- setModelDataType<QQmlDMAbstractItemModelData>(&builder, this);
-
- const QByteArray propertyType = QByteArrayLiteral("QVariant");
- const QAbstractItemModel *aim = model.aim();
- const QHash<int, QByteArray> names = aim ? aim->roleNames() : QHash<int, QByteArray>();
- for (QHash<int, QByteArray>::const_iterator it = names.begin(), cend = names.end(); it != cend; ++it) {
- const int propertyId = propertyRoles.size();
- propertyRoles.append(it.key());
- roleNames.insert(it.value(), it.key());
- addProperty(&builder, propertyId, it.value(), propertyType);
- }
- if (propertyRoles.size() == 1) {
- hasModelData = true;
- const int role = names.begin().key();
- const QByteArray propertyName = QByteArrayLiteral("modelData");
-
- propertyRoles.append(role);
- roleNames.insert(propertyName, role);
- addProperty(&builder, 1, propertyName, propertyType);
- }
-
- metaObject.reset(builder.toMetaObject());
- *static_cast<QMetaObject *>(this) = *metaObject;
- propertyCache = QQmlPropertyCache::createStandalone(
- metaObject.data(), model.modelItemRevision);
- }
-};
-
-//-----------------------------------------------------------------
-// QQmlListAccessor
-//-----------------------------------------------------------------
-
-class QQmlDMListAccessorData : public QQmlDelegateModelItem
-{
- Q_OBJECT
- Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
-public:
- QQmlDMListAccessorData(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
- QQmlAdaptorModel::Accessors *accessor,
- int index, int row, int column, const QVariant &value)
- : QQmlDelegateModelItem(metaType, accessor, index, row, column)
- , cachedData(value)
- {
- }
-
- QVariant modelData() const
- {
- return cachedData;
- }
-
- void setModelData(const QVariant &data)
- {
- if (data == cachedData)
- return;
-
- cachedData = data;
- emit modelDataChanged();
- }
-
- static QV4::ReturnedValue get_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
- {
- QV4::ExecutionEngine *v4 = b->engine();
- const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
- if (!o)
- return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
-
- return v4->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData);
- }
-
- static QV4::ReturnedValue set_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
- {
- QV4::ExecutionEngine *v4 = b->engine();
- const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
- if (!o)
- return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
- if (!argc)
- return v4->throwTypeError();
-
- static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(
- QV4::ExecutionEngine::toVariant(argv[0], QMetaType {}));
- return QV4::Encode::undefined();
- }
-
- QV4::ReturnedValue get() override
- {
- QQmlAdaptorModelEngineData *data = engineData(v4);
- QV4::Scope scope(v4);
- QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
- QV4::ScopedObject p(scope, data->listItemProto.value());
- o->setPrototypeOf(p);
- ++scriptRef;
- return o.asReturnedValue();
- }
-
- void setValue(const QString &role, const QVariant &value) override
- {
- if (role == QLatin1String("modelData"))
- cachedData = value;
- }
-
- bool resolveIndex(const QQmlAdaptorModel &model, int idx) override
- {
- if (index == -1) {
- index = idx;
- cachedData = model.list.at(idx);
- emit modelIndexChanged();
- emit modelDataChanged();
- return true;
- } else {
- return false;
- }
- }
-
-
-Q_SIGNALS:
- void modelDataChanged();
-
-private:
- QVariant cachedData;
-};
-
-
-class VDMListDelegateDataType : public QQmlRefCount, public QQmlAdaptorModel::Accessors
-{
-public:
- VDMListDelegateDataType()
- : QQmlRefCount()
- , QQmlAdaptorModel::Accessors()
- {}
-
- void cleanup(QQmlAdaptorModel &) const override
- {
- const_cast<VDMListDelegateDataType *>(this)->release();
- }
-
- int rowCount(const QQmlAdaptorModel &model) const override
- {
- return model.list.count();
- }
-
- int columnCount(const QQmlAdaptorModel &) const override
- {
- return 1;
- }
-
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
- {
- const QVariant entry = model.list.at(index);
- if (role == QLatin1String("modelData"))
- return entry;
-
- const QMetaType type = entry.metaType();
- if (type == QMetaType::fromType<QVariantMap>())
- return entry.toMap().value(role);
-
- if (type == QMetaType::fromType<QVariantHash>())
- return entry.toHash().value(role);
-
- const QMetaType::TypeFlags typeFlags = type.flags();
- if (typeFlags & QMetaType::PointerToQObject)
- return entry.value<QObject *>()->property(role.toUtf8());
-
- const QMetaObject *metaObject = type.metaObject();
- if (!metaObject) {
- // NB: This acquires the lock on QQmlMetaTypeData. If we had a QQmlEngine here,
- // we could use QQmlGadgetPtrWrapper::instance() to avoid this.
- if (const QQmlValueType *valueType = QQmlMetaType::valueType(type))
- metaObject = valueType->staticMetaObject();
- else
- return QVariant();
- }
-
- const int propertyIndex = metaObject->indexOfProperty(role.toUtf8());
- return metaObject->property(propertyIndex).readOnGadget(entry.constData());
- }
-
- QQmlDelegateModelItem *createItem(
- QQmlAdaptorModel &model,
- const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
- int index, int row, int column) const override
- {
- VDMListDelegateDataType *dataType = const_cast<VDMListDelegateDataType *>(this);
- if (!propertyCache) {
- dataType->propertyCache = QQmlPropertyCache::createStandalone(
- &QQmlDMListAccessorData::staticMetaObject, model.modelItemRevision);
- }
-
- return new QQmlDMListAccessorData(
- metaType,
- dataType,
- index, row, column,
- index >= 0 && index < model.list.count() ? model.list.at(index) : QVariant());
- }
-
- bool notify(const QQmlAdaptorModel &model, const QList<QQmlDelegateModelItem *> &items, int index, int count, const QVector<int> &) const override
- {
- for (auto modelItem : items) {
- const int modelItemIndex = modelItem->index;
- if (modelItemIndex < index || modelItemIndex >= index + count)
- continue;
-
- auto listModelItem = static_cast<QQmlDMListAccessorData *>(modelItem);
- QVariant updatedModelData = model.list.at(listModelItem->index);
- listModelItem->setModelData(updatedModelData);
- }
- return true;
- }
-};
-
-//-----------------------------------------------------------------
-// QObject
-//-----------------------------------------------------------------
-
-class VDMObjectDelegateDataType;
-class QQmlDMObjectData : public QQmlDelegateModelItem, public QQmlAdaptorModelProxyInterface
-{
- Q_OBJECT
- Q_PROPERTY(QObject *modelData READ modelData NOTIFY modelDataChanged)
- Q_INTERFACES(QQmlAdaptorModelProxyInterface)
-public:
- QQmlDMObjectData(
- const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
- VDMObjectDelegateDataType *dataType,
- int index, int row, int column,
- QObject *object);
-
- void setModelData(QObject *modelData)
- {
- if (modelData == object)
- return;
-
- object = modelData;
- emit modelDataChanged();
- }
-
- QObject *modelData() const { return object; }
- QObject *proxiedObject() override { return object; }
-
- QPointer<QObject> object;
-
-Q_SIGNALS:
- void modelDataChanged();
-};
-
-class VDMObjectDelegateDataType : public QQmlRefCount, public QQmlAdaptorModel::Accessors
-{
-public:
- int propertyOffset;
- int signalOffset;
- bool shared;
- QMetaObjectBuilder builder;
-
- VDMObjectDelegateDataType()
- : propertyOffset(0)
- , signalOffset(0)
- , shared(true)
- {
- }
-
- VDMObjectDelegateDataType(const VDMObjectDelegateDataType &type)
- : QQmlRefCount()
- , QQmlAdaptorModel::Accessors()
- , propertyOffset(type.propertyOffset)
- , signalOffset(type.signalOffset)
- , shared(false)
- , builder(type.metaObject.data(), QMetaObjectBuilder::Properties
- | QMetaObjectBuilder::Signals
- | QMetaObjectBuilder::SuperClass
- | QMetaObjectBuilder::ClassName)
- {
- builder.setFlags(MetaObjectFlag::DynamicMetaObject);
- }
-
- int rowCount(const QQmlAdaptorModel &model) const override
- {
- return model.list.count();
- }
-
- int columnCount(const QQmlAdaptorModel &) const override
- {
- return 1;
- }
-
- QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
- {
- if (QObject *object = model.list.at(index).value<QObject *>())
- return object->property(role.toUtf8());
- return QVariant();
- }
-
- QQmlDelegateModelItem *createItem(
- QQmlAdaptorModel &model,
- const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
- int index, int row, int column) const override
- {
- VDMObjectDelegateDataType *dataType = const_cast<VDMObjectDelegateDataType *>(this);
- if (!metaObject)
- dataType->initializeMetaType(model);
- return index >= 0 && index < model.list.count()
- ? new QQmlDMObjectData(metaType, dataType, index, row, column, qvariant_cast<QObject *>(model.list.at(index)))
- : nullptr;
- }
-
- void initializeMetaType(QQmlAdaptorModel &model)
- {
- Q_UNUSED(model);
- setModelDataType<QQmlDMObjectData>(&builder, this);
-
- metaObject.reset(builder.toMetaObject());
- // Note: ATM we cannot create a shared property cache for this class, since each model
- // object can have different properties. And to make those properties available to the
- // delegate, QQmlDMObjectData makes use of a QAbstractDynamicMetaObject subclass
- // (QQmlDMObjectDataMetaObject), which we cannot represent in a QQmlPropertyCache.
- // By not having a shared property cache, revisioned properties in QQmlDelegateModelItem
- // will always be available to the delegate, regardless of the import version.
- }
-
- void cleanup(QQmlAdaptorModel &) const override
- {
- const_cast<VDMObjectDelegateDataType *>(this)->release();
- }
-
- bool notify(const QQmlAdaptorModel &model, const QList<QQmlDelegateModelItem *> &items, int index, int count, const QVector<int> &) const override
- {
- for (auto modelItem : items) {
- const int modelItemIndex = modelItem->index;
- if (modelItemIndex < index || modelItemIndex >= index + count)
- continue;
-
- auto objectModelItem = static_cast<QQmlDMObjectData *>(modelItem);
- QObject *updatedModelData = qvariant_cast<QObject *>(model.list.at(objectModelItem->index));
- objectModelItem->setModelData(updatedModelData);
- }
- return true;
- }
-};
-
-class QQmlDMObjectDataMetaObject : public QAbstractDynamicMetaObject
-{
-public:
- QQmlDMObjectDataMetaObject(QQmlDMObjectData *data, VDMObjectDelegateDataType *type)
- : m_data(data)
- , m_type(type)
- {
- QObjectPrivate *op = QObjectPrivate::get(m_data);
- *static_cast<QMetaObject *>(this) = *type->metaObject;
- op->metaObject = this;
- m_type->addref();
- }
-
- ~QQmlDMObjectDataMetaObject()
- {
- m_type->release();
- }
-
- int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments) override
- {
- Q_ASSERT(o == m_data);
- Q_UNUSED(o);
-
- static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
- if (id >= m_type->propertyOffset
- && (call == QMetaObject::ReadProperty
- || call == QMetaObject::WriteProperty
- || call == QMetaObject::ResetProperty)) {
- if (m_data->object)
- QMetaObject::metacall(m_data->object, call, id - m_type->propertyOffset + objectPropertyOffset, arguments);
- return -1;
- } else if (id >= m_type->signalOffset && call == QMetaObject::InvokeMetaMethod) {
- QMetaObject::activate(m_data, this, id - m_type->signalOffset, nullptr);
- return -1;
- } else {
- return m_data->qt_metacall(call, id, arguments);
- }
- }
-
- int createProperty(const char *name, const char *) override
- {
- if (!m_data->object)
- return -1;
- const QMetaObject *metaObject = m_data->object->metaObject();
- static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
-
- const int previousPropertyCount = propertyCount() - propertyOffset();
- int propertyIndex = metaObject->indexOfProperty(name);
- if (propertyIndex == -1)
- return -1;
- if (previousPropertyCount + objectPropertyOffset == metaObject->propertyCount())
- return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
-
- if (m_type->shared) {
- VDMObjectDelegateDataType *type = m_type;
- m_type = new VDMObjectDelegateDataType(*m_type);
- type->release();
- }
-
- const int previousMethodCount = methodCount();
- int notifierId = previousMethodCount - methodOffset();
- for (int propertyId = previousPropertyCount; propertyId < metaObject->propertyCount() - objectPropertyOffset; ++propertyId) {
- QMetaProperty property = metaObject->property(propertyId + objectPropertyOffset);
- QMetaPropertyBuilder propertyBuilder;
- if (property.hasNotifySignal()) {
- m_type->builder.addSignal("__" + QByteArray::number(propertyId) + "()");
- propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName(), notifierId);
- ++notifierId;
- } else {
- propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName());
- }
- propertyBuilder.setWritable(property.isWritable());
- propertyBuilder.setResettable(property.isResettable());
- propertyBuilder.setConstant(property.isConstant());
- }
-
- m_type->metaObject.reset(m_type->builder.toMetaObject());
- *static_cast<QMetaObject *>(this) = *m_type->metaObject;
-
- notifierId = previousMethodCount;
- for (int i = previousPropertyCount; i < metaObject->propertyCount() - objectPropertyOffset; ++i) {
- QMetaProperty property = metaObject->property(i + objectPropertyOffset);
- if (property.hasNotifySignal()) {
- QQmlPropertyPrivate::connect(
- m_data->object, property.notifySignalIndex(), m_data, notifierId);
- ++notifierId;
- }
- }
- return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
- }
-
- QQmlDMObjectData *m_data;
- VDMObjectDelegateDataType *m_type;
-};
-
-QQmlDMObjectData::QQmlDMObjectData(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
- VDMObjectDelegateDataType *dataType,
- int index, int row, int column,
- QObject *object)
- : QQmlDelegateModelItem(metaType, dataType, index, row, column)
- , object(object)
-{
- new QQmlDMObjectDataMetaObject(this, dataType);
-}
-
-//-----------------------------------------------------------------
-// QQmlAdaptorModel
-//-----------------------------------------------------------------
-
-static const QQmlAdaptorModel::Accessors qt_vdm_null_accessors;
-
QQmlAdaptorModel::Accessors::~Accessors()
{
}
QQmlAdaptorModel::QQmlAdaptorModel()
: QQmlGuard<QObject>(QQmlAdaptorModel::objectDestroyedImpl, nullptr)
- , accessors(&qt_vdm_null_accessors)
+ , accessors(&m_nullAccessors)
{
}
@@ -983,24 +53,24 @@ void QQmlAdaptorModel::setModel(const QVariant &variant)
} else if (list.type() != QQmlListAccessor::Invalid
&& list.type() != QQmlListAccessor::Instance) { // Null QObject
setObject(nullptr);
- accessors = new VDMListDelegateDataType;
+ accessors = new VDMListDelegateDataType(this);
} else {
setObject(nullptr);
- accessors = &qt_vdm_null_accessors;
+ accessors = &m_nullAccessors;
}
}
void QQmlAdaptorModel::invalidateModel()
{
accessors->cleanup(*this);
- accessors = &qt_vdm_null_accessors;
+ accessors = &m_nullAccessors;
// Don't clear the model object as we still need the guard to clear the list variant if the
// object is destroyed.
}
bool QQmlAdaptorModel::isValid() const
{
- return accessors != &qt_vdm_null_accessors;
+ return accessors != &m_nullAccessors;
}
int QQmlAdaptorModel::count() const
@@ -1046,21 +116,4 @@ void QQmlAdaptorModel::objectDestroyedImpl(QQmlGuardImpl *guard)
This->setModel(QVariant());
}
-QQmlAdaptorModelEngineData::QQmlAdaptorModelEngineData(QV4::ExecutionEngine *v4)
- : v4(v4)
-{
- QV4::Scope scope(v4);
- QV4::ScopedObject proto(scope, v4->newObject());
- proto->defineAccessorProperty(QStringLiteral("index"), get_index, nullptr);
- proto->defineAccessorProperty(QStringLiteral("modelData"),
- QQmlDMListAccessorData::get_modelData, QQmlDMListAccessorData::set_modelData);
- listItemProto.set(v4, proto);
-}
-
-QQmlAdaptorModelEngineData::~QQmlAdaptorModelEngineData()
-{
-}
-
QT_END_NAMESPACE
-
-#include <qqmladaptormodel.moc>
diff --git a/src/qmlmodels/qqmladaptormodel_p.h b/src/qmlmodels/qqmladaptormodel_p.h
index da8a4881a6..d43cff129d 100644
--- a/src/qmlmodels/qqmladaptormodel_p.h
+++ b/src/qmlmodels/qqmladaptormodel_p.h
@@ -34,7 +34,7 @@ class QQmlDelegateModel;
class QQmlDelegateModelItem;
class QQmlDelegateModelItemMetaType;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlAdaptorModel : public QQmlGuard<QObject>
+class Q_QMLMODELS_EXPORT QQmlAdaptorModel : public QQmlGuard<QObject>
{
public:
class Accessors
@@ -52,7 +52,7 @@ public:
virtual QQmlDelegateModelItem *createItem(
QQmlAdaptorModel &,
const QQmlRefPointer<QQmlDelegateModelItemMetaType> &,
- int, int, int) const { return nullptr; }
+ int, int, int) { return nullptr; }
virtual bool notify(
const QQmlAdaptorModel &,
@@ -75,7 +75,7 @@ public:
QQmlPropertyCache::ConstPtr propertyCache;
};
- const Accessors *accessors;
+ Accessors *accessors;
QPersistentModelIndex rootIndex;
QQmlListAccessor list;
// we need to ensure that a JS created model does not get gced, but cannot
@@ -136,6 +136,8 @@ public:
private:
static void objectDestroyedImpl(QQmlGuardImpl *);
+
+ Accessors m_nullAccessors;
};
class QQmlAdaptorModelProxyInterface
diff --git a/src/qmlmodels/qqmladaptormodelenginedata.cpp b/src/qmlmodels/qqmladaptormodelenginedata.cpp
new file mode 100644
index 0000000000..dd3301d258
--- /dev/null
+++ b/src/qmlmodels/qqmladaptormodelenginedata.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qqmladaptormodelenginedata_p.h>
+#include <private/qqmldmlistaccessordata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlAdaptorModelEngineData::QQmlAdaptorModelEngineData(QV4::ExecutionEngine *v4)
+ : v4(v4)
+{
+ QV4::Scope scope(v4);
+ QV4::ScopedObject proto(scope, v4->newObject());
+ proto->defineAccessorProperty(QStringLiteral("index"), get_index, nullptr);
+ proto->defineAccessorProperty(
+ QStringLiteral("modelData"),
+ QQmlDMListAccessorData::get_modelData, QQmlDMListAccessorData::set_modelData);
+ proto->defineAccessorProperty(
+ QString(),
+ QQmlDMListAccessorData::get_modelData, QQmlDMListAccessorData::set_modelData);
+ listItemProto.set(v4, proto);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmladaptormodelenginedata_p.h b/src/qmlmodels/qqmladaptormodelenginedata_p.h
new file mode 100644
index 0000000000..290a74e1ee
--- /dev/null
+++ b/src/qmlmodels/qqmladaptormodelenginedata_p.h
@@ -0,0 +1,68 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+
+#ifndef QQMLADAPTORMODELENGINEDATA_P_H
+#define QQMLADAPTORMODELENGINEDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmldelegatemodel_p_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+#include <private/qqmlproperty_p.h>
+
+#include <private/qv4value_p.h>
+#include <private/qv4functionobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlAdaptorModelEngineData : public QV4::ExecutionEngine::Deletable
+{
+public:
+ QQmlAdaptorModelEngineData(QV4::ExecutionEngine *v4);
+
+ QV4::ExecutionEngine *v4;
+ QV4::PersistentValue listItemProto;
+
+ static QV4::ReturnedValue get_index(const QV4::FunctionObject *f, const QV4::Value *thisObject, const QV4::Value *, int)
+ {
+ QV4::Scope scope(f);
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
+ if (!o)
+ RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object")));
+
+ RETURN_RESULT(QV4::Encode(o->d()->item->index));
+ }
+
+ template <typename T, typename M> static void setModelDataType(QMetaObjectBuilder *builder, M *metaType)
+ {
+ builder->setFlags(MetaObjectFlag::DynamicMetaObject);
+ builder->setClassName(T::staticMetaObject.className());
+ builder->setSuperClass(&T::staticMetaObject);
+ metaType->propertyOffset = T::staticMetaObject.propertyCount();
+ metaType->signalOffset = T::staticMetaObject.methodCount();
+ }
+
+ static void addProperty(QMetaObjectBuilder *builder, int propertyId, const QByteArray &propertyName, const QByteArray &propertyType)
+ {
+ builder->addSignal("__" + QByteArray::number(propertyId) + "()");
+ QMetaPropertyBuilder property = builder->addProperty(
+ propertyName, propertyType, propertyId);
+ property.setWritable(true);
+ }
+
+ V4_DEFINE_EXTENSION(QQmlAdaptorModelEngineData, get)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLADAPTORMODELENGINEDATA_P_H
diff --git a/src/qmlmodels/qqmlchangeset.cpp b/src/qmlmodels/qqmlchangeset.cpp
index 24e8f315dc..35fa95d6a8 100644
--- a/src/qmlmodels/qqmlchangeset.cpp
+++ b/src/qmlmodels/qqmlchangeset.cpp
@@ -516,6 +516,8 @@ void QQmlChangeSet::change(QVector<Change> *changes)
}
/*!
+ \internal
+ \relates QQmlChangeSet
Prints the contents of a change \a set to the \a debug stream.
*/
@@ -536,6 +538,8 @@ QDebug operator <<(QDebug debug, const QQmlChangeSet &set)
}
/*!
+ \internal
+ \relates QQmlChangeSet
Prints a \a change to the \a debug stream.
*/
diff --git a/src/qmlmodels/qqmlchangeset_p.h b/src/qmlmodels/qqmlchangeset_p.h
index eed46d4f4d..b31177bf45 100644
--- a/src/qmlmodels/qqmlchangeset_p.h
+++ b/src/qmlmodels/qqmlchangeset_p.h
@@ -15,14 +15,17 @@
// We mean it.
//
+#include <QtQmlIntegration/qqmlintegration.h>
#include <QtCore/qdebug.h>
#include <QtCore/qvector.h>
#include <QtQmlModels/private/qtqmlmodelsglobal_p.h>
QT_BEGIN_NAMESPACE
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlChangeSet
+class Q_QMLMODELS_EXPORT QQmlChangeSet
{
+ Q_GADGET
+ QML_ANONYMOUS
public:
struct MoveKey
{
@@ -117,8 +120,8 @@ inline size_t qHash(const QQmlChangeSet::MoveKey &key) { return qHash(qMakePair(
inline bool operator ==(const QQmlChangeSet::MoveKey &l, const QQmlChangeSet::MoveKey &r) {
return l.moveId == r.moveId && l.offset == r.offset; }
-Q_QMLMODELS_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet::Change &change);
-Q_QMLMODELS_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet &change);
+Q_QMLMODELS_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet::Change &change);
+Q_QMLMODELS_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet &change);
QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index fcbcec15a1..3df3f09336 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -31,7 +31,7 @@ namespace QV4 {
namespace Heap {
struct DelegateModelGroupFunction : FunctionObject {
- void init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg));
+ void init(ExecutionEngine *engine, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg));
QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg);
uint flag;
@@ -60,9 +60,11 @@ struct DelegateModelGroupFunction : QV4::FunctionObject
{
V4_OBJECT2(DelegateModelGroupFunction, FunctionObject)
- static Heap::DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
+ static Heap::DelegateModelGroupFunction *create(
+ QV4::ExecutionEngine *engine, uint flag,
+ QV4::ReturnedValue (*code)(QQmlDelegateModelItem *, uint, const QV4::Value &))
{
- return scope->engine()->memoryManager->allocate<DelegateModelGroupFunction>(scope, flag, code);
+ return engine->memoryManager->allocate<DelegateModelGroupFunction>(engine, flag, code);
}
static ReturnedValue virtualCall(const QV4::FunctionObject *that, const Value *thisObject, const Value *argv, int argc)
@@ -78,9 +80,11 @@ struct DelegateModelGroupFunction : QV4::FunctionObject
}
};
-void Heap::DelegateModelGroupFunction::init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
+void Heap::DelegateModelGroupFunction::init(
+ QV4::ExecutionEngine *engine, uint flag,
+ QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
{
- QV4::Heap::FunctionObject::init(scope, QStringLiteral("DelegateModelGroupFunction"));
+ QV4::Heap::FunctionObject::init(engine, QStringLiteral("DelegateModelGroupFunction"));
this->flag = flag;
this->code = code;
}
@@ -103,7 +107,7 @@ public:
QV4::PersistentValue changeProto;
};
-V4_DEFINE_EXTENSION(QQmlDelegateModelEngineData, engineData)
+V4_DEFINE_EXTENSION(QQmlDelegateModelEngineData, qdmEngineData)
void QQmlDelegateModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
@@ -351,26 +355,16 @@ void QQmlDelegateModelPrivate::connectToAbstractItemModel()
auto aim = m_adaptorModel.aim();
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsInserted(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_columnsInserted(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- q, QQmlDelegateModel, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- q, QQmlDelegateModel, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
- 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()));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- q, QQmlDelegateModel, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ QObject::connect(aim, &QAbstractItemModel::rowsInserted, q, &QQmlDelegateModel::_q_rowsInserted);
+ QObject::connect(aim, &QAbstractItemModel::rowsRemoved, q, &QQmlDelegateModel::_q_rowsRemoved);
+ QObject::connect(aim, &QAbstractItemModel::rowsAboutToBeRemoved, q, &QQmlDelegateModel::_q_rowsAboutToBeRemoved);
+ QObject::connect(aim, &QAbstractItemModel::columnsInserted, q, &QQmlDelegateModel::_q_columnsInserted);
+ QObject::connect(aim, &QAbstractItemModel::columnsRemoved, q, &QQmlDelegateModel::_q_columnsRemoved);
+ QObject::connect(aim, &QAbstractItemModel::columnsMoved, q, &QQmlDelegateModel::_q_columnsMoved);
+ QObject::connect(aim, &QAbstractItemModel::dataChanged, q, &QQmlDelegateModel::_q_dataChanged);
+ QObject::connect(aim, &QAbstractItemModel::rowsMoved, q, &QQmlDelegateModel::_q_rowsMoved);
+ QObject::connect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset);
+ QObject::connect(aim, &QAbstractItemModel::layoutChanged, q, &QQmlDelegateModel::_q_layoutChanged);
}
void QQmlDelegateModelPrivate::disconnectFromAbstractItemModel()
@@ -381,26 +375,16 @@ void QQmlDelegateModelPrivate::disconnectFromAbstractItemModel()
auto aim = m_adaptorModel.aim();
- QObject::disconnect(aim, SIGNAL(rowsInserted(QModelIndex,int,int)),
- q, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- q, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- q, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(columnsInserted(QModelIndex,int,int)), q,
- SLOT(_q_columnsInserted(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(columnsRemoved(QModelIndex,int,int)), q,
- SLOT(_q_columnsRemoved(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), q,
- SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
- QObject::disconnect(aim, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- q, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
- 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, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- q, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ QObject::disconnect(aim, &QAbstractItemModel::rowsInserted, q, &QQmlDelegateModel::_q_rowsInserted);
+ QObject::disconnect(aim, &QAbstractItemModel::rowsAboutToBeRemoved, q, &QQmlDelegateModel::_q_rowsAboutToBeRemoved);
+ QObject::disconnect(aim, &QAbstractItemModel::rowsRemoved, q, &QQmlDelegateModel::_q_rowsRemoved);
+ QObject::disconnect(aim, &QAbstractItemModel::columnsInserted, q, &QQmlDelegateModel::_q_columnsInserted);
+ QObject::disconnect(aim, &QAbstractItemModel::columnsRemoved, q, &QQmlDelegateModel::_q_columnsRemoved);
+ QObject::disconnect(aim, &QAbstractItemModel::columnsMoved, q, &QQmlDelegateModel::_q_columnsMoved);
+ QObject::disconnect(aim, &QAbstractItemModel::dataChanged, q, &QQmlDelegateModel::_q_dataChanged);
+ QObject::disconnect(aim, &QAbstractItemModel::rowsMoved, q, &QQmlDelegateModel::_q_rowsMoved);
+ QObject::disconnect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset);
+ QObject::disconnect(aim, &QAbstractItemModel::layoutChanged, q, &QQmlDelegateModel::_q_layoutChanged);
}
void QQmlDelegateModel::setModel(const QVariant &model)
@@ -461,7 +445,7 @@ void QQmlDelegateModel::setDelegate(QQmlComponent *delegate)
qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
if (adc) {
d->m_delegateChooser = adc;
- d->m_delegateChooserChanged = connect(adc, &QQmlAbstractDelegateComponent::delegateChanged,
+ d->m_delegateChooserChanged = connect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this,
[d](){ d->delegateChanged(); });
}
}
@@ -922,7 +906,7 @@ void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *mod
if (incubatorPriv->hadTopLevelRequiredProperties()) {
// If we have required properties, we clear the context object
// so that the model role names are not polluting the context.
- // Unless the context is bound, in which case we have never set context object.
+ // Unless the context is bound, in which case we have never set the context object.
if (incubating && !isBound) {
Q_ASSERT(incubating->contextData);
incubating->contextData->setContextObject(nullptr);
@@ -931,16 +915,20 @@ void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *mod
proxyContext->setContextObject(nullptr);
}
+ // Retrieve the metaObject before the potential return so that the accessors have a chance
+ // to perform some finalization in case they produce a dynamic metaobject. Here we know for
+ // sure that we are using required properties.
+ const QMetaObject *qmlMetaObject = modelItemToIncubate->metaObject();
+
if (incubatorPriv->requiredProperties()->empty())
return;
RequiredProperties *requiredProperties = incubatorPriv->requiredProperties();
- auto qmlMetaObject = modelItemToIncubate->metaObject();
// if a required property was not in the model, it might still be a static property of the
// QQmlDelegateModelItem or one of its derived classes this is the case for index, row,
// column, model and more
- // the most derived subclass of QQmlDelegateModelItem is QQmlDMAbstractModelData at depth 2,
- // so 4 should be plenty
+ // the most derived subclasses of QQmlDelegateModelItem are QQmlDMAbstractItemModelData and
+ // QQmlDMObjectData at depth 2, so 4 should be plenty
QVarLengthArray<QPair<const QMetaObject *, QObject *>, 4> mos;
// we first check the dynamic meta object for properties originating from the model
// contains abstractitemmodelproperties
@@ -987,6 +975,13 @@ void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *mod
modelItemToIncubate->contextData->setContextObject(modelItemToIncubate);
if (proxiedObject)
proxyContext->setContextObject(proxiedObject);
+
+ // Retrieve the metaObject() once so that the accessors have a chance to perform some
+ // finalization in case they produce a dynamic metaobject. For example, they might be
+ // inclined to create a propertyCache now because there are no required properties and any
+ // revisioned properties should be hidden after all. Here is the first time we know for
+ // sure whether we are using context properties.
+ modelItemToIncubate->metaObject();
}
}
@@ -1203,6 +1198,9 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
addCacheItem(cacheItem, it);
reuseItem(cacheItem, index, flags);
cacheItem->referenceObject();
+
+ if (index == m_compositor.count(group) - 1)
+ requestMoreIfNecessary();
return cacheItem->object;
}
@@ -1285,7 +1283,9 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
if (cacheItem->object && (!cacheItem->incubationTask || isDoneIncubating(cacheItem->incubationTask->status())))
return cacheItem->object;
- cacheItem->releaseObject();
+ if (cacheItem->objectRef > 0)
+ cacheItem->releaseObject();
+
if (!cacheItem->isReferenced()) {
removeCacheItem(cacheItem);
delete cacheItem;
@@ -1450,6 +1450,50 @@ void QQmlDelegateModel::_q_itemsChanged(int index, int count, const QVector<int>
d->itemsChanged(changes);
d->emitChanges();
}
+ const bool needToCheckDelegateChoiceInvalidation = d->m_delegateChooser && !roles.isEmpty();
+ if (!needToCheckDelegateChoiceInvalidation)
+ return;
+
+ // here, we only really can handle AIM based models, because only there
+ // we can do something sensible with roles
+ if (!d->m_adaptorModel.adaptsAim())
+ return;
+
+ const auto aim = d->m_adaptorModel.aim();
+ const auto choiceRole = d->m_delegateChooser->role().toUtf8();
+ const auto &roleNames = aim->roleNames();
+ auto it = std::find_if(roles.begin(), roles.end(), [&](int role) {
+ return roleNames[role] == choiceRole;
+ });
+ if (it == roles.end())
+ return;
+
+ // Compare handleModelReset - we're doing a more localized version
+
+ /* A role change affecting the DelegateChoice is equivalent to removing all
+ affected items (including invalidating their cache entries) and afterwards
+ reinserting them.
+ */
+ QVector<Compositor::Remove> removes;
+ QVector<Compositor::Insert> inserts;
+ d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
+ const QList<QQmlDelegateModelItem *> cache = d->m_cache;
+ for (QQmlDelegateModelItem *item : cache)
+ item->referenceObject();
+ for (const auto& removed: removes) {
+ if (!d->m_cache.isSharedWith(cache))
+ break;
+ QQmlDelegateModelItem *item = cache.value(removed.cacheIndex(), nullptr);
+ if (!d->m_cache.contains(item))
+ continue;
+ if (item->modelIndex() != -1)
+ item->setModelIndex(-1, -1, -1);
+ }
+ for (QQmlDelegateModelItem *item : cache)
+ item->releaseObject();
+ d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
+ d->itemsMoved(removes, inserts);
+ d->emitChanges();
}
static void incrementIndexes(QQmlDelegateModelItem *cacheItem, int count, const int *deltas)
@@ -1602,8 +1646,8 @@ void QQmlDelegateModelPrivate::itemsRemoved(
if (movedItems && remove.isMove()) {
movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex(), remove.count));
- QList<QQmlDelegateModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex();
- QList<QQmlDelegateModelItem *>::iterator end = begin + remove.count;
+ QList<QQmlDelegateModelItem *>::const_iterator begin = m_cache.constBegin() + remove.cacheIndex();
+ QList<QQmlDelegateModelItem *>::const_iterator end = begin + remove.count;
m_cache.erase(begin, end);
} else {
for (; cacheIndex < remove.cacheIndex() + remove.count - removedCache; ++cacheIndex) {
@@ -1617,7 +1661,7 @@ void QQmlDelegateModelPrivate::itemsRemoved(
emitDestroyingItem(object);
cacheItem->scriptRef -= 1;
}
- if (!cacheItem->isReferenced()) {
+ if (!cacheItem->isReferenced() && !remove.inGroup(Compositor::Persisted)) {
m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
m_cache.removeAt(cacheIndex);
delete cacheItem;
@@ -1833,14 +1877,45 @@ void QQmlDelegateModelPrivate::emitChanges()
for (int i = 1; i < m_groupCount; ++i)
QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
- auto cacheCopy = m_cache; // deliberate; emitChanges may alter m_cache
- for (QQmlDelegateModelItem *cacheItem : std::as_const(cacheCopy)) {
- if (cacheItem->attached)
- cacheItem->attached->emitChanges();
+ // emitChanges may alter m_cache and delete items
+ QVarLengthArray<QPointer<QQmlDelegateModelAttached>> attachedObjects;
+ attachedObjects.reserve(m_cache.length());
+ for (const QQmlDelegateModelItem *cacheItem : std::as_const(m_cache))
+ attachedObjects.append(cacheItem->attached);
+
+ for (const QPointer<QQmlDelegateModelAttached> &attached : std::as_const(attachedObjects)) {
+ if (attached && attached->m_cacheItem)
+ attached->emitChanges();
}
}
-void QQmlDelegateModel::_q_modelReset()
+void QQmlDelegateModel::_q_modelAboutToBeReset()
+{
+ Q_D(QQmlDelegateModel);
+ if (!d->m_adaptorModel.adaptsAim())
+ return;
+ auto aim = d->m_adaptorModel.aim();
+ 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, [this, d, oldRoleNames, aim](){
+ if (!d->m_adaptorModel.adaptsAim() || d->m_adaptorModel.aim() != aim)
+ return;
+ 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 +2080,7 @@ void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &par
// Ignored
} else {
// We don't know what's going on, so reset the model
- _q_modelReset();
+ handleModelReset();
}
}
@@ -2018,26 +2093,28 @@ QQmlDelegateModelAttached *QQmlDelegateModel::qmlAttachedProperties(QObject *obj
return new QQmlDelegateModelAttached(obj);
}
-bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups)
+QQmlDelegateModelPrivate::InsertionResult
+QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups)
{
if (!m_context || !m_context->isValid())
- return false;
+ return InsertionResult::Error;
QQmlDelegateModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, -1);
if (!cacheItem)
- return false;
+ return InsertionResult::Error;
if (!object.isObject())
- return false;
+ return InsertionResult::Error;
QV4::ExecutionEngine *v4 = object.as<QV4::Object>()->engine();
QV4::Scope scope(v4);
QV4::ScopedObject o(scope, object);
if (!o)
- return false;
+ return InsertionResult::Error;
QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
QV4::ScopedValue propertyName(scope);
QV4::ScopedValue v(scope);
+ const auto oldCache = m_cache;
while (1) {
propertyName = it.nextPropertyNameAsString(v);
if (propertyName->isNull())
@@ -2046,6 +2123,9 @@ bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const
propertyName->toQStringNoThrow(),
QV4::ExecutionEngine::toVariant(v, QMetaType {}));
}
+ const bool cacheModified = !m_cache.isSharedWith(oldCache);
+ if (cacheModified)
+ return InsertionResult::Retry;
cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
@@ -2055,7 +2135,7 @@ bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const
m_cache.insert(before.cacheIndex(), cacheItem);
m_compositor.insert(before, nullptr, 0, 1, cacheItem->groups);
- return true;
+ return InsertionResult::Success;
}
//============================================================================
@@ -2115,27 +2195,27 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
s = v4Engine->newString(QStringLiteral("isUnresolved"));
QV4::ScopedFunctionObject f(scope);
- QV4::ExecutionContext *global = scope.engine->rootContext();
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, 30, QQmlDelegateModelItem::get_member)));
+ QV4::ExecutionEngine *engine = scope.engine;
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, 30, QQmlDelegateModelItem::get_member)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("inItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("inPersistedItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("itemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("persistedItemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
@@ -2143,14 +2223,14 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
QString propertyName = QLatin1String("in") + groupNames.at(i);
propertyName.replace(2, 1, propertyName.at(2).toUpper());
s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
for (int i = 2; i < groupNames.size(); ++i) {
const QString propertyName = groupNames.at(i) + QLatin1String("Index");
s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::get_index)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
@@ -2720,20 +2800,24 @@ void QQmlDelegateModelAttached::emitChanges()
m_previousGroups = m_cacheItem->groups;
int indexChanges = 0;
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
+ const int groupCount = m_cacheItem->metaType->groupCount;
+ for (int i = 1; i < groupCount; ++i) {
if (m_previousIndex[i] != m_currentIndex[i]) {
m_previousIndex[i] = m_currentIndex[i];
indexChanges |= (1 << i);
}
}
+ // Don't access m_cacheItem anymore once we've started sending signals.
+ // We don't own it and someone might delete it.
+
int notifierId = 0;
const QMetaObject *meta = metaObject();
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
if (groupChanges & (1 << i))
QMetaObject::activate(this, meta, notifierId, nullptr);
}
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
if (indexChanges & (1 << i))
QMetaObject::activate(this, meta, notifierId, nullptr);
}
@@ -2762,9 +2846,9 @@ void QQmlDelegateModelGroupPrivate::emitChanges(QV4::ExecutionEngine *v4)
Q_Q(QQmlDelegateModelGroup);
if (isChangedConnected() && !changeSet.isEmpty()) {
emit q->changed(QJSValuePrivate::fromReturnedValue(
- engineData(v4)->array(v4, changeSet.removes())),
+ qdmEngineData(v4)->array(v4, changeSet.removes())),
QJSValuePrivate::fromReturnedValue(
- engineData(v4)->array(v4, changeSet.inserts())));
+ qdmEngineData(v4)->array(v4, changeSet.inserts())));
}
if (changeSet.difference() != 0)
emit q->countChanged();
@@ -3028,7 +3112,7 @@ bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::Value &value, int *ind
items that are later replaced by actual data.
*/
-void QQmlDelegateModelGroup::insert(QQmlV4Function *args)
+void QQmlDelegateModelGroup::insert(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
@@ -3052,9 +3136,8 @@ void QQmlDelegateModelGroup::insert(QQmlV4Function *args)
v = (*args)[i];
}
- Compositor::insert_iterator before = index < model->m_compositor.count(group)
- ? model->m_compositor.findInsertPosition(group, index)
- : model->m_compositor.end();
+ if (v->as<QV4::ArrayObject>())
+ return;
int groups = 1 << d->group;
if (++i < args->length()) {
@@ -3062,11 +3145,16 @@ void QQmlDelegateModelGroup::insert(QQmlV4Function *args)
groups |= model->m_cacheMetaType->parseGroups(val);
}
- if (v->as<QV4::ArrayObject>()) {
- return;
- } else if (v->as<QV4::Object>()) {
- model->insert(before, v, groups);
- model->emitChanges();
+ if (v->as<QV4::Object>()) {
+ auto insertionResult = QQmlDelegateModelPrivate::InsertionResult::Retry;
+ do {
+ Compositor::insert_iterator before = index < model->m_compositor.count(group)
+ ? model->m_compositor.findInsertPosition(group, index)
+ : model->m_compositor.end();
+ insertionResult = model->insert(before, v, groups);
+ } while (insertionResult == QQmlDelegateModelPrivate::InsertionResult::Retry);
+ if (insertionResult == QQmlDelegateModelPrivate::InsertionResult::Success)
+ model->emitChanges();
}
}
@@ -3087,7 +3175,7 @@ void QQmlDelegateModelGroup::insert(QQmlV4Function *args)
group remain instantiated when not referenced by any view.
*/
-void QQmlDelegateModelGroup::create(QQmlV4Function *args)
+void QQmlDelegateModelGroup::create(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
if (!d->model)
@@ -3116,16 +3204,19 @@ void QQmlDelegateModelGroup::create(QQmlV4Function *args)
groups |= model->m_cacheMetaType->parseGroups(val);
}
- Compositor::insert_iterator before = index < model->m_compositor.count(group)
- ? model->m_compositor.findInsertPosition(group, index)
- : model->m_compositor.end();
+ auto insertionResult = QQmlDelegateModelPrivate::InsertionResult::Retry;
+ do {
+ Compositor::insert_iterator before = index < model->m_compositor.count(group)
+ ? model->m_compositor.findInsertPosition(group, index)
+ : model->m_compositor.end();
- index = before.index[d->group];
- group = d->group;
+ index = before.index[d->group];
+ group = d->group;
- if (!model->insert(before, v, groups)) {
+ insertionResult = model->insert(before, v, groups);
+ } while (insertionResult == QQmlDelegateModelPrivate::InsertionResult::Retry);
+ if (insertionResult == QQmlDelegateModelPrivate::InsertionResult::Error)
return;
- }
}
}
if (index < 0 || index >= model->m_compositor.count(group)) {
@@ -3162,7 +3253,7 @@ void QQmlDelegateModelGroup::create(QQmlV4Function *args)
that the previously unresolved item has simply moved.
*/
-void QQmlDelegateModelGroup::resolve(QQmlV4Function *args)
+void QQmlDelegateModelGroup::resolve(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
if (!d->model)
@@ -3266,7 +3357,7 @@ void QQmlDelegateModelGroup::resolve(QQmlV4Function *args)
Removes \a count items starting at \a index from the group.
*/
-void QQmlDelegateModelGroup::remove(QQmlV4Function *args)
+void QQmlDelegateModelGroup::remove(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
if (!d->model)
@@ -3306,7 +3397,7 @@ void QQmlDelegateModelGroup::remove(QQmlV4Function *args)
}
bool QQmlDelegateModelGroupPrivate::parseGroupArgs(
- QQmlV4Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
+ QQmlV4FunctionPtr args, Compositor::Group *group, int *index, int *count, int *groups) const
{
if (!model || !QQmlDelegateModelPrivate::get(model)->m_cacheMetaType)
return false;
@@ -3340,7 +3431,7 @@ bool QQmlDelegateModelGroupPrivate::parseGroupArgs(
Adds \a count items starting at \a index to \a groups.
*/
-void QQmlDelegateModelGroup::addGroups(QQmlV4Function *args)
+void QQmlDelegateModelGroup::addGroups(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
Compositor::Group group = d->group;
@@ -3370,7 +3461,7 @@ void QQmlDelegateModelGroup::addGroups(QQmlV4Function *args)
Removes \a count items starting at \a index from \a groups.
*/
-void QQmlDelegateModelGroup::removeGroups(QQmlV4Function *args)
+void QQmlDelegateModelGroup::removeGroups(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
Compositor::Group group = d->group;
@@ -3401,7 +3492,7 @@ void QQmlDelegateModelGroup::removeGroups(QQmlV4Function *args)
their existing groups and added to \a groups.
*/
-void QQmlDelegateModelGroup::setGroups(QQmlV4Function *args)
+void QQmlDelegateModelGroup::setGroups(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
Compositor::Group group = d->group;
@@ -3436,7 +3527,7 @@ void QQmlDelegateModelGroup::setGroups(QQmlV4Function *args)
reordering you have done via this function.
*/
-void QQmlDelegateModelGroup::move(QQmlV4Function *args)
+void QQmlDelegateModelGroup::move(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
@@ -3926,7 +4017,7 @@ public:
const QQmlChangeSet::Change &change = array->at(index);
- QV4::ScopedObject changeProto(scope, engineData(v4)->changeProto.value());
+ QV4::ScopedObject changeProto(scope, qdmEngineData(v4)->changeProto.value());
QV4::Scoped<QQmlDelegateModelGroupChange> object(scope, QQmlDelegateModelGroupChange::create(v4));
object->setPrototypeOf(changeProto);
object->d()->change = change;
diff --git a/src/qmlmodels/qqmldelegatemodel_p.h b/src/qmlmodels/qqmldelegatemodel_p.h
index bfb5b6d38a..2eeffb9e0c 100644
--- a/src/qmlmodels/qqmldelegatemodel_p.h
+++ b/src/qmlmodels/qqmldelegatemodel_p.h
@@ -29,13 +29,12 @@ QT_BEGIN_NAMESPACE
class QQmlChangeSet;
class QQuickPackage;
-class QQmlV4Function;
class QQmlDelegateModelGroup;
class QQmlDelegateModelAttached;
class QQmlDelegateModelPrivate;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, public QQmlParserStatus
+class Q_QMLMODELS_EXPORT QQmlDelegateModel : public QQmlInstanceModel, public QQmlParserStatus
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlDelegateModel)
@@ -114,7 +113,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,13 +125,14 @@ private Q_SLOTS:
void _q_layoutChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint);
private:
+ void handleModelReset();
bool isDescendantOf(const QPersistentModelIndex &desc, const QList<QPersistentModelIndex> &parents) const;
Q_DISABLE_COPY(QQmlDelegateModel)
};
class QQmlDelegateModelGroupPrivate;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModelGroup : public QObject
+class Q_QMLMODELS_EXPORT QQmlDelegateModelGroup : public QObject
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
@@ -156,14 +156,14 @@ public:
Q_INVOKABLE QJSValue get(int index);
public Q_SLOTS:
- void insert(QQmlV4Function *);
- void create(QQmlV4Function *);
- void resolve(QQmlV4Function *);
- void remove(QQmlV4Function *);
- void addGroups(QQmlV4Function *);
- void removeGroups(QQmlV4Function *);
- void setGroups(QQmlV4Function *);
- void move(QQmlV4Function *);
+ void insert(QQmlV4FunctionPtr);
+ void create(QQmlV4FunctionPtr);
+ void resolve(QQmlV4FunctionPtr);
+ void remove(QQmlV4FunctionPtr);
+ void addGroups(QQmlV4FunctionPtr);
+ void removeGroups(QQmlV4FunctionPtr);
+ void setGroups(QQmlV4FunctionPtr);
+ void move(QQmlV4FunctionPtr);
Q_SIGNALS:
void countChanged();
@@ -179,13 +179,13 @@ class QQmlDelegateModelAttachedMetaObject;
class QQmlDelegateModelAttached : public QObject
{
Q_OBJECT
- Q_PROPERTY(QQmlDelegateModel *model READ model CONSTANT)
- Q_PROPERTY(QStringList groups READ groups WRITE setGroups NOTIFY groupsChanged)
- Q_PROPERTY(bool isUnresolved READ isUnresolved NOTIFY unresolvedChanged)
- Q_PROPERTY(bool inPersistedItems READ inPersistedItems WRITE setInPersistedItems NOTIFY groupsChanged)
- Q_PROPERTY(bool inItems READ inItems WRITE setInItems NOTIFY groupsChanged)
- Q_PROPERTY(int persistedItemsIndex READ persistedItemsIndex NOTIFY groupsChanged)
- Q_PROPERTY(int itemsIndex READ itemsIndex NOTIFY groupsChanged)
+ Q_PROPERTY(QQmlDelegateModel *model READ model CONSTANT FINAL)
+ Q_PROPERTY(QStringList groups READ groups WRITE setGroups NOTIFY groupsChanged FINAL)
+ Q_PROPERTY(bool isUnresolved READ isUnresolved NOTIFY unresolvedChanged FINAL)
+ Q_PROPERTY(bool inPersistedItems READ inPersistedItems WRITE setInPersistedItems NOTIFY groupsChanged FINAL)
+ Q_PROPERTY(bool inItems READ inItems WRITE setInItems NOTIFY groupsChanged FINAL)
+ Q_PROPERTY(int persistedItemsIndex READ persistedItemsIndex NOTIFY groupsChanged FINAL)
+ Q_PROPERTY(int itemsIndex READ itemsIndex NOTIFY groupsChanged FINAL)
public:
QQmlDelegateModelAttached(QObject *parent);
@@ -232,7 +232,4 @@ public:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlDelegateModel)
-QML_DECLARE_TYPE(QQmlDelegateModelGroup)
-
#endif // QQMLDATAMODEL_P_H
diff --git a/src/qmlmodels/qqmldelegatemodel_p_p.h b/src/qmlmodels/qqmldelegatemodel_p_p.h
index a6ab5a970d..3c7ab9281d 100644
--- a/src/qmlmodels/qqmldelegatemodel_p_p.h
+++ b/src/qmlmodels/qqmldelegatemodel_p_p.h
@@ -14,6 +14,7 @@
#include <private/qqmlopenmetaobject_p.h>
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qpointer.h>
//
// W A R N I N G
@@ -37,7 +38,8 @@ typedef QQmlListCompositor Compositor;
class QQmlDelegateModelAttachedMetaObject;
class QQmlAbstractDelegateComponent;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModelItemMetaType : public QQmlRefCount
+class Q_QMLMODELS_EXPORT QQmlDelegateModelItemMetaType final
+ : public QQmlRefCounted<QQmlDelegateModelItemMetaType>
{
public:
QQmlDelegateModelItemMetaType(QV4::ExecutionEngine *engine, QQmlDelegateModel *model, const QStringList &groupNames);
@@ -231,7 +233,7 @@ public:
bool parseIndex(const QV4::Value &value, int *index, Compositor::Group *group) const;
bool parseGroupArgs(
- QQmlV4Function *args, Compositor::Group *group, int *index, int *count, int *groups) const;
+ QQmlV4FunctionPtr args, Compositor::Group *group, int *index, int *count, int *groups) const;
Compositor::Group group;
QPointer<QQmlDelegateModel> model;
@@ -301,7 +303,12 @@ public:
void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override;
void delegateChanged(bool add = true, bool remove = true);
- bool insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups);
+ enum class InsertionResult {
+ Success,
+ Error,
+ Retry
+ };
+ InsertionResult insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups);
int adaptorModelCount() const;
@@ -354,7 +361,7 @@ public:
class QQmlPartsModel : public QQmlInstanceModel, public QQmlDelegateModelGroupEmitter
{
Q_OBJECT
- Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup)
+ Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup FINAL)
public:
QQmlPartsModel(QQmlDelegateModel *model, const QString &part, QObject *parent = nullptr);
~QQmlPartsModel();
@@ -419,7 +426,9 @@ public:
QList<QQmlPartsModel *> models;
};
-class QQmlDelegateModelAttachedMetaObject : public QAbstractDynamicMetaObject, public QQmlRefCount
+class QQmlDelegateModelAttachedMetaObject final
+ : public QAbstractDynamicMetaObject,
+ public QQmlRefCounted<QQmlDelegateModelAttachedMetaObject>
{
public:
QQmlDelegateModelAttachedMetaObject(
diff --git a/src/qmlmodels/qqmldmabstractitemmodeldata.cpp b/src/qmlmodels/qqmldmabstractitemmodeldata.cpp
new file mode 100644
index 0000000000..bf4a0226b1
--- /dev/null
+++ b/src/qmlmodels/qqmldmabstractitemmodeldata.cpp
@@ -0,0 +1,253 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qqmldmabstractitemmodeldata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlDMAbstractItemModelData::QQmlDMAbstractItemModelData(
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ VDMAbstractItemModelDataType *dataType, int index, int row, int column)
+ : QQmlDelegateModelItem(metaType, dataType, index, row, column)
+ , m_type(dataType)
+{
+ if (index == -1)
+ m_cachedData.resize(m_type->propertyRoles.size());
+
+ QObjectPrivate::get(this)->metaObject = m_type;
+
+ m_type->addref();
+}
+
+int QQmlDMAbstractItemModelData::metaCall(QMetaObject::Call call, int id, void **arguments)
+{
+ if (call == QMetaObject::ReadProperty && id >= m_type->propertyOffset) {
+ const int propertyIndex = id - m_type->propertyOffset;
+ if (index == -1) {
+ if (!m_cachedData.isEmpty())
+ *static_cast<QVariant *>(arguments[0]) = m_cachedData.at(propertyIndex);
+ } else if (*m_type->model) {
+ *static_cast<QVariant *>(arguments[0]) = value(m_type->propertyRoles.at(propertyIndex));
+ }
+ return -1;
+ } else if (call == QMetaObject::WriteProperty && id >= m_type->propertyOffset) {
+ const int propertyIndex = id - m_type->propertyOffset;
+ const QMetaObject *meta = metaObject();
+ if (index == -1) {
+ if (m_cachedData.size() > 1) {
+ m_cachedData[propertyIndex] = *static_cast<QVariant *>(arguments[0]);
+ QMetaObject::activate(this, meta, propertyIndex, nullptr);
+ } else if (m_cachedData.size() == 1) {
+ m_cachedData[0] = *static_cast<QVariant *>(arguments[0]);
+ QMetaObject::activate(this, meta, 0, nullptr);
+ }
+ } else if (*m_type->model) {
+ QQmlGuard<QQmlDMAbstractItemModelData> guard(this);
+ setValue(m_type->propertyRoles.at(propertyIndex), *static_cast<QVariant *>(arguments[0]));
+ if (guard.isNull())
+ return -1;
+
+ QMetaObject::activate(this, meta, propertyIndex, nullptr);
+ }
+ emit modelDataChanged();
+ return -1;
+ } else {
+ return qt_metacall(call, id, arguments);
+ }
+}
+
+void QQmlDMAbstractItemModelData::setValue(const QString &role, const QVariant &value)
+{
+ // Used only for initialization of the cached data. Does not have to emit change signals.
+
+ if (m_type->propertyRoles.size() == 1
+ && (role.isEmpty() || role == QLatin1String("modelData"))) {
+ // If the model has only a single role, the modelData is that role.
+ m_cachedData[0] = value;
+ return;
+ }
+
+ const auto it = m_type->roleNames.constFind(role.toUtf8());
+ if (it != m_type->roleNames.cend()) {
+ for (int i = 0; i < m_type->propertyRoles.size(); ++i) {
+ if (m_type->propertyRoles.at(i) == *it) {
+ m_cachedData[i] = value;
+ return;
+ }
+ }
+ }
+}
+
+bool QQmlDMAbstractItemModelData::resolveIndex(const QQmlAdaptorModel &adaptorModel, int idx)
+{
+ if (index == -1) {
+ Q_ASSERT(idx >= 0);
+ m_cachedData.clear();
+ setModelIndex(idx, adaptorModel.rowAt(idx), adaptorModel.columnAt(idx));
+ const QMetaObject *meta = metaObject();
+ const int propertyCount = m_type->propertyRoles.size();
+ for (int i = 0; i < propertyCount; ++i)
+ QMetaObject::activate(this, meta, i, nullptr);
+ emit modelDataChanged();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+QV4::ReturnedValue QQmlDMAbstractItemModelData::get_property(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
+{
+ QV4::Scope scope(b);
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
+ if (!o)
+ return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
+
+ const qsizetype propertyId = static_cast<const QV4::IndexedBuiltinFunction *>(b)->d()->index;
+
+ QQmlDMAbstractItemModelData *modelData = static_cast<QQmlDMAbstractItemModelData *>(o->d()->item);
+ if (o->d()->item->index == -1) {
+ if (!modelData->m_cachedData.isEmpty())
+ return scope.engine->fromVariant(modelData->m_cachedData.at(propertyId));
+ } else if (*modelData->m_type->model) {
+ return scope.engine->fromVariant(
+ modelData->value(modelData->m_type->propertyRoles.at(propertyId)));
+ }
+ return QV4::Encode::undefined();
+}
+
+QV4::ReturnedValue QQmlDMAbstractItemModelData::set_property(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
+{
+ QV4::Scope scope(b);
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
+ if (!o)
+ return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
+ if (!argc)
+ return scope.engine->throwTypeError();
+
+ const qsizetype propertyId = static_cast<const QV4::IndexedBuiltinFunction *>(b)->d()->index;
+
+ if (o->d()->item->index == -1) {
+ QQmlDMAbstractItemModelData *modelData = static_cast<QQmlDMAbstractItemModelData *>(o->d()->item);
+ if (!modelData->m_cachedData.isEmpty()) {
+ if (modelData->m_cachedData.size() > 1) {
+ modelData->m_cachedData[propertyId]
+ = QV4::ExecutionEngine::toVariant(argv[0], QMetaType {});
+ QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), propertyId, nullptr);
+ } else if (modelData->m_cachedData.size() == 1) {
+ modelData->m_cachedData[0] = QV4::ExecutionEngine::toVariant(argv[0], QMetaType {});
+ QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 0, nullptr);
+ }
+ emit modelData->modelDataChanged();
+ }
+ }
+ return QV4::Encode::undefined();
+}
+
+QV4::ReturnedValue QQmlDMAbstractItemModelData::get_modelData(
+ const QV4::FunctionObject *b, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc)
+{
+ Q_UNUSED(argv)
+ Q_UNUSED(argc)
+
+ QV4::Scope scope(b);
+ QV4::Scoped<QQmlDelegateModelItemObject> o(
+ scope, thisObject->as<QQmlDelegateModelItemObject>());
+ if (!o)
+ return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
+
+ return scope.engine->fromVariant(
+ static_cast<QQmlDMAbstractItemModelData *>(o->d()->item)->modelData());
+}
+
+QV4::ReturnedValue QQmlDMAbstractItemModelData::set_modelData(
+ const QV4::FunctionObject *b, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc)
+{
+ QV4::Scope scope(b);
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
+ if (!o)
+ return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
+ if (!argc)
+ return scope.engine->throwTypeError();
+
+ static_cast<QQmlDMAbstractItemModelData *>(o->d()->item)->setModelData(
+ QV4::ExecutionEngine::toVariant(argv[0], QMetaType()));
+
+ return QV4::Encode::undefined();
+}
+
+QVariant QQmlDMAbstractItemModelData::modelData() const
+{
+ if (m_type->propertyRoles.size() == 1) {
+ // If the model has only a single role, the modelData is that role.
+ return index == -1
+ ? m_cachedData.isEmpty() ? QVariant() : m_cachedData[0]
+ : value(m_type->propertyRoles[0]);
+ }
+
+ // If we're using context properties, the model object is also the context object.
+ // In that case we cannot provide modelData. Otherwise return the object itself as modelData.
+ return (contextData->contextObject() == this)
+ ? QVariant()
+ : QVariant::fromValue(this);
+}
+
+void QQmlDMAbstractItemModelData::setModelData(const QVariant &modelData)
+{
+ if (m_type->propertyRoles.size() != 1) {
+ qWarning() << "Cannot overwrite model object";
+ return;
+ }
+
+ // If the model has only a single role, the modelData is that role.
+ if (index == -1) {
+ if (m_cachedData.isEmpty())
+ m_cachedData.append(modelData);
+ else
+ m_cachedData[0] = modelData;
+ } else {
+ setValue(m_type->propertyRoles[0], modelData);
+ }
+
+ QMetaObject::activate(this, metaObject(), 0, nullptr);
+ emit modelDataChanged();
+}
+
+bool QQmlDMAbstractItemModelData::hasModelChildren() const
+{
+ if (index >= 0) {
+ if (const QAbstractItemModel *const model = m_type->model->aim())
+ return model->hasChildren(model->index(row, column, m_type->model->rootIndex));
+ }
+ return false;
+}
+
+QVariant QQmlDMAbstractItemModelData::value(int role) const
+{
+ if (const QAbstractItemModel *aim = m_type->model->aim())
+ return aim->index(row, column, m_type->model->rootIndex).data(role);
+ return QVariant();
+}
+
+void QQmlDMAbstractItemModelData::setValue(int role, const QVariant &value)
+{
+ if (QAbstractItemModel *aim = m_type->model->aim())
+ aim->setData(aim->index(row, column, m_type->model->rootIndex), value, role);
+}
+
+QV4::ReturnedValue QQmlDMAbstractItemModelData::get()
+{
+ if (m_type->prototype.isUndefined()) {
+ QQmlAdaptorModelEngineData * const data = QQmlAdaptorModelEngineData::get(v4);
+ m_type->initializeConstructor(data);
+ }
+ QV4::Scope scope(v4);
+ QV4::ScopedObject proto(scope, m_type->prototype.value());
+ QV4::ScopedObject o(scope, proto->engine()->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
+ o->setPrototypeOf(proto);
+ ++scriptRef;
+ return o.asReturnedValue();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmldmabstractitemmodeldata_p.h b/src/qmlmodels/qqmldmabstractitemmodeldata_p.h
new file mode 100644
index 0000000000..2994b59730
--- /dev/null
+++ b/src/qmlmodels/qqmldmabstractitemmodeldata_p.h
@@ -0,0 +1,339 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLDMABSTRACTITEMMODELDATA_P_H
+#define QQMLDMABSTRACTITEMMODELDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmladaptormodelenginedata_p.h>
+#include <private/qqmldelegatemodel_p_p.h>
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class VDMAbstractItemModelDataType;
+class QQmlDMAbstractItemModelData : public QQmlDelegateModelItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT)
+ Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
+ QT_ANONYMOUS_PROPERTY(QVariant READ modelData NOTIFY modelDataChanged FINAL)
+
+public:
+ QQmlDMAbstractItemModelData(
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ VDMAbstractItemModelDataType *dataType,
+ int index, int row, int column);
+
+ int metaCall(QMetaObject::Call call, int id, void **arguments);
+ bool hasModelChildren() const;
+
+ QV4::ReturnedValue get() override;
+ void setValue(const QString &role, const QVariant &value) override;
+ bool resolveIndex(const QQmlAdaptorModel &model, int idx) override;
+
+ static QV4::ReturnedValue get_property(
+ const QV4::FunctionObject *b, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue set_property(
+ const QV4::FunctionObject *b, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc);
+
+ static QV4::ReturnedValue get_modelData(
+ const QV4::FunctionObject *b, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue set_modelData(
+ const QV4::FunctionObject *b, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc);
+
+ QVariant modelData() const;
+ void setModelData(const QVariant &modelData);
+
+ const VDMAbstractItemModelDataType *type() const { return m_type; }
+
+Q_SIGNALS:
+ void modelDataChanged();
+
+private:
+ QVariant value(int role) const;
+ void setValue(int role, const QVariant &value);
+
+ VDMAbstractItemModelDataType *m_type;
+ QVector<QVariant> m_cachedData;
+};
+
+class VDMAbstractItemModelDataType final
+ : public QQmlRefCounted<VDMAbstractItemModelDataType>
+ , public QQmlAdaptorModel::Accessors
+ , public QAbstractDynamicMetaObject
+{
+public:
+ VDMAbstractItemModelDataType(QQmlAdaptorModel *model)
+ : model(model)
+ , propertyOffset(0)
+ , signalOffset(0)
+ {
+ }
+
+ bool notify(
+ const QQmlAdaptorModel &,
+ const QList<QQmlDelegateModelItem *> &items,
+ int index,
+ int count,
+ const QVector<int> &roles) const override
+ {
+ bool changed = roles.isEmpty() && !watchedRoles.isEmpty();
+ if (!changed && !watchedRoles.isEmpty() && watchedRoleIds.isEmpty()) {
+ QList<int> roleIds;
+ for (const QByteArray &r : watchedRoles) {
+ QHash<QByteArray, int>::const_iterator it = roleNames.find(r);
+ if (it != roleNames.end())
+ roleIds << it.value();
+ }
+ const_cast<VDMAbstractItemModelDataType *>(this)->watchedRoleIds = roleIds;
+ }
+
+ QVector<int> signalIndexes;
+ for (int i = 0; i < roles.size(); ++i) {
+ const int role = roles.at(i);
+ if (!changed && watchedRoleIds.contains(role))
+ changed = true;
+
+ int propertyId = propertyRoles.indexOf(role);
+ if (propertyId != -1)
+ signalIndexes.append(propertyId + signalOffset);
+ }
+ if (roles.isEmpty()) {
+ const int propertyRolesCount = propertyRoles.size();
+ signalIndexes.reserve(propertyRolesCount);
+ for (int propertyId = 0; propertyId < propertyRolesCount; ++propertyId)
+ signalIndexes.append(propertyId + signalOffset);
+ }
+
+ QVarLengthArray<QQmlGuard<QQmlDMAbstractItemModelData>> guardedItems;
+ for (const auto item : items) {
+ Q_ASSERT(qobject_cast<QQmlDMAbstractItemModelData *>(item) == item);
+ guardedItems.append(static_cast<QQmlDMAbstractItemModelData *>(item));
+ }
+
+ for (const auto &item : std::as_const(guardedItems)) {
+ if (item.isNull())
+ continue;
+
+ const int idx = item->modelIndex();
+ if (idx >= index && idx < index + count) {
+ for (int i = 0; i < signalIndexes.size(); ++i)
+ QMetaObject::activate(item, signalIndexes.at(i), nullptr);
+ emit item->modelDataChanged();
+ }
+ }
+ return changed;
+ }
+
+ void replaceWatchedRoles(
+ QQmlAdaptorModel &,
+ const QList<QByteArray> &oldRoles,
+ const QList<QByteArray> &newRoles) const override
+ {
+ VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
+
+ dataType->watchedRoleIds.clear();
+ for (const QByteArray &oldRole : oldRoles)
+ dataType->watchedRoles.removeOne(oldRole);
+ dataType->watchedRoles += newRoles;
+ }
+
+ static QV4::ReturnedValue get_hasModelChildren(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
+ {
+ QV4::Scope scope(b);
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
+ if (!o)
+ RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object")));
+
+ const QQmlAdaptorModel *const model
+ = static_cast<QQmlDMAbstractItemModelData *>(o->d()->item)->type()->model;
+ if (o->d()->item->index >= 0) {
+ if (const QAbstractItemModel *const aim = model->aim())
+ RETURN_RESULT(QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex))));
+ }
+ RETURN_RESULT(QV4::Encode(false));
+ }
+
+
+ void initializeConstructor(QQmlAdaptorModelEngineData *const data)
+ {
+ QV4::ExecutionEngine *v4 = data->v4;
+ QV4::Scope scope(v4);
+ QV4::ScopedObject proto(scope, v4->newObject());
+ proto->defineAccessorProperty(QStringLiteral("index"), QQmlAdaptorModelEngineData::get_index, nullptr);
+ proto->defineAccessorProperty(QStringLiteral("hasModelChildren"), get_hasModelChildren, nullptr);
+ proto->defineAccessorProperty(QStringLiteral("modelData"),
+ QQmlDMAbstractItemModelData::get_modelData,
+ QQmlDMAbstractItemModelData::set_modelData);
+ QV4::ScopedProperty p(scope);
+
+ typedef QHash<QByteArray, int>::const_iterator iterator;
+ for (iterator it = roleNames.constBegin(), end = roleNames.constEnd(); it != end; ++it) {
+ const qsizetype propertyId = propertyRoles.indexOf(it.value());
+ const QByteArray &propertyName = it.key();
+
+ QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
+ QV4::ScopedFunctionObject g(
+ scope,
+ v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(
+ v4, propertyId, QQmlDMAbstractItemModelData::get_property));
+ QV4::ScopedFunctionObject s(
+ scope,
+ v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(
+ v4, propertyId, QQmlDMAbstractItemModelData::set_property));
+ p->setGetter(g);
+ p->setSetter(s);
+ proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
+ }
+ prototype.set(v4, proto);
+ }
+
+ // QAbstractDynamicMetaObject
+
+ void objectDestroyed(QObject *) override
+ {
+ release();
+ }
+
+ int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) override
+ {
+ return static_cast<QQmlDMAbstractItemModelData *>(object)->metaCall(call, id, arguments);
+ }
+
+ int rowCount(const QQmlAdaptorModel &model) const override
+ {
+ if (const QAbstractItemModel *aim = model.aim())
+ return aim->rowCount(model.rootIndex);
+ return 0;
+ }
+
+ int columnCount(const QQmlAdaptorModel &model) const override
+ {
+ if (const QAbstractItemModel *aim = model.aim())
+ return aim->columnCount(model.rootIndex);
+ return 0;
+ }
+
+ void cleanup(QQmlAdaptorModel &) const override
+ {
+ release();
+ }
+
+ QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
+ {
+ if (!metaObject) {
+ VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
+ dataType->initializeMetaType(model);
+ }
+
+ if (const QAbstractItemModel *aim = model.aim()) {
+ const QModelIndex modelIndex
+ = aim->index(model.rowAt(index), model.columnAt(index), model.rootIndex);
+
+ const auto it = roleNames.find(role.toUtf8()), end = roleNames.end();
+ if (it != roleNames.end())
+ return modelIndex.data(*it);
+
+ if (role.isEmpty() || role == QLatin1String("modelData")) {
+ if (roleNames.size() == 1)
+ return modelIndex.data(roleNames.begin().value());
+
+ QVariantMap modelData;
+ for (auto jt = roleNames.begin(); jt != end; ++jt)
+ modelData.insert(QString::fromUtf8(jt.key()), modelIndex.data(jt.value()));
+ return modelData;
+ }
+
+ if (role == QLatin1String("hasModelChildren"))
+ return QVariant(aim->hasChildren(modelIndex));
+ }
+ return QVariant();
+ }
+
+ QVariant parentModelIndex(const QQmlAdaptorModel &model) const override
+ {
+ if (const QAbstractItemModel *aim = model.aim())
+ return QVariant::fromValue(aim->parent(model.rootIndex));
+ return QVariant();
+ }
+
+ QVariant modelIndex(const QQmlAdaptorModel &model, int index) const override
+ {
+ if (const QAbstractItemModel *aim = model.aim())
+ return QVariant::fromValue(aim->index(model.rowAt(index), model.columnAt(index),
+ model.rootIndex));
+ return QVariant();
+ }
+
+ bool canFetchMore(const QQmlAdaptorModel &model) const override
+ {
+ if (const QAbstractItemModel *aim = model.aim())
+ return aim->canFetchMore(model.rootIndex);
+ return false;
+ }
+
+ void fetchMore(QQmlAdaptorModel &model) const override
+ {
+ if (QAbstractItemModel *aim = model.aim())
+ aim->fetchMore(model.rootIndex);
+ }
+
+ QQmlDelegateModelItem *createItem(
+ QQmlAdaptorModel &model,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ int index, int row, int column) override
+ {
+ if (!metaObject)
+ initializeMetaType(model);
+ return new QQmlDMAbstractItemModelData(metaType, this, index, row, column);
+ }
+
+ void initializeMetaType(const QQmlAdaptorModel &model)
+ {
+ QMetaObjectBuilder builder;
+ QQmlAdaptorModelEngineData::setModelDataType<QQmlDMAbstractItemModelData>(&builder, this);
+
+ const QByteArray propertyType = QByteArrayLiteral("QVariant");
+ const QAbstractItemModel *aim = model.aim();
+ const QHash<int, QByteArray> names = aim ? aim->roleNames() : QHash<int, QByteArray>();
+ for (QHash<int, QByteArray>::const_iterator it = names.begin(), cend = names.end(); it != cend; ++it) {
+ const int propertyId = propertyRoles.size();
+ propertyRoles.append(it.key());
+ roleNames.insert(it.value(), it.key());
+ QQmlAdaptorModelEngineData::addProperty(&builder, propertyId, it.value(), propertyType);
+ }
+
+ metaObject.reset(builder.toMetaObject());
+ *static_cast<QMetaObject *>(this) = *metaObject;
+ propertyCache = QQmlPropertyCache::createStandalone(
+ metaObject.data(), model.modelItemRevision);
+ }
+
+ QV4::PersistentValue prototype;
+ QList<int> propertyRoles;
+ QList<int> watchedRoleIds;
+ QList<QByteArray> watchedRoles;
+ QHash<QByteArray, int> roleNames;
+ QQmlAdaptorModel *model;
+ int propertyOffset;
+ int signalOffset;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDMABSTRACTITEMMODELDATA_P_H
diff --git a/src/qmlmodels/qqmldmlistaccessordata.cpp b/src/qmlmodels/qqmldmlistaccessordata.cpp
new file mode 100644
index 0000000000..bfd353771c
--- /dev/null
+++ b/src/qmlmodels/qqmldmlistaccessordata.cpp
@@ -0,0 +1,157 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qqmldmlistaccessordata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlDMListAccessorData::QQmlDMListAccessorData(
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ VDMListDelegateDataType *dataType,
+ int index, int row, int column, const QVariant &value)
+ : QQmlDelegateModelItem(metaType, dataType, index, row, column)
+ , cachedData(value)
+{
+ QObjectPrivate::get(this)->metaObject = dataType;
+ dataType->addref();
+}
+
+QQmlDMListAccessorData::~QQmlDMListAccessorData()
+{
+ QObjectPrivate *d = QObjectPrivate::get(this);
+ static_cast<VDMListDelegateDataType *>(d->metaObject)->release();
+ d->metaObject = nullptr;
+}
+
+void QQmlDMListAccessorData::setModelData(const QVariant &data) {
+ if (data == cachedData)
+ return;
+
+ cachedData = data;
+ cachedDataClean = false;
+ static_cast<const VDMListDelegateDataType *>(QObjectPrivate::get(this)->metaObject)
+ ->emitAllSignals(this);
+}
+
+void QQmlDMListAccessorData::setValue(const QString &role, const QVariant &value)
+{
+ // Used only for initialization of the cached data. Does not have to emit change signals.
+ Q_ASSERT(!cachedDataClean);
+
+ if (role == QLatin1String("modelData") || role.isEmpty())
+ cachedData = value;
+ else
+ VDMListDelegateDataType::setValue(&cachedData, role, value);
+}
+
+bool QQmlDMListAccessorData::resolveIndex(const QQmlAdaptorModel &model, int idx)
+{
+ if (index == -1) {
+ index = idx;
+ setModelData(model.list.at(idx));
+ emit modelIndexChanged();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void VDMListDelegateDataType::emitAllSignals(QQmlDMListAccessorData *accessor) const
+{
+ for (int i = propertyOffset, end = propertyCount(); i != end; ++i)
+ QMetaObject::activate(accessor, this, i - propertyOffset, nullptr);
+ emit accessor->modelDataChanged();
+}
+
+int VDMListDelegateDataType::metaCall(
+ QObject *object, QMetaObject::Call call, int id, void **arguments)
+{
+ Q_ASSERT(qobject_cast<QQmlDMListAccessorData *>(object));
+ QQmlDMListAccessorData *accessor = static_cast<QQmlDMListAccessorData *>(object);
+
+ switch (call) {
+ case QMetaObject::ReadProperty: {
+ if (id < propertyOffset)
+ break;
+
+ QVariant *result = static_cast<QVariant *>(arguments[0]);
+ const QByteArray name = property(id).name();
+ const QVariant data = accessor->index == -1
+ ? accessor->modelData()
+ : model->list.at(accessor->index);
+ *result = value(&data, name);
+ return -1;
+ }
+ case QMetaObject::WriteProperty: {
+ if (id < propertyOffset)
+ break;
+
+ const QVariant &argument = *static_cast<QVariant *>(arguments[0]);
+ const QByteArray name = property(id).name();
+ QVariant data = accessor->index == -1
+ ? accessor->modelData()
+ : model->list.at(accessor->index);
+ if (argument == value(&data, name))
+ return -1;
+ setValue(&data, name, argument);
+ if (accessor->index == -1) {
+ accessor->cachedData = data;
+ accessor->cachedDataClean = false;
+ } else {
+ model->list.set(accessor->index, data);
+ }
+ QMetaObject::activate(accessor, this, id - propertyOffset, nullptr);
+ emit accessor->modelDataChanged();
+ return -1;
+ }
+ default:
+ break;
+ }
+
+ return accessor->qt_metacall(call, id, arguments);
+}
+
+int VDMListDelegateDataType::createProperty(const char *name, const char *)
+{
+ const int propertyIndex = propertyCount() - propertyOffset;
+
+ // We use QVariant because the types may be different in the different objects.
+ QQmlAdaptorModelEngineData::addProperty(
+ &builder, propertyIndex, name, QByteArrayLiteral("QVariant"));
+
+ metaObject.reset(builder.toMetaObject());
+ *static_cast<QMetaObject *>(this) = *metaObject;
+ return propertyIndex + propertyOffset;
+}
+
+QMetaObject *VDMListDelegateDataType::toDynamicMetaObject(QObject *object)
+{
+ if (const QQmlRefPointer<QQmlContextData> &contextData
+ = static_cast<QQmlDMListAccessorData *>(object)->contextData) {
+ if (contextData->contextObject() == object) {
+ // We are using context properties. There should be a propertyCache so that row and
+ // column are hidden. We shall also return the static metaObject in that case.
+
+ if (!propertyCache) {
+ propertyCache = QQmlPropertyCache::createStandalone(
+ &QQmlDMListAccessorData::staticMetaObject, model->modelItemRevision);
+ if (QQmlData *ddata = QQmlData::get(object, true))
+ ddata->propertyCache = propertyCache;
+ }
+
+ // ### Qt 7: Return const from toDynamicMetaObject() and drop the const_cast.
+ return const_cast<QMetaObject *>(&QQmlDMListAccessorData::staticMetaObject);
+ }
+ }
+
+ // If the context object is not the model object, we are using required properties.
+ // In that case, create any extra properties.
+ QQmlDMListAccessorData *data = static_cast<QQmlDMListAccessorData *>(object);
+ if (!data->cachedDataClean) {
+ createMissingProperties(&data->cachedData);
+ data->cachedDataClean = true;
+ }
+ return this;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmldmlistaccessordata_p.h b/src/qmlmodels/qqmldmlistaccessordata_p.h
new file mode 100644
index 0000000000..e02c3a88f6
--- /dev/null
+++ b/src/qmlmodels/qqmldmlistaccessordata_p.h
@@ -0,0 +1,293 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLDMLISTACCESSORDATA_P_H
+#define QQMLDMLISTACCESSORDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmladaptormodelenginedata_p.h>
+#include <private/qqmldelegatemodel_p_p.h>
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class VDMListDelegateDataType;
+
+class QQmlDMListAccessorData : public QQmlDelegateModelItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
+ QT_ANONYMOUS_PROPERTY(QVariant READ modelData WRITE setModelData NOTIFY modelDataChanged FINAL)
+public:
+ QQmlDMListAccessorData(
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ VDMListDelegateDataType *dataType, int index, int row, int column,
+ const QVariant &value);
+ ~QQmlDMListAccessorData();
+
+ QVariant modelData() const
+ {
+ return cachedData;
+ }
+
+ void setModelData(const QVariant &data);
+
+ static QV4::ReturnedValue get_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
+ {
+ QV4::ExecutionEngine *v4 = b->engine();
+ const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
+ if (!o)
+ return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
+
+ return v4->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData);
+ }
+
+ static QV4::ReturnedValue set_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
+ {
+ QV4::ExecutionEngine *v4 = b->engine();
+ const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
+ if (!o)
+ return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
+ if (!argc)
+ return v4->throwTypeError();
+
+ static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(
+ QV4::ExecutionEngine::toVariant(argv[0], QMetaType {}));
+ return QV4::Encode::undefined();
+ }
+
+ QV4::ReturnedValue get() override
+ {
+ QQmlAdaptorModelEngineData *data = QQmlAdaptorModelEngineData::get(v4);
+ QV4::Scope scope(v4);
+ QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
+ QV4::ScopedObject p(scope, data->listItemProto.value());
+ o->setPrototypeOf(p);
+ ++scriptRef;
+ return o.asReturnedValue();
+ }
+
+ void setValue(const QString &role, const QVariant &value) override;
+ bool resolveIndex(const QQmlAdaptorModel &model, int idx) override;
+
+Q_SIGNALS:
+ void modelDataChanged();
+
+private:
+ friend class VDMListDelegateDataType;
+ QVariant cachedData;
+
+ // Gets cleaned when the metaobject has processed it.
+ bool cachedDataClean = false;
+};
+
+
+class VDMListDelegateDataType final
+ : public QQmlRefCounted<VDMListDelegateDataType>
+ , public QQmlAdaptorModel::Accessors
+ , public QAbstractDynamicMetaObject
+{
+public:
+ VDMListDelegateDataType(QQmlAdaptorModel *model)
+ : model(model)
+ {
+ QQmlAdaptorModelEngineData::setModelDataType<QQmlDMListAccessorData>(&builder, this);
+ metaObject.reset(builder.toMetaObject());
+ *static_cast<QMetaObject *>(this) = *metaObject.data();
+ }
+
+ void cleanup(QQmlAdaptorModel &) const override
+ {
+ release();
+ }
+
+ int rowCount(const QQmlAdaptorModel &model) const override
+ {
+ return model.list.count();
+ }
+
+ int columnCount(const QQmlAdaptorModel &model) const override
+ {
+ switch (model.list.type()) {
+ case QQmlListAccessor::Invalid:
+ return 0;
+ case QQmlListAccessor::StringList:
+ case QQmlListAccessor::UrlList:
+ case QQmlListAccessor::Integer:
+ return 1;
+ default:
+ break;
+ }
+
+ // If there are no properties, we can get modelData itself.
+ return std::max(1, propertyCount() - propertyOffset);
+ }
+
+ static const QMetaObject *metaObjectFromType(QMetaType type)
+ {
+ if (const QMetaObject *metaObject = type.metaObject())
+ return metaObject;
+
+ // NB: This acquires the lock on QQmlMetaTypeData. If we had a QQmlEngine here,
+ // we could use QQmlGadgetPtrWrapper::instance() to avoid this.
+ if (const QQmlValueType *valueType = QQmlMetaType::valueType(type))
+ return valueType->staticMetaObject();
+
+ return nullptr;
+ }
+
+ template<typename String>
+ static QString toQString(const String &string)
+ {
+ if constexpr (std::is_same_v<String, QString>)
+ return string;
+ else if constexpr (std::is_same_v<String, QByteArray>)
+ return QString::fromUtf8(string);
+ else if constexpr (std::is_same_v<String, const char *>)
+ return QString::fromUtf8(string);
+ Q_UNREACHABLE_RETURN(QString());
+ }
+
+ template<typename String>
+ static QByteArray toUtf8(const String &string)
+ {
+ if constexpr (std::is_same_v<String, QString>)
+ return string.toUtf8();
+ else if constexpr (std::is_same_v<String, QByteArray>)
+ return string;
+ else if constexpr (std::is_same_v<String, const char *>)
+ return QByteArray::fromRawData(string, qstrlen(string));
+ Q_UNREACHABLE_RETURN(QByteArray());
+ }
+
+ template<typename String>
+ static QVariant value(const QVariant *row, const String &role)
+ {
+ const QMetaType type = row->metaType();
+ if (type == QMetaType::fromType<QVariantMap>())
+ return row->toMap().value(toQString(role));
+
+ if (type == QMetaType::fromType<QVariantHash>())
+ return row->toHash().value(toQString(role));
+
+ const QMetaType::TypeFlags typeFlags = type.flags();
+ if (typeFlags & QMetaType::PointerToQObject)
+ return row->value<QObject *>()->property(toUtf8(role));
+
+ if (const QMetaObject *metaObject = metaObjectFromType(type)) {
+ const int propertyIndex = metaObject->indexOfProperty(toUtf8(role));
+ if (propertyIndex >= 0)
+ return metaObject->property(propertyIndex).readOnGadget(row->constData());
+ }
+
+ return QVariant();
+ }
+
+ template<typename String>
+ void createPropertyIfMissing(const String &string)
+ {
+ for (int i = 0, end = propertyCount(); i < end; ++i) {
+ if (QAnyStringView(property(i).name()) == QAnyStringView(string))
+ return;
+ }
+
+ createProperty(toUtf8(string), nullptr);
+ }
+
+ void createMissingProperties(const QVariant *row)
+ {
+ const QMetaType type = row->metaType();
+ if (type == QMetaType::fromType<QVariantMap>()) {
+ const QVariantMap map = row->toMap();
+ for (auto it = map.keyBegin(), end = map.keyEnd(); it != end; ++it)
+ createPropertyIfMissing(*it);
+ } else if (type == QMetaType::fromType<QVariantHash>()) {
+ const QVariantHash map = row->toHash();
+ for (auto it = map.keyBegin(), end = map.keyEnd(); it != end; ++it)
+ createPropertyIfMissing(*it);
+ } else if (type.flags() & QMetaType::PointerToQObject) {
+ const QMetaObject *metaObject = row->value<QObject *>()->metaObject();
+ for (int i = 0, end = metaObject->propertyCount(); i < end; ++i)
+ createPropertyIfMissing(metaObject->property(i).name());
+ } else if (const QMetaObject *metaObject = metaObjectFromType(type)) {
+ for (int i = 0, end = metaObject->propertyCount(); i < end; ++i)
+ createPropertyIfMissing(metaObject->property(i).name());
+ }
+ }
+
+ template<typename String>
+ static void setValue(QVariant *row, const String &role, const QVariant &value)
+ {
+ const QMetaType type = row->metaType();
+ if (type == QMetaType::fromType<QVariantMap>()) {
+ static_cast<QVariantMap *>(row->data())->insert(toQString(role), value);
+ } else if (type == QMetaType::fromType<QVariantHash>()) {
+ static_cast<QVariantHash *>(row->data())->insert(toQString(role), value);
+ } else if (type.flags() & QMetaType::PointerToQObject) {
+ row->value<QObject *>()->setProperty(toUtf8(role), value);
+ } else if (const QMetaObject *metaObject = metaObjectFromType(type)) {
+ const int propertyIndex = metaObject->indexOfProperty(toUtf8(role));
+ if (propertyIndex >= 0)
+ metaObject->property(propertyIndex).writeOnGadget(row->data(), value);
+ }
+ }
+
+ QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
+ {
+ const QVariant entry = model.list.at(index);
+ if (role == QLatin1String("modelData") || role.isEmpty())
+ return entry;
+
+ return value(&entry, role);
+ }
+
+ QQmlDelegateModelItem *createItem(
+ QQmlAdaptorModel &model,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ int index, int row, int column) override
+ {
+ const QVariant value = (index >= 0 && index < model.list.count())
+ ? model.list.at(index)
+ : QVariant();
+ return new QQmlDMListAccessorData(metaType, this, index, row, column, value);
+ }
+
+ bool notify(const QQmlAdaptorModel &model, const QList<QQmlDelegateModelItem *> &items, int index, int count, const QVector<int> &) const override
+ {
+ for (auto modelItem : items) {
+ const int modelItemIndex = modelItem->index;
+ if (modelItemIndex < index || modelItemIndex >= index + count)
+ continue;
+
+ auto listModelItem = static_cast<QQmlDMListAccessorData *>(modelItem);
+ QVariant updatedModelData = model.list.at(listModelItem->index);
+ listModelItem->setModelData(updatedModelData);
+ }
+ return true;
+ }
+
+ void emitAllSignals(QQmlDMListAccessorData *accessor) const;
+
+ int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) final;
+ int createProperty(const char *name, const char *) final;
+ QMetaObject *toDynamicMetaObject(QObject *accessors) final;
+
+ QMetaObjectBuilder builder;
+ QQmlAdaptorModel *model = nullptr;
+ int propertyOffset = 0;
+ int signalOffset = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDMLISTACCESSORDATA_P_H
diff --git a/src/qmlmodels/qqmldmobjectdata.cpp b/src/qmlmodels/qqmldmobjectdata.cpp
new file mode 100644
index 0000000000..d10d80d80a
--- /dev/null
+++ b/src/qmlmodels/qqmldmobjectdata.cpp
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qqmldmobjectdata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlDMObjectData::QQmlDMObjectData(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ VDMObjectDelegateDataType *dataType,
+ int index, int row, int column,
+ QObject *object)
+ : QQmlDelegateModelItem(metaType, dataType, index, row, column)
+ , object(object)
+{
+ new QQmlDMObjectDataMetaObject(this, dataType);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmldmobjectdata_p.h b/src/qmlmodels/qqmldmobjectdata_p.h
new file mode 100644
index 0000000000..0368572b36
--- /dev/null
+++ b/src/qmlmodels/qqmldmobjectdata_p.h
@@ -0,0 +1,247 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLDMOBJECTDATA_P_H
+#define QQMLDMOBJECTDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmladaptormodelenginedata_p.h>
+#include <private/qqmldelegatemodel_p_p.h>
+
+#include <private/qobject_p.h>
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class VDMObjectDelegateDataType;
+class QQmlDMObjectData : public QQmlDelegateModelItem, public QQmlAdaptorModelProxyInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *modelData READ modelData NOTIFY modelDataChanged)
+ QT_ANONYMOUS_PROPERTY(QObject * READ modelData NOTIFY modelDataChanged FINAL)
+ Q_INTERFACES(QQmlAdaptorModelProxyInterface)
+public:
+ QQmlDMObjectData(
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ VDMObjectDelegateDataType *dataType,
+ int index, int row, int column,
+ QObject *object);
+
+ void setModelData(QObject *modelData)
+ {
+ if (modelData == object)
+ return;
+
+ object = modelData;
+ emit modelDataChanged();
+ }
+
+ QObject *modelData() const { return object; }
+ QObject *proxiedObject() override { return object; }
+
+ QPointer<QObject> object;
+
+Q_SIGNALS:
+ void modelDataChanged();
+};
+
+class VDMObjectDelegateDataType final
+ : public QQmlRefCounted<VDMObjectDelegateDataType>,
+ public QQmlAdaptorModel::Accessors
+{
+public:
+ int propertyOffset;
+ int signalOffset;
+ bool shared;
+ QMetaObjectBuilder builder;
+
+ VDMObjectDelegateDataType()
+ : propertyOffset(0)
+ , signalOffset(0)
+ , shared(true)
+ {
+ }
+
+ VDMObjectDelegateDataType(const VDMObjectDelegateDataType &type)
+ : propertyOffset(type.propertyOffset)
+ , signalOffset(type.signalOffset)
+ , shared(false)
+ , builder(type.metaObject.data(), QMetaObjectBuilder::Properties
+ | QMetaObjectBuilder::Signals
+ | QMetaObjectBuilder::SuperClass
+ | QMetaObjectBuilder::ClassName)
+ {
+ builder.setFlags(MetaObjectFlag::DynamicMetaObject);
+ }
+
+ int rowCount(const QQmlAdaptorModel &model) const override
+ {
+ return model.list.count();
+ }
+
+ int columnCount(const QQmlAdaptorModel &) const override
+ {
+ return 1;
+ }
+
+ QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
+ {
+ if (QObject *object = model.list.at(index).value<QObject *>())
+ return object->property(role.toUtf8());
+ return QVariant();
+ }
+
+ QQmlDelegateModelItem *createItem(
+ QQmlAdaptorModel &model,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ int index, int row, int column) override
+ {
+ if (!metaObject)
+ initializeMetaType(model);
+ return index >= 0 && index < model.list.count()
+ ? new QQmlDMObjectData(metaType, this, index, row, column, qvariant_cast<QObject *>(model.list.at(index)))
+ : nullptr;
+ }
+
+ void initializeMetaType(QQmlAdaptorModel &model)
+ {
+ Q_UNUSED(model);
+ QQmlAdaptorModelEngineData::setModelDataType<QQmlDMObjectData>(&builder, this);
+
+ metaObject.reset(builder.toMetaObject());
+ // Note: ATM we cannot create a shared property cache for this class, since each model
+ // object can have different properties. And to make those properties available to the
+ // delegate, QQmlDMObjectData makes use of a QAbstractDynamicMetaObject subclass
+ // (QQmlDMObjectDataMetaObject), which we cannot represent in a QQmlPropertyCache.
+ // By not having a shared property cache, revisioned properties in QQmlDelegateModelItem
+ // will always be available to the delegate, regardless of the import version.
+ }
+
+ void cleanup(QQmlAdaptorModel &) const override
+ {
+ release();
+ }
+
+ bool notify(const QQmlAdaptorModel &model, const QList<QQmlDelegateModelItem *> &items, int index, int count, const QVector<int> &) const override
+ {
+ for (auto modelItem : items) {
+ const int modelItemIndex = modelItem->index;
+ if (modelItemIndex < index || modelItemIndex >= index + count)
+ continue;
+
+ auto objectModelItem = static_cast<QQmlDMObjectData *>(modelItem);
+ QObject *updatedModelData = qvariant_cast<QObject *>(model.list.at(objectModelItem->index));
+ objectModelItem->setModelData(updatedModelData);
+ }
+ return true;
+ }
+};
+
+class QQmlDMObjectDataMetaObject : public QAbstractDynamicMetaObject
+{
+public:
+ QQmlDMObjectDataMetaObject(QQmlDMObjectData *data, VDMObjectDelegateDataType *type)
+ : m_data(data)
+ , m_type(type)
+ {
+ QObjectPrivate *op = QObjectPrivate::get(m_data);
+ *static_cast<QMetaObject *>(this) = *type->metaObject;
+ op->metaObject = this;
+ m_type->addref();
+ }
+
+ ~QQmlDMObjectDataMetaObject()
+ {
+ m_type->release();
+ }
+
+ int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments) override
+ {
+ Q_ASSERT(o == m_data);
+ Q_UNUSED(o);
+
+ static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
+ if (id >= m_type->propertyOffset
+ && (call == QMetaObject::ReadProperty
+ || call == QMetaObject::WriteProperty
+ || call == QMetaObject::ResetProperty)) {
+ if (m_data->object)
+ QMetaObject::metacall(m_data->object, call, id - m_type->propertyOffset + objectPropertyOffset, arguments);
+ return -1;
+ } else if (id >= m_type->signalOffset && call == QMetaObject::InvokeMetaMethod) {
+ QMetaObject::activate(m_data, this, id - m_type->signalOffset, nullptr);
+ return -1;
+ } else {
+ return m_data->qt_metacall(call, id, arguments);
+ }
+ }
+
+ int createProperty(const char *name, const char *) override
+ {
+ if (!m_data->object)
+ return -1;
+ const QMetaObject *metaObject = m_data->object->metaObject();
+ static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
+
+ const int previousPropertyCount = propertyCount() - propertyOffset();
+ int propertyIndex = metaObject->indexOfProperty(name);
+ if (propertyIndex == -1)
+ return -1;
+ if (previousPropertyCount + objectPropertyOffset == metaObject->propertyCount())
+ return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
+
+ if (m_type->shared) {
+ VDMObjectDelegateDataType *type = m_type;
+ m_type = new VDMObjectDelegateDataType(*m_type);
+ type->release();
+ }
+
+ const int previousMethodCount = methodCount();
+ int notifierId = previousMethodCount - methodOffset();
+ for (int propertyId = previousPropertyCount; propertyId < metaObject->propertyCount() - objectPropertyOffset; ++propertyId) {
+ QMetaProperty property = metaObject->property(propertyId + objectPropertyOffset);
+ QMetaPropertyBuilder propertyBuilder;
+ if (property.hasNotifySignal()) {
+ m_type->builder.addSignal("__" + QByteArray::number(propertyId) + "()");
+ propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName(), notifierId);
+ ++notifierId;
+ } else {
+ propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName());
+ }
+ propertyBuilder.setWritable(property.isWritable());
+ propertyBuilder.setResettable(property.isResettable());
+ propertyBuilder.setConstant(property.isConstant());
+ }
+
+ m_type->metaObject.reset(m_type->builder.toMetaObject());
+ *static_cast<QMetaObject *>(this) = *m_type->metaObject;
+
+ notifierId = previousMethodCount;
+ for (int i = previousPropertyCount; i < metaObject->propertyCount() - objectPropertyOffset; ++i) {
+ QMetaProperty property = metaObject->property(i + objectPropertyOffset);
+ if (property.hasNotifySignal()) {
+ QQmlPropertyPrivate::connect(
+ m_data->object, property.notifySignalIndex(), m_data, notifierId);
+ ++notifierId;
+ }
+ }
+ return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
+ }
+
+ QQmlDMObjectData *m_data;
+ VDMObjectDelegateDataType *m_type;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDMOBJECTDATA_P_H
diff --git a/src/qmlmodels/qqmlinstantiator.cpp b/src/qmlmodels/qqmlinstantiator.cpp
index fca56dd45a..552d1a6b73 100644
--- a/src/qmlmodels/qqmlinstantiator.cpp
+++ b/src/qmlmodels/qqmlinstantiator.cpp
@@ -29,25 +29,25 @@ QQmlInstantiatorPrivate::QQmlInstantiatorPrivate()
{
}
-QQmlInstantiatorPrivate::~QQmlInstantiatorPrivate()
-{
- qDeleteAll(objects);
-}
-
void QQmlInstantiatorPrivate::clear()
{
Q_Q(QQmlInstantiator);
if (!instanceModel)
return;
- if (!objects.size())
+
+ if (objects.isEmpty())
return;
for (int i=0; i < objects.size(); i++) {
- q->objectRemoved(i, objects[i]);
- instanceModel->release(objects[i]);
+ QObject *object = objects[i];
+ emit q->objectRemoved(i, object);
+ instanceModel->release(object);
+ if (object && object->parent() == q)
+ object->setParent(nullptr);
}
+
objects.clear();
- q->objectChanged();
+ emit q->objectChanged();
}
QObject *QQmlInstantiatorPrivate::modelObject(int index, bool async)
@@ -207,10 +207,12 @@ QQmlInstantiator::QQmlInstantiator(QObject *parent)
QQmlInstantiator::~QQmlInstantiator()
{
+ Q_D(QQmlInstantiator);
+ d->clear();
}
/*!
- \qmlsignal QtQml::Instantiator::objectAdded(int index, QtObject object)
+ \qmlsignal QtQml.Models::Instantiator::objectAdded(int index, QtObject object)
This signal is emitted when an object is added to the Instantiator. The \a index
parameter holds the index which the object has been given, and the \a object
@@ -218,7 +220,7 @@ QQmlInstantiator::~QQmlInstantiator()
*/
/*!
- \qmlsignal QtQml::Instantiator::objectRemoved(int index, QtObject object)
+ \qmlsignal QtQml.Models::Instantiator::objectRemoved(int index, QtObject object)
This signal is emitted when an object is removed from the Instantiator. The \a index
parameter holds the index which the object had been given, and the \a object
@@ -228,7 +230,7 @@ QQmlInstantiator::~QQmlInstantiator()
in these cases it will be deleted shortly after the signal is handled.
*/
/*!
- \qmlproperty bool QtQml::Instantiator::active
+ \qmlproperty bool QtQml.Models::Instantiator::active
When active is true, and the delegate component is ready, the Instantiator will
create objects according to the model. When active is false, no objects
@@ -253,7 +255,7 @@ void QQmlInstantiator::setActive(bool newVal)
}
/*!
- \qmlproperty bool QtQml::Instantiator::asynchronous
+ \qmlproperty bool QtQml.Models::Instantiator::asynchronous
When asynchronous is true the Instantiator will attempt to create objects
asynchronously. This means that objects may not be available immediately,
@@ -280,7 +282,7 @@ void QQmlInstantiator::setAsync(bool newVal)
/*!
- \qmlproperty int QtQml::Instantiator::count
+ \qmlproperty int QtQml.Models::Instantiator::count
The number of objects the Instantiator is currently managing.
*/
@@ -292,7 +294,7 @@ int QQmlInstantiator::count() const
}
/*!
- \qmlproperty QtQml::Component QtQml::Instantiator::delegate
+ \qmlproperty QtQml::Component QtQml.Models::Instantiator::delegate
\qmldefault
The component used to create all objects.
@@ -331,7 +333,7 @@ void QQmlInstantiator::setDelegate(QQmlComponent* c)
}
/*!
- \qmlproperty variant QtQml::Instantiator::model
+ \qmlproperty variant QtQml.Models::Instantiator::model
This property can be set to any of the supported \l {qml-data-models}{data models}:
@@ -412,7 +414,7 @@ void QQmlInstantiator::setModel(const QVariant &v)
}
/*!
- \qmlproperty QtObject QtQml::Instantiator::object
+ \qmlproperty QtObject QtQml.Models::Instantiator::object
This is a reference to the first created object, intended as a convenience
for the case where only one object has been created.
@@ -426,7 +428,7 @@ QObject *QQmlInstantiator::object() const
}
/*!
- \qmlmethod QtObject QtQml::Instantiator::objectAt(int index)
+ \qmlmethod QtObject QtQml.Models::Instantiator::objectAt(int index)
Returns a reference to the object with the given \a index.
*/
diff --git a/src/qmlmodels/qqmlinstantiator_p.h b/src/qmlmodels/qqmlinstantiator_p.h
index 264b2b86be..9f0b83d1a0 100644
--- a/src/qmlmodels/qqmlinstantiator_p.h
+++ b/src/qmlmodels/qqmlinstantiator_p.h
@@ -24,7 +24,7 @@ QT_REQUIRE_CONFIG(qml_object_model);
QT_BEGIN_NAMESPACE
class QQmlInstantiatorPrivate;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlInstantiator : public QObject, public QQmlParserStatus
+class Q_QMLMODELS_EXPORT QQmlInstantiator : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
diff --git a/src/qmlmodels/qqmlinstantiator_p_p.h b/src/qmlmodels/qqmlinstantiator_p_p.h
index 49bd54f010..b65d19d767 100644
--- a/src/qmlmodels/qqmlinstantiator_p_p.h
+++ b/src/qmlmodels/qqmlinstantiator_p_p.h
@@ -21,17 +21,18 @@
#include <private/qqmlchangeset_p.h>
#include <private/qqmlobjectmodel_p.h>
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(qml_object_model);
QT_BEGIN_NAMESPACE
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlInstantiatorPrivate : public QObjectPrivate
+class Q_QMLMODELS_EXPORT QQmlInstantiatorPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQmlInstantiator)
public:
QQmlInstantiatorPrivate();
- ~QQmlInstantiatorPrivate();
void clear();
void regenerate();
diff --git a/src/qmlmodels/qqmlitemmodels.qdoc b/src/qmlmodels/qqmlitemmodels.qdoc
index 7f52e795c0..188ef3252d 100644
--- a/src/qmlmodels/qqmlitemmodels.qdoc
+++ b/src/qmlmodels/qqmlitemmodels.qdoc
@@ -29,7 +29,12 @@
\li \b internalId : quint64
\endlist
- All these properties are read-only, as are their C++ counterparts.
+ All these properties are read-only, as are their C++ counterparts. In addition,
+ we also expose the following functions:
+
+ \list
+ \li QVariant \b{data}(int \e role) (since Qt 6.7)
+ \endlist
\note The usual caveats apply to QModelIndex in QML. If the underlying model changes
or gets deleted, it may become dangerous to access its properties. Therefore, you
diff --git a/src/qmlmodels/qqmllistaccessor.cpp b/src/qmlmodels/qqmllistaccessor.cpp
index f1728d5e6c..acf6a14e02 100644
--- a/src/qmlmodels/qqmllistaccessor.cpp
+++ b/src/qmlmodels/qqmllistaccessor.cpp
@@ -5,13 +5,11 @@
#include <private/qqmlmetatype_p.h>
-#include <QtCore/qstringlist.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qsequentialiterable.h>
+#include <QtCore/qstringlist.h>
#include <QtCore/qurl.h>
-// ### Remove me
-#include <private/qqmlengine_p.h>
-
QT_BEGIN_NAMESPACE
QQmlListAccessor::QQmlListAccessor()
@@ -42,22 +40,46 @@ void QQmlListAccessor::setList(const QVariant &v)
if (!d.isValid()) {
m_type = Invalid;
- } else if (variantsType == QMetaType::fromType<QStringList>()) {
+ return;
+ }
+
+ if (variantsType == QMetaType::fromType<QStringList>()) {
m_type = StringList;
- } else if (variantsType == QMetaType::fromType<QList<QUrl>>()) {
+ return;
+ }
+
+ if (variantsType == QMetaType::fromType<QList<QUrl>>()) {
m_type = UrlList;
- } else if (variantsType == QMetaType::fromType<QVariantList>()) {
+ return;
+ }
+
+ if (variantsType == QMetaType::fromType<QVariantList>()) {
m_type = VariantList;
- } else if (variantsType == QMetaType::fromType<QList<QObject *>>()) {
+ return;
+ }
+
+ if (variantsType == QMetaType::fromType<QList<QObject *>>()) {
m_type = ObjectList;
- } else if (variantsType.flags() & QMetaType::IsQmlList) {
+ return;
+ }
+
+ if (variantsType.flags() & QMetaType::IsQmlList) {
d = QVariant::fromValue(QQmlListReference(d));
m_type = ListProperty;
- } else if (variantsType == QMetaType::fromType<QQmlListReference>()) {
+ return;
+ }
+
+ if (variantsType == QMetaType::fromType<QQmlListReference>()) {
m_type = ListProperty;
- } else if (variantsType.flags() & QMetaType::PointerToQObject) {
+ return;
+ }
+
+ if (variantsType.flags() & QMetaType::PointerToQObject) {
m_type = Instance;
- } else if (int i = 0; [&](){bool ok = false; i = v.toInt(&ok); return ok;}()) {
+ return;
+ }
+
+ if (int i = 0; [&](){bool ok = false; i = v.toInt(&ok); return ok;}()) {
// Here we have to check for an upper limit, because down the line code might (well, will)
// allocate memory depending on the number of elements. The upper limit cannot be INT_MAX:
// QVector<QPointer<QQuickItem>> something;
@@ -71,22 +93,54 @@ void QQmlListAccessor::setList(const QVariant &v)
if (i < 0) {
qWarning("Model size of %d is less than 0", i);
m_type = Invalid;
- } else if (i > upperLimit) {
+ return;
+ }
+
+ if (i > upperLimit) {
qWarning("Model size of %d is bigger than the upper limit %d", i, upperLimit);
m_type = Invalid;
- } else {
- m_type = Integer;
- d = i;
+ return;
}
- } else {
- const QQmlType type = QQmlMetaType::qmlListType(v.metaType());
- if (type.isSequentialContainer()) {
- m_metaSequence = type.listMetaSequence();
+
+ m_type = Integer;
+ d = i;
+ return;
+ }
+
+ const QQmlType type = QQmlMetaType::qmlListType(variantsType);
+ if (type.isSequentialContainer()) {
+ m_metaSequence = type.listMetaSequence();
+ m_type = Sequence;
+ return;
+ }
+
+ QSequentialIterable iterable;
+ if (QMetaType::convert(
+ variantsType, d.constData(),
+ QMetaType::fromType<QSequentialIterable>(), &iterable)) {
+ const QMetaSequence sequence = iterable.metaContainer();
+
+ if (sequence.hasSize() && sequence.canGetValueAtIndex()) {
+ // If the resulting iterable is useful for anything, use it.
+ m_metaSequence = sequence;
m_type = Sequence;
- } else {
- m_type = Instance;
+ return;
+ }
+
+ if (sequence.hasConstIterator() && sequence.canGetValueAtConstIterator()) {
+ // As a last resort, try to read the contents of the container via an iterator
+ // and build a QVariantList from them.
+ QVariantList variantList;
+ for (auto it = iterable.constBegin(), end = iterable.constEnd(); it != end; ++it)
+ variantList.push_back(*it);
+ d = std::move(variantList);
+ m_type = VariantList;
+ return;
}
}
+
+ m_type = Instance;
+ return;
}
qsizetype QQmlListAccessor::count() const
@@ -161,6 +215,54 @@ QVariant QQmlListAccessor::at(qsizetype idx) const
Q_UNREACHABLE_RETURN(QVariant());
}
+void QQmlListAccessor::set(qsizetype idx, const QVariant &value)
+{
+ Q_ASSERT(idx >= 0 && idx < count());
+ switch (m_type) {
+ case StringList:
+ Q_ASSERT(d.metaType() == QMetaType::fromType<QStringList>());
+ (*static_cast<QStringList *>(d.data()))[idx] = value.toString();
+ break;
+ case UrlList:
+ Q_ASSERT(d.metaType() == QMetaType::fromType<QList<QUrl>>());
+ (*static_cast<QList<QUrl> *>(d.data()))[idx] = value.value<QUrl>();
+ break;
+ case VariantList:
+ Q_ASSERT(d.metaType() == QMetaType::fromType<QVariantList>());
+ (*static_cast<QVariantList *>(d.data()))[idx] = value;
+ break;
+ case ObjectList:
+ Q_ASSERT(d.metaType() == QMetaType::fromType<QList<QObject *>>());
+ (*static_cast<QList<QObject *> *>(d.data()))[idx] = value.value<QObject *>();
+ break;
+ case ListProperty:
+ Q_ASSERT(d.metaType() == QMetaType::fromType<QQmlListReference>());
+ static_cast<QQmlListReference *>(d.data())->replace(idx, value.value<QObject *>());
+ break;
+ case Sequence: {
+ Q_ASSERT(m_metaSequence != QMetaSequence());
+ const QMetaType valueMetaType = m_metaSequence.valueMetaType();
+ if (valueMetaType == QMetaType::fromType<QVariant>()) {
+ m_metaSequence.setValueAtIndex(d.data(), idx, &value);
+ } else if (valueMetaType == value.metaType()) {
+ m_metaSequence.setValueAtIndex(d.data(), idx, value.constData());
+ } else {
+ QVariant converted = value;
+ converted.convert(valueMetaType);
+ m_metaSequence.setValueAtIndex(d.data(), idx, converted.constData());
+ }
+ break;
+ }
+ case Instance:
+ d = value;
+ break;
+ case Integer:
+ break;;
+ case Invalid:
+ break;
+ }
+}
+
bool QQmlListAccessor::isValid() const
{
return m_type != Invalid;
diff --git a/src/qmlmodels/qqmllistaccessor_p.h b/src/qmlmodels/qqmllistaccessor_p.h
index 31c8713cee..d713ad7f85 100644
--- a/src/qmlmodels/qqmllistaccessor_p.h
+++ b/src/qmlmodels/qqmllistaccessor_p.h
@@ -34,6 +34,7 @@ public:
qsizetype count() const;
QVariant at(qsizetype) const;
+ void set(qsizetype, const QVariant &);
enum Type {
Invalid,
diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp
index 14c8a6fd85..de7d97af2f 100644
--- a/src/qmlmodels/qqmllistmodel.cpp
+++ b/src/qmlmodels/qqmllistmodel.cpp
@@ -3,22 +3,25 @@
#include "qqmllistmodel_p_p.h"
#include "qqmllistmodelworkeragent_p.h"
-#include <private/qqmlopenmetaobject_p.h>
-#include <private/qqmljsast_p.h>
-#include <private/qqmljsengine_p.h>
+
#include <private/qjsvalue_p.h>
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlengine_p.h>
+#include <private/qqmljsast_p.h>
+#include <private/qqmljsengine_p.h>
+#include <private/qqmllistwrapper_p.h>
#include <private/qqmlnotifier_p.h>
+#include <private/qqmlopenmetaobject_p.h>
-#include <private/qv4object_p.h>
-#include <private/qv4dateobject_p.h>
-#include <private/qv4urlobject_p.h>
-#include <private/qv4objectiterator_p.h>
#include <private/qv4alloca_p.h>
+#include <private/qv4dateobject_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4objectiterator_p.h>
#include <private/qv4qmlcontext_p.h>
+#include <private/qv4sequenceobject_p.h>
+#include <private/qv4urlobject_p.h>
#include <qqmlcontext.h>
#include <qqmlinfo.h>
@@ -319,9 +322,12 @@ QObject *ListModel::getOrCreateModelObject(QQmlListModel *model, int elementInde
void *memory = operator new(sizeof(QObject) + sizeof(QQmlData));
void *ddataMemory = ((char *)memory) + sizeof(QObject);
e->m_objectCache = new (memory) QObject;
- QQmlData *ddata = new (ddataMemory) QQmlData;
- ddata->ownMemory = false;
- QObjectPrivate::get(e->m_objectCache)->declarativeData = ddata;
+
+ const QAbstractDeclarativeData *old = std::exchange(
+ QObjectPrivate::get(e->m_objectCache)->declarativeData,
+ new (ddataMemory) QQmlData(QQmlData::DoesNotOwnMemory));
+ Q_ASSERT(!old); // QObject should really not manipulate QQmlData
+
(void)new ModelNodeMetaObject(e->m_objectCache, model, elementIndex);
}
return e->m_objectCache;
@@ -678,18 +684,11 @@ void ListModel::set(int elementIndex, QV4::Object *object, ListModel::SetElement
e->setDoublePropertyFast(r, propertyValue->asDouble());
}
} else if (QV4::ArrayObject *a = propertyValue->as<QV4::ArrayObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List);
- if (r.type == ListLayout::Role::List) {
- ListModel *subModel = new ListModel(r.subLayout, nullptr);
-
- int arrayLength = a->getLength();
- for (int j=0 ; j < arrayLength ; ++j) {
- o = a->get(j);
- subModel->append(o);
- }
-
- e->setListPropertyFast(r, subModel);
- }
+ setArrayLike(&o, propertyName, e, a);
+ } else if (QV4::Sequence *s = propertyValue->as<QV4::Sequence>()) {
+ setArrayLike(&o, propertyName, e, s);
+ } else if (QV4::QmlListWrapper *l = propertyValue->as<QV4::QmlListWrapper>()) {
+ setArrayLike(&o, propertyName, e, l);
} else if (propertyValue->isBoolean()) {
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool);
if (r.type == ListLayout::Role::Bool) {
@@ -1913,6 +1912,7 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
/*!
\qmltype ListModel
\instantiates QQmlListModel
+ \inherits AbstractListModel
\inqmlmodule QtQml.Models
\ingroup qtquick-models
\brief Defines a free-form list data source.
@@ -1930,6 +1930,10 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
Elements can be manipulated via the model using the setProperty() method, which
allows the roles of the specified element to be set and changed.
+ ListModel inherits from \l{QAbstractListModel} and provides its \l{Q_INVOKABLE}
+ methods. You can, for example use \l{QAbstractItemModel::index} to retrieve a
+ \l{QModelIndex} for a row and column.
+
\section1 Example Usage
The following example shows a ListModel containing three elements, with the roles
@@ -1978,7 +1982,7 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
\section1 Using Threaded List Models with WorkerScript
- ListModel can be used together with WorkerScript access a list model
+ ListModel can be used together with WorkerScript to access a list model
from multiple threads. This is useful if list modifications are
synchronous and take some time: the list operations can be moved to a
different thread to avoid blocking of the main GUI thread.
@@ -1986,11 +1990,11 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
Here is an example that uses WorkerScript to periodically append the
current time to a list model:
- \snippet ../../examples/quick/threading/threadedlistmodel/timedisplay.qml 0
+ \snippet qml/listmodel/WorkerScript.qml 0
The included file, \tt dataloader.mjs, looks like this:
- \snippet ../../examples/quick/threading/threadedlistmodel/dataloader.mjs 0
+ \snippet qml/listmodel/dataloader.mjs 0
The timer in the main example sends messages to the worker script by calling
\l WorkerScript::sendMessage(). When this message is received,
@@ -2001,7 +2005,7 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
You must call sync() or else the changes made to the list from that
thread will not be reflected in the list model in the main thread.
- \sa {qml-data-models}{Data Models}, {Qt Quick Examples - Threading}, {Qt QML}
+ \sa {qml-data-models}{Data Models}, {Qt Qml}
*/
QQmlListModel::QQmlListModel(QObject *parent)
@@ -2381,7 +2385,7 @@ void QQmlListModel::clear()
\sa clear()
*/
-void QQmlListModel::remove(QQmlV4Function *args)
+void QQmlListModel::remove(QQmlV4FunctionPtr args)
{
int argLength = args->length();
@@ -2469,7 +2473,7 @@ void QQmlListModel::updateTranslations()
\sa set(), append()
*/
-void QQmlListModel::insert(QQmlV4Function *args)
+void QQmlListModel::insert(QQmlV4FunctionPtr args)
{
if (args->length() == 2) {
QV4::Scope scope(args->v4engine());
@@ -2585,7 +2589,7 @@ void QQmlListModel::move(int from, int to, int n)
\sa set(), remove()
*/
-void QQmlListModel::append(QQmlV4Function *args)
+void QQmlListModel::append(QQmlV4FunctionPtr args)
{
if (args->length() == 1) {
QV4::Scope scope(args->v4engine());
diff --git a/src/qmlmodels/qqmllistmodel_p.h b/src/qmlmodels/qqmllistmodel_p.h
index 5c44405626..f623fe6112 100644
--- a/src/qmlmodels/qqmllistmodel_p.h
+++ b/src/qmlmodels/qqmllistmodel_p.h
@@ -41,7 +41,7 @@ namespace QV4 {
struct ModelObject;
}
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlListModel : public QAbstractListModel
+class Q_QMLMODELS_EXPORT QQmlListModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
@@ -65,9 +65,9 @@ public:
int count() const;
Q_INVOKABLE void clear();
- Q_INVOKABLE void remove(QQmlV4Function *args);
- Q_INVOKABLE void append(QQmlV4Function *args);
- Q_INVOKABLE void insert(QQmlV4Function *args);
+ Q_INVOKABLE void remove(QQmlV4FunctionPtr args);
+ Q_INVOKABLE void append(QQmlV4FunctionPtr args);
+ Q_INVOKABLE void insert(QQmlV4FunctionPtr args);
Q_INVOKABLE QJSValue get(int index) const;
Q_INVOKABLE void set(int index, const QJSValue &value);
Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
@@ -181,7 +181,4 @@ inline QQmlCustomParser *qmlCreateCustomParser<QQmlListModel>()
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlListModel)
-QML_DECLARE_TYPE(QQmlListElement)
-
#endif // QQMLLISTMODEL_H
diff --git a/src/qmlmodels/qqmllistmodel_p_p.h b/src/qmlmodels/qqmllistmodel_p_p.h
index 662a12f9e7..36afe209d0 100644
--- a/src/qmlmodels/qqmllistmodel_p_p.h
+++ b/src/qmlmodels/qqmllistmodel_p_p.h
@@ -391,6 +391,23 @@ private:
void updateCacheIndices(int start = 0, int end = -1);
+ template<typename ArrayLike>
+ void setArrayLike(QV4::ScopedObject *o, QV4::String *propertyName, ListElement *e, ArrayLike *a)
+ {
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List);
+ if (r.type == ListLayout::Role::List) {
+ ListModel *subModel = new ListModel(r.subLayout, nullptr);
+
+ int arrayLength = a->getLength();
+ for (int j=0 ; j < arrayLength ; ++j) {
+ *o = a->get(j);
+ subModel->append(*o);
+ }
+
+ e->setListPropertyFast(r, subModel);
+ }
+ }
+
friend class ListElement;
friend class QQmlListModelWorkerAgent;
friend class QQmlListModelParser;
diff --git a/src/qmlmodels/qqmllistmodelworkeragent.cpp b/src/qmlmodels/qqmllistmodelworkeragent.cpp
index 74c4e812bf..c50296b1f5 100644
--- a/src/qmlmodels/qqmllistmodelworkeragent.cpp
+++ b/src/qmlmodels/qqmllistmodelworkeragent.cpp
@@ -71,17 +71,17 @@ void QQmlListModelWorkerAgent::clear()
m_copy->clear();
}
-void QQmlListModelWorkerAgent::remove(QQmlV4Function *args)
+void QQmlListModelWorkerAgent::remove(QQmlV4FunctionPtr args)
{
m_copy->remove(args);
}
-void QQmlListModelWorkerAgent::append(QQmlV4Function *args)
+void QQmlListModelWorkerAgent::append(QQmlV4FunctionPtr args)
{
m_copy->append(args);
}
-void QQmlListModelWorkerAgent::insert(QQmlV4Function *args)
+void QQmlListModelWorkerAgent::insert(QQmlV4FunctionPtr args)
{
m_copy->insert(args);
}
diff --git a/src/qmlmodels/qqmllistmodelworkeragent_p.h b/src/qmlmodels/qqmllistmodelworkeragent_p.h
index 21e99f0ec4..647cc1b997 100644
--- a/src/qmlmodels/qqmllistmodelworkeragent_p.h
+++ b/src/qmlmodels/qqmllistmodelworkeragent_p.h
@@ -34,8 +34,8 @@ class QQmlListModel;
class QQmlListModelWorkerAgent : public QObject
{
Q_OBJECT
- Q_PROPERTY(int count READ count)
- Q_PROPERTY(QV4::ExecutionEngine *engine READ engine WRITE setEngine NOTIFY engineChanged)
+ Q_PROPERTY(int count READ count FINAL)
+ Q_PROPERTY(QQmlV4ExecutionEnginePtr engine READ engine WRITE setEngine NOTIFY engineChanged FINAL)
QML_ANONYMOUS
QML_ADDED_IN_VERSION(2, 0)
@@ -52,9 +52,9 @@ public:
int count() const;
Q_INVOKABLE void clear();
- Q_INVOKABLE void remove(QQmlV4Function *args);
- Q_INVOKABLE void append(QQmlV4Function *args);
- Q_INVOKABLE void insert(QQmlV4Function *args);
+ Q_INVOKABLE void remove(QQmlV4FunctionPtr args);
+ Q_INVOKABLE void append(QQmlV4FunctionPtr args);
+ Q_INVOKABLE void insert(QQmlV4FunctionPtr args);
Q_INVOKABLE QJSValue get(int index) const;
Q_INVOKABLE void set(int index, const QJSValue &value);
Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
@@ -64,7 +64,7 @@ public:
void modelDestroyed();
Q_SIGNALS:
- void engineChanged(QV4::ExecutionEngine *engine);
+ void engineChanged(QQmlV4ExecutionEnginePtr engine);
protected:
bool event(QEvent *) override;
diff --git a/src/qmlmodels/qqmlmodelindexvaluetype_p.h b/src/qmlmodels/qqmlmodelindexvaluetype_p.h
index 9d5099a8f1..35ebacc051 100644
--- a/src/qmlmodels/qqmlmodelindexvaluetype_p.h
+++ b/src/qmlmodels/qqmlmodelindexvaluetype_p.h
@@ -42,6 +42,9 @@ public:
Q_INVOKABLE QString toString() const
{ return QLatin1String("QModelIndex") + propertiesString(v); }
+ Q_REVISION(6, 7) Q_INVOKABLE QVariant data(int role = Qt::DisplayRole) const
+ { return v.data(role); }
+
inline int row() const noexcept { return v.row(); }
inline int column() const noexcept { return v.column(); }
inline QModelIndex parent() const { return v.parent(); }
@@ -54,6 +57,8 @@ public:
static QPersistentModelIndex toPersistentModelIndex(const QModelIndex &index)
{ return QPersistentModelIndex(index); }
+
+ operator QModelIndex() const { return v; }
};
struct QQmlPersistentModelIndexValueType
@@ -76,12 +81,17 @@ public:
Q_INVOKABLE QString toString() const
{ return QLatin1String("QPersistentModelIndex") + QQmlModelIndexValueType::propertiesString(v); }
+ Q_REVISION(6, 7) Q_INVOKABLE QVariant data(int role = Qt::DisplayRole) const
+ { return v.data(role); }
+
inline int row() const { return v.row(); }
inline int column() const { return v.column(); }
inline QModelIndex parent() const { return v.parent(); }
inline bool isValid() const { return v.isValid(); }
inline QAbstractItemModel *model() const { return const_cast<QAbstractItemModel *>(v.model()); }
inline quint64 internalId() const { return v.internalId(); }
+
+ operator QPersistentModelIndex() const { return v; }
};
struct QQmlItemSelectionRangeValueType
@@ -129,6 +139,8 @@ public:
inline QAbstractItemModel *model() const { return const_cast<QAbstractItemModel *>(v.model()); }
inline bool isValid() const { return v.isValid(); }
inline bool isEmpty() const { return v.isEmpty(); }
+
+ operator QItemSelectionRange() const { return v; }
};
struct QModelIndexListForeign
diff --git a/src/qmlmodels/qqmlobjectmodel_p.h b/src/qmlmodels/qqmlobjectmodel_p.h
index c15913220a..e161586c90 100644
--- a/src/qmlmodels/qqmlobjectmodel_p.h
+++ b/src/qmlmodels/qqmlobjectmodel_p.h
@@ -28,7 +28,7 @@ class QObject;
class QQmlChangeSet;
class QAbstractItemModel;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlInstanceModel : public QObject
+class Q_QMLMODELS_EXPORT QQmlInstanceModel : public QObject
{
Q_OBJECT
@@ -82,7 +82,7 @@ private:
class QQmlObjectModelAttached;
class QQmlObjectModelPrivate;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlObjectModel : public QQmlInstanceModel
+class Q_QMLMODELS_EXPORT QQmlObjectModel : public QQmlInstanceModel
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlObjectModel)
@@ -138,7 +138,7 @@ public:
attachedProperties.remove(parent());
}
- Q_PROPERTY(int index READ index NOTIFY indexChanged)
+ Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL)
int index() const { return m_index; }
void setIndex(int idx) {
if (m_index != idx) {
@@ -168,7 +168,4 @@ public:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlInstanceModel)
-QML_DECLARE_TYPE(QQmlObjectModel)
-
#endif // QQMLINSTANCEMODEL_P_H
diff --git a/src/qmlmodels/qqmltableinstancemodel.cpp b/src/qmlmodels/qqmltableinstancemodel.cpp
index e4fcae2a44..dcc15f90a5 100644
--- a/src/qmlmodels/qqmltableinstancemodel.cpp
+++ b/src/qmlmodels/qqmltableinstancemodel.cpp
@@ -436,11 +436,15 @@ void QQmlTableInstanceModel::setModel(const QVariant &model)
// needs to stay in sync with the model. So we need to drain the pool
// completely when the model changes.
drainReusableItemsPool(0);
- if (auto const aim = abstractItemModel())
+ if (auto const aim = abstractItemModel()) {
disconnect(aim, &QAbstractItemModel::dataChanged, this, &QQmlTableInstanceModel::dataChangedCallback);
+ disconnect(aim, &QAbstractItemModel::modelAboutToBeReset, this, &QQmlTableInstanceModel::modelAboutToBeResetCallback);
+ }
m_adaptorModel.setModel(model);
- if (auto const aim = abstractItemModel())
+ if (auto const aim = abstractItemModel()) {
connect(aim, &QAbstractItemModel::dataChanged, this, &QQmlTableInstanceModel::dataChangedCallback);
+ connect(aim, &QAbstractItemModel::modelAboutToBeReset, this, &QQmlTableInstanceModel::modelAboutToBeResetCallback);
+ }
}
void QQmlTableInstanceModel::dataChangedCallback(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles)
@@ -458,6 +462,21 @@ void QQmlTableInstanceModel::dataChangedCallback(const QModelIndex &begin, const
}
}
+void QQmlTableInstanceModel::modelAboutToBeResetCallback()
+{
+ // When the model is reset, we can no longer rely on any of the data it has
+ // provided us so far. Normally it's enough for the view to recreate all the
+ // delegate items in that case, except if the model roles has changed as well
+ // (since those are cached by QQmlAdaptorModel / Accessors). For the latter case, we
+ // simply set the model once more in the delegate model to rebuild everything.
+ auto const aim = abstractItemModel();
+ auto oldRoleNames = aim->roleNames();
+ QObject::connect(aim, &QAbstractItemModel::modelReset, this, [this, aim, oldRoleNames](){
+ if (oldRoleNames != aim->roleNames())
+ setModel(model());
+ }, Qt::SingleShotConnection);
+}
+
QQmlComponent *QQmlTableInstanceModel::delegate() const
{
return m_delegate;
diff --git a/src/qmlmodels/qqmltableinstancemodel_p.h b/src/qmlmodels/qqmltableinstancemodel_p.h
index 6d3f455adc..cb4fb4c0dd 100644
--- a/src/qmlmodels/qqmltableinstancemodel_p.h
+++ b/src/qmlmodels/qqmltableinstancemodel_p.h
@@ -18,6 +18,8 @@
#include <QtQmlModels/private/qqmldelegatemodel_p.h>
#include <QtQmlModels/private/qqmldelegatemodel_p_p.h>
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(qml_table_model);
QT_BEGIN_NAMESPACE
@@ -45,7 +47,7 @@ public:
QQmlTableInstanceModel *tableInstanceModel = nullptr;
};
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableInstanceModel : public QQmlInstanceModel
+class Q_QMLMODELS_EXPORT QQmlTableInstanceModel : public QQmlInstanceModel
{
Q_OBJECT
@@ -115,6 +117,7 @@ private:
void destroyModelItem(QQmlDelegateModelItem *modelItem, DestructionMode mode);
void dataChangedCallback(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles);
+ void modelAboutToBeResetCallback();
static bool isDoneIncubating(QQmlDelegateModelItem *modelItem);
static void deleteModelItemLater(QQmlDelegateModelItem *modelItem);
diff --git a/src/qmlmodels/qqmltreemodeltotablemodel.cpp b/src/qmlmodels/qqmltreemodeltotablemodel.cpp
index d300ff2d1a..db128761cd 100644
--- a/src/qmlmodels/qqmltreemodeltotablemodel.cpp
+++ b/src/qmlmodels/qqmltreemodeltotablemodel.cpp
@@ -26,53 +26,62 @@ QAbstractItemModel *QQmlTreeModelToTableModel::model() const
return m_model;
}
-void QQmlTreeModelToTableModel::setModel(QAbstractItemModel *arg)
+void QQmlTreeModelToTableModel::connectToModel()
{
- struct Cx {
- const char *signal;
- const char *slot;
- };
- static const Cx connections[] = {
- { SIGNAL(destroyed(QObject*)),
- SLOT(modelHasBeenDestroyed()) },
- { SIGNAL(modelReset()),
- SLOT(modelHasBeenReset()) },
- { SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)),
- SLOT(modelDataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)) },
-
- { SIGNAL(layoutAboutToBeChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint)),
- SLOT(modelLayoutAboutToBeChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint)) },
- { SIGNAL(layoutChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint)),
- SLOT(modelLayoutChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint)) },
-
- { SIGNAL(rowsAboutToBeInserted(const QModelIndex&, int, int)),
- SLOT(modelRowsAboutToBeInserted(const QModelIndex &, int, int)) },
- { SIGNAL(rowsInserted(const QModelIndex&, int, int)),
- SLOT(modelRowsInserted(const QModelIndex&, int, int)) },
- { SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)),
- SLOT(modelRowsAboutToBeRemoved(const QModelIndex&, int, int)) },
- { SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
- SLOT(modelRowsRemoved(const QModelIndex&, int, int)) },
- { SIGNAL(rowsAboutToBeMoved(const QModelIndex&, int, int, const QModelIndex&, int)),
- SLOT(modelRowsAboutToBeMoved(const QModelIndex&, int, int, const QModelIndex&, int)) },
- { SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)),
- SLOT(modelRowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)) },
- { nullptr, nullptr }
+ m_connections = {
+ QObject::connect(m_model, &QAbstractItemModel::destroyed,
+ this, &QQmlTreeModelToTableModel::modelHasBeenDestroyed),
+ QObject::connect(m_model, &QAbstractItemModel::modelReset,
+ this, &QQmlTreeModelToTableModel::modelHasBeenReset),
+ QObject::connect(m_model, &QAbstractItemModel::dataChanged,
+ this, &QQmlTreeModelToTableModel::modelDataChanged),
+
+ QObject::connect(m_model, &QAbstractItemModel::layoutAboutToBeChanged,
+ this, &QQmlTreeModelToTableModel::modelLayoutAboutToBeChanged),
+ QObject::connect(m_model, &QAbstractItemModel::layoutChanged,
+ this, &QQmlTreeModelToTableModel::modelLayoutChanged),
+
+ QObject::connect(m_model, &QAbstractItemModel::rowsAboutToBeInserted,
+ this, &QQmlTreeModelToTableModel::modelRowsAboutToBeInserted),
+ QObject::connect(m_model, &QAbstractItemModel::rowsInserted,
+ this, &QQmlTreeModelToTableModel::modelRowsInserted),
+ QObject::connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &QQmlTreeModelToTableModel::modelRowsAboutToBeRemoved),
+ QObject::connect(m_model, &QAbstractItemModel::rowsRemoved,
+ this, &QQmlTreeModelToTableModel::modelRowsRemoved),
+ QObject::connect(m_model, &QAbstractItemModel::rowsAboutToBeMoved,
+ this, &QQmlTreeModelToTableModel::modelRowsAboutToBeMoved),
+ QObject::connect(m_model, &QAbstractItemModel::rowsMoved,
+ this, &QQmlTreeModelToTableModel::modelRowsMoved),
+
+ QObject::connect(m_model, &QAbstractItemModel::columnsAboutToBeInserted,
+ this, &QQmlTreeModelToTableModel::modelColumnsAboutToBeInserted),
+ QObject::connect(m_model, &QAbstractItemModel::columnsAboutToBeRemoved,
+ this, &QQmlTreeModelToTableModel::modelColumnsAboutToBeRemoved),
+ QObject::connect(m_model, &QAbstractItemModel::columnsInserted,
+ this, &QQmlTreeModelToTableModel::modelColumnsInserted),
+ QObject::connect(m_model, &QAbstractItemModel::columnsRemoved,
+ this, &QQmlTreeModelToTableModel::modelColumnsRemoved)
};
+}
+void QQmlTreeModelToTableModel::setModel(QAbstractItemModel *arg)
+{
if (m_model != arg) {
if (m_model) {
- for (const Cx *c = &connections[0]; c->signal; c++)
- disconnect(m_model, c->signal, this, c->slot);
+ for (const auto &c : m_connections)
+ QObject::disconnect(c);
+ m_connections.fill({});
}
clearModelData();
m_model = arg;
- if (m_model) {
- for (const Cx *c = &connections[0]; c->signal; c++)
- connect(m_model, c->signal, this, c->slot);
+ if (m_rootIndex.isValid() && m_rootIndex.model() != m_model)
+ m_rootIndex = QModelIndex();
+ if (m_model) {
+ connectToModel();
showModelTopLevelItems();
}
@@ -971,6 +980,40 @@ void QQmlTreeModelToTableModel::modelRowsMoved(const QModelIndex & sourceParent,
ASSERT_CONSISTENCY();
}
+void QQmlTreeModelToTableModel::modelColumnsAboutToBeInserted(const QModelIndex & parent, int start, int end)
+{
+ Q_UNUSED(parent);
+ beginInsertColumns({}, start, end);
+}
+
+void QQmlTreeModelToTableModel::modelColumnsAboutToBeRemoved(const QModelIndex & parent, int start, int end)
+{
+ Q_UNUSED(parent);
+ beginRemoveColumns({}, start, end);
+}
+
+void QQmlTreeModelToTableModel::modelColumnsInserted(const QModelIndex & parent, int start, int end)
+{
+ Q_UNUSED(parent);
+ Q_UNUSED(start);
+ Q_UNUSED(end);
+ endInsertColumns();
+ m_items.clear();
+ showModelTopLevelItems();
+ ASSERT_CONSISTENCY();
+}
+
+void QQmlTreeModelToTableModel::modelColumnsRemoved(const QModelIndex & parent, int start, int end)
+{
+ Q_UNUSED(parent);
+ Q_UNUSED(start);
+ Q_UNUSED(end);
+ endRemoveColumns();
+ m_items.clear();
+ showModelTopLevelItems();
+ ASSERT_CONSISTENCY();
+}
+
void QQmlTreeModelToTableModel::dump() const
{
if (!m_model)
diff --git a/src/qmlmodels/qqmltreemodeltotablemodel_p_p.h b/src/qmlmodels/qqmltreemodeltotablemodel_p_p.h
index 1c503ca37c..209977f48b 100644
--- a/src/qmlmodels/qqmltreemodeltotablemodel_p_p.h
+++ b/src/qmlmodels/qqmltreemodeltotablemodel_p_p.h
@@ -26,11 +26,11 @@ QT_BEGIN_NAMESPACE
class QAbstractItemModel;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlTreeModelToTableModel : public QAbstractItemModel
+class Q_QMLMODELS_EXPORT QQmlTreeModelToTableModel : public QAbstractItemModel
{
Q_OBJECT
- Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
- Q_PROPERTY(QModelIndex rootIndex READ rootIndex WRITE setRootIndex RESET resetRootIndex NOTIFY rootIndexChanged)
+ Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged FINAL)
+ Q_PROPERTY(QModelIndex rootIndex READ rootIndex WRITE setRootIndex RESET resetRootIndex NOTIFY rootIndexChanged FINAL)
struct TreeItem;
@@ -118,6 +118,10 @@ private Q_SLOTS:
void modelRowsInserted(const QModelIndex & parent, int start, int end);
void modelRowsMoved(const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow);
void modelRowsRemoved(const QModelIndex & parent, int start, int end);
+ void modelColumnsAboutToBeInserted(const QModelIndex & parent, int start, int end);
+ void modelColumnsAboutToBeRemoved(const QModelIndex & parent, int start, int end);
+ void modelColumnsInserted(const QModelIndex & parent, int start, int end);
+ void modelColumnsRemoved(const QModelIndex & parent, int start, int end);
private:
struct TreeItem {
@@ -158,6 +162,7 @@ private:
const QModelIndex &bottomRight,
const QVector<int> &roles);
void emitQueuedSignals();
+ void connectToModel();
QPointer<QAbstractItemModel> m_model = nullptr;
QPersistentModelIndex m_rootIndex;
@@ -169,6 +174,7 @@ private:
bool m_modelLayoutChanged = false;
int m_signalAggregatorStack = 0;
QVector<DataChangedParams> m_queuedDataChanged;
+ std::array<QMetaObject::Connection, 15> m_connections;
int m_column = 0;
};
diff --git a/src/qmlmodels/qquickpackage.cpp b/src/qmlmodels/qquickpackage.cpp
index 70a3a6c19b..7ab1e8345f 100644
--- a/src/qmlmodels/qquickpackage.cpp
+++ b/src/qmlmodels/qquickpackage.cpp
@@ -38,11 +38,11 @@ QT_BEGIN_NAMESPACE
\note Package is part of QtQml.Models since version 2.14 and part of QtQuick since version 2.0.
Importing Package via QtQuick is deprecated since Qt 5.14.
- \sa {Qt Quick Examples - Views}, {Qt Quick Demo - Photo Viewer}, {Qt QML}
+ \sa {Qt Quick Examples - Views}, {Qt Qml}
*/
/*!
- \qmlattachedproperty string QtQuick::Package::name
+ \qmlattachedproperty string QtQml.Models::Package::name
This attached property holds the name of an item within a Package.
*/
diff --git a/src/qmlmodels/qquickpackage_p.h b/src/qmlmodels/qquickpackage_p.h
index ba30f79390..827d718248 100644
--- a/src/qmlmodels/qquickpackage_p.h
+++ b/src/qmlmodels/qquickpackage_p.h
@@ -24,7 +24,7 @@ QT_BEGIN_NAMESPACE
class QQuickPackagePrivate;
class QQuickPackageAttached;
-class Q_QMLMODELS_PRIVATE_EXPORT QQuickPackage : public QObject
+class Q_QMLMODELS_EXPORT QQuickPackage : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickPackage)
@@ -49,7 +49,7 @@ public:
class QQuickPackageAttached : public QObject
{
Q_OBJECT
-Q_PROPERTY(QString name READ name WRITE setName)
+Q_PROPERTY(QString name READ name WRITE setName FINAL)
public:
QQuickPackageAttached(QObject *parent);
virtual ~QQuickPackageAttached();
@@ -64,6 +64,4 @@ private:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQuickPackage)
-
#endif // QQUICKPACKAGE_H
diff --git a/src/qmlmodels/qtqmlmodelsglobal_p.h b/src/qmlmodels/qtqmlmodelsglobal_p.h
index 65e48f6554..966836ec6b 100644
--- a/src/qmlmodels/qtqmlmodelsglobal_p.h
+++ b/src/qmlmodels/qtqmlmodelsglobal_p.h
@@ -18,7 +18,7 @@
#include <QtQml/private/qtqmlglobal_p.h>
#include <QtQmlModels/qtqmlmodelsglobal.h>
#include <QtQmlModels/private/qtqmlmodels-config_p.h>
-#include <QtQmlModels/private/qtqmlmodelsexports_p.h>
+#include <QtQmlModels/qtqmlmodelsexports.h>
#define Q_QMLMODELS_AUTOTEST_EXPORT Q_AUTOTEST_EXPORT