1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QQMLDATAMODEL_P_P_H
41#define QQMLDATAMODEL_P_P_H
42
43#include "qqmldelegatemodel_p.h"
44#include <private/qv4qobjectwrapper_p.h>
45
46#include <QtQml/qqmlcontext.h>
47#include <QtQml/qqmlincubator.h>
48
49#include <private/qqmladaptormodel_p.h>
50#include <private/qqmlopenmetaobject_p.h>
51
52#include <QtCore/qloggingcategory.h>
53
54//
55// W A R N I N G
56// -------------
57//
58// This file is not part of the Qt API. It exists purely as an
59// implementation detail. This header file may change from version to
60// version without notice, or even be removed.
61//
62// We mean it.
63//
64
65QT_REQUIRE_CONFIG(qml_delegate_model);
66
67QT_BEGIN_NAMESPACE
68
69Q_DECLARE_LOGGING_CATEGORY(lcItemViewDelegateRecycling)
70
71typedef QQmlListCompositor Compositor;
72
73class QQmlDelegateModelAttachedMetaObject;
74class QQmlAbstractDelegateComponent;
75
76class Q_QMLMODELS_PRIVATE_EXPORT QQmlDelegateModelItemMetaType : public QQmlRefCount
77{
78public:
79 QQmlDelegateModelItemMetaType(QV4::ExecutionEngine *engine, QQmlDelegateModel *model, const QStringList &groupNames);
80 ~QQmlDelegateModelItemMetaType();
81
82 void initializeMetaObject();
83 void initializePrototype();
84
85 int parseGroups(const QStringList &groupNames) const;
86 int parseGroups(const QV4::Value &groupNames) const;
87
88 QPointer<QQmlDelegateModel> model;
89 const int groupCount;
90 QV4::ExecutionEngine * const v4Engine;
91 QQmlDelegateModelAttachedMetaObject *metaObject;
92 const QStringList groupNames;
93 QV4::PersistentValue modelItemProto;
94};
95
96class QQmlAdaptorModel;
97class QQDMIncubationTask;
98
99class QQmlDelegateModelItem : public QObject
100{
101 Q_OBJECT
102 Q_PROPERTY(int index READ modelIndex NOTIFY modelIndexChanged)
103 Q_PROPERTY(int row READ modelRow NOTIFY rowChanged REVISION 12)
104 Q_PROPERTY(int column READ modelColumn NOTIFY columnChanged REVISION 12)
105 Q_PROPERTY(QObject *model READ modelObject CONSTANT)
106public:
107 QQmlDelegateModelItem(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
108 QQmlAdaptorModel::Accessors *accessor, int modelIndex,
109 int row, int column);
110 ~QQmlDelegateModelItem();
111
112 void referenceObject() { ++objectRef; }
113 bool releaseObject() { return --objectRef == 0 && !(groups & Compositor::PersistedFlag); }
114 bool isObjectReferenced() const { return objectRef != 0 || (groups & Compositor::PersistedFlag); }
115 void childContextObjectDestroyed(QObject *childContextObject);
116
117 bool isReferenced() const {
118 return scriptRef
119 || incubationTask
120 || ((groups & Compositor::UnresolvedFlag) && (groups & Compositor::GroupMask));
121 }
122
123 void Dispose();
124
125 QObject *modelObject() { return this; }
126
127 void destroyObject();
128
129 static QQmlDelegateModelItem *dataForObject(QObject *object);
130
131 int groupIndex(Compositor::Group group);
132
133 int modelRow() const { return row; }
134 int modelColumn() const { return column; }
135 int modelIndex() const { return index; }
136 virtual void setModelIndex(int idx, int newRow, int newColumn, bool alwaysEmit = false);
137
138 virtual QV4::ReturnedValue get() { return QV4::QObjectWrapper::wrap(engine: v4, object: this); }
139
140 virtual void setValue(const QString &role, const QVariant &value) { Q_UNUSED(role); Q_UNUSED(value); }
141 virtual bool resolveIndex(const QQmlAdaptorModel &, int) { return false; }
142
143 static QV4::ReturnedValue get_model(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
144 static QV4::ReturnedValue get_groups(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
145 static QV4::ReturnedValue set_groups(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
146 static QV4::ReturnedValue get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &);
147 static QV4::ReturnedValue set_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
148 static QV4::ReturnedValue get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
149
150 QV4::ExecutionEngine *v4;
151 QQmlRefPointer<QQmlDelegateModelItemMetaType> const metaType;
152 QQmlContextDataRef contextData;
153 QPointer<QObject> object;
154 QPointer<QQmlDelegateModelAttached> attached;
155 QQDMIncubationTask *incubationTask;
156 QQmlComponent *delegate;
157 int poolTime;
158 int objectRef;
159 int scriptRef;
160 int groups;
161 int index;
162
163Q_SIGNALS:
164 void modelIndexChanged();
165 Q_REVISION(12) void rowChanged();
166 Q_REVISION(12) void columnChanged();
167
168protected:
169 void objectDestroyed(QObject *);
170 int row;
171 int column;
172};
173
174namespace QV4 {
175namespace Heap {
176struct QQmlDelegateModelItemObject : Object {
177 inline void init(QQmlDelegateModelItem *item);
178 void destroy();
179 QQmlDelegateModelItem *item;
180};
181
182}
183}
184
185struct QQmlDelegateModelItemObject : QV4::Object
186{
187 V4_OBJECT2(QQmlDelegateModelItemObject, QV4::Object)
188 V4_NEEDS_DESTROY
189};
190
191void QV4::Heap::QQmlDelegateModelItemObject::init(QQmlDelegateModelItem *item)
192{
193 Object::init();
194 this->item = item;
195}
196
197class QQmlReusableDelegateModelItemsPool
198{
199public:
200 void insertItem(QQmlDelegateModelItem *modelItem);
201 QQmlDelegateModelItem *takeItem(const QQmlComponent *delegate, int newIndexHint);
202 void reuseItem(QQmlDelegateModelItem *item, int newModelIndex);
203 void drain(int maxPoolTime, std::function<void(QQmlDelegateModelItem *cacheItem)> releaseItem);
204 int size() { return m_reusableItemsPool.size(); }
205
206private:
207 QList<QQmlDelegateModelItem *> m_reusableItemsPool;
208};
209
210class QQmlDelegateModelPrivate;
211class QQDMIncubationTask : public QQmlIncubator
212{
213public:
214 QQDMIncubationTask(QQmlDelegateModelPrivate *l, IncubationMode mode)
215 : QQmlIncubator(mode)
216 , incubating(nullptr)
217 , vdm(l) {}
218
219 void initializeRequiredProperties(QQmlDelegateModelItem *modelItemToIncubate, QObject* object);
220 void statusChanged(Status) override;
221 void setInitialState(QObject *) override;
222
223 QQmlDelegateModelItem *incubating = nullptr;
224 QQmlDelegateModelPrivate *vdm = nullptr;
225 QQmlContextData *proxyContext = nullptr;
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 QQmlV4Function *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 bool insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups);
337
338 int adaptorModelCount() const;
339
340 static void group_append(QQmlListProperty<QQmlDelegateModelGroup> *property, QQmlDelegateModelGroup *group);
341 static int group_count(QQmlListProperty<QQmlDelegateModelGroup> *property);
342 static QQmlDelegateModelGroup *group_at(QQmlListProperty<QQmlDelegateModelGroup> *property, int index);
343
344 void releaseIncubator(QQDMIncubationTask *incubationTask);
345 void incubatorStatusChanged(QQDMIncubationTask *incubationTask, QQmlIncubator::Status status);
346 void setInitialState(QQDMIncubationTask *incubationTask, QObject *o);
347
348 QQmlAdaptorModel m_adaptorModel;
349 QQmlListCompositor m_compositor;
350 QQmlStrongJSQObjectReference<QQmlComponent> m_delegate;
351 QQmlAbstractDelegateComponent *m_delegateChooser;
352 QMetaObject::Connection m_delegateChooserChanged;
353 QQmlDelegateModelItemMetaType *m_cacheMetaType;
354 QPointer<QQmlContext> m_context;
355 QQmlDelegateModelParts *m_parts;
356 QQmlDelegateModelGroupEmitterList m_pendingParts;
357
358 QList<QQmlDelegateModelItem *> m_cache;
359 QQmlReusableDelegateModelItemsPool m_reusableItemsPool;
360 QList<QQDMIncubationTask *> m_finishedIncubating;
361 QList<QByteArray> m_watchedRoles;
362
363 QString m_filterGroup;
364
365 int m_count;
366 int m_groupCount;
367
368 QQmlListCompositor::Group m_compositorGroup;
369 bool m_complete : 1;
370 bool m_delegateValidated : 1;
371 bool m_reset : 1;
372 bool m_transaction : 1;
373 bool m_incubatorCleanupScheduled : 1;
374 bool m_waitingToFetchMore : 1;
375
376 union {
377 struct {
378 QQmlDelegateModelGroup *m_cacheItems;
379 QQmlDelegateModelGroup *m_items;
380 QQmlDelegateModelGroup *m_persistedItems;
381 };
382 QQmlDelegateModelGroup *m_groups[Compositor::MaximumGroupCount];
383 };
384};
385
386class QQmlPartsModel : public QQmlInstanceModel, public QQmlDelegateModelGroupEmitter
387{
388 Q_OBJECT
389 Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup)
390public:
391 QQmlPartsModel(QQmlDelegateModel *model, const QString &part, QObject *parent = nullptr);
392 ~QQmlPartsModel();
393
394 QString filterGroup() const;
395 void setFilterGroup(const QString &group);
396 void resetFilterGroup();
397 void updateFilterGroup();
398 void updateFilterGroup(Compositor::Group group, const QQmlChangeSet &changeSet);
399
400 int count() const override;
401 bool isValid() const override;
402 QObject *object(int index, QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested) override;
403 ReleaseFlags release(QObject *item, ReusableFlag reusable = NotReusable) override;
404 QVariant variantValue(int index, const QString &role) override;
405 QList<QByteArray> watchedRoles() const { return m_watchedRoles; }
406 void setWatchedRoles(const QList<QByteArray> &roles) override;
407 QQmlIncubator::Status incubationStatus(int index) override;
408
409 int indexOf(QObject *item, QObject *objectContext) const override;
410
411 void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override;
412
413 void createdPackage(int index, QQuickPackage *package) override;
414 void initPackage(int index, QQuickPackage *package) override;
415 void destroyingPackage(QQuickPackage *package) override;
416
417Q_SIGNALS:
418 void filterGroupChanged();
419
420private:
421 QQmlDelegateModel *m_model;
422 QMultiHash<QObject *, QQuickPackage *> m_packaged;
423 QString m_part;
424 QString m_filterGroup;
425 QList<QByteArray> m_watchedRoles;
426 QVector<int> m_pendingPackageInitializations; // vector holds model indices
427 Compositor::Group m_compositorGroup;
428 bool m_inheritGroup;
429 bool m_modelUpdatePending = true;
430};
431
432class QMetaPropertyBuilder;
433
434class QQmlDelegateModelPartsMetaObject : public QQmlOpenMetaObject
435{
436public:
437 QQmlDelegateModelPartsMetaObject(QObject *parent)
438 : QQmlOpenMetaObject(parent) {}
439
440 void propertyCreated(int, QMetaPropertyBuilder &) override;
441 QVariant initialValue(int) override;
442};
443
444class QQmlDelegateModelParts : public QObject
445{
446Q_OBJECT
447public:
448 QQmlDelegateModelParts(QQmlDelegateModel *parent);
449
450 QQmlDelegateModel *model;
451 QList<QQmlPartsModel *> models;
452};
453
454class QQmlDelegateModelAttachedMetaObject : public QAbstractDynamicMetaObject, public QQmlRefCount
455{
456public:
457 QQmlDelegateModelAttachedMetaObject(
458 QQmlDelegateModelItemMetaType *metaType, QMetaObject *metaObject);
459 ~QQmlDelegateModelAttachedMetaObject();
460
461 void objectDestroyed(QObject *) override;
462 int metaCall(QObject *, QMetaObject::Call, int _id, void **) override;
463
464private:
465 QQmlDelegateModelItemMetaType * const metaType;
466 QMetaObject * const metaObject;
467 const int memberPropertyOffset;
468 const int indexPropertyOffset;
469};
470
471class PropertyUpdater : public QObject
472{
473 Q_OBJECT
474
475public:
476 PropertyUpdater(QObject *parent);
477 QHash<int, QMetaObject::Connection> senderToConnection;
478 QHash<int, int> changeSignalIndexToPropertyIndex;
479 int updateCount = 0;
480public Q_SLOTS:
481 void doUpdate();
482 void breakBinding();
483};
484
485QT_END_NAMESPACE
486
487#endif
488

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