aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquicktableview.cpp37
-rw-r--r--src/quick/items/qquicktableview_p.h8
-rw-r--r--src/quick/items/qquicktableview_p_p.h4
-rw-r--r--tests/auto/quick/qquicktableview/data/delegateModelAccess.qml92
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp120
5 files changed, 260 insertions, 1 deletions
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 3e83cb1d09..d9ac4328fd 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -4508,6 +4508,7 @@ void QQuickTableViewPrivate::syncWithPendingChanges()
syncViewportRect();
syncModel();
syncDelegate();
+ syncDelegateModelAccess();
syncSyncView();
syncPositionView();
@@ -4556,6 +4557,18 @@ void QQuickTableViewPrivate::syncDelegate()
tableModel->setDelegate(assignedDelegate);
}
+void QQuickTableViewPrivate::syncDelegateModelAccess()
+{
+ if (!tableModel) {
+ // Only the tableModel uses the delegateModelAccess assigned to a
+ // TableView. DelegateModel has its own delegateModelAccess, and
+ // ObjectModel doesn't use one.
+ return;
+ }
+
+ tableModel->setDelegateModelAccess(assignedDelegateModelAccess);
+}
+
QVariant QQuickTableViewPrivate::modelImpl() const
{
return assignedModel;
@@ -5808,6 +5821,30 @@ void QQuickTableView::setEditTriggers(QQuickTableView::EditTriggers editTriggers
emit editTriggersChanged();
}
+/*!
+ \qmlproperty enumeration QtQuick::TableView::delegateModelAccess
+
+ \include delegatemodelaccess.qdocinc
+*/
+QQmlDelegateModel::DelegateModelAccess QQuickTableView::delegateModelAccess() const
+{
+ Q_D(const QQuickTableView);
+ return d->assignedDelegateModelAccess;
+}
+
+void QQuickTableView::setDelegateModelAccess(
+ QQmlDelegateModel::DelegateModelAccess delegateModelAccess)
+{
+ Q_D(QQuickTableView);
+ if (delegateModelAccess == d->assignedDelegateModelAccess)
+ return;
+
+ d->assignedDelegateModelAccess = delegateModelAccess;
+ d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::All);
+
+ emit delegateModelAccessChanged();
+}
+
bool QQuickTableView::reuseItems() const
{
return bool(d_func()->reusableFlag == QQmlTableInstanceModel::Reusable);
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
index cfcc9eae8a..d437f29724 100644
--- a/src/quick/items/qquicktableview_p.h
+++ b/src/quick/items/qquicktableview_p.h
@@ -27,6 +27,7 @@ QT_REQUIRE_CONFIG(quick_tableview);
#include <QtQml/private/qqmlnullablevalue_p.h>
#include <QtQml/private/qqmlfinalizer_p.h>
#include <QtQml/private/qqmlguard_p.h>
+#include <QtQmlModels/private/qqmldelegatemodel_p.h>
QT_BEGIN_NAMESPACE
@@ -68,6 +69,8 @@ class Q_QUICK_EXPORT QQuickTableView : public QQuickFlickable, public QQmlFinali
Q_PROPERTY(bool resizableRows READ resizableRows WRITE setResizableRows NOTIFY resizableRowsChanged REVISION(6, 5) FINAL)
Q_PROPERTY(EditTriggers editTriggers READ editTriggers WRITE setEditTriggers NOTIFY editTriggersChanged REVISION(6, 5) FINAL)
Q_PROPERTY(SelectionMode selectionMode READ selectionMode WRITE setSelectionMode NOTIFY selectionModeChanged REVISION(6, 6) FINAL)
+ Q_PROPERTY(QQmlDelegateModel::DelegateModelAccess delegateModelAccess READ delegateModelAccess
+ WRITE setDelegateModelAccess NOTIFY delegateModelAccessChanged REVISION(6, 10) FINAL)
QML_NAMED_ELEMENT(TableView)
QML_ADDED_IN_VERSION(2, 12)
@@ -185,6 +188,9 @@ public:
EditTriggers editTriggers() const;
void setEditTriggers(EditTriggers editTriggers);
+ QQmlDelegateModel::DelegateModelAccess delegateModelAccess() const;
+ void setDelegateModelAccess(QQmlDelegateModel::DelegateModelAccess delegateModelAccess);
+
Q_INVOKABLE void forceLayout();
Q_INVOKABLE void positionViewAtCell(const QPoint &cell, PositionMode mode, const QPointF &offset = QPointF(), const QRectF &subRect = QRectF());
Q_INVOKABLE void positionViewAtIndex(const QModelIndex &index, PositionMode mode, const QPointF &offset = QPointF(), const QRectF &subRect = QRectF());
@@ -274,7 +280,7 @@ Q_SIGNALS:
Q_REVISION(6, 6) void selectionModeChanged();
Q_REVISION(6, 8) void rowMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
Q_REVISION(6, 8) void columnMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
-
+ Q_REVISION(6, 10) void delegateModelAccessChanged();
protected:
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index c25772eaef..ee25d2cc44 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -393,6 +393,9 @@ public:
bool warnNoSelectionModel = true;
+ QQmlDelegateModel::DelegateModelAccess assignedDelegateModelAccess
+ = QQmlDelegateModel::Qt5ReadWrite;
+
QJSValue rowHeightProvider;
QJSValue columnWidthProvider;
@@ -594,6 +597,7 @@ public:
virtual void syncWithPendingChanges();
virtual void syncDelegate();
+ virtual void syncDelegateModelAccess();
virtual QVariant modelImpl() const;
virtual void setModelImpl(const QVariant &newModel);
virtual void syncModel();
diff --git a/tests/auto/quick/qquicktableview/data/delegateModelAccess.qml b/tests/auto/quick/qquicktableview/data/delegateModelAccess.qml
new file mode 100644
index 0000000000..21e67bb5d3
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/delegateModelAccess.qml
@@ -0,0 +1,92 @@
+import QtQuick
+import Test
+
+Item {
+ width: 100
+ height: 100
+
+ property alias tableView: root
+
+ TableView {
+ id: root
+ width: 100
+ height: 100
+
+ property Component typedDelegate: Item {
+ implicitWidth: 10
+ implicitHeight: 10
+
+ required property QtObject model
+
+ required property real a
+
+ property real immediateX: a
+ property real modelX: model.a
+
+ function writeImmediate() {
+ a = 1;
+ }
+
+ function writeThroughModel() {
+ model.a = 3;
+ }
+ }
+
+ property Component untypedDelegate: Item {
+ implicitWidth: 10
+ implicitHeight: 10
+
+ property real immediateX: a
+ property real modelX: model.a
+
+ function writeImmediate() {
+ a = 1;
+ }
+
+ function writeThroughModel() {
+ model.a = 3;
+ }
+ }
+
+ property ListModel singularModel: ListModel {
+ ListElement {
+ a: 11
+ }
+ }
+
+ property ListModel listModel: ListModel {
+ ListElement {
+ a: 11
+ y: 12
+ }
+ }
+
+ property var array: [ {a: 11, y: 12} ]
+
+ property QtObject object: QtObject {
+ property int a: 11
+ property int y: 12
+ }
+
+ property int modelIndex: Model.None
+ property int delegateIndex: Delegate.None
+
+ model: {
+ switch (modelIndex) {
+ case Model.Singular: return singularModel
+ case Model.List: return listModel
+ case Model.Array: return array
+ case Model.Object: return object
+ }
+ return undefined;
+ }
+
+ delegate: {
+ switch (delegateIndex) {
+ case Delegate.Untyped: return untypedDelegate
+ case Delegate.Typed: return typedDelegate
+ }
+ return null
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 59a8e76a80..190181c523 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -304,6 +304,9 @@ private slots:
void typedModelData();
void requiredModelData();
+ void delegateModelAccess_data();
+ void delegateModelAccess();
+
// Row and column reordering
void checkVisualRowColumnAfterReorder();
void checkColumnRowSizeAfterReorder();
@@ -8192,6 +8195,123 @@ void tst_QQuickTableView::requiredModelData()
}
}
+namespace Model {
+Q_NAMESPACE
+QML_ELEMENT
+enum Kind : qint8
+{
+ None = -1,
+ Singular,
+ List,
+ Array,
+ Object
+};
+Q_ENUM_NS(Kind)
+}
+
+namespace Delegate {
+Q_NAMESPACE
+QML_ELEMENT
+enum Kind : qint8
+{
+ None = -1,
+ Untyped,
+ Typed
+};
+Q_ENUM_NS(Kind)
+}
+
+template<typename Enum>
+const char *enumKey(Enum value) {
+ const QMetaObject *mo = qt_getEnumMetaObject(value);
+ const QMetaEnum metaEnum = mo->enumerator(mo->indexOfEnumerator(qt_getEnumName(value)));
+ return metaEnum.valueToKey(value);
+}
+
+void tst_QQuickTableView::delegateModelAccess_data()
+{
+ QTest::addColumn<QQmlDelegateModel::DelegateModelAccess>("access");
+ QTest::addColumn<Model::Kind>("modelKind");
+ QTest::addColumn<Delegate::Kind>("delegateKind");
+
+ using Access = QQmlDelegateModel::DelegateModelAccess;
+ for (auto access : { Access::Qt5ReadWrite, Access::ReadOnly, Access::ReadWrite }) {
+ for (auto model : { Model::Singular, Model::List, Model::Array, Model::Object }) {
+ for (auto delegate : { Delegate::Untyped, Delegate::Typed }) {
+ QTest::addRow("%s-%s-%s", enumKey(access), enumKey(model), enumKey(delegate))
+ << access << model << delegate;
+ }
+ }
+ }
+}
+
+void tst_QQuickTableView::delegateModelAccess()
+{
+ static const bool initialized = []() {
+ qmlRegisterNamespaceAndRevisions(&Model::staticMetaObject, "Test", 1);
+ qmlRegisterNamespaceAndRevisions(&Delegate::staticMetaObject, "Test", 1);
+ return true;
+ }();
+ QVERIFY(initialized);
+
+ QFETCH(QQmlDelegateModel::DelegateModelAccess, access);
+ QFETCH(Model::Kind, modelKind);
+ QFETCH(Delegate::Kind, delegateKind);
+
+ const QUrl url = testFileUrl("delegateModelAccess.qml");
+ LOAD_TABLEVIEW("delegateModelAccess.qml");
+
+ if (delegateKind == Delegate::Untyped && modelKind == Model::Array)
+ QSKIP("Properties of objects in arrays are not exposed as context properties");
+
+ if (access == QQmlDelegateModel::ReadOnly) {
+ const QRegularExpression message(
+ url.toString() + ":[0-9]+: TypeError: Cannot assign to read-only property \"a\"");
+
+ QTest::ignoreMessage(QtWarningMsg, message);
+ if (delegateKind == Delegate::Untyped)
+ QTest::ignoreMessage(QtWarningMsg, message);
+ }
+
+ tableView->setProperty("delegateModelAccess", access);
+ tableView->setProperty("modelIndex", modelKind);
+ tableView->setProperty("delegateIndex", delegateKind);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(QQuickTableViewPrivate::get(tableView)->loadedItems.size(), 1);
+ QObject *delegate = QQuickTableViewPrivate::get(tableView)->loadedItems.begin().value()->item;
+ QVERIFY(delegate);
+
+ const bool modelWritable = access != QQmlDelegateModel::ReadOnly;
+ const bool immediateWritable = (delegateKind == Delegate::Untyped)
+ ? access != QQmlDelegateModel::ReadOnly
+ : access == QQmlDelegateModel::ReadWrite;
+
+ double expected = 11;
+
+ QCOMPARE(delegate->property("immediateX").toDouble(), expected);
+ QCOMPARE(delegate->property("modelX").toDouble(), expected);
+
+ if (modelWritable)
+ expected = 3;
+
+ QMetaObject::invokeMethod(delegate, "writeThroughModel");
+ QCOMPARE(delegate->property("immediateX").toDouble(), expected);
+ QCOMPARE(delegate->property("modelX").toDouble(), expected);
+
+ if (immediateWritable)
+ expected = 1;
+
+ QMetaObject::invokeMethod(delegate, "writeImmediate");
+
+ // Writes to required properties always succeed, but might not be propagated to the model
+ QCOMPARE(delegate->property("immediateX").toDouble(),
+ delegateKind == Delegate::Untyped ? expected : 1);
+
+ QCOMPARE(delegate->property("modelX").toDouble(), expected);
+}
+
void tst_QQuickTableView::checkVisualRowColumnAfterReorder()
{
LOAD_TABLEVIEW("reordertableview.qml"); // gives us 'tableView' variable