aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlmodels')
-rw-r--r--src/qmlmodels/dependencies.json2
-rw-r--r--src/qmlmodels/qmlmodels.pro18
-rw-r--r--src/qmlmodels/qqmlabstractdelegatecomponent.cpp61
-rw-r--r--src/qmlmodels/qqmlabstractdelegatecomponent_p.h (renamed from src/qmlmodels/qqmldelegatecomponent_p.h)86
-rw-r--r--src/qmlmodels/qqmladaptormodel.cpp36
-rw-r--r--src/qmlmodels/qqmladaptormodel_p.h14
-rw-r--r--src/qmlmodels/qqmldelegatecomponent.cpp321
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp434
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p.h12
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p_p.h49
-rw-r--r--src/qmlmodels/qqmlinstantiator.cpp4
-rw-r--r--src/qmlmodels/qqmlinstantiator_p.h2
-rw-r--r--src/qmlmodels/qqmllistaccessor.cpp10
-rw-r--r--src/qmlmodels/qqmllistaccessor_p.h2
-rw-r--r--src/qmlmodels/qqmllistmodel.cpp26
-rw-r--r--src/qmlmodels/qqmllistmodel_p.h12
-rw-r--r--src/qmlmodels/qqmllistmodelworkeragent_p.h2
-rw-r--r--src/qmlmodels/qqmlmodelsmodule.cpp54
-rw-r--r--src/qmlmodels/qqmlmodelsmodule_p.h17
-rw-r--r--src/qmlmodels/qqmlobjectmodel.cpp40
-rw-r--r--src/qmlmodels/qqmlobjectmodel_p.h21
-rw-r--r--src/qmlmodels/qqmltableinstancemodel.cpp124
-rw-r--r--src/qmlmodels/qqmltableinstancemodel_p.h27
-rw-r--r--src/qmlmodels/qqmltablemodel.cpp1072
-rw-r--r--src/qmlmodels/qqmltablemodel_p.h172
-rw-r--r--src/qmlmodels/qqmltablemodelcolumn.cpp200
-rw-r--r--src/qmlmodels/qqmltablemodelcolumn_p.h226
-rw-r--r--src/qmlmodels/qquickpackage.cpp19
-rw-r--r--src/qmlmodels/qquickpackage_p.h4
-rw-r--r--src/qmlmodels/qtqmlmodelsglobal_p.h2
30 files changed, 715 insertions, 2354 deletions
diff --git a/src/qmlmodels/dependencies.json b/src/qmlmodels/dependencies.json
new file mode 100644
index 0000000000..0d4f101c7a
--- /dev/null
+++ b/src/qmlmodels/dependencies.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/src/qmlmodels/qmlmodels.pro b/src/qmlmodels/qmlmodels.pro
index 1d733f5bdb..4ac093556d 100644
--- a/src/qmlmodels/qmlmodels.pro
+++ b/src/qmlmodels/qmlmodels.pro
@@ -28,14 +28,10 @@ qtConfig(qml-object-model) {
qtConfig(qml-table-model) {
SOURCES += \
- $$PWD/qqmltableinstancemodel.cpp \
- $$PWD/qqmltablemodel.cpp \
- $$PWD/qqmltablemodelcolumn.cpp
+ $$PWD/qqmltableinstancemodel.cpp
HEADERS += \
- $$PWD/qqmltableinstancemodel_p.h \
- $$PWD/qqmltablemodel_p.h \
- $$PWD/qqmltablemodelcolumn_p.h
+ $$PWD/qqmltableinstancemodel_p.h
}
qtConfig(qml-list-model) {
@@ -51,21 +47,27 @@ qtConfig(qml-list-model) {
qtConfig(qml-delegate-model) {
SOURCES += \
+ $$PWD/qqmlabstractdelegatecomponent.cpp \
$$PWD/qqmladaptormodel.cpp \
$$PWD/qqmldelegatemodel.cpp \
- $$PWD/qqmldelegatecomponent.cpp \
$$PWD/qqmllistaccessor.cpp \
$$PWD/qqmllistcompositor.cpp \
$$PWD/qquickpackage.cpp
HEADERS += \
+ $$PWD/qqmlabstractdelegatecomponent_p.h \
$$PWD/qqmladaptormodel_p.h \
$$PWD/qqmldelegatemodel_p.h \
$$PWD/qqmldelegatemodel_p_p.h \
- $$PWD/qqmldelegatecomponent_p.h \
$$PWD/qqmllistaccessor_p.h \
$$PWD/qqmllistcompositor_p.h \
$$PWD/qquickpackage_p.h
}
+QMLTYPES_FILENAME = plugins.qmltypes
+QMLTYPES_INSTALL_DIR = $$[QT_INSTALL_QML]/QtQml/Models.2
+QML_IMPORT_NAME = QtQml.Models
+IMPORT_VERSION = 2.$$QT_MINOR_VERSION
+CONFIG += qmltypes install_qmltypes install_metatypes
+
load(qt_module)
diff --git a/src/qmlmodels/qqmlabstractdelegatecomponent.cpp b/src/qmlmodels/qqmlabstractdelegatecomponent.cpp
new file mode 100644
index 0000000000..1058d87485
--- /dev/null
+++ b/src/qmlmodels/qqmlabstractdelegatecomponent.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQmlModels/private/qqmlabstractdelegatecomponent_p.h>
+#include <QtQmlModels/private/qqmladaptormodel_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQmlAbstractDelegateComponent::QQmlAbstractDelegateComponent(QObject *parent)
+ : QQmlComponent(parent)
+{
+}
+
+QQmlAbstractDelegateComponent::~QQmlAbstractDelegateComponent()
+{
+}
+
+QVariant QQmlAbstractDelegateComponent::value(QQmlAdaptorModel *adaptorModel, int row, int column, const QString &role) const
+{
+ if (!adaptorModel)
+ return QVariant();
+ return adaptorModel->value(adaptorModel->indexAt(row, column), role);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmldelegatecomponent_p.h b/src/qmlmodels/qqmlabstractdelegatecomponent_p.h
index 1d20f0327b..07cae6b092 100644
--- a/src/qmlmodels/qqmldelegatecomponent_p.h
+++ b/src/qmlmodels/qqmlabstractdelegatecomponent_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QQMLDELEGATECOMPONENT_P_H
-#define QQMLDELEGATECOMPONENT_P_H
+#ifndef QQMLABSTRACTDELEGATECOMPONENT_P_H
+#define QQMLABSTRACTDELEGATECOMPONENT_P_H
//
// W A R N I N G
@@ -52,6 +52,7 @@
//
#include <private/qtqmlmodelsglobal_p.h>
+#include <private/qqmlcomponentattached_p.h>
#include <qqmlcomponent.h>
QT_REQUIRE_CONFIG(qml_delegate_model);
@@ -59,11 +60,13 @@ QT_REQUIRE_CONFIG(qml_delegate_model);
QT_BEGIN_NAMESPACE
// TODO: consider making QQmlAbstractDelegateComponent public API
-class QQmlAbstractDelegateComponentPrivate;
class QQmlAdaptorModel;
class Q_QMLMODELS_PRIVATE_EXPORT QQmlAbstractDelegateComponent : public QQmlComponent
{
Q_OBJECT
+ QML_NAMED_ELEMENT(AbstractDelegateComponent)
+ QML_UNCREATABLE("Cannot create instance of abstract class AbstractDelegateComponent.")
+
public:
QQmlAbstractDelegateComponent(QObject *parent = nullptr);
~QQmlAbstractDelegateComponent() override;
@@ -75,81 +78,8 @@ signals:
protected:
QVariant value(QQmlAdaptorModel *adaptorModel,int row, int column, const QString &role) const;
-
-private:
- Q_DECLARE_PRIVATE(QQmlAbstractDelegateComponent)
- Q_DISABLE_COPY(QQmlAbstractDelegateComponent)
-};
-
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateChoice : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QVariant roleValue READ roleValue WRITE setRoleValue NOTIFY roleValueChanged)
- Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged)
- Q_PROPERTY(int index READ row WRITE setRow NOTIFY indexChanged)
- Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged)
- Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
- Q_CLASSINFO("DefaultProperty", "delegate")
-public:
- QVariant roleValue() const;
- void setRoleValue(const QVariant &roleValue);
-
- int row() const;
- void setRow(int r);
-
- int column() const;
- void setColumn(int c);
-
- QQmlComponent *delegate() const;
- void setDelegate(QQmlComponent *delegate);
-
- virtual bool match(int row, int column, const QVariant &value) const;
-
-signals:
- void roleValueChanged();
- void rowChanged();
- void indexChanged();
- void columnChanged();
- void delegateChanged();
- void changed();
-
-private:
- QVariant m_value;
- int m_row = -1;
- int m_column = -1;
- QQmlComponent *m_delegate = nullptr;
-};
-
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateChooser : public QQmlAbstractDelegateComponent
-{
- Q_OBJECT
- Q_PROPERTY(QString role READ role WRITE setRole NOTIFY roleChanged)
- Q_PROPERTY(QQmlListProperty<QQmlDelegateChoice> choices READ choices CONSTANT)
- Q_CLASSINFO("DefaultProperty", "choices")
-
-public:
- QString role() const { return m_role; }
- void setRole(const QString &role);
-
- virtual QQmlListProperty<QQmlDelegateChoice> choices();
- static void choices_append(QQmlListProperty<QQmlDelegateChoice> *, QQmlDelegateChoice *);
- static int choices_count(QQmlListProperty<QQmlDelegateChoice> *);
- static QQmlDelegateChoice *choices_at(QQmlListProperty<QQmlDelegateChoice> *, int);
- static void choices_clear(QQmlListProperty<QQmlDelegateChoice> *);
-
- QQmlComponent *delegate(QQmlAdaptorModel *adaptorModel, int row, int column = -1) const override;
-
-signals:
- void roleChanged();
-
-private:
- QString m_role;
- QList<QQmlDelegateChoice *> m_choices;
};
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQmlDelegateChoice)
-QML_DECLARE_TYPE(QQmlDelegateChooser)
-
-#endif // QQMLDELEGATECOMPONENT_P_H
+#endif // QQMLABSTRACTDELEGATECOMPONENT_P_H
diff --git a/src/qmlmodels/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp
index 64d9723a6d..2126ad3dc5 100644
--- a/src/qmlmodels/qqmladaptormodel.cpp
+++ b/src/qmlmodels/qqmladaptormodel.cpp
@@ -93,7 +93,7 @@ class QQmlDMCachedModelData : public QQmlDelegateModelItem
{
public:
QQmlDMCachedModelData(
- QQmlDelegateModelItemMetaType *metaType,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
VDMModelDelegateDataType *dataType,
int index, int row, int column);
@@ -255,7 +255,9 @@ public:
bool hasModelData;
};
-QQmlDMCachedModelData::QQmlDMCachedModelData(QQmlDelegateModelItemMetaType *metaType, VDMModelDelegateDataType *dataType, int index, int row, int column)
+QQmlDMCachedModelData::QQmlDMCachedModelData(
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ VDMModelDelegateDataType *dataType, int index, int row, int column)
: QQmlDelegateModelItem(metaType, dataType, index, row, column)
, type(dataType)
{
@@ -367,10 +369,10 @@ QV4::ReturnedValue QQmlDMCachedModelData::set_property(const QV4::FunctionObject
QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item);
if (!modelData->cachedData.isEmpty()) {
if (modelData->cachedData.count() > 1) {
- modelData->cachedData[propertyId] = scope.engine->toVariant(argv[0], QVariant::Invalid);
+ modelData->cachedData[propertyId] = scope.engine->toVariant(argv[0], QMetaType::UnknownType);
QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), propertyId, nullptr);
} else if (modelData->cachedData.count() == 1) {
- modelData->cachedData[0] = scope.engine->toVariant(argv[0], QVariant::Invalid);
+ modelData->cachedData[0] = scope.engine->toVariant(argv[0], QMetaType::UnknownType);
QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 0, nullptr);
QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 1, nullptr);
}
@@ -390,7 +392,7 @@ class QQmlDMAbstractItemModelData : public QQmlDMCachedModelData
public:
QQmlDMAbstractItemModelData(
- QQmlDelegateModelItemMetaType *metaType,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
VDMModelDelegateDataType *dataType,
int index, int row, int column)
: QQmlDMCachedModelData(metaType, dataType, index, row, column)
@@ -463,6 +465,11 @@ public:
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()) {
@@ -507,7 +514,7 @@ public:
QQmlDelegateModelItem *createItem(
QQmlAdaptorModel &model,
- QQmlDelegateModelItemMetaType *metaType,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
int index, int row, int column) const override
{
VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
@@ -516,7 +523,7 @@ public:
return new QQmlDMAbstractItemModelData(metaType, dataType, index, row, column);
}
- void initializeMetaType(QQmlAdaptorModel &model)
+ void initializeMetaType(const QQmlAdaptorModel &model)
{
QMetaObjectBuilder builder;
setModelDataType<QQmlDMAbstractItemModelData>(&builder, this);
@@ -555,7 +562,7 @@ class QQmlDMListAccessorData : public QQmlDelegateModelItem
Q_OBJECT
Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
public:
- QQmlDMListAccessorData(QQmlDelegateModelItemMetaType *metaType,
+ QQmlDMListAccessorData(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
QQmlAdaptorModel::Accessors *accessor,
int index, int row, int column, const QVariant &value)
: QQmlDelegateModelItem(metaType, accessor, index, row, column)
@@ -596,7 +603,7 @@ public:
if (!argc)
return v4->throwTypeError();
- static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(v4->toVariant(argv[0], QVariant::Invalid));
+ static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(v4->toVariant(argv[0], QMetaType::UnknownType));
return QV4::Encode::undefined();
}
@@ -671,7 +678,7 @@ public:
QQmlDelegateModelItem *createItem(
QQmlAdaptorModel &model,
- QQmlDelegateModelItemMetaType *metaType,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
int index, int row, int column) const override
{
VDMListDelegateDataType *dataType = const_cast<VDMListDelegateDataType *>(this);
@@ -714,7 +721,7 @@ class QQmlDMObjectData : public QQmlDelegateModelItem, public QQmlAdaptorModelPr
Q_INTERFACES(QQmlAdaptorModelProxyInterface)
public:
QQmlDMObjectData(
- QQmlDelegateModelItemMetaType *metaType,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
VDMObjectDelegateDataType *dataType,
int index, int row, int column,
QObject *object);
@@ -785,7 +792,7 @@ public:
QQmlDelegateModelItem *createItem(
QQmlAdaptorModel &model,
- QQmlDelegateModelItemMetaType *metaType,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
int index, int row, int column) const override
{
VDMObjectDelegateDataType *dataType = const_cast<VDMObjectDelegateDataType *>(this);
@@ -925,7 +932,7 @@ public:
VDMObjectDelegateDataType *m_type;
};
-QQmlDMObjectData::QQmlDMObjectData(QQmlDelegateModelItemMetaType *metaType,
+QQmlDMObjectData::QQmlDMObjectData(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
VDMObjectDelegateDataType *dataType,
int index, int row, int column,
QObject *object)
@@ -970,6 +977,9 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QObject *parent, QQmlEn
} else if (list.type() == QQmlListAccessor::ListProperty) {
setObject(static_cast<const QQmlListReference *>(variant.constData())->object(), parent);
accessors = new VDMObjectDelegateDataType;
+ } else if (list.type() == QQmlListAccessor::ObjectList) {
+ setObject(nullptr, parent);
+ accessors = new VDMObjectDelegateDataType;
} else if (list.type() != QQmlListAccessor::Invalid
&& list.type() != QQmlListAccessor::Instance) { // Null QObject
setObject(nullptr, parent);
diff --git a/src/qmlmodels/qqmladaptormodel_p.h b/src/qmlmodels/qqmladaptormodel_p.h
index a4549127af..ba54c864c6 100644
--- a/src/qmlmodels/qqmladaptormodel_p.h
+++ b/src/qmlmodels/qqmladaptormodel_p.h
@@ -87,7 +87,7 @@ public:
virtual QQmlDelegateModelItem *createItem(
QQmlAdaptorModel &,
- QQmlDelegateModelItemMetaType *,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &,
int, int, int) const { return nullptr; }
virtual bool notify(
@@ -140,10 +140,16 @@ public:
inline QVariant value(int index, const QString &role) const {
return accessors->value(*this, index, role); }
- inline QQmlDelegateModelItem *createItem(QQmlDelegateModelItemMetaType *metaType, int index) {
- return accessors->createItem(*this, metaType, index, rowAt(index), columnAt(index)); }
+ inline QQmlDelegateModelItem *createItem(
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, int index)
+ {
+ return accessors->createItem(*this, metaType, index, rowAt(index), columnAt(index));
+ }
inline bool hasProxyObject() const {
- return list.type() == QQmlListAccessor::Instance || list.type() == QQmlListAccessor::ListProperty; }
+ return list.type() == QQmlListAccessor::Instance
+ || list.type() == QQmlListAccessor::ListProperty
+ || list.type() == QQmlListAccessor::ObjectList;
+ }
inline bool notify(
const QList<QQmlDelegateModelItem *> &items,
diff --git a/src/qmlmodels/qqmldelegatecomponent.cpp b/src/qmlmodels/qqmldelegatecomponent.cpp
deleted file mode 100644
index ccd54bccec..0000000000
--- a/src/qmlmodels/qqmldelegatecomponent.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmldelegatecomponent_p.h"
-#include <QtQmlModels/private/qqmladaptormodel_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QQmlAbstractDelegateComponent::QQmlAbstractDelegateComponent(QObject *parent)
- : QQmlComponent(parent)
-{
-}
-
-QQmlAbstractDelegateComponent::~QQmlAbstractDelegateComponent()
-{
-}
-
-QVariant QQmlAbstractDelegateComponent::value(QQmlAdaptorModel *adaptorModel, int row, int column, const QString &role) const
-{
- if (!adaptorModel)
- return QVariant();
- return adaptorModel->value(adaptorModel->indexAt(row, column), role);
-}
-
-/*!
- \qmltype DelegateChoice
- \instantiates QQmlDelegateChoice
- \inqmlmodule Qt.labs.qmlmodels
- \brief Encapsulates a delegate and when to use it.
-
- The DelegateChoice type wraps a delegate and defines the circumstances
- in which it should be chosen.
-
- DelegateChoices can be nested inside a DelegateChooser.
-
- \sa DelegateChooser
-*/
-
-/*!
- \qmlproperty variant QtQml.Models::DelegateChoice::roleValue
- This property holds the value used to match the role data for the role provided by \l DelegateChooser::role.
-*/
-QVariant QQmlDelegateChoice::roleValue() const
-{
- return m_value;
-}
-
-void QQmlDelegateChoice::setRoleValue(const QVariant &value)
-{
- if (m_value == value)
- return;
- m_value = value;
- emit roleValueChanged();
- emit changed();
-}
-
-/*!
- \qmlproperty int QtQml.Models::DelegateChoice::row
- This property holds the value used to match the row value of model elements.
- With models that have only the index property (and thus only one column), this property
- should be intended as an index, and set to the desired index value.
-
- \note Setting both row and index has undefined behavior. The two are equivalent and only
- one should be used.
-
- \sa index
-*/
-
-/*!
- \qmlproperty int QtQml.Models::DelegateChoice::index
- This property holds the value used to match the index value of model elements.
- This is effectively an alias for \l row.
-
- \sa row
-*/
-int QQmlDelegateChoice::row() const
-{
- return m_row;
-}
-
-void QQmlDelegateChoice::setRow(int r)
-{
- if (m_row == r)
- return;
- m_row = r;
- emit rowChanged();
- emit indexChanged();
- emit changed();
-}
-
-/*!
- \qmlproperty int QtQml.Models::DelegateChoice::column
- This property holds the value used to match the column value of model elements.
-*/
-int QQmlDelegateChoice::column() const
-{
- return m_column;
-}
-
-void QQmlDelegateChoice::setColumn(int c)
-{
- if (m_column == c)
- return;
- m_column = c;
- emit columnChanged();
- emit changed();
-}
-
-QQmlComponent *QQmlDelegateChoice::delegate() const
-{
- return m_delegate;
-}
-
-/*!
- \qmlproperty Component QtQml.Models::DelegateChoice::delegate
- This property holds the delegate to use if this choice matches the model item.
-*/
-void QQmlDelegateChoice::setDelegate(QQmlComponent *delegate)
-{
- if (m_delegate == delegate)
- return;
- QQmlAbstractDelegateComponent *adc = static_cast<QQmlAbstractDelegateComponent *>(m_delegate);
- if (adc)
- disconnect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this, &QQmlDelegateChoice::delegateChanged);
- m_delegate = delegate;
- adc = static_cast<QQmlAbstractDelegateComponent *>(delegate);
- if (adc)
- connect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this, &QQmlDelegateChoice::delegateChanged);
- emit delegateChanged();
- emit changed();
-}
-
-bool QQmlDelegateChoice::match(int row, int column, const QVariant &value) const
-{
- if (!m_value.isValid() && m_row < 0 && m_column < 0)
- return true;
-
- const bool roleMatched = (m_value.isValid()) ? value == m_value : true;
- const bool rowMatched = (m_row < 0 ) ? true : m_row == row;
- const bool columnMatched = (m_column < 0 ) ? true : m_column == column;
- return roleMatched && rowMatched && columnMatched;
-}
-
-/*!
- \qmltype DelegateChooser
- \instantiates QQmlDelegateChooser
- \inqmlmodule Qt.labs.qmlmodels
- \brief Allows a view to use different delegates for different types of items in the model.
-
- The DelegateChooser is a special \l Component type intended for those scenarios where a Component is required
- by a view and used as a delegate.
- DelegateChooser encapsulates a set of \l {DelegateChoice}s.
- These choices are used to determine the delegate that will be instantiated for each
- item in the model.
- The selection of the choice is performed based on the value that a model item has for \l role,
- and also based on index.
-
- DelegateChooser is commonly used when a view needs to display a set of delegates that are significantly
- different from each other. For example, a typical phone settings view might include toggle switches,
- sliders, radio buttons, and other visualizations based on the type of each setting. In this case, DelegateChooser
- could provide an easy way to associate a different type of delegate with each setting:
-
- \qml \QtMinorVersion
- import QtQuick 2.\1
- import QtQuick.Controls 2.\1
- import Qt.labs.qmlmodels 1.0
-
- ListView {
- width: 200; height: 400
-
- ListModel {
- id: listModel
- ListElement { type: "info"; ... }
- ListElement { type: "switch"; ... }
- ListElement { type: "swipe"; ... }
- ListElement { type: "switch"; ... }
- }
-
- DelegateChooser {
- id: chooser
- role: "type"
- DelegateChoice { roleValue: "info"; ItemDelegate { ... } }
- DelegateChoice { roleValue: "switch"; SwitchDelegate { ... } }
- DelegateChoice { roleValue: "swipe"; SwipeDelegate { ... } }
- }
-
- model: listModel
- delegate: chooser
- }
- \endqml
-
- \note This type is intended to transparently work only with TableView and any DelegateModel-based view.
- Views (including user-defined views) that aren't internally based on a DelegateModel need to explicitly support
- this type of component to make it function as described.
-
- \sa DelegateChoice
-*/
-
-/*!
- \qmlproperty string QtQml.Models::DelegateChooser::role
- This property holds the role used to determine the delegate for a given model item.
-
- \sa DelegateChoice
-*/
-void QQmlDelegateChooser::setRole(const QString &role)
-{
- if (m_role == role)
- return;
- m_role = role;
- emit roleChanged();
-}
-
-/*!
- \qmlproperty list<DelegateChoice> QtQml.Models::DelegateChooser::choices
- \default
-
- The list of DelegateChoices for the chooser.
-
- The list is treated as an ordered list, where the first DelegateChoice to match
- will be used be a view.
-
- It should not generally be necessary to refer to the \c choices property,
- as it is the default property for DelegateChooser and thus all child items are
- automatically assigned to this property.
-*/
-
-QQmlListProperty<QQmlDelegateChoice> QQmlDelegateChooser::choices()
-{
- return QQmlListProperty<QQmlDelegateChoice>(this, nullptr,
- QQmlDelegateChooser::choices_append,
- QQmlDelegateChooser::choices_count,
- QQmlDelegateChooser::choices_at,
- QQmlDelegateChooser::choices_clear);
-}
-
-void QQmlDelegateChooser::choices_append(QQmlListProperty<QQmlDelegateChoice> *prop, QQmlDelegateChoice *choice)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
- q->m_choices.append(choice);
- connect(choice, &QQmlDelegateChoice::changed, q, &QQmlAbstractDelegateComponent::delegateChanged);
- q->delegateChanged();
-}
-
-int QQmlDelegateChooser::choices_count(QQmlListProperty<QQmlDelegateChoice> *prop)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser*>(prop->object);
- return q->m_choices.count();
-}
-
-QQmlDelegateChoice *QQmlDelegateChooser::choices_at(QQmlListProperty<QQmlDelegateChoice> *prop, int index)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser*>(prop->object);
- return q->m_choices.at(index);
-}
-
-void QQmlDelegateChooser::choices_clear(QQmlListProperty<QQmlDelegateChoice> *prop)
-{
- QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
- for (QQmlDelegateChoice *choice : q->m_choices)
- disconnect(choice, &QQmlDelegateChoice::changed, q, &QQmlAbstractDelegateComponent::delegateChanged);
- q->m_choices.clear();
- q->delegateChanged();
-}
-
-QQmlComponent *QQmlDelegateChooser::delegate(QQmlAdaptorModel *adaptorModel, int row, int column) const
-{
- QVariant v;
- if (!m_role.isNull())
- v = value(adaptorModel, row, column, m_role);
- if (!v.isValid()) { // check if the row only has modelData, for example if the row is a QVariantMap
- v = value(adaptorModel, row, column, QStringLiteral("modelData"));
- if (v.isValid())
- v = v.toMap().value(m_role);
- }
- // loop through choices, finding first one that fits
- for (int i = 0; i < m_choices.count(); ++i) {
- const QQmlDelegateChoice *choice = m_choices.at(i);
- if (choice->match(row, column, v))
- return choice->delegate();
- }
-
- return nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index d5b30df45b..cee096035a 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -38,17 +38,16 @@
****************************************************************************/
#include "qqmldelegatemodel_p_p.h"
-#include "qqmldelegatecomponent_p.h"
#include <QtQml/qqmlinfo.h>
+#include <private/qqmlabstractdelegatecomponent_p.h>
#include <private/qquickpackage_p.h>
#include <private/qmetaobjectbuilder_p.h>
#include <private/qqmladaptormodel_p.h>
#include <private/qqmlchangeset_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
-#include <private/qqmlincubator_p.h>
#include <private/qv4value_p.h>
#include <private/qv4functionobject_p.h>
@@ -56,6 +55,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcItemViewDelegateRecycling, "qt.quick.itemview.delegaterecycling")
+
class QQmlDelegateModelItem;
namespace QV4 {
@@ -206,6 +207,9 @@ QQmlDelegateModelPrivate::~QQmlDelegateModelPrivate()
{
qDeleteAll(m_finishedIncubating);
+ // Free up all items in the pool
+ drainReusableItemsPool(0);
+
if (m_cacheMetaType)
m_cacheMetaType->release();
}
@@ -265,13 +269,23 @@ QQmlDelegateModel::~QQmlDelegateModel()
Q_ASSERT(cacheItem->contextData->refCount == 1);
cacheItem->contextData = nullptr;
cacheItem->scriptRef -= 1;
+ } else if (cacheItem->incubationTask) {
+ // Both the incubationTask and the object may hold a scriptRef,
+ // but if both are present, only one scriptRef is held in total.
+ cacheItem->scriptRef -= 1;
}
+
cacheItem->groups &= ~Compositor::UnresolvedFlag;
cacheItem->objectRef = 0;
+
+ if (cacheItem->incubationTask) {
+ d->releaseIncubator(cacheItem->incubationTask);
+ cacheItem->incubationTask->vdm = nullptr;
+ cacheItem->incubationTask = nullptr;
+ }
+
if (!cacheItem->isReferenced())
delete cacheItem;
- else if (cacheItem->incubationTask)
- cacheItem->incubationTask->vdm = nullptr;
}
}
@@ -589,36 +603,47 @@ int QQmlDelegateModel::count() const
return d->m_compositor.count(d->m_compositorGroup);
}
-QQmlDelegateModel::ReleaseFlags QQmlDelegateModelPrivate::release(QObject *object)
+QQmlDelegateModel::ReleaseFlags QQmlDelegateModelPrivate::release(QObject *object, QQmlInstanceModel::ReusableFlag reusableFlag)
{
if (!object)
- return QQmlDelegateModel::ReleaseFlags(0);
+ return QQmlDelegateModel::ReleaseFlags{};
QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(object);
if (!cacheItem)
- return QQmlDelegateModel::ReleaseFlags(0);
+ return QQmlDelegateModel::ReleaseFlags{};
if (!cacheItem->releaseObject())
return QQmlDelegateModel::Referenced;
+ if (reusableFlag == QQmlInstanceModel::Reusable) {
+ removeCacheItem(cacheItem);
+ m_reusableItemsPool.insertItem(cacheItem);
+ emit q_func()->itemPooled(cacheItem->index, cacheItem->object);
+ return QQmlInstanceModel::Pooled;
+ }
+
+ destroyCacheItem(cacheItem);
+ return QQmlInstanceModel::Destroyed;
+}
+
+void QQmlDelegateModelPrivate::destroyCacheItem(QQmlDelegateModelItem *cacheItem)
+{
+ emitDestroyingItem(cacheItem->object);
cacheItem->destroyObject();
- emitDestroyingItem(object);
if (cacheItem->incubationTask) {
releaseIncubator(cacheItem->incubationTask);
cacheItem->incubationTask = nullptr;
}
cacheItem->Dispose();
- return QQmlInstanceModel::Destroyed;
}
/*
Returns ReleaseStatus flags.
*/
-
-QQmlDelegateModel::ReleaseFlags QQmlDelegateModel::release(QObject *item)
+QQmlDelegateModel::ReleaseFlags QQmlDelegateModel::release(QObject *item, QQmlInstanceModel::ReusableFlag reusableFlag)
{
Q_D(QQmlDelegateModel);
- QQmlInstanceModel::ReleaseFlags stat = d->release(item);
+ QQmlInstanceModel::ReleaseFlags stat = d->release(item, reusableFlag);
return stat;
}
@@ -626,7 +651,7 @@ QQmlDelegateModel::ReleaseFlags QQmlDelegateModel::release(QObject *item)
void QQmlDelegateModel::cancel(int index)
{
Q_D(QQmlDelegateModel);
- if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
+ if (index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
qWarning() << "DelegateModel::cancel: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
return;
}
@@ -716,7 +741,7 @@ QQmlListProperty<QQmlDelegateModelGroup> QQmlDelegateModel::groups()
QQmlDelegateModelPrivate::group_append,
QQmlDelegateModelPrivate::group_count,
QQmlDelegateModelPrivate::group_at,
- nullptr);
+ nullptr, nullptr, nullptr);
}
/*!
@@ -892,6 +917,125 @@ static bool isDoneIncubating(QQmlIncubator::Status status)
return status == QQmlIncubator::Ready || status == QQmlIncubator::Error;
}
+PropertyUpdater::PropertyUpdater(QObject *parent) :
+ QObject(parent) {}
+
+void PropertyUpdater::doUpdate()
+{
+ auto sender = QObject::sender();
+ auto mo = sender->metaObject();
+ auto signalIndex = QObject::senderSignalIndex();
+ ++updateCount;
+ auto property = mo->property(changeSignalIndexToPropertyIndex[signalIndex]);
+ // we synchronize between required properties and model rolenames by name
+ // that's why the QQmlProperty and the metaobject property must have the same name
+ QQmlProperty qmlProp(parent(), QString::fromLatin1(property.name()));
+ qmlProp.write(property.read(QObject::sender()));
+}
+
+void PropertyUpdater::breakBinding()
+{
+ auto it = senderToConnection.find(QObject::senderSignalIndex());
+ if (it == senderToConnection.end())
+ return;
+ if (updateCount == 0) {
+ QObject::disconnect(*it);
+ senderToConnection.erase(it);
+ QQmlError warning;
+ if (auto context = qmlContext(QObject::sender()))
+ warning.setUrl(context->baseUrl());
+ else
+ return;
+ auto signalName = QString::fromLatin1(QObject::sender()->metaObject()->method(QObject::senderSignalIndex()).name());
+ signalName.chop(sizeof("changed")-1);
+ QString propName = signalName;
+ propName[0] = propName[0].toLower();
+ warning.setDescription(QString::fromUtf8("Writing to \"%1\" broke the binding to the underlying model").arg(propName));
+ qmlWarning(this, warning);
+ } else {
+ --updateCount;
+ }
+}
+
+void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *modelItemToIncubate, QObject *object)
+{
+ auto incubatorPriv = QQmlIncubatorPrivate::get(this);
+ if (incubatorPriv->hadRequiredProperties()) {
+ QQmlData *d = QQmlData::get(object);
+ auto contextData = d ? d->context : nullptr;
+ if (contextData) {
+ contextData->hasExtraObject = true;
+ contextData->extraObject = modelItemToIncubate;
+ }
+
+ 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
+ QVarLengthArray<QPair<const QMetaObject *, QObject *>, 4> mos;
+ // we first check the dynamic meta object for properties originating from the model
+ // contains abstractitemmodelproperties
+ mos.push_back(qMakePair(qmlMetaObject, modelItemToIncubate));
+ auto delegateModelItemSubclassMO = qmlMetaObject->superClass();
+ mos.push_back(qMakePair(delegateModelItemSubclassMO, modelItemToIncubate));
+
+ while (strcmp(delegateModelItemSubclassMO->className(),
+ modelItemToIncubate->staticMetaObject.className())) {
+ delegateModelItemSubclassMO = delegateModelItemSubclassMO->superClass();
+ mos.push_back(qMakePair(delegateModelItemSubclassMO, modelItemToIncubate));
+ }
+ if (proxiedObject)
+ mos.push_back(qMakePair(proxiedObject->metaObject(), proxiedObject));
+
+ auto updater = new PropertyUpdater(object);
+ for (const auto &metaObjectAndObject : mos) {
+ const QMetaObject *mo = metaObjectAndObject.first;
+ QObject *itemOrProxy = metaObjectAndObject.second;
+ for (int i = mo->propertyOffset(); i < mo->propertyCount() + mo->propertyOffset(); ++i) {
+ auto prop = mo->property(i);
+ if (!prop.name())
+ continue;
+ auto propName = QString::fromUtf8(prop.name());
+ bool wasInRequired = false;
+ QQmlProperty componentProp = QQmlComponentPrivate::removePropertyFromRequired(
+ object, propName, requiredProperties, &wasInRequired);
+ // only write to property if it was actually requested by the component
+ if (wasInRequired && prop.hasNotifySignal()) {
+ QMetaMethod changeSignal = prop.notifySignal();
+ static QMetaMethod updateSlot = PropertyUpdater::staticMetaObject.method(
+ PropertyUpdater::staticMetaObject.indexOfSlot("doUpdate()"));
+
+ QMetaObject::Connection conn = QObject::connect(itemOrProxy, changeSignal,
+ updater, updateSlot);
+ updater->changeSignalIndexToPropertyIndex[changeSignal.methodIndex()] = i;
+ auto propIdx = object->metaObject()->indexOfProperty(propName.toUtf8());
+ QMetaMethod writeToPropSignal
+ = object->metaObject()->property(propIdx).notifySignal();
+ updater->senderToConnection[writeToPropSignal.methodIndex()] = conn;
+ static QMetaMethod breakBinding = PropertyUpdater::staticMetaObject.method(
+ PropertyUpdater::staticMetaObject.indexOfSlot("breakBinding()"));
+ componentProp.write(prop.read(itemOrProxy));
+ // the connection needs to established after the write,
+ // else the signal gets triggered by it and breakBinding will remove the connection
+ QObject::connect(object, writeToPropSignal, updater, breakBinding);
+ }
+ else if (wasInRequired) // we still have to write, even if there is no change signal
+ componentProp.write(prop.read(itemOrProxy));
+ }
+ }
+ } else {
+ modelItemToIncubate->contextData->contextObject = modelItemToIncubate;
+ if (proxiedObject)
+ proxyContext->contextObject = proxiedObject;
+ }
+}
+
void QQDMIncubationTask::statusChanged(Status status)
{
if (vdm) {
@@ -923,6 +1067,71 @@ void QQmlDelegateModelPrivate::releaseIncubator(QQDMIncubationTask *incubationTa
}
}
+void QQmlDelegateModelPrivate::reuseItem(QQmlDelegateModelItem *item, int newModelIndex, int newGroups)
+{
+ Q_ASSERT(item->object);
+
+ // Update/reset which groups the item belongs to
+ item->groups = newGroups;
+
+ // Update context property index (including row and column) on the delegate
+ // item, and inform the application about it. For a list, the row is the same
+ // as the index, and the column is always 0. We set alwaysEmit to true, to
+ // force all bindings to be reevaluated, even if the index didn't change.
+ const bool alwaysEmit = true;
+ item->setModelIndex(newModelIndex, newModelIndex, 0, alwaysEmit);
+
+ // Notify the application that all 'dynamic'/role-based context data has
+ // changed as well (their getter function will use the updated index).
+ auto const itemAsList = QList<QQmlDelegateModelItem *>() << item;
+ auto const updateAllRoles = QVector<int>();
+ m_adaptorModel.notify(itemAsList, newModelIndex, 1, updateAllRoles);
+
+ if (QQmlDelegateModelAttached *att = static_cast<QQmlDelegateModelAttached *>(
+ qmlAttachedPropertiesObject<QQmlDelegateModel>(item->object, false))) {
+ // Update currentIndex of the attached DelegateModel object
+ // to the index the item has in the cache.
+ att->resetCurrentIndex();
+ // emitChanges will emit both group-, and index changes to the application
+ att->emitChanges();
+ }
+
+ // Inform the view that the item is recycled. This will typically result
+ // in the view updating its own attached delegate item properties.
+ emit q_func()->itemReused(newModelIndex, item->object);
+}
+
+void QQmlDelegateModelPrivate::drainReusableItemsPool(int maxPoolTime)
+{
+ m_reusableItemsPool.drain(maxPoolTime, [=](QQmlDelegateModelItem *cacheItem){ destroyCacheItem(cacheItem); });
+}
+
+void QQmlDelegateModel::drainReusableItemsPool(int maxPoolTime)
+{
+ d_func()->drainReusableItemsPool(maxPoolTime);
+}
+
+int QQmlDelegateModel::poolSize()
+{
+ return d_func()->m_reusableItemsPool.size();
+}
+
+QQmlComponent *QQmlDelegateModelPrivate::resolveDelegate(int index)
+{
+ if (!m_delegateChooser)
+ return m_delegate;
+
+ QQmlComponent *delegate = nullptr;
+ QQmlAbstractDelegateComponent *chooser = m_delegateChooser;
+
+ do {
+ delegate = chooser->delegate(&m_adaptorModel, index);
+ chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
+ } while (chooser);
+
+ return delegate;
+}
+
void QQmlDelegateModelPrivate::addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it)
{
m_cache.insert(it.cacheIndex, item);
@@ -992,6 +1201,7 @@ void QQDMIncubationTask::setInitialState(QObject *o)
void QQmlDelegateModelPrivate::setInitialState(QQDMIncubationTask *incubationTask, QObject *o)
{
QQmlDelegateModelItem *cacheItem = incubationTask->incubating;
+ incubationTask->initializeRequiredProperties(incubationTask->incubating, o);
cacheItem->object = o;
if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
@@ -1010,16 +1220,38 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
}
Compositor::iterator it = m_compositor.find(group, index);
+ const auto flags = it->flags;
+ const auto modelIndex = it.modelIndex();
QQmlDelegateModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex) : 0;
- if (!cacheItem) {
- cacheItem = m_adaptorModel.createItem(m_cacheMetaType, it.modelIndex());
- if (!cacheItem)
+ if (!cacheItem || !cacheItem->delegate) {
+ QQmlComponent *delegate = resolveDelegate(modelIndex);
+ if (!delegate)
return nullptr;
- cacheItem->groups = it->flags;
- addCacheItem(cacheItem, it);
+ if (!cacheItem) {
+ cacheItem = m_reusableItemsPool.takeItem(delegate, index);
+ if (cacheItem) {
+ // Move the pooled item back into the cache, update
+ // all related properties, and return the object (which
+ // has already been incubated, otherwise it wouldn't be in the pool).
+ addCacheItem(cacheItem, it);
+ reuseItem(cacheItem, index, flags);
+ cacheItem->referenceObject();
+ return cacheItem->object;
+ }
+
+ // Since we could't find an available item in the pool, we create a new one
+ cacheItem = m_adaptorModel.createItem(m_cacheMetaType, modelIndex);
+ if (!cacheItem)
+ return nullptr;
+
+ cacheItem->groups = flags;
+ addCacheItem(cacheItem, it);
+ }
+
+ cacheItem->delegate = delegate;
}
// Bump the reference counts temporarily so neither the content data or the delegate object
@@ -1034,18 +1266,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
cacheItem->incubationTask->forceCompletion();
}
} else if (!cacheItem->object) {
- QQmlComponent *delegate = m_delegate;
- if (m_delegateChooser) {
- QQmlAbstractDelegateComponent *chooser = m_delegateChooser;
- do {
- delegate = chooser->delegate(&m_adaptorModel, cacheItem->index);
- chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
- } while (chooser);
- if (!delegate)
- return nullptr;
- }
-
- QQmlContext *creationContext = delegate->creationContext();
+ QQmlContext *creationContext = cacheItem->delegate->creationContext();
cacheItem->scriptRef += 1;
@@ -1058,7 +1279,6 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
QQmlContextData *ctxt = new QQmlContextData;
ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context.data()));
- ctxt->contextObject = cacheItem;
cacheItem->contextData = ctxt;
if (m_adaptorModel.hasProxyObject()) {
@@ -1067,17 +1287,18 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
ctxt = new QQmlContextData;
ctxt->setParent(cacheItem->contextData, /*stronglyReferencedByParent*/true);
QObject *proxied = proxy->proxiedObject();
- ctxt->contextObject = proxied;
+ cacheItem->incubationTask->proxiedObject = proxied;
+ cacheItem->incubationTask->proxyContext = ctxt;
// We don't own the proxied object. We need to clear it if it goes away.
QObject::connect(proxied, &QObject::destroyed,
cacheItem, &QQmlDelegateModelItem::childContextObjectDestroyed);
}
}
- QQmlComponentPrivate *cp = QQmlComponentPrivate::get(delegate);
+ QQmlComponentPrivate *cp = QQmlComponentPrivate::get(cacheItem->delegate);
cp->incubateObject(
cacheItem->incubationTask,
- delegate,
+ cacheItem->delegate,
m_context->engine(),
ctxt,
QQmlContextData::get(m_context));
@@ -1801,7 +2022,7 @@ bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const
propertyName = it.nextPropertyNameAsString(v);
if (propertyName->isNull())
break;
- cacheItem->setValue(propertyName->toQStringNoThrow(), scope.engine->toVariant(v, QVariant::Invalid));
+ cacheItem->setValue(propertyName->toQStringNoThrow(), scope.engine->toVariant(v, QMetaType::UnknownType));
}
cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
@@ -2057,9 +2278,10 @@ void QV4::Heap::QQmlDelegateModelItemObject::destroy()
}
-QQmlDelegateModelItem::QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType,
- QQmlAdaptorModel::Accessors *accessor,
- int modelIndex, int row, int column)
+QQmlDelegateModelItem::QQmlDelegateModelItem(
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ QQmlAdaptorModel::Accessors *accessor,
+ int modelIndex, int row, int column)
: v4(metaType->v4Engine)
, metaType(metaType)
, contextData(nullptr)
@@ -2075,8 +2297,6 @@ QQmlDelegateModelItem::QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *meta
, row(row)
, column(column)
{
- metaType->addref();
-
if (accessor->propertyCache) {
// The property cache in the accessor is common for all the model
// items in the model it wraps. It describes available model roles,
@@ -2105,9 +2325,6 @@ QQmlDelegateModelItem::~QQmlDelegateModelItem()
else
delete incubationTask;
}
-
- metaType->release();
-
}
void QQmlDelegateModelItem::Dispose()
@@ -2171,6 +2388,8 @@ QQmlDelegateModelItem *QQmlDelegateModelItem::dataForObject(QObject *object)
{
QQmlData *d = QQmlData::get(object);
QQmlContextData *context = d ? d->context : nullptr;
+ if (context && context->hasExtraObject)
+ return qobject_cast<QQmlDelegateModelItem *>(context->extraObject);
for (context = context ? context->parent : nullptr; context; context = context->parent) {
if (QQmlDelegateModelItem *cacheItem = qobject_cast<QQmlDelegateModelItem *>(
context->contextObject)) {
@@ -3182,8 +3401,6 @@ void QQmlDelegateModelGroup::move(QQmlV4Function *args)
Each index is adjusted for previous changes with all removed items preceding any inserted
items.
-
- The corresponding handler is \c onChanged.
*/
//============================================================================
@@ -3324,7 +3541,7 @@ QObject *QQmlPartsModel::object(int index, QQmlIncubator::IncubationMode incubat
QObject *part = package->part(m_part);
if (!part)
return nullptr;
- m_packaged.insertMulti(part, package);
+ m_packaged.insert(part, package);
return part;
}
@@ -3338,11 +3555,11 @@ QObject *QQmlPartsModel::object(int index, QQmlIncubator::IncubationMode incubat
return nullptr;
}
-QQmlInstanceModel::ReleaseFlags QQmlPartsModel::release(QObject *item)
+QQmlInstanceModel::ReleaseFlags QQmlPartsModel::release(QObject *item, ReusableFlag)
{
- QQmlInstanceModel::ReleaseFlags flags = nullptr;
+ QQmlInstanceModel::ReleaseFlags flags;
- QHash<QObject *, QQuickPackage *>::iterator it = m_packaged.find(item);
+ auto it = m_packaged.find(item);
if (it != m_packaged.end()) {
QQuickPackage *package = *it;
QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(m_model);
@@ -3383,7 +3600,7 @@ QQmlIncubator::Status QQmlPartsModel::incubationStatus(int index)
int QQmlPartsModel::indexOf(QObject *item, QObject *) const
{
- QHash<QObject *, QQuickPackage *>::const_iterator it = m_packaged.find(item);
+ auto it = m_packaged.find(item);
if (it != m_packaged.end()) {
if (QQmlDelegateModelItem *cacheItem = QQmlDelegateModelItem::dataForObject(*it))
return cacheItem->groupIndex(m_compositorGroup);
@@ -3431,6 +3648,121 @@ void QQmlPartsModel::emitModelUpdated(const QQmlChangeSet &changeSet, bool reset
}
}
+void QQmlReusableDelegateModelItemsPool::insertItem(QQmlDelegateModelItem *modelItem)
+{
+ // Currently, the only way for a view to reuse items is to call release()
+ // in the model class with the second argument explicitly set to
+ // QQmlReuseableDelegateModelItemsPool::Reusable. If the released item is
+ // no longer referenced, it will be added to the pool. Reusing of items can
+ // be specified per item, in case certain items cannot be recycled. A
+ // QQmlDelegateModelItem knows which delegate its object was created from.
+ // So when we are about to create a new item, we first check if the pool
+ // contains an item based on the same delegate from before. If so, we take
+ // it out of the pool (instead of creating a new item), and update all its
+ // context properties and attached properties.
+
+ // When a view is recycling items, it should call drain() regularly. As
+ // there is currently no logic to 'hibernate' items in the pool, they are
+ // only meant to rest there for a short while, ideally only from the time
+ // e.g a row is unloaded on one side of the view, and until a new row is
+ // loaded on the opposite side. Between these times, the application will
+ // see the item as fully functional and 'alive' (just not visible on
+ // screen). Since this time is supposed to be short, we don't take any
+ // action to notify the application about it, since we don't want to
+ // trigger any bindings that can disturb performance.
+
+ // A recommended time for calling drain() is each time a view has finished
+ // loading e.g a new row or column. If there are more items in the pool
+ // after that, it means that the view most likely doesn't need them anytime
+ // soon. Those items should be destroyed to reduce resource consumption.
+
+ // Depending on if a view is a list or a table, it can sometimes be
+ // performant to keep items in the pool for a bit longer than one "row
+ // out/row in" cycle. E.g for a table, if the number of visible rows in a
+ // view is much larger than the number of visible columns. In that case, if
+ // you flick out a row, and then flick in a column, you would throw away a
+ // lot of items in the pool if completely draining it. The reason is that
+ // unloading a row places more items in the pool than what ends up being
+ // recycled when loading a new column. And then, when you next flick in a
+ // new row, you would need to load all those drained items again from
+ // scratch. For that reason, you can specify a maxPoolTime to the
+ // drainReusableItemsPool() that allows you to keep items in the pool for a
+ // bit longer, effectively keeping more items in circulation. A recommended
+ // maxPoolTime would be equal to the number of dimensions in the view,
+ // which means 1 for a list view and 2 for a table view. If you specify 0,
+ // all items will be drained.
+
+ Q_ASSERT(!modelItem->incubationTask);
+ Q_ASSERT(!modelItem->isObjectReferenced());
+ Q_ASSERT(modelItem->object);
+ Q_ASSERT(modelItem->delegate);
+
+ modelItem->poolTime = 0;
+ m_reusableItemsPool.append(modelItem);
+
+ qCDebug(lcItemViewDelegateRecycling)
+ << "item:" << modelItem
+ << "delegate:" << modelItem->delegate
+ << "index:" << modelItem->modelIndex()
+ << "row:" << modelItem->modelRow()
+ << "column:" << modelItem->modelColumn()
+ << "pool size:" << m_reusableItemsPool.size();
+}
+
+QQmlDelegateModelItem *QQmlReusableDelegateModelItemsPool::takeItem(const QQmlComponent *delegate, int newIndexHint)
+{
+ // Find the oldest item in the pool that was made from the same delegate as
+ // the given argument, remove it from the pool, and return it.
+ for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end(); ++it) {
+ if ((*it)->delegate != delegate)
+ continue;
+ auto modelItem = *it;
+ m_reusableItemsPool.erase(it);
+
+ qCDebug(lcItemViewDelegateRecycling)
+ << "item:" << modelItem
+ << "delegate:" << delegate
+ << "old index:" << modelItem->modelIndex()
+ << "old row:" << modelItem->modelRow()
+ << "old column:" << modelItem->modelColumn()
+ << "new index:" << newIndexHint
+ << "pool size:" << m_reusableItemsPool.size();
+
+ return modelItem;
+ }
+
+ qCDebug(lcItemViewDelegateRecycling)
+ << "no available item for delegate:" << delegate
+ << "new index:" << newIndexHint
+ << "pool size:" << m_reusableItemsPool.size();
+
+ return nullptr;
+}
+
+void QQmlReusableDelegateModelItemsPool::drain(int maxPoolTime, std::function<void(QQmlDelegateModelItem *cacheItem)> releaseItem)
+{
+ // Rather than releasing all pooled items upon a call to this function, each
+ // item has a poolTime. The poolTime specifies for how many loading cycles an item
+ // has been resting in the pool. And for each invocation of this function, poolTime
+ // will increase. If poolTime is equal to, or exceeds, maxPoolTime, it will be removed
+ // from the pool and released. This way, the view can tweak a bit for how long
+ // items should stay in "circulation", even if they are not recycled right away.
+ qCDebug(lcItemViewDelegateRecycling) << "pool size before drain:" << m_reusableItemsPool.size();
+
+ for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end();) {
+ auto modelItem = *it;
+ modelItem->poolTime++;
+ if (modelItem->poolTime <= maxPoolTime) {
+ ++it;
+ } else {
+ it = m_reusableItemsPool.erase(it);
+ releaseItem(modelItem);
+ }
+ }
+
+ qCDebug(lcItemViewDelegateRecycling) << "pool size after drain:" << m_reusableItemsPool.size();
+}
+
//============================================================================
struct QQmlDelegateModelGroupChange : QV4::Object
diff --git a/src/qmlmodels/qqmldelegatemodel_p.h b/src/qmlmodels/qqmldelegatemodel_p.h
index 9e846ccc3e..8aab4badca 100644
--- a/src/qmlmodels/qqmldelegatemodel_p.h
+++ b/src/qmlmodels/qqmldelegatemodel_p.h
@@ -85,7 +85,11 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModel : public QQmlInstanceModel, p
Q_PROPERTY(QObject *parts READ parts CONSTANT)
Q_PROPERTY(QVariant rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
Q_CLASSINFO("DefaultProperty", "delegate")
+ QML_NAMED_ELEMENT(DelegateModel)
+ QML_ADDED_IN_MINOR_VERSION(1)
+ QML_ATTACHED(QQmlDelegateModelAttached)
Q_INTERFACES(QQmlParserStatus)
+
public:
QQmlDelegateModel();
QQmlDelegateModel(QQmlContext *, QObject *parent=nullptr);
@@ -109,12 +113,15 @@ public:
int count() const override;
bool isValid() const override { return delegate() != nullptr; }
QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override;
+ ReleaseFlags release(QObject *object, ReusableFlag reusableFlag = NotReusable) override;
void cancel(int index) override;
QVariant variantValue(int index, const QString &role) override;
void setWatchedRoles(const QList<QByteArray> &roles) override;
QQmlIncubator::Status incubationStatus(int index) override;
+ void drainReusableItemsPool(int maxPoolTime) override;
+ int poolSize() override;
+
int indexOf(QObject *object, QObject *objectContext) const override;
QString filterGroup() const;
@@ -164,6 +171,8 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModelGroup : public QObject
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(bool includeByDefault READ defaultInclude WRITE setDefaultInclude NOTIFY defaultIncludeChanged)
+ QML_NAMED_ELEMENT(DelegateModelGroup)
+ QML_ADDED_IN_MINOR_VERSION(1)
public:
QQmlDelegateModelGroup(QObject *parent = nullptr);
QQmlDelegateModelGroup(const QString &name, QQmlDelegateModel *model, int compositorType, QObject *parent = nullptr);
@@ -241,7 +250,6 @@ public:
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQmlDelegateModel)
-QML_DECLARE_TYPEINFO(QQmlDelegateModel, QML_HAS_ATTACHED_PROPERTIES)
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 3c8af5ca43..2dc409b222 100644
--- a/src/qmlmodels/qqmldelegatemodel_p_p.h
+++ b/src/qmlmodels/qqmldelegatemodel_p_p.h
@@ -49,6 +49,8 @@
#include <private/qqmladaptormodel_p.h>
#include <private/qqmlopenmetaobject_p.h>
+#include <QtCore/qloggingcategory.h>
+
//
// W A R N I N G
// -------------
@@ -64,6 +66,8 @@ QT_REQUIRE_CONFIG(qml_delegate_model);
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcItemViewDelegateRecycling)
+
typedef QQmlListCompositor Compositor;
class QQmlDelegateModelAttachedMetaObject;
@@ -100,7 +104,7 @@ class QQmlDelegateModelItem : public QObject
Q_PROPERTY(int column READ modelColumn NOTIFY columnChanged REVISION 12)
Q_PROPERTY(QObject *model READ modelObject CONSTANT)
public:
- QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType,
+ QQmlDelegateModelItem(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
QQmlAdaptorModel::Accessors *accessor, int modelIndex,
int row, int column);
~QQmlDelegateModelItem();
@@ -144,7 +148,7 @@ public:
static QV4::ReturnedValue get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
QV4::ExecutionEngine *v4;
- QQmlDelegateModelItemMetaType * const metaType;
+ QQmlRefPointer<QQmlDelegateModelItemMetaType> const metaType;
QQmlContextDataRef contextData;
QPointer<QObject> object;
QPointer<QQmlDelegateModelAttached> attached;
@@ -190,7 +194,18 @@ void QV4::Heap::QQmlDelegateModelItemObject::init(QQmlDelegateModelItem *item)
this->item = item;
}
+class QQmlReusableDelegateModelItemsPool
+{
+public:
+ void insertItem(QQmlDelegateModelItem *modelItem);
+ QQmlDelegateModelItem *takeItem(const QQmlComponent *delegate, int newIndexHint);
+ void reuseItem(QQmlDelegateModelItem *item, int newModelIndex);
+ void drain(int maxPoolTime, std::function<void(QQmlDelegateModelItem *cacheItem)> releaseItem);
+ int size() { return m_reusableItemsPool.size(); }
+private:
+ QList<QQmlDelegateModelItem *> m_reusableItemsPool;
+};
class QQmlDelegateModelPrivate;
class QQDMIncubationTask : public QQmlIncubator
@@ -201,11 +216,14 @@ public:
, incubating(nullptr)
, vdm(l) {}
+ void initializeRequiredProperties(QQmlDelegateModelItem *modelItemToIncubate, QObject* object);
void statusChanged(Status) override;
void setInitialState(QObject *) override;
QQmlDelegateModelItem *incubating = nullptr;
QQmlDelegateModelPrivate *vdm = nullptr;
+ QQmlContextData *proxyContext = nullptr;
+ QPointer<QObject> proxiedObject = nullptr; // the proxied object might disapear, so we use a QPointer instead of a raw one
int index[QQmlListCompositor::MaximumGroupCount];
};
@@ -275,7 +293,7 @@ public:
void requestMoreIfNecessary();
QObject *object(Compositor::Group group, int index, QQmlIncubator::IncubationMode incubationMode);
- QQmlDelegateModel::ReleaseFlags release(QObject *object);
+ QQmlDelegateModel::ReleaseFlags release(QObject *object, QQmlInstanceModel::ReusableFlag reusable = QQmlInstanceModel::NotReusable);
QVariant variantValue(Compositor::Group group, int index, const QString &name);
void emitCreatedPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
void emitInitPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
@@ -287,9 +305,13 @@ public:
void emitDestroyingItem(QObject *item) { Q_EMIT q_func()->destroyingItem(item); }
void addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it);
void removeCacheItem(QQmlDelegateModelItem *cacheItem);
-
+ void destroyCacheItem(QQmlDelegateModelItem *cacheItem);
void updateFilterGroup();
+ void reuseItem(QQmlDelegateModelItem *item, int newModelIndex, int newGroups);
+ void drainReusableItemsPool(int maxPoolTime);
+ QQmlComponent *resolveDelegate(int index);
+
void addGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
void removeGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
void setGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
@@ -334,6 +356,7 @@ public:
QQmlDelegateModelGroupEmitterList m_pendingParts;
QList<QQmlDelegateModelItem *> m_cache;
+ QQmlReusableDelegateModelItemsPool m_reusableItemsPool;
QList<QQDMIncubationTask *> m_finishedIncubating;
QList<QByteArray> m_watchedRoles;
@@ -377,7 +400,7 @@ public:
int count() const override;
bool isValid() const override;
QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *item) override;
+ ReleaseFlags release(QObject *item, ReusableFlag reusable = NotReusable) override;
QVariant variantValue(int index, const QString &role) override;
QList<QByteArray> watchedRoles() const { return m_watchedRoles; }
void setWatchedRoles(const QList<QByteArray> &roles) override;
@@ -396,7 +419,7 @@ Q_SIGNALS:
private:
QQmlDelegateModel *m_model;
- QHash<QObject *, QQuickPackage *> m_packaged;
+ QMultiHash<QObject *, QQuickPackage *> m_packaged;
QString m_part;
QString m_filterGroup;
QList<QByteArray> m_watchedRoles;
@@ -445,6 +468,20 @@ private:
const int indexPropertyOffset;
};
+class PropertyUpdater : public QObject
+{
+ Q_OBJECT
+
+public:
+ PropertyUpdater(QObject *parent);
+ QHash<int, QMetaObject::Connection> senderToConnection;
+ QHash<int, int> changeSignalIndexToPropertyIndex;
+ int updateCount = 0;
+public Q_SLOTS:
+ void doUpdate();
+ void breakBinding();
+};
+
QT_END_NAMESPACE
#endif
diff --git a/src/qmlmodels/qqmlinstantiator.cpp b/src/qmlmodels/qqmlinstantiator.cpp
index f9d5762f6e..3a0d746eb6 100644
--- a/src/qmlmodels/qqmlinstantiator.cpp
+++ b/src/qmlmodels/qqmlinstantiator.cpp
@@ -250,8 +250,6 @@ QQmlInstantiator::~QQmlInstantiator()
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
parameter holds the \l QtObject that has been added.
-
- The corresponding handler is \c onObjectAdded.
*/
/*!
@@ -263,8 +261,6 @@ QQmlInstantiator::~QQmlInstantiator()
Do not keep a reference to \a object if it was created by this Instantiator, as
in these cases it will be deleted shortly after the signal is handled.
-
- The corresponding handler is \c onObjectRemoved.
*/
/*!
\qmlproperty bool QtQml::Instantiator::active
diff --git a/src/qmlmodels/qqmlinstantiator_p.h b/src/qmlmodels/qqmlinstantiator_p.h
index 87accc304f..60b611128d 100644
--- a/src/qmlmodels/qqmlinstantiator_p.h
+++ b/src/qmlmodels/qqmlinstantiator_p.h
@@ -72,6 +72,8 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlInstantiator : public QObject, public QQmlP
Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
Q_PROPERTY(QObject *object READ object NOTIFY objectChanged)
Q_CLASSINFO("DefaultProperty", "delegate")
+ QML_NAMED_ELEMENT(Instantiator)
+ QML_ADDED_IN_MINOR_VERSION(14)
public:
QQmlInstantiator(QObject *parent = nullptr);
diff --git a/src/qmlmodels/qqmllistaccessor.cpp b/src/qmlmodels/qqmllistaccessor.cpp
index 46a11e2bc2..69427df184 100644
--- a/src/qmlmodels/qqmllistaccessor.cpp
+++ b/src/qmlmodels/qqmllistaccessor.cpp
@@ -76,11 +76,13 @@ void QQmlListAccessor::setList(const QVariant &v, QQmlEngine *engine)
if (!d.isValid()) {
m_type = Invalid;
- } else if (d.userType() == QVariant::StringList) {
+ } else if (d.userType() == QMetaType::QStringList) {
m_type = StringList;
} else if (d.userType() == QMetaType::QVariantList) {
m_type = VariantList;
- } else if (d.canConvert(QVariant::Int)) {
+ } else if (d.userType() == qMetaTypeId<QList<QObject *>>()) {
+ m_type = ObjectList;
+ } else if (d.canConvert(QMetaType::Int)) {
// 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;
@@ -120,6 +122,8 @@ int QQmlListAccessor::count() const
return qvariant_cast<QStringList>(d).count();
case VariantList:
return qvariant_cast<QVariantList>(d).count();
+ case ObjectList:
+ return qvariant_cast<QList<QObject *>>(d).count();
case ListProperty:
return ((const QQmlListReference *)d.constData())->count();
case Instance:
@@ -140,6 +144,8 @@ QVariant QQmlListAccessor::at(int idx) const
return QVariant::fromValue(qvariant_cast<QStringList>(d).at(idx));
case VariantList:
return qvariant_cast<QVariantList>(d).at(idx);
+ case ObjectList:
+ return QVariant::fromValue(qvariant_cast<QList<QObject *>>(d).at(idx));
case ListProperty:
return QVariant::fromValue(((const QQmlListReference *)d.constData())->at(idx));
case Instance:
diff --git a/src/qmlmodels/qqmllistaccessor_p.h b/src/qmlmodels/qqmllistaccessor_p.h
index bcd079adef..a57e4173e3 100644
--- a/src/qmlmodels/qqmllistaccessor_p.h
+++ b/src/qmlmodels/qqmllistaccessor_p.h
@@ -70,7 +70,7 @@ public:
int count() const;
QVariant at(int) const;
- enum Type { Invalid, StringList, VariantList, ListProperty, Instance, Integer };
+ enum Type { Invalid, StringList, VariantList, ObjectList, ListProperty, Instance, Integer };
Type type() const { return m_type; }
private:
diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp
index 083e80a0a3..e07951cab3 100644
--- a/src/qmlmodels/qqmllistmodel.cpp
+++ b/src/qmlmodels/qqmllistmodel.cpp
@@ -219,14 +219,14 @@ const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QV
{
Role::DataType type;
- switch (data.type()) {
- case QVariant::Double: type = Role::Number; break;
- case QVariant::Int: type = Role::Number; break;
- case QVariant::Bool: type = Role::Bool; break;
- case QVariant::String: type = Role::String; break;
- case QVariant::Map: type = Role::VariantMap; break;
- case QVariant::DateTime: type = Role::DateTime; break;
- case QVariant::UserType: {
+ switch (data.userType()) {
+ case QMetaType::Double: type = Role::Number; break;
+ case QMetaType::Int: type = Role::Number; break;
+ case QMetaType::Bool: type = Role::Bool; break;
+ case QMetaType::QString: type = Role::String; break;
+ case QMetaType::QVariantMap: type = Role::VariantMap; break;
+ case QMetaType::QDateTime: type = Role::DateTime; break;
+ default: {
if (data.userType() == qMetaTypeId<QJSValue>() &&
data.value<QJSValue>().isCallable()) {
type = Role::Function;
@@ -235,12 +235,14 @@ const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QV
&& data.value<const QV4::CompiledData::Binding*>()->isTranslationBinding()) {
type = Role::String;
break;
- } else {
+ } else if (data.userType() >= QMetaType::User) {
type = Role::List;
break;
+ } else {
+ type = Role::Invalid;
+ break;
}
}
- default: type = Role::Invalid; break;
}
if (type == Role::Invalid) {
@@ -1740,7 +1742,7 @@ void DynamicRoleModelNode::updateValues(const QVariantMap &object, QVector<int>
if (value.userType() == qMetaTypeId<QJSValue>())
value = value.value<QJSValue>().toVariant();
- if (value.type() == QVariant::List) {
+ if (value.userType() == QMetaType::QVariantList) {
QQmlListModel *subModel = QQmlListModel::createWithOwner(m_owner);
QVariantList subArray = value.toList();
@@ -1803,7 +1805,7 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
if (v.userType() == qMetaTypeId<QJSValue>())
v= v.value<QJSValue>().toVariant();
- if (v.type() == QVariant::List) {
+ if (v.userType() == QMetaType::QVariantList) {
QQmlListModel *subModel = QQmlListModel::createWithOwner(parentModel);
QVariantList subArray = v.toList();
diff --git a/src/qmlmodels/qqmllistmodel_p.h b/src/qmlmodels/qqmllistmodel_p.h
index 10d67c1c6f..9a4358ac6f 100644
--- a/src/qmlmodels/qqmllistmodel_p.h
+++ b/src/qmlmodels/qqmllistmodel_p.h
@@ -83,6 +83,8 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlListModel : public QAbstractListModel
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(bool dynamicRoles READ dynamicRoles WRITE setDynamicRoles)
Q_PROPERTY(QObject *agent READ agent CONSTANT REVISION(14))
+ QML_NAMED_ELEMENT(ListModel)
+ QML_ADDED_IN_MINOR_VERSION(1)
public:
QQmlListModel(QObject *parent=nullptr);
@@ -171,7 +173,9 @@ private:
// ### FIXME
class QQmlListElement : public QObject
{
-Q_OBJECT
+ Q_OBJECT
+ QML_NAMED_ELEMENT(ListElement)
+ QML_ADDED_IN_MINOR_VERSION(1)
};
class QQmlListModelParser : public QQmlCustomParser
@@ -201,6 +205,12 @@ private:
QString listElementTypeName;
};
+template<>
+inline QQmlCustomParser *qmlCreateCustomParser<QQmlListModel>()
+{
+ return new QQmlListModelParser;
+}
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQmlListModel)
diff --git a/src/qmlmodels/qqmllistmodelworkeragent_p.h b/src/qmlmodels/qqmllistmodelworkeragent_p.h
index 1ef27cea3f..f65909dcec 100644
--- a/src/qmlmodels/qqmllistmodelworkeragent_p.h
+++ b/src/qmlmodels/qqmllistmodelworkeragent_p.h
@@ -56,6 +56,7 @@
#include <QEvent>
#include <QMutex>
#include <QWaitCondition>
+#include <QtQml/qqml.h>
#include <private/qv4engine_p.h>
@@ -71,6 +72,7 @@ class QQmlListModelWorkerAgent : public QObject
Q_OBJECT
Q_PROPERTY(int count READ count)
Q_PROPERTY(QV4::ExecutionEngine *engine READ engine WRITE setEngine NOTIFY engineChanged)
+ QML_ANONYMOUS
public:
QQmlListModelWorkerAgent(QQmlListModel *);
diff --git a/src/qmlmodels/qqmlmodelsmodule.cpp b/src/qmlmodels/qqmlmodelsmodule.cpp
index d569d8e23c..155ded6c65 100644
--- a/src/qmlmodels/qqmlmodelsmodule.cpp
+++ b/src/qmlmodels/qqmlmodelsmodule.cpp
@@ -40,25 +40,20 @@
#include "qqmlmodelsmodule_p.h"
#include <private/qtqmlmodelsglobal_p.h>
-#if QT_CONFIG(itemmodel)
-#include <QtCore/qitemselectionmodel.h>
-#endif
#if QT_CONFIG(qml_list_model)
#include <private/qqmllistmodel_p.h>
+#include <private/qqmllistmodelworkeragent_p.h>
#endif
#if QT_CONFIG(qml_delegate_model)
+#include <private/qqmlabstractdelegatecomponent_p.h>
#include <private/qqmldelegatemodel_p.h>
-#include <private/qqmldelegatecomponent_p.h>
#include <private/qquickpackage_p.h>
+#include <private/qqmlcomponentattached_p.h>
#endif
#if QT_CONFIG(qml_object_model)
#include <private/qqmlobjectmodel_p.h>
#include <private/qqmlinstantiator_p.h>
#endif
-#if QT_CONFIG(qml_table_model)
-#include <private/qqmltablemodel_p.h>
-#include <private/qqmltablemodelcolumn_p.h>
-#endif
QT_BEGIN_NAMESPACE
@@ -67,6 +62,8 @@ QT_BEGIN_NAMESPACE
void QQmlModelsModule::registerQmlTypes()
{
// Don't add anything here. These are only for backwards compatibility.
+ // Don't convert these to qmlRegisterTypesAndRevisions!
+ // -> the annotations in the headers are for the QtQml.Models module <-
#if QT_CONFIG(qml_object_model)
qmlRegisterType<QQmlInstantiator>("QtQml", 2, 1, "Instantiator"); // Only available in >= 2.1
qmlRegisterAnonymousType<QQmlInstanceModel>("QtQml", 2);
@@ -76,6 +73,8 @@ void QQmlModelsModule::registerQmlTypes()
void QQmlModelsModule::registerQuickTypes()
{
// Don't add anything here. These are only for backwards compatibility.
+ // Don't convert these to qmlRegisterTypesAndRevisions!
+ // -> the annotations in the headers are for the QtQml.Models module <-
const char uri[] = "QtQuick";
@@ -97,43 +96,4 @@ void QQmlModelsModule::registerQuickTypes()
#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-void QQmlModelsModule::defineModule()
-{
- const char uri[] = "QtQml.Models";
-
-#if QT_CONFIG(qml_list_model)
- qmlRegisterType<QQmlListElement>(uri, 2, 1, "ListElement");
- qmlRegisterCustomType<QQmlListModel>(uri, 2, 1, "ListModel", new QQmlListModelParser);
-#endif
-#if QT_CONFIG(qml_delegate_model)
- qmlRegisterType<QQmlDelegateModel>(uri, 2, 1, "DelegateModel");
- qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 1, "DelegateModelGroup");
- qmlRegisterType<QQuickPackage>(uri, 2, 14, "Package");
-#endif
-#if QT_CONFIG(qml_object_model)
- qmlRegisterType<QQmlObjectModel>(uri, 2, 1, "ObjectModel");
- qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel");
- qmlRegisterType<QQmlInstantiator>(uri, 2, 14, "Instantiator");
- qmlRegisterAnonymousType<QQmlInstanceModel>(uri, 2);
-#endif
-#if QT_CONFIG(itemmodel)
- qmlRegisterType<QItemSelectionModel>(uri, 2, 2, "ItemSelectionModel");
-#endif
-}
-
-void QQmlModelsModule::defineLabsModule()
-{
- const char uri[] = "Qt.labs.qmlmodels";
-
-#if QT_CONFIG(qml_delegate_model)
- qmlRegisterUncreatableType<QQmlAbstractDelegateComponent>(uri, 1, 0, "AbstractDelegateComponent", QQmlAbstractDelegateComponent::tr("Cannot create instance of abstract class AbstractDelegateComponent."));
- qmlRegisterType<QQmlDelegateChooser>(uri, 1, 0, "DelegateChooser");
- qmlRegisterType<QQmlDelegateChoice>(uri, 1, 0, "DelegateChoice");
-#endif
-#if QT_CONFIG(qml_table_model)
- qmlRegisterType<QQmlTableModel>(uri, 1, 0, "TableModel");
- qmlRegisterType<QQmlTableModelColumn>(uri, 1, 0, "TableModelColumn");
-#endif
-}
-
QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmlmodelsmodule_p.h b/src/qmlmodels/qqmlmodelsmodule_p.h
index 7e02578db9..feed0f88fe 100644
--- a/src/qmlmodels/qqmlmodelsmodule_p.h
+++ b/src/qmlmodels/qqmlmodelsmodule_p.h
@@ -51,6 +51,12 @@
// We mean it.
//
+#include <QtQml/qqml.h>
+
+#if QT_CONFIG(itemmodel)
+#include <QtCore/qitemselectionmodel.h>
+#endif
+
#include <private/qtqmlmodelsglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -62,10 +68,17 @@ public:
static void registerQmlTypes();
static void registerQuickTypes();
#endif
+};
- static void defineModule();
- static void defineLabsModule();
+#if QT_CONFIG(itemmodel)
+struct QItemSelectionModelForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QItemSelectionModel)
+ QML_NAMED_ELEMENT(ItemSelectionModel)
+ QML_ADDED_IN_MINOR_VERSION(2)
};
+#endif
QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmlobjectmodel.cpp b/src/qmlmodels/qqmlobjectmodel.cpp
index 7409178616..90469d06c2 100644
--- a/src/qmlmodels/qqmlobjectmodel.cpp
+++ b/src/qmlmodels/qqmlobjectmodel.cpp
@@ -91,6 +91,15 @@ public:
static_cast<QQmlObjectModelPrivate *>(prop->data)->clear();
}
+ static void children_replace(QQmlListProperty<QObject> *prop, int index, QObject *item) {
+ static_cast<QQmlObjectModelPrivate *>(prop->data)->replace(index, item);
+ }
+
+ static void children_removeLast(QQmlListProperty<QObject> *prop) {
+ auto data = static_cast<QQmlObjectModelPrivate *>(prop->data);
+ data->remove(data->children.count() - 1, 1);
+ }
+
void insert(int index, QObject *item) {
Q_Q(QQmlObjectModel);
children.insert(index, Item(item));
@@ -105,6 +114,18 @@ public:
emit q->childrenChanged();
}
+ void replace(int index, QObject *item) {
+ Q_Q(QQmlObjectModel);
+ auto *attached = QQmlObjectModelAttached::properties(children.at(index).item);
+ attached->setIndex(-1);
+ children.replace(index, Item(item));
+ QQmlObjectModelAttached::properties(children.at(index).item)->setIndex(index);
+ QQmlChangeSet changeSet;
+ changeSet.change(index, 1);
+ emit q->modelUpdated(changeSet, false);
+ emit q->childrenChanged();
+ }
+
void move(int from, int to, int n) {
Q_Q(QQmlObjectModel);
if (from > to) {
@@ -226,12 +247,13 @@ QQmlObjectModel::QQmlObjectModel(QObject *parent)
QQmlListProperty<QObject> QQmlObjectModel::children()
{
Q_D(QQmlObjectModel);
- return QQmlListProperty<QObject>(this,
- d,
- d->children_append,
- d->children_count,
- d->children_at,
- d->children_clear);
+ return QQmlListProperty<QObject>(this, d,
+ QQmlObjectModelPrivate::children_append,
+ QQmlObjectModelPrivate::children_count,
+ QQmlObjectModelPrivate::children_at,
+ QQmlObjectModelPrivate::children_clear,
+ QQmlObjectModelPrivate::children_replace,
+ QQmlObjectModelPrivate::children_removeLast);
}
/*!
@@ -262,7 +284,7 @@ QObject *QQmlObjectModel::object(int index, QQmlIncubator::IncubationMode)
return item.item;
}
-QQmlInstanceModel::ReleaseFlags QQmlObjectModel::release(QObject *item)
+QQmlInstanceModel::ReleaseFlags QQmlObjectModel::release(QObject *item, ReusableFlag)
{
Q_D(QQmlObjectModel);
int idx = d->indexOf(item);
@@ -270,7 +292,7 @@ QQmlInstanceModel::ReleaseFlags QQmlObjectModel::release(QObject *item)
if (!d->children[idx].deref())
return QQmlInstanceModel::Referenced;
}
- return nullptr;
+ return {};
}
QVariant QQmlObjectModel::variantValue(int index, const QString &role)
@@ -278,7 +300,7 @@ QVariant QQmlObjectModel::variantValue(int index, const QString &role)
Q_D(QQmlObjectModel);
if (index < 0 || index >= d->children.count())
return QString();
- return QQmlEngine::contextForObject(d->children.at(index).item)->contextProperty(role);
+ return d->children.at(index).item->property(role.toUtf8().constData());
}
QQmlIncubator::Status QQmlObjectModel::incubationStatus(int)
diff --git a/src/qmlmodels/qqmlobjectmodel_p.h b/src/qmlmodels/qqmlobjectmodel_p.h
index 78a5615ae2..866d010cd3 100644
--- a/src/qmlmodels/qqmlobjectmodel_p.h
+++ b/src/qmlmodels/qqmlobjectmodel_p.h
@@ -69,23 +69,32 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlInstanceModel : public QObject
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
+ QML_ANONYMOUS
public:
+ enum ReusableFlag {
+ NotReusable,
+ Reusable
+ };
+
virtual ~QQmlInstanceModel() {}
- enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02 };
+ enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02, Pooled = 0x04 };
Q_DECLARE_FLAGS(ReleaseFlags, ReleaseFlag)
virtual int count() const = 0;
virtual bool isValid() const = 0;
virtual QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) = 0;
- virtual ReleaseFlags release(QObject *object) = 0;
+ virtual ReleaseFlags release(QObject *object, ReusableFlag reusableFlag = NotReusable) = 0;
virtual void cancel(int) {}
QString stringValue(int index, const QString &role) { return variantValue(index, role).toString(); }
virtual QVariant variantValue(int, const QString &) = 0;
virtual void setWatchedRoles(const QList<QByteArray> &roles) = 0;
virtual QQmlIncubator::Status incubationStatus(int index) = 0;
+ virtual void drainReusableItemsPool(int maxPoolTime) { Q_UNUSED(maxPoolTime) }
+ virtual int poolSize() { return 0; }
+
virtual int indexOf(QObject *object, QObject *objectContext) const = 0;
virtual const QAbstractItemModel *abstractItemModel() const { return nullptr; }
@@ -95,6 +104,8 @@ Q_SIGNALS:
void createdItem(int index, QObject *object);
void initItem(int index, QObject *object);
void destroyingItem(QObject *object);
+ Q_REVISION(15) void itemPooled(int index, QObject *object);
+ Q_REVISION(15) void itemReused(int index, QObject *object);
protected:
QQmlInstanceModel(QObjectPrivate &dd, QObject *parent = nullptr)
@@ -113,6 +124,9 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlObjectModel : public QQmlInstanceModel
Q_PROPERTY(QQmlListProperty<QObject> children READ children NOTIFY childrenChanged DESIGNABLE false)
Q_CLASSINFO("DefaultProperty", "children")
+ QML_NAMED_ELEMENT(ObjectModel)
+ QML_ADDED_IN_MINOR_VERSION(1)
+ QML_ATTACHED(QQmlObjectModelAttached)
public:
QQmlObjectModel(QObject *parent=nullptr);
@@ -121,7 +135,7 @@ public:
int count() const override;
bool isValid() const override;
QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override;
+ ReleaseFlags release(QObject *object, ReusableFlag reusable = NotReusable) override;
QVariant variantValue(int index, const QString &role) override;
void setWatchedRoles(const QList<QByteArray> &) override {}
QQmlIncubator::Status incubationStatus(int index) override;
@@ -191,6 +205,5 @@ QT_END_NAMESPACE
QML_DECLARE_TYPE(QQmlInstanceModel)
QML_DECLARE_TYPE(QQmlObjectModel)
-QML_DECLARE_TYPEINFO(QQmlObjectModel, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQMLINSTANCEMODEL_P_H
diff --git a/src/qmlmodels/qqmltableinstancemodel.cpp b/src/qmlmodels/qqmltableinstancemodel.cpp
index e2cecfef79..6e21f2f389 100644
--- a/src/qmlmodels/qqmltableinstancemodel.cpp
+++ b/src/qmlmodels/qqmltableinstancemodel.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qqmltableinstancemodel_p.h"
-#include "qqmldelegatecomponent_p.h"
+#include "qqmlabstractdelegatecomponent_p.h"
#include <QtCore/QTimer>
@@ -78,10 +78,8 @@ void QQmlTableInstanceModel::deleteModelItemLater(QQmlDelegateModelItem *modelIt
QQmlTableInstanceModel::QQmlTableInstanceModel(QQmlContext *qmlContext, QObject *parent)
: QQmlInstanceModel(*(new QObjectPrivate()), parent)
, m_qmlContext(qmlContext)
- , m_metaType(
- new QQmlDelegateModelItemMetaType(m_qmlContext->engine()->handle(), nullptr,
- QStringList()),
- QQmlRefPointer<QQmlDelegateModelItemMetaType>::Adopt)
+ , m_metaType(new QQmlDelegateModelItemMetaType(m_qmlContext->engine()->handle(), nullptr, QStringList()),
+ QQmlRefPointer<QQmlDelegateModelItemMetaType>::Adopt)
{
}
@@ -144,7 +142,7 @@ QQmlDelegateModelItem *QQmlTableInstanceModel::resolveModelItem(int index)
return nullptr;
// Check if the pool contains an item that can be reused
- modelItem = takeFromReusableItemsPool(delegate);
+ modelItem = m_reusableItemsPool.takeItem(delegate, index);
if (modelItem) {
reuseItem(modelItem, index);
m_modelItems.insert(index, modelItem);
@@ -228,16 +226,24 @@ QQmlInstanceModel::ReleaseFlags QQmlTableInstanceModel::release(QObject *object,
m_modelItems.remove(modelItem->index);
if (reusable == Reusable) {
- insertIntoReusableItemsPool(modelItem);
- return QQmlInstanceModel::Referenced;
+ m_reusableItemsPool.insertItem(modelItem);
+ emit itemPooled(modelItem->index, modelItem->object);
+ return QQmlInstanceModel::Pooled;
}
// The item is not reused or referenced by anyone, so just delete it
- modelItem->destroyObject();
- emit destroyingItem(object);
+ destroyModelItem(modelItem, Deferred);
+ return QQmlInstanceModel::Destroyed;
+}
+void QQmlTableInstanceModel::destroyModelItem(QQmlDelegateModelItem *modelItem, DestructionMode mode)
+{
+ emit destroyingItem(modelItem->object);
+ if (mode == Deferred)
+ modelItem->destroyObject();
+ else
+ delete modelItem->object;
delete modelItem;
- return QQmlInstanceModel::Destroyed;
}
void QQmlTableInstanceModel::dispose(QObject *object)
@@ -279,92 +285,11 @@ void QQmlTableInstanceModel::cancel(int index)
delete modelItem;
}
-void QQmlTableInstanceModel::insertIntoReusableItemsPool(QQmlDelegateModelItem *modelItem)
-{
- // Currently, the only way for a view to reuse items is to call QQmlTableInstanceModel::release()
- // with the second argument explicitly set to QQmlTableInstanceModel::Reusable. If the released
- // item is no longer referenced, it will be added to the pool. Reusing of items can be specified
- // per item, in case certain items cannot be recycled.
- // A QQmlDelegateModelItem knows which delegate its object was created from. So when we are
- // about to create a new item, we first check if the pool contains an item based on the same
- // delegate from before. If so, we take it out of the pool (instead of creating a new item), and
- // update all its context-, and attached properties.
- // When a view is recycling items, it should call QQmlTableInstanceModel::drainReusableItemsPool()
- // regularly. As there is currently no logic to 'hibernate' items in the pool, they are only
- // meant to rest there for a short while, ideally only from the time e.g a row is unloaded
- // on one side of the view, and until a new row is loaded on the opposite side. In-between
- // this time, the application will see the item as fully functional and 'alive' (just not
- // visible on screen). Since this time is supposed to be short, we don't take any action to
- // notify the application about it, since we don't want to trigger any bindings that can
- // disturb performance.
- // A recommended time for calling drainReusableItemsPool() is each time a view has finished
- // loading e.g a new row or column. If there are more items in the pool after that, it means
- // that the view most likely doesn't need them anytime soon. Those items should be destroyed to
- // not consume resources.
- // Depending on if a view is a list or a table, it can sometimes be performant to keep
- // items in the pool for a bit longer than one "row out/row in" cycle. E.g for a table, if the
- // number of visible rows in a view is much larger than the number of visible columns.
- // In that case, if you flick out a row, and then flick in a column, you would throw away a lot
- // of items in the pool if completely draining it. The reason is that unloading a row places more
- // items in the pool than what ends up being recycled when loading a new column. And then, when you
- // next flick in a new row, you would need to load all those drained items again from scratch. For
- // that reason, you can specify a maxPoolTime to the drainReusableItemsPool() that allows you to keep
- // items in the pool for a bit longer, effectively keeping more items in circulation.
- // A recommended maxPoolTime would be equal to the number of dimenstions in the view, which
- // means 1 for a list view and 2 for a table view. If you specify 0, all items will be drained.
- Q_ASSERT(!modelItem->incubationTask);
- Q_ASSERT(!modelItem->isObjectReferenced());
- Q_ASSERT(!modelItem->isReferenced());
- Q_ASSERT(modelItem->object);
-
- modelItem->poolTime = 0;
- m_reusableItemsPool.append(modelItem);
- emit itemPooled(modelItem->index, modelItem->object);
-}
-
-QQmlDelegateModelItem *QQmlTableInstanceModel::takeFromReusableItemsPool(const QQmlComponent *delegate)
-{
- // Find the oldest item in the pool that was made from the same delegate as
- // the given argument, remove it from the pool, and return it.
- if (m_reusableItemsPool.isEmpty())
- return nullptr;
-
- for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end(); ++it) {
- if ((*it)->delegate != delegate)
- continue;
- auto modelItem = *it;
- m_reusableItemsPool.erase(it);
- return modelItem;
- }
-
- return nullptr;
-}
-
void QQmlTableInstanceModel::drainReusableItemsPool(int maxPoolTime)
{
- // Rather than releasing all pooled items upon a call to this function, each
- // item has a poolTime. The poolTime specifies for how many loading cycles an item
- // has been resting in the pool. And for each invocation of this function, poolTime
- // will increase. If poolTime is equal to, or exceeds, maxPoolTime, it will be removed
- // from the pool and released. This way, the view can tweak a bit for how long
- // items should stay in "circulation", even if they are not recycled right away.
- for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end();) {
- auto modelItem = *it;
- modelItem->poolTime++;
- if (modelItem->poolTime <= maxPoolTime) {
- ++it;
- } else {
- it = m_reusableItemsPool.erase(it);
-
- Q_ASSERT(!modelItem->incubationTask);
- Q_ASSERT(!modelItem->isObjectReferenced());
- Q_ASSERT(!modelItem->isReferenced());
- Q_ASSERT(modelItem->object);
- emit destroyingItem(modelItem->object);
- delete modelItem->object;
- delete modelItem;
- }
- }
+ m_reusableItemsPool.drain(maxPoolTime, [this](QQmlDelegateModelItem *modelItem) {
+ destroyModelItem(modelItem, Immediate);
+ });
}
void QQmlTableInstanceModel::reuseItem(QQmlDelegateModelItem *item, int newModelIndex)
@@ -558,8 +483,13 @@ const QAbstractItemModel *QQmlTableInstanceModel::abstractItemModel() const
void QQmlTableInstanceModelIncubationTask::setInitialState(QObject *object)
{
- modelItemToIncubate->object = object;
- emit tableInstanceModel->initItem(modelItemToIncubate->index, object);
+ initializeRequiredProperties(modelItemToIncubate, object);
+ if (QQmlIncubatorPrivate::get(this)->requiredProperties().empty()) {
+ modelItemToIncubate->object = object;
+ emit tableInstanceModel->initItem(modelItemToIncubate->index, object);
+ } else {
+ object->deleteLater();
+ }
}
void QQmlTableInstanceModelIncubationTask::statusChanged(QQmlIncubator::Status status)
diff --git a/src/qmlmodels/qqmltableinstancemodel_p.h b/src/qmlmodels/qqmltableinstancemodel_p.h
index 4ea1d85d16..0d96d35a5e 100644
--- a/src/qmlmodels/qqmltableinstancemodel_p.h
+++ b/src/qmlmodels/qqmltableinstancemodel_p.h
@@ -86,12 +86,6 @@ class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableInstanceModel : public QQmlInstanceMod
Q_OBJECT
public:
-
- enum ReusableFlag {
- NotReusable,
- Reusable
- };
-
QQmlTableInstanceModel(QQmlContext *qmlContext, QObject *parent = nullptr);
~QQmlTableInstanceModel() override;
@@ -115,15 +109,12 @@ public:
const QAbstractItemModel *abstractItemModel() const override;
QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
- ReleaseFlags release(QObject *object) override { return release(object, NotReusable); }
- ReleaseFlags release(QObject *object, ReusableFlag reusable);
+ ReleaseFlags release(QObject *object, ReusableFlag reusable = NotReusable) override;
void dispose(QObject *object);
void cancel(int) override;
- void insertIntoReusableItemsPool(QQmlDelegateModelItem *modelItem);
- QQmlDelegateModelItem *takeFromReusableItemsPool(const QQmlComponent *delegate);
- void drainReusableItemsPool(int maxPoolTime);
- int poolSize() { return m_reusableItemsPool.size(); }
+ void drainReusableItemsPool(int maxPoolTime) override;
+ int poolSize() override { return m_reusableItemsPool.size(); }
void reuseItem(QQmlDelegateModelItem *item, int newModelIndex);
QQmlIncubator::Status incubationStatus(int index) override;
@@ -132,11 +123,12 @@ public:
void setWatchedRoles(const QList<QByteArray> &) override { Q_UNREACHABLE(); }
int indexOf(QObject *, QObject *) const override { Q_UNREACHABLE(); return 0; }
-Q_SIGNALS:
- void itemPooled(int index, QObject *object);
- void itemReused(int index, QObject *object);
-
private:
+ enum DestructionMode {
+ Deferred,
+ Immediate
+ };
+
QQmlComponent *resolveDelegate(int index);
QQmlAdaptorModel m_adaptorModel;
@@ -146,7 +138,7 @@ private:
QQmlRefPointer<QQmlDelegateModelItemMetaType> m_metaType;
QHash<int, QQmlDelegateModelItem *> m_modelItems;
- QList<QQmlDelegateModelItem *> m_reusableItemsPool;
+ QQmlReusableDelegateModelItemsPool m_reusableItemsPool;
QList<QQmlIncubator *> m_finishedIncubationTasks;
void incubateModelItem(QQmlDelegateModelItem *modelItem, QQmlIncubator::IncubationMode incubationMode);
@@ -154,6 +146,7 @@ private:
void deleteIncubationTaskLater(QQmlIncubator *incubationTask);
void deleteAllFinishedIncubationTasks();
QQmlDelegateModelItem *resolveModelItem(int index);
+ void destroyModelItem(QQmlDelegateModelItem *modelItem, DestructionMode mode);
void dataChangedCallback(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles);
diff --git a/src/qmlmodels/qqmltablemodel.cpp b/src/qmlmodels/qqmltablemodel.cpp
deleted file mode 100644
index fab20f7410..0000000000
--- a/src/qmlmodels/qqmltablemodel.cpp
+++ /dev/null
@@ -1,1072 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmltablemodel_p.h"
-
-#include <QtCore/qloggingcategory.h>
-#include <QtQml/qqmlinfo.h>
-#include <QtQml/qqmlengine.h>
-
-QT_BEGIN_NAMESPACE
-
-Q_LOGGING_CATEGORY(lcTableModel, "qt.qml.tablemodel")
-
-/*!
- \qmltype TableModel
- \instantiates QQmlTableModel
- \inqmlmodule Qt.labs.qmlmodels
- \brief Encapsulates a simple table model.
- \since 5.14
-
- The TableModel type stores JavaScript/JSON objects as data for a table
- model that can be used with \l TableView. It is intended to support
- very simple models without requiring the creation of a custom
- QAbstractTableModel subclass in C++.
-
- \snippet qml/tablemodel/fruit-example-simpledelegate.qml file
-
- The model's initial row data is set with either the \l rows property or by
- calling \l appendRow(). Each column in the model is specified by declaring
- a \l TableModelColumn instance, where the order of each instance determines
- its column index. Once the model's \l Component::completed() signal has been
- emitted, the columns and roles will have been established and are then
- fixed for the lifetime of the model.
-
- To access a specific row, the \l getRow() function can be used.
- It's also possible to access the model's JavaScript data
- directly via the \l rows property, but it is not possible to
- modify the model data this way.
-
- To add new rows, use \l appendRow() and \l insertRow(). To modify
- existing rows, use \l setRow(), \l moveRow(), \l removeRow(), and
- \l clear().
-
- It is also possible to modify the model's data via the delegate,
- as shown in the example above:
-
- \snippet qml/tablemodel/fruit-example-simpledelegate.qml delegate
-
- If the type of the data at the modified role does not match the type of the
- data that is set, it will be automatically converted via
- \l {QVariant::canConvert()}{QVariant}.
-
- \section1 Supported Row Data Structures
-
- TableModel is designed to work with JavaScript/JSON data, where each row
- is a simple key-pair object:
-
- \code
- {
- // Each property is one cell/column.
- checked: false,
- amount: 1,
- fruitType: "Apple",
- fruitName: "Granny Smith",
- fruitPrice: 1.50
- },
- // ...
- \endcode
-
- As model manipulation in Qt is done via row and column indices,
- and because object keys are unordered, each column must be specified via
- TableModelColumn. This allows mapping Qt's built-in roles to any property
- in each row object.
-
- Complex row structures are supported, but with limited functionality.
- As TableModel has no way of knowing how each row is structured,
- it cannot manipulate it. As a consequence of this, the copy of the
- model data that TableModel has stored in \l rows is not kept in sync
- with the source data that was set in QML. For these reasons, TableModel
- relies on the user to handle simple data manipulation.
-
- For example, suppose you wanted to have several roles per column. One way
- of doing this is to use a data source where each row is an array and each
- cell is an object. To use this data source with TableModel, define a
- getter and setter:
-
- \code
- TableModel {
- TableModelColumn {
- display: function(modelIndex) { return rows[modelIndex.row][0].checked }
- setDisplay: function(modelIndex, cellData) { rows[modelIndex.row][0].checked = cellData }
- }
- // ...
-
- rows: [
- [
- { checked: false, checkable: true },
- { amount: 1 },
- { fruitType: "Apple" },
- { fruitName: "Granny Smith" },
- { fruitPrice: 1.50 }
- ]
- // ...
- ]
- }
- \endcode
-
- The row above is one example of a complex row.
-
- \note Row manipulation functions such as \l appendRow(), \l removeRow(),
- etc. are not supported when using complex rows.
-
- \section1 Using DelegateChooser with TableModel
-
- For most real world use cases, it is recommended to use DelegateChooser
- as the delegate of a TableView that uses TableModel. This allows you to
- use specific roles in the relevant delegates. For example, the snippet
- above can be rewritten to use DelegateChooser like so:
-
- \snippet qml/tablemodel/fruit-example-delegatechooser.qml file
-
- The most specific delegates are declared first: the columns at index \c 0
- and \c 1 have \c bool and \c integer data types, so they use a
- \l [QtQuickControls2]{CheckBox} and \l [QtQuickControls2]{SpinBox},
- respectively. The remaining columns can simply use a
- \l [QtQuickControls2]{TextField}, and so that delegate is declared
- last as a fallback.
-
- \sa TableModelColumn, TableView, QAbstractTableModel
-*/
-
-QQmlTableModel::QQmlTableModel(QObject *parent)
- : QAbstractTableModel(parent)
-{
-}
-
-QQmlTableModel::~QQmlTableModel()
-{
-}
-
-/*!
- \qmlproperty object TableModel::rows
-
- This property holds the model data in the form of an array of rows:
-
- \snippet qml/tablemodel/fruit-example-simpledelegate.qml rows
-
- \sa getRow(), setRow(), moveRow(), appendRow(), insertRow(), clear(), rowCount, columnCount
-*/
-QVariant QQmlTableModel::rows() const
-{
- return mRows;
-}
-
-void QQmlTableModel::setRows(const QVariant &rows)
-{
- if (rows.userType() != qMetaTypeId<QJSValue>()) {
- qmlWarning(this) << "setRows(): \"rows\" must be an array; actual type is " << rows.typeName();
- return;
- }
-
- const QJSValue rowsAsJSValue = rows.value<QJSValue>();
- const QVariantList rowsAsVariantList = rowsAsJSValue.toVariant().toList();
- if (rowsAsVariantList == mRows) {
- // No change.
- return;
- }
-
- if (!componentCompleted) {
- // Store the rows until we can call doSetRows() after component completion.
- mRows = rowsAsVariantList;
- return;
- }
-
- doSetRows(rowsAsVariantList);
-}
-
-void QQmlTableModel::doSetRows(const QVariantList &rowsAsVariantList)
-{
- Q_ASSERT(componentCompleted);
-
- // By now, all TableModelColumns should have been set.
- if (mColumns.isEmpty()) {
- qmlWarning(this) << "No TableModelColumns were set; model will be empty";
- return;
- }
-
- const bool firstTimeValidRowsHaveBeenSet = mColumnMetadata.isEmpty();
- if (!firstTimeValidRowsHaveBeenSet) {
- // This is not the first time rows have been set; validate each one.
- for (int rowIndex = 0; rowIndex < rowsAsVariantList.size(); ++rowIndex) {
- // validateNewRow() expects a QVariant wrapping a QJSValue, so to
- // simplify the code, just create one here.
- const QVariant row = QVariant::fromValue(rowsAsVariantList.at(rowIndex));
- if (!validateNewRow("setRows()", row, rowIndex, SetRowsOperation))
- return;
- }
- }
-
- const int oldRowCount = mRowCount;
- const int oldColumnCount = mColumnCount;
-
- beginResetModel();
-
- // We don't clear the column or role data, because a TableModel should not be reused in that way.
- // Once it has valid data, its columns and roles are fixed.
- mRows = rowsAsVariantList;
- mRowCount = mRows.size();
-
- // Gather metadata the first time rows is set.
- if (firstTimeValidRowsHaveBeenSet && !mRows.isEmpty())
- fetchColumnMetadata();
-
- endResetModel();
-
- emit rowsChanged();
-
- if (mRowCount != oldRowCount)
- emit rowCountChanged();
- if (mColumnCount != oldColumnCount)
- emit columnCountChanged();
-}
-
-QQmlTableModel::ColumnRoleMetadata QQmlTableModel::fetchColumnRoleData(const QString &roleNameKey,
- QQmlTableModelColumn *tableModelColumn, int columnIndex) const
-{
- const QVariant firstRow = mRows.first();
- ColumnRoleMetadata roleData;
-
- QJSValue columnRoleGetter = tableModelColumn->getterAtRole(roleNameKey);
- if (columnRoleGetter.isUndefined()) {
- // This role is not defined, which is fine; just skip it.
- return roleData;
- }
-
- if (columnRoleGetter.isString()) {
- // The role is set as a string, so we assume the row is a simple object.
- if (firstRow.type() != QVariant::Map) {
- qmlWarning(this).quote() << "expected row for role "
- << roleNameKey << " of TableModelColumn at index "
- << columnIndex << " to be a simple object, but it's "
- << firstRow.typeName() << " instead: " << firstRow;
- return roleData;
- }
- const QVariantMap firstRowAsMap = firstRow.toMap();
- const QString rolePropertyName = columnRoleGetter.toString();
- const QVariant roleProperty = firstRowAsMap.value(rolePropertyName);
-
- roleData.isStringRole = true;
- roleData.name = rolePropertyName;
- roleData.type = roleProperty.type();
- roleData.typeName = QString::fromLatin1(roleProperty.typeName());
- } else if (columnRoleGetter.isCallable()) {
- // The role is provided via a function, which means the row is complex and
- // the user needs to provide the data for it.
- const auto modelIndex = index(0, columnIndex);
- const auto args = QJSValueList() << qmlEngine(this)->toScriptValue(modelIndex);
- const QVariant cellData = columnRoleGetter.call(args).toVariant();
-
- // We don't know the property name since it's provided through the function.
- // roleData.name = ???
- roleData.isStringRole = false;
- roleData.type = cellData.type();
- roleData.typeName = QString::fromLatin1(cellData.typeName());
- } else {
- // Invalid role.
- qmlWarning(this) << "TableModelColumn role for column at index "
- << columnIndex << " must be either a string or a function; actual type is: "
- << columnRoleGetter.toString();
- }
-
- return roleData;
-}
-
-void QQmlTableModel::fetchColumnMetadata()
-{
- qCDebug(lcTableModel) << "gathering metadata for" << mColumnCount << "columns from first row:";
-
- static const auto supportedRoleNames = QQmlTableModelColumn::supportedRoleNames();
-
- // Since we support different data structures at the row level, we require that there
- // is a TableModelColumn for each column.
- // Collect and cache metadata for each column. This makes data lookup faster.
- for (int columnIndex = 0; columnIndex < mColumns.size(); ++columnIndex) {
- QQmlTableModelColumn *column = mColumns.at(columnIndex);
- qCDebug(lcTableModel).nospace() << "- column " << columnIndex << ":";
-
- ColumnMetadata metaData;
- const auto builtInRoleKeys = supportedRoleNames.keys();
- for (const int builtInRoleKey : builtInRoleKeys) {
- const QString builtInRoleName = supportedRoleNames.value(builtInRoleKey);
- ColumnRoleMetadata roleData = fetchColumnRoleData(builtInRoleName, column, columnIndex);
- if (roleData.type == QVariant::Invalid) {
- // This built-in role was not specified in this column.
- continue;
- }
-
- qCDebug(lcTableModel).nospace() << " - added metadata for built-in role "
- << builtInRoleName << " at column index " << columnIndex
- << ": name=" << roleData.name << " typeName=" << roleData.typeName
- << " type=" << roleData.type;
-
- // This column now supports this specific built-in role.
- metaData.roles.insert(builtInRoleName, roleData);
- // Add it if it doesn't already exist.
- mRoleNames[builtInRoleKey] = builtInRoleName.toLatin1();
- }
- mColumnMetadata.insert(columnIndex, metaData);
- }
-}
-
-/*!
- \qmlmethod TableModel::appendRow(object row)
-
- Adds a new row to the end of the model, with the
- values (cells) in \a row.
-
- \code
- model.appendRow({
- checkable: true,
- amount: 1,
- fruitType: "Pear",
- fruitName: "Williams",
- fruitPrice: 1.50,
- })
- \endcode
-
- \sa insertRow(), setRow(), removeRow()
-*/
-void QQmlTableModel::appendRow(const QVariant &row)
-{
- if (!validateNewRow("appendRow()", row, -1, AppendOperation))
- return;
-
- doInsert(mRowCount, row);
-}
-
-/*!
- \qmlmethod TableModel::clear()
-
- Removes all rows from the model.
-
- \sa removeRow()
-*/
-void QQmlTableModel::clear()
-{
- QQmlEngine *engine = qmlEngine(this);
- Q_ASSERT(engine);
- setRows(QVariant::fromValue(engine->newArray()));
-}
-
-/*!
- \qmlmethod object TableModel::getRow(int rowIndex)
-
- Returns the row at \a rowIndex in the model.
-
- Note that this equivalent to accessing the row directly
- through the \l rows property:
-
- \code
- Component.onCompleted: {
- // These two lines are equivalent.
- console.log(model.getRow(0).display);
- console.log(model.rows[0].fruitName);
- }
- \endcode
-
- \note the returned object cannot be used to modify the contents of the
- model; use setRow() instead.
-
- \sa setRow(), appendRow(), insertRow(), removeRow(), moveRow()
-*/
-QVariant QQmlTableModel::getRow(int rowIndex)
-{
- if (!validateRowIndex("getRow()", "rowIndex", rowIndex))
- return QVariant();
-
- return mRows.at(rowIndex);
-}
-
-/*!
- \qmlmethod TableModel::insertRow(int rowIndex, object row)
-
- Adds a new row to the list model at position \a rowIndex, with the
- values (cells) in \a row.
-
- \code
- model.insertRow(2, {
- checkable: true, checked: false,
- amount: 1,
- fruitType: "Pear",
- fruitName: "Williams",
- fruitPrice: 1.50,
- })
- \endcode
-
- The \a rowIndex must be to an existing item in the list, or one past
- the end of the list (equivalent to \l appendRow()).
-
- \sa appendRow(), setRow(), removeRow(), rowCount
-*/
-void QQmlTableModel::insertRow(int rowIndex, const QVariant &row)
-{
- if (!validateNewRow("insertRow()", row, rowIndex))
- return;
-
- doInsert(rowIndex, row);
-}
-
-void QQmlTableModel::doInsert(int rowIndex, const QVariant &row)
-{
- beginInsertRows(QModelIndex(), rowIndex, rowIndex);
-
- // Adding rowAsVariant.toList() will add each invidual variant in the list,
- // which is definitely not what we want.
- const QVariant rowAsVariant = row.value<QJSValue>().toVariant();
- mRows.insert(rowIndex, rowAsVariant);
- ++mRowCount;
-
- qCDebug(lcTableModel).nospace() << "inserted the following row to the model at index "
- << rowIndex << ":\n" << rowAsVariant.toMap();
-
- // Gather metadata the first time a row is added.
- if (mColumnMetadata.isEmpty())
- fetchColumnMetadata();
-
- endInsertRows();
- emit rowCountChanged();
-}
-
-void QQmlTableModel::classBegin()
-{
-}
-
-void QQmlTableModel::componentComplete()
-{
- componentCompleted = true;
-
- mColumnCount = mColumns.size();
- if (mColumnCount > 0)
- emit columnCountChanged();
-
- doSetRows(mRows);
-}
-
-/*!
- \qmlmethod TableModel::moveRow(int fromRowIndex, int toRowIndex, int rows)
-
- Moves \a rows from the index at \a fromRowIndex to the index at
- \a toRowIndex.
-
- The from and to ranges must exist; for example, to move the first 3 items
- to the end of the list:
-
- \code
- model.moveRow(0, model.rowCount - 3, 3)
- \endcode
-
- \sa appendRow(), insertRow(), removeRow(), rowCount
-*/
-void QQmlTableModel::moveRow(int fromRowIndex, int toRowIndex, int rows)
-{
- if (fromRowIndex == toRowIndex) {
- qmlWarning(this) << "moveRow(): \"fromRowIndex\" cannot be equal to \"toRowIndex\"";
- return;
- }
-
- if (rows <= 0) {
- qmlWarning(this) << "moveRow(): \"rows\" is less than or equal to 0";
- return;
- }
-
- if (!validateRowIndex("moveRow()", "fromRowIndex", fromRowIndex))
- return;
-
- if (!validateRowIndex("moveRow()", "toRowIndex", toRowIndex))
- return;
-
- if (fromRowIndex + rows > mRowCount) {
- qmlWarning(this) << "moveRow(): \"fromRowIndex\" (" << fromRowIndex
- << ") + \"rows\" (" << rows << ") = " << (fromRowIndex + rows)
- << ", which is greater than rowCount() of " << mRowCount;
- return;
- }
-
- if (toRowIndex + rows > mRowCount) {
- qmlWarning(this) << "moveRow(): \"toRowIndex\" (" << toRowIndex
- << ") + \"rows\" (" << rows << ") = " << (toRowIndex + rows)
- << ", which is greater than rowCount() of " << mRowCount;
- return;
- }
-
- qCDebug(lcTableModel).nospace() << "moving " << rows
- << " row(s) from index " << fromRowIndex
- << " to index " << toRowIndex;
-
- // Based on the same call in QQmlListModel::moveRow().
- beginMoveRows(QModelIndex(), fromRowIndex, fromRowIndex + rows - 1, QModelIndex(),
- toRowIndex > fromRowIndex ? toRowIndex + rows : toRowIndex);
-
- // Based on ListModel::moveRow().
- if (fromRowIndex > toRowIndex) {
- // Only move forwards - flip if moving backwards.
- const int from = fromRowIndex;
- const int to = toRowIndex;
- fromRowIndex = to;
- toRowIndex = to + rows;
- rows = from - to;
- }
-
- QVector<QVariant> store;
- store.reserve(rows);
- for (int i = 0; i < (toRowIndex - fromRowIndex); ++i)
- store.append(mRows.at(fromRowIndex + rows + i));
- for (int i = 0; i < rows; ++i)
- store.append(mRows.at(fromRowIndex + i));
- for (int i = 0; i < store.size(); ++i)
- mRows[fromRowIndex + i] = store[i];
-
- qCDebug(lcTableModel).nospace() << "after moving, rows are:\n" << mRows;
-
- endMoveRows();
-}
-
-/*!
- \qmlmethod TableModel::removeRow(int rowIndex, int rows = 1)
-
- Removes the row at \a rowIndex from the model.
-
- \sa clear(), rowCount
-*/
-void QQmlTableModel::removeRow(int rowIndex, int rows)
-{
- if (!validateRowIndex("removeRow()", "rowIndex", rowIndex))
- return;
-
- if (rows <= 0) {
- qmlWarning(this) << "removeRow(): \"rows\" is less than or equal to zero";
- return;
- }
-
- if (rowIndex + rows - 1 >= mRowCount) {
- qmlWarning(this) << "removeRow(): \"rows\" " << rows
- << " exceeds available rowCount() of " << mRowCount
- << " when removing from \"rowIndex\" " << rowIndex;
- return;
- }
-
- beginRemoveRows(QModelIndex(), rowIndex, rowIndex + rows - 1);
-
- auto firstIterator = mRows.begin() + rowIndex;
- // The "last" argument to erase() is exclusive, so we go one past the last item.
- auto lastIterator = firstIterator + rows;
- mRows.erase(firstIterator, lastIterator);
- mRowCount -= rows;
-
- endRemoveRows();
- emit rowCountChanged();
-
- qCDebug(lcTableModel).nospace() << "removed " << rows
- << " items from the model, starting at index " << rowIndex;
-}
-
-/*!
- \qmlmethod TableModel::setRow(int rowIndex, object row)
-
- Changes the row at \a rowIndex in the model with \a row.
-
- All columns/cells must be present in \c row, and in the correct order.
-
- \code
- model.setRow(0, {
- checkable: true,
- amount: 1,
- fruitType: "Pear",
- fruitName: "Williams",
- fruitPrice: 1.50,
- })
- \endcode
-
- If \a rowIndex is equal to \c rowCount(), then a new row is appended to the
- model. Otherwise, \a rowIndex must point to an existing row in the model.
-
- \sa appendRow(), insertRow(), rowCount
-*/
-void QQmlTableModel::setRow(int rowIndex, const QVariant &row)
-{
- if (!validateNewRow("setRow()", row, rowIndex))
- return;
-
- if (rowIndex != mRowCount) {
- // Setting an existing row.
- mRows[rowIndex] = row;
-
- // For now we just assume the whole row changed, as it's simpler.
- const QModelIndex topLeftModelIndex(createIndex(rowIndex, 0));
- const QModelIndex bottomRightModelIndex(createIndex(rowIndex, mColumnCount - 1));
- emit dataChanged(topLeftModelIndex, bottomRightModelIndex);
- } else {
- // Appending a row.
- doInsert(rowIndex, row);
- }
-}
-
-QQmlListProperty<QQmlTableModelColumn> QQmlTableModel::columns()
-{
- return QQmlListProperty<QQmlTableModelColumn>(this, nullptr,
- &QQmlTableModel::columns_append,
- &QQmlTableModel::columns_count,
- &QQmlTableModel::columns_at,
- &QQmlTableModel::columns_clear);
-}
-
-void QQmlTableModel::columns_append(QQmlListProperty<QQmlTableModelColumn> *property,
- QQmlTableModelColumn *value)
-{
- QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
- QQmlTableModelColumn *column = qobject_cast<QQmlTableModelColumn*>(value);
- if (column)
- model->mColumns.append(column);
-}
-
-int QQmlTableModel::columns_count(QQmlListProperty<QQmlTableModelColumn> *property)
-{
- const QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
- return model->mColumns.count();
-}
-
-QQmlTableModelColumn *QQmlTableModel::columns_at(QQmlListProperty<QQmlTableModelColumn> *property, int index)
-{
- const QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
- return model->mColumns.at(index);
-}
-
-void QQmlTableModel::columns_clear(QQmlListProperty<QQmlTableModelColumn> *property)
-{
- QQmlTableModel *model = static_cast<QQmlTableModel*>(property->object);
- return model->mColumns.clear();
-}
-
-/*!
- \qmlmethod QModelIndex TableModel::index(int row, int column)
-
- Returns a \l QModelIndex object referencing the given \a row and \a column,
- which can be passed to the data() function to get the data from that cell,
- or to setData() to edit the contents of that cell.
-
- \code
- import QtQml 2.14
- import Qt.labs.qmlmodels 1.0
-
- TableModel {
- id: model
-
- TableModelColumn { display: "fruitType" }
- TableModelColumn { display: "fruitPrice" }
-
- rows: [
- { fruitType: "Apple", fruitPrice: 1.50 },
- { fruitType: "Orange", fruitPrice: 2.50 }
- ]
-
- Component.onCompleted: {
- for (var r = 0; r < model.rowCount; ++r) {
- console.log("An " + model.data(model.index(r, 0)).display +
- " costs " + model.data(model.index(r, 1)).display.toFixed(2))
- }
- }
- }
- \endcode
-
- \sa {QModelIndex and related Classes in QML}, data()
-*/
-// Note: we don't document the parent argument, because you never need it, because
-// cells in a TableModel don't have parents. But it is there because this function is an override.
-QModelIndex QQmlTableModel::index(int row, int column, const QModelIndex &parent) const
-{
- return row >= 0 && row < rowCount() && column >= 0 && column < columnCount() && !parent.isValid()
- ? createIndex(row, column)
- : QModelIndex();
-}
-
-/*!
- \qmlproperty int TableModel::rowCount
- \readonly
-
- This read-only property holds the number of rows in the model.
-
- This value changes whenever rows are added or removed from the model.
-*/
-int QQmlTableModel::rowCount(const QModelIndex &parent) const
-{
- if (parent.isValid())
- return 0;
-
- return mRowCount;
-}
-
-/*!
- \qmlproperty int TableModel::columnCount
- \readonly
-
- This read-only property holds the number of columns in the model.
-
- The number of columns is fixed for the lifetime of the model
- after the \l rows property is set or \l appendRow() is called for the first
- time.
-*/
-int QQmlTableModel::columnCount(const QModelIndex &parent) const
-{
- if (parent.isValid())
- return 0;
-
- return mColumnCount;
-}
-
-/*!
- \qmlmethod variant TableModel::data(QModelIndex index, string role)
-
- Returns the data from the table cell at the given \a index belonging to the
- given \a role.
-
- \sa index()
-*/
-QVariant QQmlTableModel::data(const QModelIndex &index, const QString &role) const
-{
- const int iRole = mRoleNames.key(role.toUtf8(), -1);
- if (iRole >= 0)
- return data(index, iRole);
- return QVariant();
-}
-
-QVariant QQmlTableModel::data(const QModelIndex &index, int role) const
-{
- const int row = index.row();
- if (row < 0 || row >= rowCount())
- return QVariant();
-
- const int column = index.column();
- if (column < 0 || column >= columnCount())
- return QVariant();
-
- const ColumnMetadata columnMetadata = mColumnMetadata.at(index.column());
- const QString roleName = QString::fromUtf8(mRoleNames.value(role));
- if (!columnMetadata.roles.contains(roleName)) {
- qmlWarning(this) << "setData(): no role named " << roleName
- << " at column index " << column << ". The available roles for that column are: "
- << columnMetadata.roles.keys();
- return QVariant();
- }
-
- const ColumnRoleMetadata roleData = columnMetadata.roles.value(roleName);
- if (roleData.isStringRole) {
- // We know the data structure, so we can get the data for the user.
- const QVariantMap rowData = mRows.at(row).toMap();
- const QString propertyName = columnMetadata.roles.value(roleName).name;
- const QVariant value = rowData.value(propertyName);
- return value;
- }
-
- // We don't know the data structure, so the user has to modify their data themselves.
- // First, find the getter for this column and role.
- QJSValue getter = mColumns.at(column)->getterAtRole(roleName);
-
- // Then, call it and return what it returned.
- const auto args = QJSValueList() << qmlEngine(this)->toScriptValue(index);
- return getter.call(args).toVariant();
-}
-
-/*!
- \qmlmethod bool TableModel::setData(QModelIndex index, string role, variant value)
-
- Inserts or updates the data field named by \a role in the table cell at the
- given \a index with \a value. Returns true if sucessful, false if not.
-
- \sa index()
-*/
-bool QQmlTableModel::setData(const QModelIndex &index, const QString &role, const QVariant &value)
-{
- const int intRole = mRoleNames.key(role.toUtf8(), -1);
- if (intRole >= 0)
- return setData(index, value, intRole);
- return false;
-}
-
-bool QQmlTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- const int row = index.row();
- if (row < 0 || row >= rowCount())
- return false;
-
- const int column = index.column();
- if (column < 0 || column >= columnCount())
- return false;
-
- const QString roleName = QString::fromUtf8(mRoleNames.value(role));
-
- qCDebug(lcTableModel).nospace() << "setData() called with index "
- << index << ", value " << value << " and role " << roleName;
-
- // Verify that the role exists for this column.
- const ColumnMetadata columnMetadata = mColumnMetadata.at(index.column());
- if (!columnMetadata.roles.contains(roleName)) {
- qmlWarning(this) << "setData(): no role named \"" << roleName
- << "\" at column index " << column << ". The available roles for that column are: "
- << columnMetadata.roles.keys();
- return false;
- }
-
- // Verify that the type of the value is what we expect.
- // If the value set is not of the expected type, we can try to convert it automatically.
- const ColumnRoleMetadata roleData = columnMetadata.roles.value(roleName);
- QVariant effectiveValue = value;
- if (value.type() != roleData.type) {
- if (!value.canConvert(int(roleData.type))) {
- qmlWarning(this).nospace() << "setData(): the value " << value
- << " set at row " << row << " column " << column << " with role " << roleName
- << " cannot be converted to " << roleData.typeName;
- return false;
- }
-
- if (!effectiveValue.convert(int(roleData.type))) {
- qmlWarning(this).nospace() << "setData(): failed converting value " << value
- << " set at row " << row << " column " << column << " with role " << roleName
- << " to " << roleData.typeName;
- return false;
- }
- }
-
- if (roleData.isStringRole) {
- // We know the data structure, so we can set it for the user.
- QVariantMap modifiedRow = mRows.at(row).toMap();
- modifiedRow[roleData.name] = value;
-
- mRows[row] = modifiedRow;
- } else {
- // We don't know the data structure, so the user has to modify their data themselves.
- auto engine = qmlEngine(this);
- auto args = QJSValueList()
- // arg 0: modelIndex.
- << engine->toScriptValue(index)
- // arg 1: cellData.
- << engine->toScriptValue(value);
- // Do the actual setting.
- QJSValue setter = mColumns.at(column)->setterAtRole(roleName);
- setter.call(args);
-
- /*
- The chain of events so far:
-
- - User did e.g.: model.edit = textInput.text
- - setData() is called
- - setData() calls the setter
- (remember that we need to emit the dataChanged() signal,
- which is why the user can't just set the data directly in the delegate)
-
- Now the user's setter function has modified *their* copy of the
- data, but *our* copy of the data is old. Imagine the getters and setters looked like this:
-
- display: function(modelIndex) { return rows[modelIndex.row][1].amount }
- setDisplay: function(modelIndex, cellData) { rows[modelIndex.row][1].amount = cellData }
-
- We don't know the structure of the user's data, so we can't just do
- what we do above for the isStringRole case:
-
- modifiedRow[column][roleName] = value
-
- This means that, besides getting the implicit row count when rows is initially set,
- our copy of the data is unused when it comes to complex columns.
-
- Another point to note is that we can't pass rowData in to the getter as a convenience,
- because we would be passing in *our* copy of the row, which is not up-to-date.
- Since the user already has access to the data, it's not a big deal for them to do:
-
- display: function(modelIndex) { return rows[modelIndex.row][1].amount }
-
- instead of:
-
- display: function(modelIndex, rowData) { return rowData[1].amount }
- */
- }
-
- QVector<int> rolesChanged;
- rolesChanged.append(role);
- emit dataChanged(index, index, rolesChanged);
-
- return true;
-}
-
-QHash<int, QByteArray> QQmlTableModel::roleNames() const
-{
- return mRoleNames;
-}
-
-QQmlTableModel::ColumnRoleMetadata::ColumnRoleMetadata()
-{
-}
-
-QQmlTableModel::ColumnRoleMetadata::ColumnRoleMetadata(
- bool isStringRole, const QString &name, QVariant::Type type, const QString &typeName) :
- isStringRole(isStringRole),
- name(name),
- type(type),
- typeName(typeName)
-{
-}
-
-bool QQmlTableModel::ColumnRoleMetadata::isValid() const
-{
- return !name.isEmpty();
-}
-
-bool QQmlTableModel::validateRowType(const char *functionName, const QVariant &row) const
-{
- if (!row.canConvert<QJSValue>()) {
- qmlWarning(this) << functionName << ": expected \"row\" argument to be a QJSValue,"
- << " but got " << row.typeName() << " instead:\n" << row;
- return false;
- }
-
- const QJSValue rowAsJSValue = row.value<QJSValue>();
- if (!rowAsJSValue.isObject() && !rowAsJSValue.isArray()) {
- qmlWarning(this) << functionName << ": expected \"row\" argument "
- << "to be an object or array, but got:\n" << rowAsJSValue.toString();
- return false;
- }
-
- return true;
-}
-
-bool QQmlTableModel::validateNewRow(const char *functionName, const QVariant &row,
- int rowIndex, NewRowOperationFlag operation) const
-{
- if (mColumnMetadata.isEmpty()) {
- // There is no column metadata, so we have nothing to validate the row against.
- // Rows have to be added before we can gather metadata from them, so just this
- // once we'll return true to allow the rows to be added.
- return true;
- }
-
- // Don't require each row to be a QJSValue when setting all rows,
- // as they won't be; they'll be QVariantMap.
- if (operation != SetRowsOperation && !validateRowType(functionName, row))
- return false;
-
- if (operation == OtherOperation) {
- // Inserting/setting.
- if (rowIndex < 0) {
- qmlWarning(this) << functionName << ": \"rowIndex\" cannot be negative";
- return false;
- }
-
- if (rowIndex > mRowCount) {
- qmlWarning(this) << functionName << ": \"rowIndex\" " << rowIndex
- << " is greater than rowCount() of " << mRowCount;
- return false;
- }
- }
-
- const QVariant rowAsVariant = operation == SetRowsOperation
- ? row : row.value<QJSValue>().toVariant();
- if (rowAsVariant.type() != QVariant::Map) {
- qmlWarning(this) << functionName << ": row manipulation functions "
- << "do not support complex rows (row index: " << rowIndex << ")";
- return false;
- }
-
- const QVariantMap rowAsMap = rowAsVariant.toMap();
- const int columnCount = rowAsMap.size();
- if (columnCount < mColumnCount) {
- qmlWarning(this) << functionName << ": expected " << mColumnCount
- << " columns, but only got " << columnCount;
- return false;
- }
-
- // We can't validate complex structures, but we can make sure that
- // each simple string-based role in each column is correct.
- for (int columnIndex = 0; columnIndex < mColumns.size(); ++columnIndex) {
- QQmlTableModelColumn *column = mColumns.at(columnIndex);
- const QHash<QString, QJSValue> getters = column->getters();
- const auto roleNames = getters.keys();
- const ColumnMetadata columnMetadata = mColumnMetadata.at(columnIndex);
- for (const QString &roleName : roleNames) {
- const ColumnRoleMetadata roleData = columnMetadata.roles.value(roleName);
- if (!roleData.isStringRole)
- continue;
-
- if (!rowAsMap.contains(roleData.name)) {
- qmlWarning(this).quote() << functionName << ": expected a property named "
- << roleData.name << " in row at index " << rowIndex << ", but couldn't find one";
- return false;
- }
-
- const QVariant rolePropertyValue = rowAsMap.value(roleData.name);
-
- if (rolePropertyValue.type() != roleData.type) {
- if (!rolePropertyValue.canConvert(int(roleData.type))) {
- qmlWarning(this).quote() << functionName << ": expected the property named "
- << roleData.name << " to be of type " << roleData.typeName
- << ", but got " << QString::fromLatin1(rolePropertyValue.typeName())
- << " instead";
- return false;
- }
-
- QVariant effectiveValue = rolePropertyValue;
- if (!effectiveValue.convert(int(roleData.type))) {
- qmlWarning(this).nospace() << functionName << ": failed converting value "
- << rolePropertyValue << " set at column " << columnIndex << " with role "
- << QString::fromLatin1(rolePropertyValue.typeName()) << " to "
- << roleData.typeName;
- return false;
- }
- }
- }
- }
-
- return true;
-}
-
-bool QQmlTableModel::validateRowIndex(const char *functionName, const char *argumentName, int rowIndex) const
-{
- if (rowIndex < 0) {
- qmlWarning(this) << functionName << ": \"" << argumentName << "\" cannot be negative";
- return false;
- }
-
- if (rowIndex >= mRowCount) {
- qmlWarning(this) << functionName << ": \"" << argumentName
- << "\" " << rowIndex << " is greater than or equal to rowCount() of " << mRowCount;
- return false;
- }
-
- return true;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmltablemodel_p.h b/src/qmlmodels/qqmltablemodel_p.h
deleted file mode 100644
index b3c0cc2848..0000000000
--- a/src/qmlmodels/qqmltablemodel_p.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLTABLEMODEL_P_H
-#define QQMLTABLEMODEL_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 <QtCore/QObject>
-#include <QtCore/QAbstractTableModel>
-#include <QtQml/qqml.h>
-#include <QtQmlModels/private/qtqmlmodelsglobal_p.h>
-#include <QtQmlModels/private/qqmltablemodelcolumn_p.h>
-#include <QtQml/QJSValue>
-#include <QtQml/QQmlListProperty>
-
-QT_REQUIRE_CONFIG(qml_table_model);
-
-QT_BEGIN_NAMESPACE
-
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableModel : public QAbstractTableModel, public QQmlParserStatus
-{
- Q_OBJECT
- Q_PROPERTY(int columnCount READ columnCount NOTIFY columnCountChanged FINAL)
- Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged FINAL)
- Q_PROPERTY(QVariant rows READ rows WRITE setRows NOTIFY rowsChanged FINAL)
- Q_PROPERTY(QQmlListProperty<QQmlTableModelColumn> columns READ columns CONSTANT FINAL)
- Q_INTERFACES(QQmlParserStatus)
- Q_CLASSINFO("DefaultProperty", "columns")
-
-public:
- QQmlTableModel(QObject *parent = nullptr);
- ~QQmlTableModel() override;
-
- QVariant rows() const;
- void setRows(const QVariant &rows);
-
- Q_INVOKABLE void appendRow(const QVariant &row);
- Q_INVOKABLE void clear();
- Q_INVOKABLE QVariant getRow(int rowIndex);
- Q_INVOKABLE void insertRow(int rowIndex, const QVariant &row);
- Q_INVOKABLE void moveRow(int fromRowIndex, int toRowIndex, int rows = 1);
- Q_INVOKABLE void removeRow(int rowIndex, int rows = 1);
- Q_INVOKABLE void setRow(int rowIndex, const QVariant &row);
-
- QQmlListProperty<QQmlTableModelColumn> columns();
-
- static void columns_append(QQmlListProperty<QQmlTableModelColumn> *property, QQmlTableModelColumn *value);
- static int columns_count(QQmlListProperty<QQmlTableModelColumn> *property);
- static QQmlTableModelColumn *columns_at(QQmlListProperty<QQmlTableModelColumn> *property, int index);
- static void columns_clear(QQmlListProperty<QQmlTableModelColumn> *property);
-
- QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- int columnCount(const QModelIndex &parent = QModelIndex()) const override;
- Q_INVOKABLE QVariant data(const QModelIndex &index, const QString &role) const;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- Q_INVOKABLE bool setData(const QModelIndex &index, const QString &role, const QVariant &value);
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole) override;
- QHash<int, QByteArray> roleNames() const override;
-
-Q_SIGNALS:
- void columnCountChanged();
- void rowCountChanged();
- void rowsChanged();
-
-private:
- class ColumnRoleMetadata
- {
- public:
- ColumnRoleMetadata();
- ColumnRoleMetadata(bool isStringRole, const QString &name, QVariant::Type type, const QString &typeName);
-
- bool isValid() const;
-
- // If this is false, it's a function role.
- bool isStringRole = false;
- QString name;
- QVariant::Type type = QVariant::Invalid;
- QString typeName;
- };
-
- struct ColumnMetadata
- {
- // Key = role name that will be made visible to the delegate
- // Value = metadata about that role, including actual name in the model data, type, etc.
- QHash<QString, ColumnRoleMetadata> roles;
- };
-
- enum NewRowOperationFlag {
- OtherOperation, // insert(), set(), etc.
- SetRowsOperation,
- AppendOperation
- };
-
- void doSetRows(const QVariantList &rowsAsVariantList);
- ColumnRoleMetadata fetchColumnRoleData(const QString &roleNameKey,
- QQmlTableModelColumn *tableModelColumn, int columnIndex) const;
- void fetchColumnMetadata();
-
- bool validateRowType(const char *functionName, const QVariant &row) const;
- bool validateNewRow(const char *functionName, const QVariant &row,
- int rowIndex, NewRowOperationFlag operation = OtherOperation) const;
- bool validateRowIndex(const char *functionName, const char *argumentName, int rowIndex) const;
-
- void doInsert(int rowIndex, const QVariant &row);
-
- void classBegin() override;
- void componentComplete() override;
-
- bool componentCompleted = false;
- QVariantList mRows;
- QList<QQmlTableModelColumn *> mColumns;
- int mRowCount = 0;
- int mColumnCount = 0;
- // Each entry contains information about the properties of the column at that index.
- QVector<ColumnMetadata> mColumnMetadata;
- // key = property index (0 to number of properties across all columns)
- // value = role name
- QHash<int, QByteArray> mRoleNames;
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlTableModel)
-
-#endif // QQMLTABLEMODEL_P_H
diff --git a/src/qmlmodels/qqmltablemodelcolumn.cpp b/src/qmlmodels/qqmltablemodelcolumn.cpp
deleted file mode 100644
index 93da0642de..0000000000
--- a/src/qmlmodels/qqmltablemodelcolumn.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmltablemodelcolumn_p.h"
-
-#include <QtQml/qqmlinfo.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \qmltype TableModelColumn
- \instantiates QQmlTableModelColumn
- \inqmlmodule Qt.labs.qmlmodels
- \brief Represents a column in a model.
- \since 5.14
-
- \section1 Supported Roles
-
- TableModelColumn supports all of \l {Qt::ItemDataRole}{Qt's roles},
- with the exception of \c Qt::InitialSortOrderRole.
-
- \sa TableModel, TableView
-*/
-
-static const QString displayRoleName = QStringLiteral("display");
-static const QString decorationRoleName = QStringLiteral("decoration");
-static const QString editRoleName = QStringLiteral("edit");
-static const QString toolTipRoleName = QStringLiteral("toolTip");
-static const QString statusTipRoleName = QStringLiteral("statusTip");
-static const QString whatsThisRoleName = QStringLiteral("whatsThis");
-
-static const QString fontRoleName = QStringLiteral("font");
-static const QString textAlignmentRoleName = QStringLiteral("textAlignment");
-static const QString backgroundRoleName = QStringLiteral("background");
-static const QString foregroundRoleName = QStringLiteral("foreground");
-static const QString checkStateRoleName = QStringLiteral("checkState");
-
-static const QString accessibleTextRoleName = QStringLiteral("accessibleText");
-static const QString accessibleDescriptionRoleName = QStringLiteral("accessibleDescription");
-
-static const QString sizeHintRoleName = QStringLiteral("sizeHint");
-
-
-QQmlTableModelColumn::QQmlTableModelColumn(QObject *parent)
- : QObject(parent)
-{
-}
-
-QQmlTableModelColumn::~QQmlTableModelColumn()
-{
-}
-
-#define DEFINE_ROLE_PROPERTIES(getterGetterName, getterSetterName, getterSignal, setterGetterName, setterSetterName, setterSignal, roleName) \
-QJSValue QQmlTableModelColumn::getterGetterName() const \
-{ \
- return mGetters.value(roleName); \
-} \
-\
-void QQmlTableModelColumn::getterSetterName(const QJSValue &stringOrFunction) \
-{ \
- if (!stringOrFunction.isString() && !stringOrFunction.isCallable()) { \
- qmlWarning(this).quote() << "getter for " << roleName << " must be a function"; \
- return; \
- } \
- if (stringOrFunction.strictlyEquals(decoration())) \
- return; \
-\
- mGetters[roleName] = stringOrFunction; \
- emit decorationChanged(); \
-} \
-\
-QJSValue QQmlTableModelColumn::setterGetterName() const \
-{ \
- return mSetters.value(roleName); \
-} \
-\
-void QQmlTableModelColumn::setterSetterName(const QJSValue &function) \
-{ \
- if (!function.isCallable()) { \
- qmlWarning(this).quote() << "setter for " << roleName << " must be a function"; \
- return; \
- } \
-\
- if (function.strictlyEquals(getSetDisplay())) \
- return; \
-\
- mSetters[roleName] = function; \
- emit setDisplayChanged(); \
-}
-
-DEFINE_ROLE_PROPERTIES(display, setDisplay, displayChanged,
- getSetDisplay, setSetDisplay, setDisplayChanged, displayRoleName)
-DEFINE_ROLE_PROPERTIES(decoration, setDecoration, decorationChanged,
- getSetDecoration, setSetDecoration, setDecorationChanged, decorationRoleName)
-DEFINE_ROLE_PROPERTIES(edit, setEdit, editChanged,
- getSetEdit, setSetEdit, setEditChanged, editRoleName)
-DEFINE_ROLE_PROPERTIES(toolTip, setToolTip, toolTipChanged,
- getSetToolTip, setSetToolTip, setToolTipChanged, toolTipRoleName)
-DEFINE_ROLE_PROPERTIES(statusTip, setStatusTip, statusTipChanged,
- getSetStatusTip, setSetStatusTip, setStatusTipChanged, statusTipRoleName)
-DEFINE_ROLE_PROPERTIES(whatsThis, setWhatsThis, whatsThisChanged,
- getSetWhatsThis, setSetWhatsThis, setWhatsThisChanged, whatsThisRoleName)
-
-DEFINE_ROLE_PROPERTIES(font, setFont, fontChanged,
- getSetFont, setSetFont, setFontChanged, fontRoleName)
-DEFINE_ROLE_PROPERTIES(textAlignment, setTextAlignment, textAlignmentChanged,
- getSetTextAlignment, setSetTextAlignment, setTextAlignmentChanged, textAlignmentRoleName)
-DEFINE_ROLE_PROPERTIES(background, setBackground, backgroundChanged,
- getSetBackground, setSetBackground, setBackgroundChanged, backgroundRoleName)
-DEFINE_ROLE_PROPERTIES(foreground, setForeground, foregroundChanged,
- getSetForeground, setSetForeground, setForegroundChanged, foregroundRoleName)
-DEFINE_ROLE_PROPERTIES(checkState, setCheckState, checkStateChanged,
- getSetCheckState, setSetCheckState, setCheckStateChanged, checkStateRoleName)
-
-DEFINE_ROLE_PROPERTIES(accessibleText, setAccessibleText, accessibleTextChanged,
- getSetAccessibleText, setSetAccessibleText, setAccessibleTextChanged, accessibleTextRoleName)
-DEFINE_ROLE_PROPERTIES(accessibleDescription, setAccessibleDescription, accessibleDescriptionChanged,
- getSetAccessibleDescription, setSetAccessibleDescription, setAccessibleDescriptionChanged, accessibleDescriptionRoleName)
-
-DEFINE_ROLE_PROPERTIES(sizeHint, setSizeHint, sizeHintChanged,
- getSetSizeHint, setSetSizeHint, setSizeHintChanged, sizeHintRoleName)
-
-QJSValue QQmlTableModelColumn::getterAtRole(const QString &roleName)
-{
- auto it = mGetters.find(roleName);
- if (it == mGetters.end())
- return QJSValue();
- return *it;
-}
-
-QJSValue QQmlTableModelColumn::setterAtRole(const QString &roleName)
-{
- auto it = mSetters.find(roleName);
- if (it == mSetters.end())
- return QJSValue();
- return *it;
-}
-
-const QHash<QString, QJSValue> QQmlTableModelColumn::getters() const
-{
- return mGetters;
-}
-
-const QHash<int, QString> QQmlTableModelColumn::supportedRoleNames()
-{
- QHash<int, QString> names;
- names[Qt::DisplayRole] = QLatin1String("display");
- names[Qt::DecorationRole] = QLatin1String("decoration");
- names[Qt::EditRole] = QLatin1String("edit");
- names[Qt::ToolTipRole] = QLatin1String("toolTip");
- names[Qt::StatusTipRole] = QLatin1String("statusTip");
- names[Qt::WhatsThisRole] = QLatin1String("whatsThis");
- names[Qt::FontRole] = QLatin1String("font");
- names[Qt::TextAlignmentRole] = QLatin1String("textAlignment");
- names[Qt::BackgroundRole] = QLatin1String("background");
- names[Qt::ForegroundRole] = QLatin1String("foreground");
- names[Qt::CheckStateRole] = QLatin1String("checkState");
- names[Qt::AccessibleTextRole] = QLatin1String("accessibleText");
- names[Qt::AccessibleDescriptionRole] = QLatin1String("accessibleDescription");
- names[Qt::SizeHintRole] = QLatin1String("sizeHint");
- return names;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmltablemodelcolumn_p.h b/src/qmlmodels/qqmltablemodelcolumn_p.h
deleted file mode 100644
index 0b6478ce38..0000000000
--- a/src/qmlmodels/qqmltablemodelcolumn_p.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLTABLEMODELCOLUMN_P_H
-#define QQMLTABLEMODELCOLUMN_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 <QtCore/QObject>
-#include <QtQml/qqml.h>
-#include <QtQmlModels/private/qtqmlmodelsglobal_p.h>
-#include <QtQml/qjsvalue.h>
-
-QT_REQUIRE_CONFIG(qml_table_model);
-
-QT_BEGIN_NAMESPACE
-
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlTableModelColumn : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QJSValue display READ display WRITE setDisplay NOTIFY displayChanged FINAL)
- Q_PROPERTY(QJSValue setDisplay READ getSetDisplay WRITE setSetDisplay NOTIFY setDisplayChanged)
- Q_PROPERTY(QJSValue decoration READ decoration WRITE setDecoration NOTIFY decorationChanged FINAL)
- Q_PROPERTY(QJSValue setDecoration READ getSetDecoration WRITE setSetDecoration NOTIFY setDecorationChanged FINAL)
- Q_PROPERTY(QJSValue edit READ edit WRITE setEdit NOTIFY editChanged FINAL)
- Q_PROPERTY(QJSValue setEdit READ getSetEdit WRITE setSetEdit NOTIFY setEditChanged FINAL)
- Q_PROPERTY(QJSValue toolTip READ toolTip WRITE setToolTip NOTIFY toolTipChanged FINAL)
- Q_PROPERTY(QJSValue setToolTip READ getSetToolTip WRITE setSetToolTip NOTIFY setToolTipChanged FINAL)
- Q_PROPERTY(QJSValue statusTip READ statusTip WRITE setStatusTip NOTIFY statusTipChanged FINAL)
- Q_PROPERTY(QJSValue setStatusTip READ getSetStatusTip WRITE setSetStatusTip NOTIFY setStatusTipChanged FINAL)
- Q_PROPERTY(QJSValue whatsThis READ whatsThis WRITE setWhatsThis NOTIFY whatsThisChanged FINAL)
- Q_PROPERTY(QJSValue setWhatsThis READ getSetWhatsThis WRITE setSetWhatsThis NOTIFY setWhatsThisChanged FINAL)
-
- Q_PROPERTY(QJSValue font READ font WRITE setFont NOTIFY fontChanged FINAL)
- Q_PROPERTY(QJSValue setFont READ getSetFont WRITE setSetFont NOTIFY setFontChanged FINAL)
- Q_PROPERTY(QJSValue textAlignment READ textAlignment WRITE setTextAlignment NOTIFY textAlignmentChanged FINAL)
- Q_PROPERTY(QJSValue setTextAlignment READ getSetTextAlignment WRITE setSetTextAlignment NOTIFY setTextAlignmentChanged FINAL)
- Q_PROPERTY(QJSValue background READ background WRITE setBackground NOTIFY backgroundChanged FINAL)
- Q_PROPERTY(QJSValue setBackground READ getSetBackground WRITE setSetBackground NOTIFY setBackgroundChanged FINAL)
- Q_PROPERTY(QJSValue foreground READ foreground WRITE setForeground NOTIFY foregroundChanged FINAL)
- Q_PROPERTY(QJSValue setForeground READ getSetForeground WRITE setSetForeground NOTIFY setForegroundChanged FINAL)
- Q_PROPERTY(QJSValue checkState READ checkState WRITE setCheckState NOTIFY checkStateChanged FINAL)
- Q_PROPERTY(QJSValue setCheckState READ getSetCheckState WRITE setSetCheckState NOTIFY setCheckStateChanged FINAL)
-
- Q_PROPERTY(QJSValue accessibleText READ accessibleText WRITE setAccessibleText NOTIFY accessibleTextChanged FINAL)
- Q_PROPERTY(QJSValue setAccessibleText READ getSetAccessibleText WRITE setSetAccessibleText NOTIFY setAccessibleTextChanged FINAL)
- Q_PROPERTY(QJSValue accessibleDescription READ accessibleDescription
- WRITE setAccessibleDescription NOTIFY accessibleDescriptionChanged FINAL)
- Q_PROPERTY(QJSValue setAccessibleDescription READ getSetAccessibleDescription
- WRITE setSetAccessibleDescription NOTIFY setAccessibleDescriptionChanged FINAL)
-
- Q_PROPERTY(QJSValue sizeHint READ sizeHint WRITE setSizeHint NOTIFY sizeHintChanged FINAL)
- Q_PROPERTY(QJSValue setSizeHint READ getSetSizeHint WRITE setSetSizeHint NOTIFY setSizeHintChanged FINAL)
-
-public:
- QQmlTableModelColumn(QObject *parent = nullptr);
- ~QQmlTableModelColumn() override;
-
- QJSValue display() const;
- void setDisplay(const QJSValue &stringOrFunction);
- QJSValue getSetDisplay() const;
- void setSetDisplay(const QJSValue &function);
-
- QJSValue decoration() const;
- void setDecoration(const QJSValue &stringOrFunction);
- QJSValue getSetDecoration() const;
- void setSetDecoration(const QJSValue &function);
-
- QJSValue edit() const;
- void setEdit(const QJSValue &stringOrFunction);
- QJSValue getSetEdit() const;
- void setSetEdit(const QJSValue &function);
-
- QJSValue toolTip() const;
- void setToolTip(const QJSValue &stringOrFunction);
- QJSValue getSetToolTip() const;
- void setSetToolTip(const QJSValue &function);
-
- QJSValue statusTip() const;
- void setStatusTip(const QJSValue &stringOrFunction);
- QJSValue getSetStatusTip() const;
- void setSetStatusTip(const QJSValue &function);
-
- QJSValue whatsThis() const;
- void setWhatsThis(const QJSValue &stringOrFunction);
- QJSValue getSetWhatsThis() const;
- void setSetWhatsThis(const QJSValue &function);
-
- QJSValue font() const;
- void setFont(const QJSValue &stringOrFunction);
- QJSValue getSetFont() const;
- void setSetFont(const QJSValue &function);
-
- QJSValue textAlignment() const;
- void setTextAlignment(const QJSValue &stringOrFunction);
- QJSValue getSetTextAlignment() const;
- void setSetTextAlignment(const QJSValue &function);
-
- QJSValue background() const;
- void setBackground(const QJSValue &stringOrFunction);
- QJSValue getSetBackground() const;
- void setSetBackground(const QJSValue &function);
-
- QJSValue foreground() const;
- void setForeground(const QJSValue &stringOrFunction);
- QJSValue getSetForeground() const;
- void setSetForeground(const QJSValue &function);
-
- QJSValue checkState() const;
- void setCheckState(const QJSValue &stringOrFunction);
- QJSValue getSetCheckState() const;
- void setSetCheckState(const QJSValue &function);
-
- QJSValue accessibleText() const;
- void setAccessibleText(const QJSValue &stringOrFunction);
- QJSValue getSetAccessibleText() const;
- void setSetAccessibleText(const QJSValue &function);
-
- QJSValue accessibleDescription() const;
- void setAccessibleDescription(const QJSValue &stringOrFunction);
- QJSValue getSetAccessibleDescription() const;
- void setSetAccessibleDescription(const QJSValue &function);
-
- QJSValue sizeHint() const;
- void setSizeHint(const QJSValue &stringOrFunction);
- QJSValue getSetSizeHint() const;
- void setSetSizeHint(const QJSValue &function);
-
- QJSValue getterAtRole(const QString &roleName);
- QJSValue setterAtRole(const QString &roleName);
-
- const QHash<QString, QJSValue> getters() const;
-
- static const QHash<int, QString> supportedRoleNames();
-
-Q_SIGNALS:
- void indexChanged();
- void displayChanged();
- void setDisplayChanged();
- void decorationChanged();
- void setDecorationChanged();
- void editChanged();
- void setEditChanged();
- void toolTipChanged();
- void setToolTipChanged();
- void statusTipChanged();
- void setStatusTipChanged();
- void whatsThisChanged();
- void setWhatsThisChanged();
-
- void fontChanged();
- void setFontChanged();
- void textAlignmentChanged();
- void setTextAlignmentChanged();
- void backgroundChanged();
- void setBackgroundChanged();
- void foregroundChanged();
- void setForegroundChanged();
- void checkStateChanged();
- void setCheckStateChanged();
-
- void accessibleTextChanged();
- void setAccessibleTextChanged();
- void accessibleDescriptionChanged();
- void setAccessibleDescriptionChanged();
- void sizeHintChanged();
- void setSizeHintChanged();
-
-private:
- int mIndex = -1;
-
- // We store these in hashes because QQuickTableModel needs string-based lookup in certain situations.
- QHash<QString, QJSValue> mGetters;
- QHash<QString, QJSValue> mSetters;
-};
-
-QT_END_NAMESPACE
-
-QML_DECLARE_TYPE(QQmlTableModelColumn)
-
-#endif // QQMLTABLEMODELCOLUMN_P_H
diff --git a/src/qmlmodels/qquickpackage.cpp b/src/qmlmodels/qquickpackage.cpp
index 567381e5ab..42e7d0e09f 100644
--- a/src/qmlmodels/qquickpackage.cpp
+++ b/src/qmlmodels/qquickpackage.cpp
@@ -115,6 +115,14 @@ public:
QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
return list->count();
}
+ static void data_replace(QQmlListProperty<QObject> *prop, int index, QObject *o) {
+ QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
+ list->replace(index, DataGuard(o, list));
+ }
+ static void data_removeLast(QQmlListProperty<QObject> *prop) {
+ QList<DataGuard> *list = static_cast<QList<DataGuard> *>(prop->data);
+ list->removeLast();
+ }
};
QHash<QObject *, QQuickPackageAttached *> QQuickPackageAttached::attached;
@@ -152,10 +160,13 @@ QQuickPackage::~QQuickPackage()
QQmlListProperty<QObject> QQuickPackage::data()
{
Q_D(QQuickPackage);
- return QQmlListProperty<QObject>(this, &d->dataList, QQuickPackagePrivate::data_append,
- QQuickPackagePrivate::data_count,
- QQuickPackagePrivate::data_at,
- QQuickPackagePrivate::data_clear);
+ return QQmlListProperty<QObject>(this, &d->dataList,
+ QQuickPackagePrivate::data_append,
+ QQuickPackagePrivate::data_count,
+ QQuickPackagePrivate::data_at,
+ QQuickPackagePrivate::data_clear,
+ QQuickPackagePrivate::data_replace,
+ QQuickPackagePrivate::data_removeLast);
}
bool QQuickPackage::hasPart(const QString &name)
diff --git a/src/qmlmodels/qquickpackage_p.h b/src/qmlmodels/qquickpackage_p.h
index 97f7818fee..97f3bab9bc 100644
--- a/src/qmlmodels/qquickpackage_p.h
+++ b/src/qmlmodels/qquickpackage_p.h
@@ -66,6 +66,9 @@ class Q_AUTOTEST_EXPORT QQuickPackage : public QObject
Q_DECLARE_PRIVATE(QQuickPackage)
Q_CLASSINFO("DefaultProperty", "data")
+ QML_NAMED_ELEMENT(Package)
+ QML_ADDED_IN_MINOR_VERSION(14)
+ QML_ATTACHED(QQuickPackageAttached)
Q_PROPERTY(QQmlListProperty<QObject> data READ data)
public:
@@ -99,6 +102,5 @@ private:
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickPackage)
-QML_DECLARE_TYPEINFO(QQuickPackage, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKPACKAGE_H
diff --git a/src/qmlmodels/qtqmlmodelsglobal_p.h b/src/qmlmodels/qtqmlmodelsglobal_p.h
index 145112c9c1..1a1157138d 100644
--- a/src/qmlmodels/qtqmlmodelsglobal_p.h
+++ b/src/qmlmodels/qtqmlmodelsglobal_p.h
@@ -58,4 +58,6 @@
#define Q_QMLMODELS_PRIVATE_EXPORT Q_QMLMODELS_EXPORT
#define Q_QMLMODELS_AUTOTEST_EXPORT Q_AUTOTEST_EXPORT
+void Q_QMLMODELS_PRIVATE_EXPORT qml_register_types_QtQml_Models();
+
#endif // QTQMLMODELSGLOBAL_P_H