1// Copyright (C) 2020 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 QQMLLISTMODEL_P_P_H
5#define QQMLLISTMODEL_P_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 "qqmllistmodel_p.h"
19#include <private/qtqmlmodelsglobal_p.h>
20#include <private/qqmlengine_p.h>
21#include <private/qqmlopenmetaobject_p.h>
22#include <private/qv4qobjectwrapper_p.h>
23#include <qqml.h>
24
25QT_REQUIRE_CONFIG(qml_list_model);
26
27QT_BEGIN_NAMESPACE
28
29
30class DynamicRoleModelNode;
31
32class DynamicRoleModelNodeMetaObject : public QQmlOpenMetaObject
33{
34public:
35 DynamicRoleModelNodeMetaObject(DynamicRoleModelNode *object);
36 ~DynamicRoleModelNodeMetaObject();
37
38 bool m_enabled;
39
40protected:
41 void propertyWrite(int index) override;
42 void propertyWritten(int index) override;
43
44private:
45 DynamicRoleModelNode *m_owner;
46};
47
48class DynamicRoleModelNode : public QObject
49{
50 Q_OBJECT
51public:
52 DynamicRoleModelNode(QQmlListModel *owner, int uid);
53
54 static DynamicRoleModelNode *create(const QVariantMap &obj, QQmlListModel *owner);
55
56 void updateValues(const QVariantMap &object, QVector<int> &roles);
57
58 QVariant getValue(const QString &name) const
59 {
60 return m_meta->value(name.toUtf8());
61 }
62
63 bool setValue(const QByteArray &name, const QVariant &val)
64 {
65 return m_meta->setValue(name, val);
66 }
67
68 void setNodeUpdatesEnabled(bool enable)
69 {
70 m_meta->m_enabled = enable;
71 }
72
73 int getUid() const
74 {
75 return m_uid;
76 }
77
78 static QVector<int> sync(DynamicRoleModelNode *src, DynamicRoleModelNode *target);
79
80private:
81 QQmlListModel *m_owner;
82 int m_uid;
83 DynamicRoleModelNodeMetaObject *m_meta;
84
85 friend class DynamicRoleModelNodeMetaObject;
86};
87
88class ModelNodeMetaObject : public QQmlOpenMetaObject
89{
90public:
91 ModelNodeMetaObject(QObject *object, QQmlListModel *model, int elementIndex);
92 ~ModelNodeMetaObject();
93
94 QMetaObject *toDynamicMetaObject(QObject *object) override;
95
96 static ModelNodeMetaObject *get(QObject *obj);
97
98 bool m_enabled;
99 QQmlListModel *m_model;
100 int m_elementIndex;
101
102 void updateValues();
103 void updateValues(const QVector<int> &roles);
104
105 bool initialized() const { return m_initialized; }
106
107protected:
108 void propertyWritten(int index) override;
109
110private:
111 using QQmlOpenMetaObject::setValue;
112
113 void emitDirectNotifies(const int *changedRoles, int roleCount);
114
115 void initialize();
116 bool m_initialized;
117};
118
119namespace QV4 {
120
121namespace Heap {
122
123struct ModelObject : public QObjectWrapper {
124 void init(QObject *object, QQmlListModel *model)
125 {
126 QObjectWrapper::init(object);
127 m_model = model;
128 }
129
130 void destroy()
131 {
132 m_model.destroy();
133 QObjectWrapper::destroy();
134 }
135
136 int elementIndex() const {
137 if (const QObject *o = object()) {
138 const QObjectPrivate *op = QObjectPrivate::get(o);
139 return static_cast<ModelNodeMetaObject *>(op->metaObject)->m_elementIndex;
140 }
141 return -1;
142 }
143
144 QV4QPointer<QQmlListModel> m_model;
145};
146
147}
148
149struct ModelObject : public QObjectWrapper
150{
151 V4_OBJECT2(ModelObject, QObjectWrapper)
152 V4_NEEDS_DESTROY
153
154protected:
155 static bool virtualPut(Managed *m, PropertyKey id, const Value& value, Value *receiver);
156 static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
157 static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
158 static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
159 static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
160};
161
162} // namespace QV4
163
164class ListLayout
165{
166public:
167 ListLayout() : currentBlock(0), currentBlockOffset(0) {}
168 ListLayout(const ListLayout *other);
169 ~ListLayout();
170
171 class Role
172 {
173 public:
174
175 Role() : type(Invalid), blockIndex(-1), blockOffset(-1), index(-1), subLayout(0) {}
176 explicit Role(const Role *other);
177 ~Role();
178
179 // This enum must be kept in sync with the roleTypeNames variable in qqmllistmodel.cpp
180 enum DataType
181 {
182 Invalid = -1,
183
184 String,
185 Number,
186 Bool,
187 List,
188 QObject,
189 VariantMap,
190 DateTime,
191 Url,
192 Function,
193
194 MaxDataType
195 };
196
197 QString name;
198 DataType type;
199 int blockIndex;
200 int blockOffset;
201 int index;
202 ListLayout *subLayout;
203 };
204
205 const Role *getRoleOrCreate(const QString &key, const QVariant &data);
206 const Role &getRoleOrCreate(QV4::String *key, Role::DataType type);
207 const Role &getRoleOrCreate(const QString &key, Role::DataType type);
208
209 const Role &getExistingRole(int index) const { return *roles.at(i: index); }
210 const Role *getExistingRole(const QString &key) const;
211 const Role *getExistingRole(QV4::String *key) const;
212
213 int roleCount() const { return roles.size(); }
214
215 static void sync(ListLayout *src, ListLayout *target);
216
217private:
218 const Role &createRole(const QString &key, Role::DataType type);
219
220 int currentBlock;
221 int currentBlockOffset;
222 QVector<Role *> roles;
223 QStringHash<Role *> roleHash;
224};
225
226struct StringOrTranslation
227{
228 ~StringOrTranslation();
229 bool isSet() const { return binding || arrayData; }
230 bool isTranslation() const { return binding && !arrayData; }
231 void setString(const QString &s);
232 void setTranslation(const QV4::CompiledData::Binding *binding);
233 QString toString(const QQmlListModel *owner) const;
234 QString asString() const;
235private:
236 void clear();
237
238 union {
239 char16_t *stringData = nullptr;
240 const QV4::CompiledData::Binding *binding;
241 };
242
243 QTypedArrayData<char16_t> *arrayData = nullptr;
244 uint stringSize = 0;
245};
246
247/*!
248\internal
249*/
250class ListElement
251{
252public:
253 enum ObjectIndestructible { Indestructible = 1, ExplicitlySet = 2 };
254 enum { BLOCK_SIZE = 64 - sizeof(int) - sizeof(ListElement *) - sizeof(ModelNodeMetaObject *) };
255
256 ListElement();
257 ListElement(int existingUid);
258 ~ListElement();
259
260 static QVector<int> sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout);
261
262private:
263
264 void destroy(ListLayout *layout);
265
266 int setVariantProperty(const ListLayout::Role &role, const QVariant &d);
267
268 int setJsProperty(const ListLayout::Role &role, const QV4::Value &d, QV4::ExecutionEngine *eng);
269
270 int setStringProperty(const ListLayout::Role &role, const QString &s);
271 int setDoubleProperty(const ListLayout::Role &role, double n);
272 int setBoolProperty(const ListLayout::Role &role, bool b);
273 int setListProperty(const ListLayout::Role &role, ListModel *m);
274 int setQObjectProperty(const ListLayout::Role &role, QV4::QObjectWrapper *o);
275 int setVariantMapProperty(const ListLayout::Role &role, QV4::Object *o);
276 int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m);
277 int setDateTimeProperty(const ListLayout::Role &role, const QDateTime &dt);
278 int setUrlProperty(const ListLayout::Role &role, const QUrl &url);
279 int setFunctionProperty(const ListLayout::Role &role, const QJSValue &f);
280 int setTranslationProperty(const ListLayout::Role &role, const QV4::CompiledData::Binding *b);
281
282 void setStringPropertyFast(const ListLayout::Role &role, const QString &s);
283 void setDoublePropertyFast(const ListLayout::Role &role, double n);
284 void setBoolPropertyFast(const ListLayout::Role &role, bool b);
285 void setQObjectPropertyFast(const ListLayout::Role &role, QV4::QObjectWrapper *o);
286 void setListPropertyFast(const ListLayout::Role &role, ListModel *m);
287 void setVariantMapFast(const ListLayout::Role &role, QV4::Object *o);
288 void setDateTimePropertyFast(const ListLayout::Role &role, const QDateTime &dt);
289 void setUrlPropertyFast(const ListLayout::Role &role, const QUrl &url);
290 void setFunctionPropertyFast(const ListLayout::Role &role, const QJSValue &f);
291
292 void clearProperty(const ListLayout::Role &role);
293
294 QVariant getProperty(const ListLayout::Role &role, const QQmlListModel *owner, QV4::ExecutionEngine *eng);
295 ListModel *getListProperty(const ListLayout::Role &role);
296 StringOrTranslation *getStringProperty(const ListLayout::Role &role);
297 QV4::QObjectWrapper *getQObjectProperty(const ListLayout::Role &role);
298 QV4::PersistentValue *getGuardProperty(const ListLayout::Role &role);
299 QVariantMap *getVariantMapProperty(const ListLayout::Role &role);
300 QDateTime *getDateTimeProperty(const ListLayout::Role &role);
301 QUrl *getUrlProperty(const ListLayout::Role &role);
302 QJSValue *getFunctionProperty(const ListLayout::Role &role);
303
304 inline char *getPropertyMemory(const ListLayout::Role &role);
305
306 int getUid() const { return uid; }
307
308 ModelNodeMetaObject *objectCache();
309
310 char data[BLOCK_SIZE];
311 ListElement *next;
312
313 int uid;
314 QObject *m_objectCache;
315
316 friend class ListModel;
317};
318
319/*!
320\internal
321*/
322class ListModel
323{
324public:
325
326 ListModel(ListLayout *layout, QQmlListModel *modelCache);
327 ~ListModel() {}
328
329 void destroy();
330
331 int setOrCreateProperty(int elementIndex, const QString &key, const QVariant &data);
332 int setExistingProperty(int uid, const QString &key, const QV4::Value &data, QV4::ExecutionEngine *eng);
333
334 QVariant getProperty(int elementIndex, int roleIndex, const QQmlListModel *owner, QV4::ExecutionEngine *eng);
335 ListModel *getListProperty(int elementIndex, const ListLayout::Role &role);
336
337 void updateTranslations();
338
339 int roleCount() const
340 {
341 return m_layout->roleCount();
342 }
343
344 const ListLayout::Role &getExistingRole(int index) const
345 {
346 return m_layout->getExistingRole(index);
347 }
348
349 const ListLayout::Role *getExistingRole(QV4::String *key) const
350 {
351 return m_layout->getExistingRole(key);
352 }
353
354 const ListLayout::Role &getOrCreateListRole(const QString &name)
355 {
356 return m_layout->getRoleOrCreate(key: name, type: ListLayout::Role::List);
357 }
358
359 int elementCount() const
360 {
361 return elements.count();
362 }
363
364 enum class SetElement {WasJustInserted, IsCurrentlyUpdated};
365
366 void set(int elementIndex, QV4::Object *object, QVector<int> *roles);
367 void set(int elementIndex, QV4::Object *object, SetElement reason = SetElement::IsCurrentlyUpdated);
368
369 int append(QV4::Object *object);
370 void insert(int elementIndex, QV4::Object *object);
371
372 Q_REQUIRED_RESULT QVector<std::function<void()>> remove(int index, int count);
373
374 int appendElement();
375 void insertElement(int index);
376
377 void move(int from, int to, int n);
378
379 static bool sync(ListModel *src, ListModel *target);
380
381 QObject *getOrCreateModelObject(QQmlListModel *model, int elementIndex);
382
383private:
384 QPODVector<ListElement *, 4> elements;
385 ListLayout *m_layout;
386
387 QQmlListModel *m_modelCache;
388
389 struct ElementSync
390 {
391 ListElement *src = nullptr;
392 ListElement *target = nullptr;
393 int srcIndex = -1;
394 int targetIndex = -1;
395 QVector<int> changedRoles;
396 };
397
398 void newElement(int index);
399
400 void updateCacheIndices(int start = 0, int end = -1);
401
402 template<typename ArrayLike>
403 void setArrayLike(QV4::ScopedObject *o, QV4::String *propertyName, ListElement *e, ArrayLike *a)
404 {
405 const ListLayout::Role &r = m_layout->getRoleOrCreate(key: propertyName, type: ListLayout::Role::List);
406 if (r.type == ListLayout::Role::List) {
407 ListModel *subModel = new ListModel(r.subLayout, nullptr);
408
409 int arrayLength = a->getLength();
410 for (int j=0 ; j < arrayLength ; ++j) {
411 *o = a->get(j);
412 subModel->append(object: *o);
413 }
414
415 e->setListPropertyFast(role: r, m: subModel);
416 }
417 }
418
419 friend class ListElement;
420 friend class QQmlListModelWorkerAgent;
421 friend class QQmlListModelParser;
422};
423
424QT_END_NAMESPACE
425
426Q_DECLARE_METATYPE(ListModel *);
427
428#endif // QQUICKLISTMODEL_P_P_H
429

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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