1 | // Copyright (C) 2023 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include <private/qqmldmlistaccessordata_p.h> |
5 | |
6 | QT_BEGIN_NAMESPACE |
7 | |
8 | QQmlDMListAccessorData::QQmlDMListAccessorData( |
9 | const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType, |
10 | VDMListDelegateDataType *dataType, |
11 | int index, int row, int column, const QVariant &value) |
12 | : QQmlDelegateModelItem(metaType, dataType, index, row, column) |
13 | , cachedData(value) |
14 | { |
15 | QObjectPrivate::get(o: this)->metaObject = dataType; |
16 | dataType->addref(); |
17 | } |
18 | |
19 | void QQmlDMListAccessorData::setModelData(const QVariant &data) { |
20 | if (data == cachedData) |
21 | return; |
22 | |
23 | cachedData = data; |
24 | static_cast<const VDMListDelegateDataType *>(QObjectPrivate::get(o: this)->metaObject) |
25 | ->emitAllSignals(accessor: this); |
26 | } |
27 | |
28 | void QQmlDMListAccessorData::setValue(const QString &role, const QVariant &value) |
29 | { |
30 | // Used only for initialization of the cached data. Does not have to emit change signals. |
31 | if (role == QLatin1String("modelData" ) || role.isEmpty()) |
32 | cachedData = value; |
33 | else |
34 | VDMListDelegateDataType::setValue(row: &cachedData, role, value); |
35 | } |
36 | |
37 | bool QQmlDMListAccessorData::resolveIndex(const QQmlAdaptorModel &model, int idx) |
38 | { |
39 | if (index == -1) { |
40 | index = idx; |
41 | setModelData(model.list.at(idx)); |
42 | emit modelIndexChanged(); |
43 | return true; |
44 | } else { |
45 | return false; |
46 | } |
47 | } |
48 | |
49 | void VDMListDelegateDataType::emitAllSignals(QQmlDMListAccessorData *accessor) const |
50 | { |
51 | for (int i = propertyOffset, end = propertyCount(); i != end; ++i) |
52 | QMetaObject::activate(sender: accessor, this, local_signal_index: i - propertyOffset, argv: nullptr); |
53 | emit accessor->modelDataChanged(); |
54 | } |
55 | |
56 | int VDMListDelegateDataType::metaCall( |
57 | QObject *object, QMetaObject::Call call, int id, void **arguments) |
58 | { |
59 | Q_ASSERT(qobject_cast<QQmlDMListAccessorData *>(object)); |
60 | QQmlDMListAccessorData *accessor = static_cast<QQmlDMListAccessorData *>(object); |
61 | |
62 | switch (call) { |
63 | case QMetaObject::ReadProperty: { |
64 | if (id < propertyOffset) |
65 | break; |
66 | |
67 | QVariant *result = static_cast<QVariant *>(arguments[0]); |
68 | const QByteArray name = property(index: id).name(); |
69 | const QVariant data = accessor->index == -1 |
70 | ? accessor->modelData() |
71 | : model->list.at(accessor->index); |
72 | *result = value(row: &data, role: name); |
73 | return -1; |
74 | } |
75 | case QMetaObject::WriteProperty: { |
76 | if (id < propertyOffset) |
77 | break; |
78 | |
79 | const QVariant &argument = *static_cast<QVariant *>(arguments[0]); |
80 | const QByteArray name = property(index: id).name(); |
81 | QVariant data = accessor->index == -1 |
82 | ? accessor->modelData() |
83 | : model->list.at(accessor->index); |
84 | if (argument == value(row: &data, role: name)) |
85 | return -1; |
86 | setValue(row: &data, role: name, value: argument); |
87 | if (accessor->index == -1) |
88 | accessor->cachedData = data; |
89 | else |
90 | model->list.set(accessor->index, data); |
91 | QMetaObject::activate(sender: accessor, this, local_signal_index: id - propertyOffset, argv: nullptr); |
92 | emit accessor->modelDataChanged(); |
93 | return -1; |
94 | } |
95 | default: |
96 | break; |
97 | } |
98 | |
99 | return accessor->qt_metacall(call, id, arguments); |
100 | } |
101 | |
102 | int VDMListDelegateDataType::createProperty(const char *name, const char *) |
103 | { |
104 | const int propertyIndex = propertyCount() - propertyOffset; |
105 | |
106 | // We use QVariant because the types may be different in the different objects. |
107 | QQmlAdaptorModelEngineData::addProperty( |
108 | builder: &builder, propertyId: propertyIndex, propertyName: name, QByteArrayLiteral("QVariant" )); |
109 | |
110 | metaObject.reset(other: builder.toMetaObject()); |
111 | *static_cast<QMetaObject *>(this) = *metaObject; |
112 | return propertyIndex + propertyOffset; |
113 | } |
114 | |
115 | QMetaObject *VDMListDelegateDataType::toDynamicMetaObject(QObject *object) |
116 | { |
117 | if (const QQmlRefPointer<QQmlContextData> &contextData |
118 | = static_cast<QQmlDMListAccessorData *>(object)->contextData) { |
119 | if (contextData->contextObject() == object) { |
120 | // We are using context properties. There should be a propertyCache so that row and |
121 | // column are hidden. We shall also return the static metaObject in that case. |
122 | |
123 | if (!propertyCache) { |
124 | propertyCache = QQmlPropertyCache::createStandalone( |
125 | &QQmlDMListAccessorData::staticMetaObject, metaObjectRevision: model->modelItemRevision); |
126 | if (QQmlData *ddata = QQmlData::get(object, create: true)) |
127 | ddata->propertyCache = propertyCache; |
128 | } |
129 | |
130 | // ### Qt 7: Return const from toDynamicMetaObject() and drop the const_cast. |
131 | return const_cast<QMetaObject *>(&QQmlDMListAccessorData::staticMetaObject); |
132 | } |
133 | } |
134 | |
135 | // If the context object is not the model object, we are using required properties. |
136 | // In that case, allow the creation of extra properties. |
137 | return this; |
138 | } |
139 | |
140 | QT_END_NAMESPACE |
141 | |