aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/types
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/types')
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp38
-rw-r--r--src/qml/types/qqmldelegatemodel_p.h7
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h4
-rw-r--r--src/qml/types/qqmllistmodel.cpp8
-rw-r--r--src/qml/types/qqmllistmodel_p.h4
-rw-r--r--src/qml/types/qqmllistmodelworkeragent.cpp4
-rw-r--r--src/qml/types/qqmllistmodelworkeragent_p.h4
-rw-r--r--src/qml/types/qqmlmodelsmodule.cpp41
-rw-r--r--src/qml/types/qqmlmodelsmodule_p.h5
-rw-r--r--src/qml/types/qqmlobjectmodel.cpp4
-rw-r--r--src/qml/types/qqmlobjectmodel_p.h5
-rw-r--r--src/qml/types/qqmltableinstancemodel_p.h2
-rw-r--r--src/qml/types/qqmltablemodel.cpp1059
-rw-r--r--src/qml/types/qqmltablemodel_p.h170
-rw-r--r--src/qml/types/qqmltablemodelcolumn.cpp200
-rw-r--r--src/qml/types/qqmltablemodelcolumn_p.h224
-rw-r--r--src/qml/types/qquickworkerscript.cpp12
-rw-r--r--src/qml/types/qquickworkerscript_p.h3
-rw-r--r--src/qml/types/types.pri8
19 files changed, 1748 insertions, 54 deletions
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 572f58339f..0e57119368 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -1127,7 +1127,7 @@ QQmlIncubator::Status QQmlDelegateModel::incubationStatus(int index)
return QQmlIncubator::Ready;
}
-QString QQmlDelegateModelPrivate::stringValue(Compositor::Group group, int index, const QString &name)
+QVariant QQmlDelegateModelPrivate::variantValue(QQmlListCompositor::Group group, int index, const QString &name)
{
Compositor::iterator it = m_compositor.find(group, index);
if (QQmlAdaptorModel *model = it.list<QQmlAdaptorModel>()) {
@@ -1139,20 +1139,20 @@ QString QQmlDelegateModelPrivate::stringValue(Compositor::Group group, int index
while (dot > 0) {
QObject *obj = qvariant_cast<QObject*>(value);
if (!obj)
- return QString();
- int from = dot+1;
+ return QVariant();
+ const int from = dot + 1;
dot = name.indexOf(QLatin1Char('.'), from);
value = obj->property(name.midRef(from, dot - from).toUtf8());
}
- return value.toString();
+ return value;
}
- return QString();
+ return QVariant();
}
-QString QQmlDelegateModel::stringValue(int index, const QString &name)
+QVariant QQmlDelegateModel::variantValue(int index, const QString &role)
{
Q_D(QQmlDelegateModel);
- return d->stringValue(d->m_compositorGroup, index, name);
+ return d->variantValue(d->m_compositorGroup, index, role);
}
int QQmlDelegateModel::indexOf(QObject *item, QObject *) const
@@ -2419,17 +2419,15 @@ void QQmlDelegateModelGroupPrivate::setModel(QQmlDelegateModel *m, Compositor::G
bool QQmlDelegateModelGroupPrivate::isChangedConnected()
{
Q_Q(QQmlDelegateModelGroup);
- IS_SIGNAL_CONNECTED(q, QQmlDelegateModelGroup, changed, (const QQmlV4Handle &,const QQmlV4Handle &));
+ IS_SIGNAL_CONNECTED(q, QQmlDelegateModelGroup, changed, (const QJSValue &,const QJSValue &));
}
void QQmlDelegateModelGroupPrivate::emitChanges(QV4::ExecutionEngine *v4)
{
Q_Q(QQmlDelegateModelGroup);
if (isChangedConnected() && !changeSet.isEmpty()) {
- QV4::Scope scope(v4);
- QV4::ScopedValue removed(scope, engineData(scope.engine)->array(v4, changeSet.removes()));
- QV4::ScopedValue inserted(scope, engineData(scope.engine)->array(v4, changeSet.inserts()));
- emit q->changed(QQmlV4Handle(removed), QQmlV4Handle(inserted));
+ emit q->changed(QJSValue(v4, engineData(v4)->array(v4, changeSet.removes())),
+ QJSValue(v4, engineData(v4)->array(v4, changeSet.inserts())));
}
if (changeSet.difference() != 0)
emit q->countChanged();
@@ -2607,18 +2605,18 @@ void QQmlDelegateModelGroup::setDefaultInclude(bool include)
\endlist
*/
-QQmlV4Handle QQmlDelegateModelGroup::get(int index)
+QJSValue QQmlDelegateModelGroup::get(int index)
{
Q_D(QQmlDelegateModelGroup);
if (!d->model)
- return QQmlV4Handle(QV4::Encode::undefined());
+ return QJSValue();
QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
if (!model->m_context || !model->m_context->isValid()) {
- return QQmlV4Handle(QV4::Encode::undefined());
+ return QJSValue();
} else if (index < 0 || index >= model->m_compositor.count(d->group)) {
qmlWarning(this) << tr("get: index out of range");
- return QQmlV4Handle(QV4::Encode::undefined());
+ return QJSValue();
}
Compositor::iterator it = model->m_compositor.find(d->group, index);
@@ -2630,7 +2628,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index)
cacheItem = model->m_adaptorModel.createItem(
model->m_cacheMetaType, it.modelIndex());
if (!cacheItem)
- return QQmlV4Handle(QV4::Encode::undefined());
+ return QJSValue();
cacheItem->groups = it->flags;
model->m_cache.insert(it.cacheIndex, cacheItem);
@@ -2646,7 +2644,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index)
o->setPrototypeOf(p);
++cacheItem->scriptRef;
- return QQmlV4Handle(o);
+ return QJSValue(v4, o->asReturnedValue());
}
bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::Value &value, int *index, Compositor::Group *group) const
@@ -3338,9 +3336,9 @@ QQmlInstanceModel::ReleaseFlags QQmlPartsModel::release(QObject *item)
return flags;
}
-QString QQmlPartsModel::stringValue(int index, const QString &role)
+QVariant QQmlPartsModel::variantValue(int index, const QString &role)
{
- return QQmlDelegateModelPrivate::get(m_model)->stringValue(m_compositorGroup, index, role);
+ return QQmlDelegateModelPrivate::get(m_model)->variantValue(m_compositorGroup, index, role);
}
void QQmlPartsModel::setWatchedRoles(const QList<QByteArray> &roles)
diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h
index 0ad8939732..2684162514 100644
--- a/src/qml/types/qqmldelegatemodel_p.h
+++ b/src/qml/types/qqmldelegatemodel_p.h
@@ -59,7 +59,6 @@
#include <QtCore/qabstractitemmodel.h>
#include <QtCore/qstringlist.h>
-#include <private/qv8engine_p.h>
#include <private/qqmlglobal_p.h>
QT_REQUIRE_CONFIG(qml_delegate_model);
@@ -114,7 +113,7 @@ public:
QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
ReleaseFlags release(QObject *object) override;
void cancel(int index) override;
- QString stringValue(int index, const QString &role) override;
+ QVariant variantValue(int index, const QString &role) override;
void setWatchedRoles(const QList<QByteArray> &roles) override;
QQmlIncubator::Status incubationStatus(int index) override;
@@ -179,7 +178,7 @@ public:
bool defaultInclude() const;
void setDefaultInclude(bool include);
- Q_INVOKABLE QQmlV4Handle get(int index);
+ Q_INVOKABLE QJSValue get(int index);
public Q_SLOTS:
void insert(QQmlV4Function *);
@@ -195,7 +194,7 @@ Q_SIGNALS:
void countChanged();
void nameChanged();
void defaultIncludeChanged();
- void changed(const QQmlV4Handle &removed, const QQmlV4Handle &inserted);
+ void changed(const QJSValue &removed, const QJSValue &inserted);
private:
Q_DECLARE_PRIVATE(QQmlDelegateModelGroup)
};
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 0028849828..7f10bbf370 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -276,7 +276,7 @@ public:
void requestMoreIfNecessary();
QObject *object(Compositor::Group group, int index, QQmlIncubator::IncubationMode incubationMode);
QQmlDelegateModel::ReleaseFlags release(QObject *object);
- QString stringValue(Compositor::Group group, int index, const QString &name);
+ QVariant variantValue(Compositor::Group group, int index, const QString &name);
void emitCreatedPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
void emitInitPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
void emitCreatedItem(QQDMIncubationTask *incubationTask, QObject *item) {
@@ -378,7 +378,7 @@ public:
bool isValid() const override;
QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
ReleaseFlags release(QObject *item) override;
- QString stringValue(int index, const QString &role) override;
+ QVariant variantValue(int index, const QString &role) override;
QList<QByteArray> watchedRoles() const { return m_watchedRoles; }
void setWatchedRoles(const QList<QByteArray> &roles) override;
QQmlIncubator::Status incubationStatus(int index) override;
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 565e60b3c1..5b5bcd8464 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -2545,7 +2545,7 @@ void QQmlListModel::append(QQmlV4Function *args)
\sa append()
*/
-QQmlV4Handle QQmlListModel::get(int index) const
+QJSValue QQmlListModel::get(int index) const
{
QV4::Scope scope(engine());
QV4::ScopedValue result(scope, QV4::Value::undefinedValue());
@@ -2568,7 +2568,7 @@ QQmlV4Handle QQmlListModel::get(int index) const
}
}
- return QQmlV4Handle(result);
+ return QJSValue(engine(), result->asReturnedValue());
}
/*!
@@ -2587,10 +2587,10 @@ QQmlV4Handle QQmlListModel::get(int index) const
\sa append()
*/
-void QQmlListModel::set(int index, const QQmlV4Handle &handle)
+void QQmlListModel::set(int index, const QJSValue &value)
{
QV4::Scope scope(engine());
- QV4::ScopedObject object(scope, handle);
+ QV4::ScopedObject object(scope, QJSValuePrivate::getValue(&value));
if (!object) {
qmlWarning(this) << tr("set: value is not an object");
diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h
index 95b797c898..471e33aa5a 100644
--- a/src/qml/types/qqmllistmodel_p.h
+++ b/src/qml/types/qqmllistmodel_p.h
@@ -100,8 +100,8 @@ public:
Q_INVOKABLE void remove(QQmlV4Function *args);
Q_INVOKABLE void append(QQmlV4Function *args);
Q_INVOKABLE void insert(QQmlV4Function *args);
- Q_INVOKABLE QQmlV4Handle get(int index) const;
- Q_INVOKABLE void set(int index, const QQmlV4Handle &);
+ Q_INVOKABLE QJSValue get(int index) const;
+ Q_INVOKABLE void set(int index, const QJSValue &value);
Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
Q_INVOKABLE void move(int from, int to, int count);
Q_INVOKABLE void sync();
diff --git a/src/qml/types/qqmllistmodelworkeragent.cpp b/src/qml/types/qqmllistmodelworkeragent.cpp
index fe3eaa3198..f7cb08dcf4 100644
--- a/src/qml/types/qqmllistmodelworkeragent.cpp
+++ b/src/qml/types/qqmllistmodelworkeragent.cpp
@@ -114,12 +114,12 @@ void QQmlListModelWorkerAgent::insert(QQmlV4Function *args)
m_copy->insert(args);
}
-QQmlV4Handle QQmlListModelWorkerAgent::get(int index) const
+QJSValue QQmlListModelWorkerAgent::get(int index) const
{
return m_copy->get(index);
}
-void QQmlListModelWorkerAgent::set(int index, const QQmlV4Handle &value)
+void QQmlListModelWorkerAgent::set(int index, const QJSValue &value)
{
m_copy->set(index, value);
}
diff --git a/src/qml/types/qqmllistmodelworkeragent_p.h b/src/qml/types/qqmllistmodelworkeragent_p.h
index ae2d4b11e0..69d1785618 100644
--- a/src/qml/types/qqmllistmodelworkeragent_p.h
+++ b/src/qml/types/qqmllistmodelworkeragent_p.h
@@ -85,8 +85,8 @@ public:
Q_INVOKABLE void remove(QQmlV4Function *args);
Q_INVOKABLE void append(QQmlV4Function *args);
Q_INVOKABLE void insert(QQmlV4Function *args);
- Q_INVOKABLE QQmlV4Handle get(int index) const;
- Q_INVOKABLE void set(int index, const QQmlV4Handle &);
+ Q_INVOKABLE QJSValue get(int index) const;
+ Q_INVOKABLE void set(int index, const QJSValue &value);
Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
Q_INVOKABLE void move(int from, int to, int count);
Q_INVOKABLE void sync();
diff --git a/src/qml/types/qqmlmodelsmodule.cpp b/src/qml/types/qqmlmodelsmodule.cpp
index bb72771cd9..840b435d18 100644
--- a/src/qml/types/qqmlmodelsmodule.cpp
+++ b/src/qml/types/qqmlmodelsmodule.cpp
@@ -47,9 +47,44 @@
#include <private/qqmldelegatecomponent_p.h>
#endif
#include <private/qqmlobjectmodel_p.h>
+#include <private/qqmltablemodel_p.h>
+#include <private/qqmltablemodelcolumn_p.h>
+#include <private/qqmlinstantiator_p.h>
+#include <private/qquickpackage_p.h>
QT_BEGIN_NAMESPACE
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+
+void QQmlModelsModule::registerQmlTypes()
+{
+ // Don't add anything here. These are only for backwards compatibility.
+ qmlRegisterType<QQmlInstantiator>("QtQml", 2, 1, "Instantiator"); // Only available in >= 2.1
+ qmlRegisterType<QQmlInstanceModel>();
+}
+
+void QQmlModelsModule::registerQuickTypes()
+{
+ // Don't add anything here. These are only for backwards compatibility.
+
+ const char uri[] = "QtQuick";
+
+ qmlRegisterType<QQmlInstantiator>(uri, 2, 1, "Instantiator");
+ qmlRegisterType<QQmlInstanceModel>();
+#if QT_CONFIG(qml_list_model)
+ qmlRegisterType<QQmlListElement>(uri, 2, 0, "ListElement");
+ qmlRegisterCustomType<QQmlListModel>(uri, 2, 0, "ListModel", new QQmlListModelParser);
+#endif
+ qmlRegisterType<QQuickPackage>(uri, 2, 0, "Package");
+#if QT_CONFIG(qml_delegate_model)
+ qmlRegisterType<QQmlDelegateModel>(uri, 2, 0, "VisualDataModel");
+ qmlRegisterType<QQmlDelegateModelGroup>(uri, 2, 0, "VisualDataGroup");
+#endif
+ qmlRegisterType<QQmlObjectModel>(uri, 2, 0, "VisualItemModel");
+}
+
+#endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+
void QQmlModelsModule::defineModule()
{
const char uri[] = "QtQml.Models";
@@ -66,6 +101,10 @@ void QQmlModelsModule::defineModule()
qmlRegisterType<QQmlObjectModel,3>(uri, 2, 3, "ObjectModel");
qmlRegisterType<QItemSelectionModel>(uri, 2, 2, "ItemSelectionModel");
+
+ qmlRegisterType<QQuickPackage>(uri, 2, 14, "Package");
+ qmlRegisterType<QQmlInstantiator>(uri, 2, 14, "Instantiator");
+ qmlRegisterType<QQmlInstanceModel>();
}
void QQmlModelsModule::defineLabsModule()
@@ -77,6 +116,8 @@ void QQmlModelsModule::defineLabsModule()
qmlRegisterType<QQmlDelegateChooser>(uri, 1, 0, "DelegateChooser");
qmlRegisterType<QQmlDelegateChoice>(uri, 1, 0, "DelegateChoice");
#endif
+ qmlRegisterType<QQmlTableModel>(uri, 1, 0, "TableModel");
+ qmlRegisterType<QQmlTableModelColumn>(uri, 1, 0, "TableModelColumn");
}
QT_END_NAMESPACE
diff --git a/src/qml/types/qqmlmodelsmodule_p.h b/src/qml/types/qqmlmodelsmodule_p.h
index 939ecc1500..2bb04f1e11 100644
--- a/src/qml/types/qqmlmodelsmodule_p.h
+++ b/src/qml/types/qqmlmodelsmodule_p.h
@@ -58,6 +58,11 @@ QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QQmlModelsModule
{
public:
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ static void registerQmlTypes();
+ static void registerQuickTypes();
+#endif
+
static void defineModule();
static void defineLabsModule();
};
diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp
index 2f4d427430..b6330b4295 100644
--- a/src/qml/types/qqmlobjectmodel.cpp
+++ b/src/qml/types/qqmlobjectmodel.cpp
@@ -273,12 +273,12 @@ QQmlInstanceModel::ReleaseFlags QQmlObjectModel::release(QObject *item)
return nullptr;
}
-QString QQmlObjectModel::stringValue(int index, const QString &name)
+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(name).toString();
+ return QQmlEngine::contextForObject(d->children.at(index).item)->contextProperty(role);
}
QQmlIncubator::Status QQmlObjectModel::incubationStatus(int)
diff --git a/src/qml/types/qqmlobjectmodel_p.h b/src/qml/types/qqmlobjectmodel_p.h
index 4ac4f1c65b..1284ba1780 100644
--- a/src/qml/types/qqmlobjectmodel_p.h
+++ b/src/qml/types/qqmlobjectmodel_p.h
@@ -79,7 +79,8 @@ public:
virtual QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) = 0;
virtual ReleaseFlags release(QObject *object) = 0;
virtual void cancel(int) {}
- virtual QString stringValue(int, const QString &) = 0;
+ 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;
@@ -119,7 +120,7 @@ public:
bool isValid() const override;
QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
ReleaseFlags release(QObject *object) override;
- QString stringValue(int index, const QString &role) override;
+ QVariant variantValue(int index, const QString &role) override;
void setWatchedRoles(const QList<QByteArray> &) override {}
QQmlIncubator::Status incubationStatus(int index) override;
diff --git a/src/qml/types/qqmltableinstancemodel_p.h b/src/qml/types/qqmltableinstancemodel_p.h
index 3dd5c4e4ce..39ec66d136 100644
--- a/src/qml/types/qqmltableinstancemodel_p.h
+++ b/src/qml/types/qqmltableinstancemodel_p.h
@@ -122,7 +122,7 @@ public:
QQmlIncubator::Status incubationStatus(int index) override;
- QString stringValue(int, const QString &) override { Q_UNREACHABLE(); return QString(); }
+ QVariant variantValue(int, const QString &) override { Q_UNREACHABLE(); return QVariant(); }
void setWatchedRoles(const QList<QByteArray> &) override { Q_UNREACHABLE(); }
int indexOf(QObject *, QObject *) const override { Q_UNREACHABLE(); return 0; }
diff --git a/src/qml/types/qqmltablemodel.cpp b/src/qml/types/qqmltablemodel.cpp
new file mode 100644
index 0000000000..4a96e7a46b
--- /dev/null
+++ b/src/qml/types/qqmltablemodel.cpp
@@ -0,0 +1,1059 @@
+/****************************************************************************
+**
+** 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) {
+ 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;
+ }
+ }
+ }
+
+ 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/qml/types/qqmltablemodel_p.h b/src/qml/types/qqmltablemodel_p.h
new file mode 100644
index 0000000000..a1bb97e7d4
--- /dev/null
+++ b/src/qml/types/qqmltablemodel_p.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** 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 <QtQml/private/qtqmlglobal_p.h>
+#include <QtQml/private/qqmltablemodelcolumn_p.h>
+#include <QtQml/QJSValue>
+#include <QtQml/QQmlListProperty>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_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/qml/types/qqmltablemodelcolumn.cpp b/src/qml/types/qqmltablemodelcolumn.cpp
new file mode 100644
index 0000000000..93da0642de
--- /dev/null
+++ b/src/qml/types/qqmltablemodelcolumn.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** 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/qml/types/qqmltablemodelcolumn_p.h b/src/qml/types/qqmltablemodelcolumn_p.h
new file mode 100644
index 0000000000..41c02482c0
--- /dev/null
+++ b/src/qml/types/qqmltablemodelcolumn_p.h
@@ -0,0 +1,224 @@
+/****************************************************************************
+**
+** 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 <QtQml/private/qtqmlglobal_p.h>
+#include <QtQml/qjsvalue.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_AUTOTEST_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/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index edb112276c..c081c9e7fc 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -39,10 +39,6 @@
#include "qtqmlglobal_p.h"
#include "qquickworkerscript_p.h"
-#if QT_CONFIG(qml_list_model)
-#include "qqmllistmodel_p.h"
-#include "qqmllistmodelworkeragent_p.h"
-#endif
#include <private/qqmlengine_p.h>
#include <private/qqmlexpression_p.h>
@@ -651,12 +647,10 @@ void QQuickWorkerScript::componentComplete()
bool QQuickWorkerScript::event(QEvent *event)
{
if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
- QQmlEngine *engine = qmlEngine(this);
- if (engine) {
+ if (QQmlEngine *engine = qmlEngine(this)) {
+ QV4::ExecutionEngine *v4 = engine->handle();
WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
- QV4::Scope scope(engine->handle());
- QV4::ScopedValue value(scope, QV4::Serialize::deserialize(workerEvent->data(), scope.engine));
- emit message(QQmlV4Handle(value));
+ emit message(QJSValue(v4, QV4::Serialize::deserialize(workerEvent->data(), v4)));
}
return true;
} else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
diff --git a/src/qml/types/qquickworkerscript_p.h b/src/qml/types/qquickworkerscript_p.h
index 1a8d2ab076..87cf2e9754 100644
--- a/src/qml/types/qquickworkerscript_p.h
+++ b/src/qml/types/qquickworkerscript_p.h
@@ -83,7 +83,6 @@ private:
};
class QQmlV4Function;
-class QQmlV4Handle;
class Q_AUTOTEST_EXPORT QQuickWorkerScript : public QObject, public QQmlParserStatus
{
Q_OBJECT
@@ -102,7 +101,7 @@ public Q_SLOTS:
Q_SIGNALS:
void sourceChanged();
- void message(const QQmlV4Handle &messageObject);
+ void message(const QJSValue &messageObject);
protected:
void classBegin() override;
diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri
index e74c89b1f1..5a56208dc4 100644
--- a/src/qml/types/types.pri
+++ b/src/qml/types/types.pri
@@ -6,7 +6,9 @@ SOURCES += \
$$PWD/qqmlobjectmodel.cpp \
$$PWD/qquickpackage.cpp \
$$PWD/qqmlinstantiator.cpp \
- $$PWD/qqmltableinstancemodel.cpp
+ $$PWD/qqmltableinstancemodel.cpp \
+ $$PWD/qqmltablemodel.cpp \
+ $$PWD/qqmltablemodelcolumn.cpp
HEADERS += \
$$PWD/qqmlbind_p.h \
@@ -17,7 +19,9 @@ HEADERS += \
$$PWD/qquickpackage_p.h \
$$PWD/qqmlinstantiator_p.h \
$$PWD/qqmlinstantiator_p_p.h \
- $$PWD/qqmltableinstancemodel_p.h
+ $$PWD/qqmltableinstancemodel_p.h \
+ $$PWD/qqmltablemodel_p.h \
+ $$PWD/qqmltablemodelcolumn_p.h
qtConfig(qml-worker-script) {
SOURCES += \