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#ifndef QQMLDMABSTRACTITEMMODELDATA_P_H
5#define QQMLDMABSTRACTITEMMODELDATA_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <private/qqmladaptormodelenginedata_p.h>
19#include <private/qqmldelegatemodel_p_p.h>
20#include <private/qobject_p.h>
21
22QT_BEGIN_NAMESPACE
23
24class VDMAbstractItemModelDataType;
25class QQmlDMAbstractItemModelData : public QQmlDelegateModelItem
26{
27 Q_OBJECT
28 Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT)
29 Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
30 QT_ANONYMOUS_PROPERTY(QVariant READ modelData NOTIFY modelDataChanged FINAL)
31
32public:
33 QQmlDMAbstractItemModelData(
34 const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
35 VDMAbstractItemModelDataType *dataType,
36 int index, int row, int column);
37
38 int metaCall(QMetaObject::Call call, int id, void **arguments);
39 bool hasModelChildren() const;
40
41 QV4::ReturnedValue get() override;
42 void setValue(const QString &role, const QVariant &value) override;
43 bool resolveIndex(const QQmlAdaptorModel &model, int idx) override;
44
45 static QV4::ReturnedValue get_property(
46 const QV4::FunctionObject *b, const QV4::Value *thisObject,
47 const QV4::Value *argv, int argc);
48 static QV4::ReturnedValue set_property(
49 const QV4::FunctionObject *b, const QV4::Value *thisObject,
50 const QV4::Value *argv, int argc);
51
52 static QV4::ReturnedValue get_modelData(
53 const QV4::FunctionObject *b, const QV4::Value *thisObject,
54 const QV4::Value *argv, int argc);
55 static QV4::ReturnedValue set_modelData(
56 const QV4::FunctionObject *b, const QV4::Value *thisObject,
57 const QV4::Value *argv, int argc);
58
59 QVariant modelData() const;
60 void setModelData(const QVariant &modelData);
61
62 const VDMAbstractItemModelDataType *type() const { return m_type; }
63
64Q_SIGNALS:
65 void modelDataChanged();
66
67private:
68 QVariant value(int role) const;
69 void setValue(int role, const QVariant &value);
70
71 VDMAbstractItemModelDataType *m_type;
72 QVector<QVariant> m_cachedData;
73};
74
75class VDMAbstractItemModelDataType final
76 : public QQmlRefCounted<VDMAbstractItemModelDataType>
77 , public QQmlAdaptorModel::Accessors
78 , public QAbstractDynamicMetaObject
79{
80public:
81 VDMAbstractItemModelDataType(QQmlAdaptorModel *model)
82 : model(model)
83 , propertyOffset(0)
84 , signalOffset(0)
85 {
86 }
87
88 void notifyItem(const QQmlGuard<QQmlDMAbstractItemModelData> &item, const QVector<int> &signalIndexes) const
89 {
90 for (const int signalIndex : signalIndexes) {
91 QMetaObject::activate(sender: item, signal_index: signalIndex, argv: nullptr);
92 if (item.isNull())
93 return;
94 }
95 emit item->modelDataChanged();
96 }
97
98 bool notify(
99 const QQmlAdaptorModel &,
100 const QList<QQmlDelegateModelItem *> &items,
101 int index,
102 int count,
103 const QVector<int> &roles) const override
104 {
105 bool changed = roles.isEmpty() && !watchedRoles.isEmpty();
106 if (!changed && !watchedRoles.isEmpty() && watchedRoleIds.isEmpty()) {
107 QList<int> roleIds;
108 for (const QByteArray &r : watchedRoles) {
109 QHash<QByteArray, int>::const_iterator it = roleNames.find(key: r);
110 if (it != roleNames.end())
111 roleIds << it.value();
112 }
113 const_cast<VDMAbstractItemModelDataType *>(this)->watchedRoleIds = roleIds;
114 }
115
116 QVector<int> signalIndexes;
117 for (int i = 0; i < roles.size(); ++i) {
118 const int role = roles.at(i);
119 if (!changed && watchedRoleIds.contains(t: role))
120 changed = true;
121
122 int propertyId = propertyRoles.indexOf(t: role);
123 if (propertyId != -1)
124 signalIndexes.append(t: propertyId + signalOffset);
125 }
126 if (roles.isEmpty()) {
127 const int propertyRolesCount = propertyRoles.size();
128 signalIndexes.reserve(asize: propertyRolesCount);
129 for (int propertyId = 0; propertyId < propertyRolesCount; ++propertyId)
130 signalIndexes.append(t: propertyId + signalOffset);
131 }
132
133 QVarLengthArray<QQmlGuard<QQmlDMAbstractItemModelData>> guardedItems;
134 for (const auto item : items) {
135 Q_ASSERT(qobject_cast<QQmlDMAbstractItemModelData *>(item) == item);
136 guardedItems.append(t: static_cast<QQmlDMAbstractItemModelData *>(item));
137 }
138
139 for (const auto &item : std::as_const(t&: guardedItems)) {
140 if (item.isNull())
141 continue;
142
143 const int idx = item->modelIndex();
144 if (idx >= index && idx < index + count)
145 notifyItem(item, signalIndexes);
146 }
147 return changed;
148 }
149
150 void replaceWatchedRoles(
151 QQmlAdaptorModel &,
152 const QList<QByteArray> &oldRoles,
153 const QList<QByteArray> &newRoles) const override
154 {
155 VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
156
157 dataType->watchedRoleIds.clear();
158 for (const QByteArray &oldRole : oldRoles)
159 dataType->watchedRoles.removeOne(t: oldRole);
160 dataType->watchedRoles += newRoles;
161 }
162
163 static QV4::ReturnedValue get_hasModelChildren(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
164 {
165 QV4::Scope scope(b);
166 QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
167 if (!o)
168 RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object")));
169
170 const QQmlAdaptorModel *const model
171 = static_cast<QQmlDMAbstractItemModelData *>(o->d()->item)->type()->model;
172 if (o->d()->item->index >= 0) {
173 if (const QAbstractItemModel *const aim = model->aim())
174 RETURN_RESULT(QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex))));
175 }
176 RETURN_RESULT(QV4::Encode(false));
177 }
178
179
180 void initializeConstructor(QQmlAdaptorModelEngineData *const data)
181 {
182 QV4::ExecutionEngine *v4 = data->v4;
183 QV4::Scope scope(v4);
184 QV4::ScopedObject proto(scope, v4->newObject());
185 proto->defineAccessorProperty(QStringLiteral("index"), getter: QQmlAdaptorModelEngineData::get_index, setter: nullptr);
186 proto->defineAccessorProperty(QStringLiteral("hasModelChildren"), getter: get_hasModelChildren, setter: nullptr);
187 proto->defineAccessorProperty(QStringLiteral("modelData"),
188 getter: QQmlDMAbstractItemModelData::get_modelData,
189 setter: QQmlDMAbstractItemModelData::set_modelData);
190 QV4::ScopedProperty p(scope);
191
192 typedef QHash<QByteArray, int>::const_iterator iterator;
193 for (iterator it = roleNames.constBegin(), end = roleNames.constEnd(); it != end; ++it) {
194 const qsizetype propertyId = propertyRoles.indexOf(t: it.value());
195 const QByteArray &propertyName = it.key();
196
197 QV4::ScopedString name(scope, v4->newString(s: QString::fromUtf8(ba: propertyName)));
198 QV4::ScopedFunctionObject g(
199 scope,
200 v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(
201 args&: v4, args: propertyId, args&: QQmlDMAbstractItemModelData::get_property));
202 QV4::ScopedFunctionObject s(
203 scope,
204 v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(
205 args&: v4, args: propertyId, args&: QQmlDMAbstractItemModelData::set_property));
206 p->setGetter(g);
207 p->setSetter(s);
208 proto->insertMember(s: name, p, attributes: QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
209 }
210 prototype.set(engine: v4, value: proto);
211 }
212
213 // QAbstractDynamicMetaObject
214
215 void objectDestroyed(QObject *) override
216 {
217 release();
218 }
219
220 int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) override
221 {
222 return static_cast<QQmlDMAbstractItemModelData *>(object)->metaCall(call, id, arguments);
223 }
224
225 int rowCount(const QQmlAdaptorModel &model) const override
226 {
227 if (const QAbstractItemModel *aim = model.aim())
228 return aim->rowCount(parent: model.rootIndex);
229 return 0;
230 }
231
232 int columnCount(const QQmlAdaptorModel &model) const override
233 {
234 if (const QAbstractItemModel *aim = model.aim())
235 return aim->columnCount(parent: model.rootIndex);
236 return 0;
237 }
238
239 void cleanup(QQmlAdaptorModel &) const override
240 {
241 release();
242 }
243
244 QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
245 {
246 if (!metaObject) {
247 VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
248 dataType->initializeMetaType(model);
249 }
250
251 if (const QAbstractItemModel *aim = model.aim()) {
252 const QModelIndex modelIndex
253 = aim->index(row: model.rowAt(index), column: model.columnAt(index), parent: model.rootIndex);
254
255 const auto it = roleNames.find(key: role.toUtf8()), end = roleNames.end();
256 if (it != roleNames.end())
257 return modelIndex.data(arole: *it);
258
259 if (role.isEmpty() || role == QLatin1String("modelData")) {
260 if (roleNames.size() == 1)
261 return modelIndex.data(arole: roleNames.begin().value());
262
263 QVariantMap modelData;
264 for (auto jt = roleNames.begin(); jt != end; ++jt)
265 modelData.insert(key: QString::fromUtf8(ba: jt.key()), value: modelIndex.data(arole: jt.value()));
266 return modelData;
267 }
268
269 if (role == QLatin1String("hasModelChildren"))
270 return QVariant(aim->hasChildren(parent: modelIndex));
271 }
272 return QVariant();
273 }
274
275 QVariant parentModelIndex(const QQmlAdaptorModel &model) const override
276 {
277 if (const QAbstractItemModel *aim = model.aim())
278 return QVariant::fromValue(value: aim->parent(child: model.rootIndex));
279 return QVariant();
280 }
281
282 QVariant modelIndex(const QQmlAdaptorModel &model, int index) const override
283 {
284 if (const QAbstractItemModel *aim = model.aim())
285 return QVariant::fromValue(value: aim->index(row: model.rowAt(index), column: model.columnAt(index),
286 parent: model.rootIndex));
287 return QVariant();
288 }
289
290 bool canFetchMore(const QQmlAdaptorModel &model) const override
291 {
292 if (const QAbstractItemModel *aim = model.aim())
293 return aim->canFetchMore(parent: model.rootIndex);
294 return false;
295 }
296
297 void fetchMore(QQmlAdaptorModel &model) const override
298 {
299 if (QAbstractItemModel *aim = model.aim())
300 aim->fetchMore(parent: model.rootIndex);
301 }
302
303 QQmlDelegateModelItem *createItem(
304 QQmlAdaptorModel &model,
305 const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
306 int index, int row, int column) override
307 {
308 if (!metaObject)
309 initializeMetaType(model);
310 return new QQmlDMAbstractItemModelData(metaType, this, index, row, column);
311 }
312
313 void initializeMetaType(const QQmlAdaptorModel &model)
314 {
315 QMetaObjectBuilder builder;
316 QQmlAdaptorModelEngineData::setModelDataType<QQmlDMAbstractItemModelData>(builder: &builder, metaType: this);
317
318 const QByteArray propertyType = QByteArrayLiteral("QVariant");
319 const QAbstractItemModel *aim = model.aim();
320 const QHash<int, QByteArray> names = aim ? aim->roleNames() : QHash<int, QByteArray>();
321 for (QHash<int, QByteArray>::const_iterator it = names.begin(), cend = names.end(); it != cend; ++it) {
322 const int propertyId = propertyRoles.size();
323 propertyRoles.append(t: it.key());
324 roleNames.insert(key: it.value(), value: it.key());
325 QQmlAdaptorModelEngineData::addProperty(builder: &builder, propertyId, propertyName: it.value(), propertyType);
326 }
327
328 metaObject.reset(other: builder.toMetaObject());
329 *static_cast<QMetaObject *>(this) = *metaObject;
330 propertyCache = QQmlPropertyCache::createStandalone(
331 metaObject.data(), metaObjectRevision: model.modelItemRevision);
332 }
333
334 QV4::PersistentValue prototype;
335 QList<int> propertyRoles;
336 QList<int> watchedRoleIds;
337 QList<QByteArray> watchedRoles;
338 QHash<QByteArray, int> roleNames;
339 QQmlAdaptorModel *model;
340 int propertyOffset;
341 int signalOffset;
342};
343
344QT_END_NAMESPACE
345
346#endif // QQMLDMABSTRACTITEMMODELDATA_P_H
347

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/qmlmodels/qqmldmabstractitemmodeldata_p.h