1// Copyright (C) 2016 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 QQMLDATAMODEL_P_P_H
5#define QQMLDATAMODEL_P_P_H
6
7#include "qqmldelegatemodel_p.h"
8#include <private/qv4qobjectwrapper_p.h>
9
10#include <QtQml/qqmlcontext.h>
11#include <QtQml/qqmlincubator.h>
12
13#include <private/qqmladaptormodel_p.h>
14#include <private/qqmlopenmetaobject_p.h>
15
16#include <QtCore/qloggingcategory.h>
17#include <QtCore/qpointer.h>
18
19//
20// W A R N I N G
21// -------------
22//
23// This file is not part of the Qt API. It exists purely as an
24// implementation detail. This header file may change from version to
25// version without notice, or even be removed.
26//
27// We mean it.
28//
29
30QT_REQUIRE_CONFIG(qml_delegate_model);
31
32QT_BEGIN_NAMESPACE
33
34Q_DECLARE_LOGGING_CATEGORY(lcItemViewDelegateRecycling)
35
36typedef QQmlListCompositor Compositor;
37
38class QQmlDelegateModelAttachedMetaObject;
39class QQmlAbstractDelegateComponent;
40
41class Q_QMLMODELS_EXPORT QQmlDelegateModelItemMetaType final
42 : public QQmlRefCounted<QQmlDelegateModelItemMetaType>
43{
44public:
45 QQmlDelegateModelItemMetaType(QV4::ExecutionEngine *engine, QQmlDelegateModel *model, const QStringList &groupNames);
46 ~QQmlDelegateModelItemMetaType();
47
48 void initializeAttachedMetaObject();
49 void initializePrototype();
50
51 int parseGroups(const QStringList &groupNames) const;
52 int parseGroups(const QV4::Value &groupNames) const;
53
54 QPointer<QQmlDelegateModel> model;
55 const int groupCount;
56 QV4::ExecutionEngine * const v4Engine;
57 QQmlRefPointer<QQmlDelegateModelAttachedMetaObject> attachedMetaObject;
58 const QStringList groupNames;
59 QV4::PersistentValue modelItemProto;
60};
61
62class QQmlAdaptorModel;
63class QQDMIncubationTask;
64
65class QQmlDelegateModelItem : public QObject
66{
67 Q_OBJECT
68 Q_PROPERTY(int index READ modelIndex NOTIFY modelIndexChanged)
69 Q_PROPERTY(int row READ modelRow NOTIFY rowChanged REVISION(2, 12))
70 Q_PROPERTY(int column READ modelColumn NOTIFY columnChanged REVISION(2, 12))
71 Q_PROPERTY(QObject *model READ modelObject CONSTANT)
72public:
73 QQmlDelegateModelItem(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
74 QQmlAdaptorModel::Accessors *accessor, int modelIndex,
75 int row, int column);
76 ~QQmlDelegateModelItem();
77
78 void referenceObject() { ++objectRef; }
79 bool releaseObject()
80 {
81 Q_ASSERT(objectRef > 0);
82 return --objectRef == 0 && !(groups & Compositor::PersistedFlag);
83 }
84 bool isObjectReferenced() const { return objectRef != 0 || (groups & Compositor::PersistedFlag); }
85 void childContextObjectDestroyed(QObject *childContextObject);
86
87 bool isReferenced() const {
88 return scriptRef
89 || incubationTask
90 || ((groups & Compositor::UnresolvedFlag) && (groups & Compositor::GroupMask));
91 }
92
93 void dispose();
94
95 QObject *modelObject() { return this; }
96
97 void destroyObject();
98
99 static QQmlDelegateModelItem *dataForObject(QObject *object);
100
101 int groupIndex(Compositor::Group group);
102
103 int modelRow() const { return row; }
104 int modelColumn() const { return column; }
105 int modelIndex() const { return index; }
106 virtual void setModelIndex(int idx, int newRow, int newColumn, bool alwaysEmit = false);
107
108 virtual QV4::ReturnedValue get() { return QV4::QObjectWrapper::wrap(engine: metaType->v4Engine, object: this); }
109
110 virtual void setValue(const QString &role, const QVariant &value) { Q_UNUSED(role); Q_UNUSED(value); }
111 virtual bool resolveIndex(const QQmlAdaptorModel &, int) { return false; }
112 virtual QQmlRefPointer<QQmlContextData> initProxy() { return contextData; }
113
114 static QV4::ReturnedValue get_model(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
115 static QV4::ReturnedValue get_groups(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
116 static QV4::ReturnedValue set_groups(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
117 static QV4::ReturnedValue get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &);
118 static QV4::ReturnedValue set_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
119 static QV4::ReturnedValue get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
120
121 QQmlRefPointer<QQmlDelegateModelItemMetaType> metaType;
122 QQmlRefPointer<QQmlContextData> contextData;
123 QPointer<QObject> object;
124 QQDMIncubationTask *incubationTask = nullptr;
125 QQmlComponent *delegate = nullptr;
126 int objectRef = 0;
127 int scriptRef = 0;
128 int groups = 0;
129
130 QQmlDelegateModelAttached *attached() const
131 {
132 if (!object)
133 return nullptr;
134
135 QQmlData *ddata = QQmlData::get(object);
136 if (!ddata || !ddata->hasExtendedData())
137 return nullptr;
138
139 return static_cast<QQmlDelegateModelAttached *>(
140 ddata->attachedProperties()->value(
141 key: QQmlPrivate::attachedPropertiesFunc<QQmlDelegateModel>()));
142 }
143
144 void disableStructuredModelData() { useStructuredModelData = false; }
145
146Q_SIGNALS:
147 void modelIndexChanged();
148 Q_REVISION(2, 12) void rowChanged();
149 Q_REVISION(2, 12) void columnChanged();
150
151protected:
152 void objectDestroyed(QObject *);
153
154 int index = -1;
155 int row = -1;
156 int column = -1;
157 bool useStructuredModelData = true;
158};
159
160namespace QV4 {
161namespace Heap {
162struct QQmlDelegateModelItemObject : Object {
163 inline void init(QQmlDelegateModelItem *item);
164 void destroy();
165 QQmlDelegateModelItem *item;
166};
167
168}
169}
170
171struct QQmlDelegateModelItemObject : QV4::Object
172{
173 V4_OBJECT2(QQmlDelegateModelItemObject, QV4::Object)
174 V4_NEEDS_DESTROY
175};
176
177void QV4::Heap::QQmlDelegateModelItemObject::init(QQmlDelegateModelItem *item)
178{
179 Object::init();
180 this->item = item;
181}
182
183class QQmlReusableDelegateModelItemsPool
184{
185public:
186 bool insertItem(QQmlDelegateModelItem *modelItem);
187 QQmlDelegateModelItem *takeItem(const QQmlComponent *delegate, int newIndexHint);
188 void reuseItem(QQmlDelegateModelItem *item, int newModelIndex);
189 void drain(int maxPoolTime, std::function<void(QQmlDelegateModelItem *cacheItem)> releaseItem);
190 int size()
191 {
192 Q_ASSERT(m_reusableItemsPool.size() <= MaxSize);
193 return int(m_reusableItemsPool.size());
194 }
195
196private:
197 struct PoolItem
198 {
199 QQmlDelegateModelItem *item = nullptr;
200 int poolTime = 0;
201 };
202
203 static constexpr size_t MaxSize = size_t(std::numeric_limits<int>::max());
204
205 std::vector<PoolItem> m_reusableItemsPool;
206};
207
208class QQmlDelegateModelPrivate;
209class QQDMIncubationTask : public QQmlIncubator
210{
211public:
212 QQDMIncubationTask(QQmlDelegateModelPrivate *l, IncubationMode mode)
213 : QQmlIncubator(mode)
214 , incubating(nullptr)
215 , vdm(l) {}
216
217 void initializeRequiredProperties(
218 QQmlDelegateModelItem *modelItemToIncubate, QObject* object,
219 QQmlDelegateModel::DelegateModelAccess access);
220 void statusChanged(Status) override;
221 void setInitialState(QObject *) override;
222
223 QQmlDelegateModelItem *incubating = nullptr;
224 QQmlDelegateModelPrivate *vdm = nullptr;
225 QQmlRefPointer<QQmlContextData> proxyContext;
226 QPointer<QObject> proxiedObject = nullptr; // the proxied object might disapear, so we use a QPointer instead of a raw one
227 int index[QQmlListCompositor::MaximumGroupCount];
228};
229
230
231class QQmlDelegateModelGroupEmitter
232{
233public:
234 virtual ~QQmlDelegateModelGroupEmitter();
235 virtual void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) = 0;
236 virtual void createdPackage(int, QQuickPackage *);
237 virtual void initPackage(int, QQuickPackage *);
238 virtual void destroyingPackage(QQuickPackage *);
239
240 QIntrusiveListNode emitterNode;
241};
242
243typedef QIntrusiveList<QQmlDelegateModelGroupEmitter, &QQmlDelegateModelGroupEmitter::emitterNode> QQmlDelegateModelGroupEmitterList;
244
245class QQmlDelegateModelGroupPrivate : public QObjectPrivate
246{
247public:
248 Q_DECLARE_PUBLIC(QQmlDelegateModelGroup)
249
250 QQmlDelegateModelGroupPrivate() : group(Compositor::Cache), defaultInclude(false) {}
251
252 static QQmlDelegateModelGroupPrivate *get(QQmlDelegateModelGroup *group) {
253 return static_cast<QQmlDelegateModelGroupPrivate *>(QObjectPrivate::get(o: group)); }
254
255 void setModel(QQmlDelegateModel *model, Compositor::Group group);
256 bool isChangedConnected();
257 void emitChanges(QV4::ExecutionEngine *engine);
258 void emitModelUpdated(bool reset);
259
260 void createdPackage(int index, QQuickPackage *package);
261 void initPackage(int index, QQuickPackage *package);
262 void destroyingPackage(QQuickPackage *package);
263
264 bool parseIndex(const QV4::Value &value, int *index, Compositor::Group *group) const;
265 bool parseGroupArgs(
266 QQmlV4FunctionPtr args, Compositor::Group *group, int *index, int *count, int *groups) const;
267
268 Compositor::Group group;
269 QPointer<QQmlDelegateModel> model;
270 QQmlDelegateModelGroupEmitterList emitters;
271 QQmlChangeSet changeSet;
272 QString name;
273 bool defaultInclude;
274};
275
276class QQmlDelegateModelParts;
277
278class QQmlDelegateModelPrivate : public QObjectPrivate, public QQmlDelegateModelGroupEmitter
279{
280 Q_DECLARE_PUBLIC(QQmlDelegateModel)
281public:
282 QQmlDelegateModelPrivate(QQmlContext *);
283 ~QQmlDelegateModelPrivate();
284
285 static QQmlDelegateModelPrivate *get(QQmlDelegateModel *m) {
286 return static_cast<QQmlDelegateModelPrivate *>(QObjectPrivate::get(o: m));
287 }
288
289 void init();
290 void connectModel(QQmlAdaptorModel *model);
291 void connectToAbstractItemModel();
292 void disconnectFromAbstractItemModel();
293
294 void requestMoreIfNecessary();
295 QObject *object(Compositor::Group group, int index, QQmlIncubator::IncubationMode incubationMode);
296 QQmlDelegateModel::ReleaseFlags release(QObject *object, QQmlInstanceModel::ReusableFlag reusable = QQmlInstanceModel::NotReusable);
297 QVariant variantValue(Compositor::Group group, int index, const QString &name);
298 void emitCreatedPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
299 void emitInitPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package);
300 void emitCreatedItem(QQDMIncubationTask *incubationTask, QObject *item) {
301 Q_EMIT q_func()->createdItem(index: incubationTask->index[m_compositorGroup], object: item); }
302 void emitInitItem(QQDMIncubationTask *incubationTask, QObject *item) {
303 Q_EMIT q_func()->initItem(index: incubationTask->index[m_compositorGroup], object: item); }
304 void emitDestroyingPackage(QQuickPackage *package);
305 void emitDestroyingItem(QObject *item) { Q_EMIT q_func()->destroyingItem(object: item); }
306 void addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it);
307 void removeCacheItem(QQmlDelegateModelItem *cacheItem);
308 void destroyCacheItem(QQmlDelegateModelItem *cacheItem);
309 void updateFilterGroup();
310
311 void reuseItem(QQmlDelegateModelItem *item, int newModelIndex, int newGroups);
312 void drainReusableItemsPool(int maxPoolTime);
313 QQmlComponent *resolveDelegate(int index);
314
315 void addGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
316 void removeGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
317 void setGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags);
318
319 void itemsInserted(
320 const QVector<Compositor::Insert> &inserts,
321 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedInserts,
322 QHash<int, QList<QQmlDelegateModelItem *> > *movedItems = nullptr);
323 void itemsInserted(const QVector<Compositor::Insert> &inserts);
324 void itemsRemoved(
325 const QVector<Compositor::Remove> &removes,
326 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves,
327 QHash<int, QList<QQmlDelegateModelItem *> > *movedItems = nullptr);
328 void itemsRemoved(const QVector<Compositor::Remove> &removes);
329 void itemsMoved(
330 const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts);
331 void itemsChanged(const QVector<Compositor::Change> &changes);
332 void emitChanges();
333 void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override;
334 void delegateChanged(bool add = true, bool remove = true);
335
336 enum class InsertionResult {
337 Success,
338 Error,
339 Retry
340 };
341 InsertionResult insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups);
342
343 int adaptorModelCount() const;
344
345 static void group_append(QQmlListProperty<QQmlDelegateModelGroup> *property, QQmlDelegateModelGroup *group);
346 static qsizetype group_count(QQmlListProperty<QQmlDelegateModelGroup> *property);
347 static QQmlDelegateModelGroup *group_at(QQmlListProperty<QQmlDelegateModelGroup> *property, qsizetype index);
348
349 void releaseIncubator(QQDMIncubationTask *incubationTask);
350 void incubatorStatusChanged(QQDMIncubationTask *incubationTask, QQmlIncubator::Status status);
351 void setInitialState(QQDMIncubationTask *incubationTask, QObject *o);
352
353 QQmlAdaptorModel m_adaptorModel;
354 QQmlListCompositor m_compositor;
355 QQmlStrongJSQObjectReference<QQmlComponent> m_delegate;
356 QQmlAbstractDelegateComponent *m_delegateChooser;
357 QMetaObject::Connection m_delegateChooserChanged;
358 QQmlRefPointer<QQmlDelegateModelItemMetaType> m_cacheMetaType;
359 QPointer<QQmlContext> m_context;
360 QQmlDelegateModelParts *m_parts;
361 QQmlDelegateModelGroupEmitterList m_pendingParts;
362
363 QList<QQmlDelegateModelItem *> m_cache;
364 QQmlReusableDelegateModelItemsPool m_reusableItemsPool;
365 QList<QQDMIncubationTask *> m_finishedIncubating;
366 QList<QByteArray> m_watchedRoles;
367
368 QString m_filterGroup;
369
370 int m_count;
371 int m_groupCount;
372
373 QQmlListCompositor::Group m_compositorGroup;
374 bool m_complete : 1;
375 bool m_delegateValidated : 1;
376 bool m_reset : 1;
377 bool m_transaction : 1;
378 bool m_incubatorCleanupScheduled : 1;
379 bool m_waitingToFetchMore : 1;
380
381 union {
382 struct {
383 QQmlDelegateModelGroup *m_cacheItems;
384 QQmlDelegateModelGroup *m_items;
385 QQmlDelegateModelGroup *m_persistedItems;
386 };
387 QQmlDelegateModelGroup *m_groups[Compositor::MaximumGroupCount];
388 };
389};
390
391class QQmlPartsModel : public QQmlInstanceModel, public QQmlDelegateModelGroupEmitter
392{
393 Q_OBJECT
394 Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup FINAL)
395public:
396 QQmlPartsModel(QQmlDelegateModel *model, const QString &part, QObject *parent = nullptr);
397 ~QQmlPartsModel();
398
399 QString filterGroup() const;
400 void setFilterGroup(const QString &group);
401 void resetFilterGroup();
402 void updateFilterGroup();
403 void updateFilterGroup(Compositor::Group group, const QQmlChangeSet &changeSet);
404
405 int count() const override;
406 bool isValid() const override;
407 QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
408 ReleaseFlags release(QObject *item, ReusableFlag reusable = NotReusable) override;
409 QVariant variantValue(int index, const QString &role) override;
410 QList<QByteArray> watchedRoles() const { return m_watchedRoles; }
411 void setWatchedRoles(const QList<QByteArray> &roles) override;
412 QQmlIncubator::Status incubationStatus(int index) override;
413
414 int indexOf(QObject *item, QObject *objectContext) const override;
415
416 void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override;
417
418 void createdPackage(int index, QQuickPackage *package) override;
419 void initPackage(int index, QQuickPackage *package) override;
420 void destroyingPackage(QQuickPackage *package) override;
421
422Q_SIGNALS:
423 void filterGroupChanged();
424
425private:
426 QQmlDelegateModel *m_model;
427 QMultiHash<QObject *, QQuickPackage *> m_packaged;
428 QString m_part;
429 QString m_filterGroup;
430 QList<QByteArray> m_watchedRoles;
431 QVector<int> m_pendingPackageInitializations; // vector holds model indices
432 Compositor::Group m_compositorGroup;
433 bool m_inheritGroup;
434 bool m_modelUpdatePending = true;
435};
436
437class QMetaPropertyBuilder;
438
439class QQmlDelegateModelPartsMetaObject : public QQmlOpenMetaObject
440{
441public:
442 QQmlDelegateModelPartsMetaObject(QObject *parent)
443 : QQmlOpenMetaObject(parent) {}
444
445 void propertyCreated(int, QMetaPropertyBuilder &) override;
446 QVariant initialValue(int) override;
447};
448
449class QQmlDelegateModelParts : public QObject
450{
451Q_OBJECT
452public:
453 QQmlDelegateModelParts(QQmlDelegateModel *parent);
454
455 QQmlDelegateModel *model;
456 QList<QQmlPartsModel *> models;
457};
458
459class QQmlDelegateModelAttachedMetaObject final
460 : public QAbstractDynamicMetaObject,
461 public QQmlRefCounted<QQmlDelegateModelAttachedMetaObject>
462{
463public:
464 QQmlDelegateModelAttachedMetaObject(
465 QQmlDelegateModelItemMetaType *metaType, QMetaObject *metaObject);
466 ~QQmlDelegateModelAttachedMetaObject();
467
468 void objectDestroyed(QObject *) override;
469 int metaCall(QObject *, QMetaObject::Call, int _id, void **) override;
470
471private:
472 QQmlDelegateModelItemMetaType * const metaType;
473 QMetaObject * const metaObject;
474 const int memberPropertyOffset;
475 const int indexPropertyOffset;
476};
477
478QT_END_NAMESPACE
479
480#endif
481

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