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