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

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