Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qqmldelegatemodel.cpp
Go to the documentation of this file.
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
5
6#include <QtQml/qqmlinfo.h>
7
8#include <private/qqmlabstractdelegatecomponent_p.h>
9#include <private/qquickpackage_p.h>
10#include <private/qmetaobjectbuilder_p.h>
11#include <private/qqmladaptormodel_p.h>
12#include <private/qqmlanybinding_p.h>
13#include <private/qqmlchangeset_p.h>
14#include <private/qqmlengine_p.h>
15#include <private/qqmlcomponent_p.h>
16#include <private/qqmlpropertytopropertybinding_p.h>
17#include <private/qjsvalue_p.h>
18
19#include <private/qv4value_p.h>
20#include <private/qv4functionobject_p.h>
21#include <private/qv4objectiterator_p.h>
22
24
25Q_LOGGING_CATEGORY(lcItemViewDelegateRecycling, "qt.qml.delegatemodel.recycling")
26
28
29namespace QV4 {
30
31namespace Heap {
32
35
38};
39
41 void init() { Object::init(); }
42
44};
45
47 void init(const QVector<QQmlChangeSet::Change> &changes);
48 void destroy() {
49 delete changes;
50 Object::destroy();
51 }
52
54};
55
56
57}
58
60{
62
64 {
65 return scope->engine()->memoryManager->allocate<DelegateModelGroupFunction>(scope, flag, code);
66 }
67
68 static ReturnedValue virtualCall(const QV4::FunctionObject *that, const Value *thisObject, const Value *argv, int argc)
69 {
70 QV4::Scope scope(that->engine());
73 if (!o)
74 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
75
76 QV4::ScopedValue v(scope, argc ? argv[0] : Value::undefinedValue());
77 return f->d()->code(o->d()->item, f->d()->flag, v);
78 }
79};
80
81void Heap::DelegateModelGroupFunction::init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
82{
83 QV4::Heap::FunctionObject::init(scope, QStringLiteral("DelegateModelGroupFunction"));
84 this->flag = flag;
85 this->code = code;
86}
87
88}
89
91
92
93
95{
96public:
99
101 const QVector<QQmlChangeSet::Change> &changes);
102
104};
105
107
108
110{
111 prop.setWritable(false);
112}
113
115{
116 QQmlDelegateModelParts *parts = static_cast<QQmlDelegateModelParts *>(object());
118 parts->model, QString::fromUtf8(name(id)), parts);
119 parts->models.append(m);
120 return QVariant::fromValue(static_cast<QObject *>(m));
121}
122
125{
127}
128
129//---------------------------------------------------------------------------
130
134
156 : m_delegateChooser(nullptr)
157 , m_cacheMetaType(nullptr)
158 , m_context(ctxt)
159 , m_parts(nullptr)
160 , m_filterGroup(QStringLiteral("items"))
161 , m_count(0)
162 , m_groupCount(Compositor::MinimumGroupCount)
163 , m_compositorGroup(Compositor::Cache)
164 , m_complete(false)
165 , m_delegateValidated(false)
166 , m_reset(false)
167 , m_transaction(false)
168 , m_incubatorCleanupScheduled(false)
169 , m_waitingToFetchMore(false)
170 , m_cacheItems(nullptr)
171 , m_items(nullptr)
172 , m_persistedItems(nullptr)
173{
174}
175
177{
179
180 // Free up all items in the pool
182
183 if (m_cacheMetaType)
185}
186
188{
189 // QQmlDelegateModel currently only support list models.
190 // So even if a model is a table model, only the first
191 // column will be used.
192 return m_adaptorModel.rowCount();
193}
194
196{
201 }
202}
203
205{
207 m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
208
209 m_items = new QQmlDelegateModelGroup(QStringLiteral("items"), q, Compositor::Default, q);
211 m_persistedItems = new QQmlDelegateModelGroup(QStringLiteral("persistedItems"), q, Compositor::Persisted, q);
213}
214
217{
218}
219
222{
224 d->init();
225}
226
228{
230 d->disconnectFromAbstractItemModel();
231 d->m_adaptorModel.setObject(nullptr);
232
233 for (QQmlDelegateModelItem *cacheItem : std::as_const(d->m_cache)) {
234 if (cacheItem->object) {
235 delete cacheItem->object;
236
237 cacheItem->object = nullptr;
238 cacheItem->contextData.reset();
239 cacheItem->scriptRef -= 1;
240 } else if (cacheItem->incubationTask) {
241 // Both the incubationTask and the object may hold a scriptRef,
242 // but if both are present, only one scriptRef is held in total.
243 cacheItem->scriptRef -= 1;
244 }
245
246 cacheItem->groups &= ~Compositor::UnresolvedFlag;
247 cacheItem->objectRef = 0;
248
249 if (cacheItem->incubationTask) {
250 d->releaseIncubator(cacheItem->incubationTask);
251 cacheItem->incubationTask->vdm = nullptr;
252 cacheItem->incubationTask = nullptr;
253 }
254
255 if (!cacheItem->isReferenced())
256 delete cacheItem;
257 }
258}
259
260
262{
264 if (!d->m_context)
265 d->m_context = qmlContext(this);
266}
267
269{
271 d->m_complete = true;
272
273 int defaultGroups = 0;
274 QStringList groupNames;
275 groupNames.append(QStringLiteral("items"));
276 groupNames.append(QStringLiteral("persistedItems"));
278 defaultGroups |= Compositor::DefaultFlag;
280 defaultGroups |= Compositor::PersistedFlag;
281 for (int i = Compositor::MinimumGroupCount; i < d->m_groupCount; ++i) {
282 QString name = d->m_groups[i]->name();
283 if (name.isEmpty()) {
284 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
285 --d->m_groupCount;
286 --i;
287 } else if (name.at(0).isUpper()) {
288 qmlWarning(d->m_groups[i]) << QQmlDelegateModelGroup::tr("Group names must start with a lower case letter");
289 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
290 --d->m_groupCount;
291 --i;
292 } else {
293 groupNames.append(name);
294
296 group->setModel(this, Compositor::Group(i));
297 if (group->defaultInclude)
298 defaultGroups |= (1 << i);
299 }
300 }
301
302 d->m_cacheMetaType = new QQmlDelegateModelItemMetaType(
303 d->m_context->engine()->handle(), this, groupNames);
304
305 d->m_compositor.setGroupCount(d->m_groupCount);
306 d->m_compositor.setDefaultGroups(defaultGroups);
307 d->updateFilterGroup();
308
309 while (!d->m_pendingParts.isEmpty())
310 static_cast<QQmlPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
311
313 d->m_count = d->adaptorModelCount();
314 d->m_compositor.append(
315 &d->m_adaptorModel,
316 0,
317 d->m_count,
318 defaultGroups | Compositor::AppendFlag | Compositor::PrependFlag,
319 &inserts);
320 d->itemsInserted(inserts);
321 d->emitChanges();
322 d->requestMoreIfNecessary();
323}
324
341{
342 Q_D(const QQmlDelegateModel);
343 return d->m_adaptorModel.model();
344}
345
347{
350 return;
351
352 auto aim = m_adaptorModel.aim();
353
354 qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
355 q, QQmlDelegateModel, SLOT(_q_rowsInserted(QModelIndex,int,int)));
356 qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
357 q, QQmlDelegateModel, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
358 qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
359 q, QQmlDelegateModel, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
360 qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsInserted(QModelIndex,int,int)),
361 q, QQmlDelegateModel, SLOT(_q_columnsInserted(QModelIndex,int,int)));
362 qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsRemoved(QModelIndex,int,int)),
363 q, QQmlDelegateModel, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
364 qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
365 q, QQmlDelegateModel, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
369 q, QQmlDelegateModel, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
370
371 QObject::connect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset);
374}
375
377{
380 return;
381
382 auto aim = m_adaptorModel.aim();
383
384 QObject::disconnect(aim, SIGNAL(rowsInserted(QModelIndex,int,int)),
385 q, SLOT(_q_rowsInserted(QModelIndex,int,int)));
386 QObject::disconnect(aim, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
387 q, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
388 QObject::disconnect(aim, SIGNAL(rowsRemoved(QModelIndex,int,int)),
389 q, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
390 QObject::disconnect(aim, SIGNAL(columnsInserted(QModelIndex,int,int)), q,
391 SLOT(_q_columnsInserted(QModelIndex,int,int)));
392 QObject::disconnect(aim, SIGNAL(columnsRemoved(QModelIndex,int,int)), q,
393 SLOT(_q_columnsRemoved(QModelIndex,int,int)));
394 QObject::disconnect(aim, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), q,
395 SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
397 q, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QList<int>)));
398 QObject::disconnect(aim, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
399 q, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
400 QObject::disconnect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset);
403}
404
406{
408
409 if (d->m_complete)
410 _q_itemsRemoved(0, d->m_count);
411
412 d->disconnectFromAbstractItemModel();
413 d->m_adaptorModel.setModel(model);
414 d->connectToAbstractItemModel();
415
416 d->m_adaptorModel.replaceWatchedRoles(QList<QByteArray>(), d->m_watchedRoles);
417 for (int i = 0; d->m_parts && i < d->m_parts->models.size(); ++i) {
418 d->m_adaptorModel.replaceWatchedRoles(
419 QList<QByteArray>(), d->m_parts->models.at(i)->watchedRoles());
420 }
421
422 if (d->m_complete) {
423 _q_itemsInserted(0, d->adaptorModelCount());
424 d->requestMoreIfNecessary();
425 }
426}
427
436{
437 Q_D(const QQmlDelegateModel);
438 return d->m_delegate;
439}
440
442{
444 if (d->m_transaction) {
445 qmlWarning(this) << tr("The delegate of a DelegateModel cannot be changed within onUpdated.");
446 return;
447 }
448 if (d->m_delegate == delegate)
449 return;
450 if (d->m_complete)
451 _q_itemsRemoved(0, d->m_count);
452 d->m_delegate.setObject(delegate, this);
453 d->m_delegateValidated = false;
454 if (d->m_delegateChooser)
455 QObject::disconnect(d->m_delegateChooserChanged);
456
457 d->m_delegateChooser = nullptr;
458 if (delegate) {
460 qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
461 if (adc) {
462 d->m_delegateChooser = adc;
463 d->m_delegateChooserChanged = connect(adc, &QQmlAbstractDelegateComponent::delegateChanged,
464 [d](){ d->delegateChanged(); });
465 }
466 }
467 if (d->m_complete) {
468 _q_itemsInserted(0, d->adaptorModelCount());
469 d->requestMoreIfNecessary();
470 }
472}
473
503{
504 Q_D(const QQmlDelegateModel);
505 return QVariant::fromValue(QModelIndex(d->m_adaptorModel.rootIndex));
506}
507
509{
511
512 QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
513 const bool changed = d->m_adaptorModel.rootIndex != modelIndex;
514 if (changed || !d->m_adaptorModel.isValid()) {
515 const int oldCount = d->m_count;
516 d->m_adaptorModel.rootIndex = modelIndex;
517 if (!d->m_adaptorModel.isValid() && d->m_adaptorModel.aim()) {
518 // The previous root index was invalidated, so we need to reconnect the model.
519 d->disconnectFromAbstractItemModel();
520 d->m_adaptorModel.setModel(d->m_adaptorModel.list.list());
521 d->connectToAbstractItemModel();
522 }
523 if (d->m_adaptorModel.canFetchMore())
524 d->m_adaptorModel.fetchMore();
525 if (d->m_complete) {
526 const int newCount = d->adaptorModelCount();
527 if (oldCount)
528 _q_itemsRemoved(0, oldCount);
529 if (newCount)
530 _q_itemsInserted(0, newCount);
531 }
532 if (changed)
534 }
535}
536
550{
551 Q_D(const QQmlDelegateModel);
552 return d->m_adaptorModel.modelIndex(idx);
553}
554
568{
569 Q_D(const QQmlDelegateModel);
570 return d->m_adaptorModel.parentModelIndex();
571}
572
578{
579 Q_D(const QQmlDelegateModel);
580 if (!d->m_delegate)
581 return 0;
582 return d->m_compositor.count(d->m_compositorGroup);
583}
584
585QQmlDelegateModel::ReleaseFlags QQmlDelegateModelPrivate::release(QObject *object, QQmlInstanceModel::ReusableFlag reusableFlag)
586{
587 if (!object)
588 return QQmlDelegateModel::ReleaseFlags{};
589
591 if (!cacheItem)
592 return QQmlDelegateModel::ReleaseFlags{};
593
594 if (!cacheItem->releaseObject())
596
597 if (reusableFlag == QQmlInstanceModel::Reusable) {
598 removeCacheItem(cacheItem);
600 emit q_func()->itemPooled(cacheItem->index, cacheItem->object);
602 }
603
604 destroyCacheItem(cacheItem);
606}
607
609{
610 emitDestroyingItem(cacheItem->object);
611 cacheItem->destroyObject();
612 if (cacheItem->incubationTask) {
614 cacheItem->incubationTask = nullptr;
615 }
616 cacheItem->Dispose();
617}
618
619/*
620 Returns ReleaseStatus flags.
621*/
622QQmlDelegateModel::ReleaseFlags QQmlDelegateModel::release(QObject *item, QQmlInstanceModel::ReusableFlag reusableFlag)
623{
625 QQmlInstanceModel::ReleaseFlags stat = d->release(item, reusableFlag);
626 return stat;
627}
628
629// Cancel a requested async item
631{
633 if (index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
634 qWarning() << "DelegateModel::cancel: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
635 return;
636 }
637
638 Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
639 QQmlDelegateModelItem *cacheItem = it->inCache() ? d->m_cache.at(it.cacheIndex()) : 0;
640 if (cacheItem) {
641 if (cacheItem->incubationTask && !cacheItem->isObjectReferenced()) {
642 d->releaseIncubator(cacheItem->incubationTask);
643 cacheItem->incubationTask = nullptr;
644
645 if (cacheItem->object) {
646 QObject *object = cacheItem->object;
647 cacheItem->destroyObject();
648 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
649 d->emitDestroyingPackage(package);
650 else
651 d->emitDestroyingItem(object);
652 }
653
654 cacheItem->scriptRef -= 1;
655 }
656 if (!cacheItem->isReferenced()) {
657 d->m_compositor.clearFlags(
658 Compositor::Cache, it.cacheIndex(), 1, Compositor::CacheFlag);
659 d->m_cache.removeAt(it.cacheIndex());
660 delete cacheItem;
661 Q_ASSERT(d->m_cache.size() == d->m_compositor.count(Compositor::Cache));
662 }
663 }
664}
665
668{
669 QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
670 if (d->m_complete)
671 return;
672 if (d->m_groupCount == Compositor::MaximumGroupCount) {
673 qmlWarning(d->q_func()) << QQmlDelegateModel::tr("The maximum number of supported DelegateModelGroups is 8");
674 return;
675 }
676 d->m_groups[d->m_groupCount] = group;
677 d->m_groupCount += 1;
678}
679
682{
683 QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
684 return d->m_groupCount - 1;
685}
686
689{
690 QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
691 return index >= 0 && index < d->m_groupCount - 1
692 ? d->m_groups[index + 1]
693 : nullptr;
694}
695
725{
728 this,
729 d,
733 nullptr, nullptr, nullptr);
734}
735
743{
745 return d->m_items;
746}
747
766{
768 return d->m_persistedItems;
769}
770
782{
783 Q_D(const QQmlDelegateModel);
784 return d->m_filterGroup;
785}
786
788{
790
791 if (d->m_transaction) {
792 qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged");
793 return;
794 }
795
796 if (d->m_filterGroup != group) {
797 d->m_filterGroup = group;
798 d->updateFilterGroup();
800 }
801}
802
804{
806}
807
809{
811 if (!m_cacheMetaType)
812 return;
813
815 m_compositorGroup = Compositor::Default;
816 for (int i = 1; i < m_groupCount; ++i) {
817 if (m_filterGroup == m_cacheMetaType->groupNames.at(i - 1)) {
818 m_compositorGroup = Compositor::Group(i);
819 break;
820 }
821 }
822
824 if (m_compositorGroup != previousGroup) {
827 m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
828
829 QQmlChangeSet changeSet;
830 changeSet.move(removes, inserts);
831 emit q->modelUpdated(changeSet, false);
832
833 if (changeSet.difference() != 0)
834 emit q->countChanged();
835
836 if (m_parts) {
837 auto partsCopy = m_parts->models; // deliberate; this may alter m_parts
838 for (QQmlPartsModel *model : std::as_const(partsCopy))
839 model->updateFilterGroup(m_compositorGroup, changeSet);
840 }
841 }
842}
843
873{
875 if (!d->m_parts)
876 d->m_parts = new QQmlDelegateModelParts(this);
877 return d->m_parts;
878}
879
881{
882 Q_D(const QQmlDelegateModel);
883 return d->m_adaptorModel.adaptsAim() ? d->m_adaptorModel.aim() : nullptr;
884}
885
887{
888 for (int i = 1; i < m_groupCount; ++i)
890}
891
893{
894 for (int i = 1; i < m_groupCount; ++i)
895 QQmlDelegateModelGroupPrivate::get(m_groups[i])->initPackage(incubationTask->index[i], package);
896}
897
899{
900 for (int i = 1; i < m_groupCount; ++i)
902}
903
905{
906 return status == QQmlIncubator::Ready || status == QQmlIncubator::Error;
907}
908
910{
911 // QQmlObjectCreator produces a private internal context.
912 // We can always attach the extra object there.
913 QQmlData *d = QQmlData::get(object);
914 if (auto contextData = d ? d->context : nullptr)
915 contextData->setExtraObject(modelItemToIncubate);
916
917 Q_ASSERT(modelItemToIncubate->delegate);
918 const bool isBound = QQmlComponentPrivate::get(modelItemToIncubate->delegate)->isBound();
919
920 auto incubatorPriv = QQmlIncubatorPrivate::get(this);
921 if (incubatorPriv->hadTopLevelRequiredProperties()) {
922 // If we have required properties, we clear the context object
923 // so that the model role names are not polluting the context.
924 // Unless the context is bound, in which case we have never set the context object.
925 if (incubating && !isBound) {
928 }
929 if (proxyContext) {
931 }
932
933 // Retrieve the metaObject before the potential return so that the accessors have a chance
934 // to perform some finalization in case they produce a dynamic metaobject. Here we know for
935 // sure that we are using required properties.
936 const QMetaObject *qmlMetaObject = modelItemToIncubate->metaObject();
937
938 if (incubatorPriv->requiredProperties()->empty())
939 return;
940 RequiredProperties *requiredProperties = incubatorPriv->requiredProperties();
941
942 // if a required property was not in the model, it might still be a static property of the
943 // QQmlDelegateModelItem or one of its derived classes this is the case for index, row,
944 // column, model and more
945 // the most derived subclasses of QQmlDelegateModelItem are QQmlDMAbstractItemModelData and
946 // QQmlDMObjectData at depth 2, so 4 should be plenty
948 // we first check the dynamic meta object for properties originating from the model
949 // contains abstractitemmodelproperties
950 mos.push_back(qMakePair(qmlMetaObject, modelItemToIncubate));
951 auto delegateModelItemSubclassMO = qmlMetaObject->superClass();
952 mos.push_back(qMakePair(delegateModelItemSubclassMO, modelItemToIncubate));
953
954 while (strcmp(delegateModelItemSubclassMO->className(),
955 modelItemToIncubate->staticMetaObject.className())) {
956 delegateModelItemSubclassMO = delegateModelItemSubclassMO->superClass();
957 mos.push_back(qMakePair(delegateModelItemSubclassMO, modelItemToIncubate));
958 }
959 if (proxiedObject)
960 mos.push_back(qMakePair(proxiedObject->metaObject(), proxiedObject));
961
962 QQmlEngine *engine = QQmlEnginePrivate::get(incubatorPriv->enginePriv);
964 QV4::Scope scope(v4);
965
966 for (const auto &metaObjectAndObject : mos) {
967 const QMetaObject *mo = metaObjectAndObject.first;
968 QObject *itemOrProxy = metaObjectAndObject.second;
970
971 for (int i = mo->propertyOffset(); i < mo->propertyCount() + mo->propertyOffset(); ++i) {
972 auto prop = mo->property(i);
973 if (!prop.name())
974 continue;
975 const QString propName = QString::fromUtf8(prop.name());
976 bool wasInRequired = false;
978 object, propName, requiredProperties,
979 engine, &wasInRequired);
980 if (wasInRequired) {
981 QQmlAnyBinding binding;
982 binding = new QQmlPropertyToPropertyBinding(
983 engine, itemOrProxy, i, targetProp.object(), targetProp.index());
984 binding.installOn(targetProp);
985 }
986 }
987 }
988 } else {
989 if (!isBound)
990 modelItemToIncubate->contextData->setContextObject(modelItemToIncubate);
991 if (proxiedObject)
993
994 // Retrieve the metaObject() once so that the accessors have a chance to perform some
995 // finalization in case they produce a dynamic metaobject. For example, they might be
996 // inclined to create a propertyCache now because there are no required properties and any
997 // revisioned properties should be hidden after all. Here is the first time we know for
998 // sure whether we are using context properties.
999 modelItemToIncubate->metaObject();
1000 }
1001}
1002
1004{
1005 if (vdm) {
1007 } else if (isDoneIncubating(status)) {
1009 // The model was deleted from under our feet, cleanup ourselves
1010 delete incubating->object;
1011 incubating->object = nullptr;
1013 incubating->scriptRef = 0;
1015 }
1016}
1017
1019{
1020 Q_Q(QQmlDelegateModel);
1021 if (!incubationTask->isError())
1022 incubationTask->clear();
1023 m_finishedIncubating.append(incubationTask);
1027 }
1028}
1029
1031{
1032 Q_ASSERT(item->object);
1033
1034 // Update/reset which groups the item belongs to
1035 item->groups = newGroups;
1036
1037 // Update context property index (including row and column) on the delegate
1038 // item, and inform the application about it. For a list, the row is the same
1039 // as the index, and the column is always 0. We set alwaysEmit to true, to
1040 // force all bindings to be reevaluated, even if the index didn't change.
1041 const bool alwaysEmit = true;
1042 item->setModelIndex(newModelIndex, newModelIndex, 0, alwaysEmit);
1043
1044 // Notify the application that all 'dynamic'/role-based context data has
1045 // changed as well (their getter function will use the updated index).
1046 auto const itemAsList = QList<QQmlDelegateModelItem *>() << item;
1047 auto const updateAllRoles = QVector<int>();
1048 m_adaptorModel.notify(itemAsList, newModelIndex, 1, updateAllRoles);
1049
1050 if (QQmlDelegateModelAttached *att = static_cast<QQmlDelegateModelAttached *>(
1051 qmlAttachedPropertiesObject<QQmlDelegateModel>(item->object, false))) {
1052 // Update currentIndex of the attached DelegateModel object
1053 // to the index the item has in the cache.
1054 att->resetCurrentIndex();
1055 // emitChanges will emit both group-, and index changes to the application
1056 att->emitChanges();
1057 }
1058
1059 // Inform the view that the item is recycled. This will typically result
1060 // in the view updating its own attached delegate item properties.
1061 emit q_func()->itemReused(newModelIndex, item->object);
1062}
1063
1065{
1066 m_reusableItemsPool.drain(maxPoolTime, [this](QQmlDelegateModelItem *cacheItem){ destroyCacheItem(cacheItem); });
1067}
1068
1070{
1071 d_func()->drainReusableItemsPool(maxPoolTime);
1072}
1073
1075{
1076 return d_func()->m_reusableItemsPool.size();
1077}
1078
1080{
1081 if (!m_delegateChooser)
1082 return m_delegate;
1083
1084 QQmlComponent *delegate = nullptr;
1086
1087 do {
1088 delegate = chooser->delegate(&m_adaptorModel, index);
1089 chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
1090 } while (chooser);
1091
1092 return delegate;
1093}
1094
1096{
1097 m_cache.insert(it.cacheIndex(), item);
1098 m_compositor.setFlags(it, 1, Compositor::CacheFlag);
1099 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1100}
1101
1103{
1104 int cidx = m_cache.lastIndexOf(cacheItem);
1105 if (cidx >= 0) {
1106 m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
1107 m_cache.removeAt(cidx);
1108 }
1109 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1110}
1111
1113{
1114 if (!isDoneIncubating(status))
1115 return;
1116
1117 const QList<QQmlError> incubationTaskErrors = incubationTask->errors();
1118
1119 QQmlDelegateModelItem *cacheItem = incubationTask->incubating;
1120 cacheItem->incubationTask = nullptr;
1121 incubationTask->incubating = nullptr;
1122 releaseIncubator(incubationTask);
1123
1124 if (status == QQmlIncubator::Ready) {
1125 cacheItem->referenceObject();
1126 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
1127 emitCreatedPackage(incubationTask, package);
1128 else
1129 emitCreatedItem(incubationTask, cacheItem->object);
1130 cacheItem->releaseObject();
1131 } else if (status == QQmlIncubator::Error) {
1132 qmlInfo(m_delegate, incubationTaskErrors + m_delegate->errors()) << "Cannot create delegate";
1133 }
1134
1135 if (!cacheItem->isObjectReferenced()) {
1136 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
1137 emitDestroyingPackage(package);
1138 else
1139 emitDestroyingItem(cacheItem->object);
1140 delete cacheItem->object;
1141 cacheItem->object = nullptr;
1142 cacheItem->scriptRef -= 1;
1143 cacheItem->contextData.reset();
1144
1145 if (!cacheItem->isReferenced()) {
1146 removeCacheItem(cacheItem);
1147 delete cacheItem;
1148 }
1149 }
1150}
1151
1153{
1154 vdm->setInitialState(this, o);
1155}
1156
1158{
1159 QQmlDelegateModelItem *cacheItem = incubationTask->incubating;
1160 incubationTask->initializeRequiredProperties(incubationTask->incubating, o);
1161 cacheItem->object = o;
1162
1163 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
1164 emitInitPackage(incubationTask, package);
1165 else
1166 emitInitItem(incubationTask, cacheItem->object);
1167}
1168
1170{
1172 = qobject_cast<QQmlAdaptorModelProxyInterface *>(cacheItem);
1173 if (!proxy)
1174 return cacheItem->contextData;
1175
1177 QObject *proxied = proxy->proxiedObject();
1178 cacheItem->incubationTask->proxiedObject = proxied;
1179 cacheItem->incubationTask->proxyContext = ctxt;
1180 ctxt->setContextObject(cacheItem);
1181 // We don't own the proxied object. We need to clear it if it goes away.
1184 return ctxt;
1185}
1186
1188{
1189 if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
1190 qWarning() << "DelegateModel::item: index out range" << index << m_compositor.count(group);
1191 return nullptr;
1192 } else if (!m_context || !m_context->isValid()) {
1193 return nullptr;
1194 }
1195
1196 Compositor::iterator it = m_compositor.find(group, index);
1197 const auto flags = it->flags;
1198 const auto modelIndex = it.modelIndex();
1199
1200 QQmlDelegateModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex()) : 0;
1201
1202 if (!cacheItem || !cacheItem->delegate) {
1203 QQmlComponent *delegate = resolveDelegate(modelIndex);
1204 if (!delegate)
1205 return nullptr;
1206
1207 if (!cacheItem) {
1208 cacheItem = m_reusableItemsPool.takeItem(delegate, index);
1209 if (cacheItem) {
1210 // Move the pooled item back into the cache, update
1211 // all related properties, and return the object (which
1212 // has already been incubated, otherwise it wouldn't be in the pool).
1213 addCacheItem(cacheItem, it);
1214 reuseItem(cacheItem, index, flags);
1215 cacheItem->referenceObject();
1216 return cacheItem->object;
1217 }
1218
1219 // Since we could't find an available item in the pool, we create a new one
1220 cacheItem = m_adaptorModel.createItem(m_cacheMetaType, modelIndex);
1221 if (!cacheItem)
1222 return nullptr;
1223
1224 cacheItem->groups = flags;
1225 addCacheItem(cacheItem, it);
1226 }
1227
1228 cacheItem->delegate = delegate;
1229 }
1230
1231 // Bump the reference counts temporarily so neither the content data or the delegate object
1232 // are deleted if incubatorStatusChanged() is called synchronously.
1233 cacheItem->scriptRef += 1;
1234 cacheItem->referenceObject();
1235
1236 if (cacheItem->incubationTask) {
1237 bool sync = (incubationMode == QQmlIncubator::Synchronous || incubationMode == QQmlIncubator::AsynchronousIfNested);
1238 if (sync && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) {
1239 // previously requested async - now needed immediately
1240 cacheItem->incubationTask->forceCompletion();
1241 }
1242 } else if (!cacheItem->object) {
1243 QQmlContext *creationContext = cacheItem->delegate->creationContext();
1244
1245 cacheItem->scriptRef += 1;
1246
1247 cacheItem->incubationTask = new QQDMIncubationTask(this, incubationMode);
1248 cacheItem->incubationTask->incubating = cacheItem;
1249 cacheItem->incubationTask->clear();
1250
1251 for (int i = 1; i < m_groupCount; ++i)
1252 cacheItem->incubationTask->index[i] = it.index[i];
1253
1254 const QQmlRefPointer<QQmlContextData> componentContext
1255 = QQmlContextData::get(creationContext ? creationContext : m_context.data());
1257
1258 if (cp->isBound()) {
1259 cacheItem->contextData = componentContext;
1260
1261 // Ignore return value of initProxy. We want to know the proxy when assigning required
1262 // properties, but we don't want it to pollute our context. The context is bound.
1264 initProxy(cacheItem);
1265
1266 cp->incubateObject(
1267 cacheItem->incubationTask,
1268 cacheItem->delegate,
1269 m_context->engine(),
1270 componentContext,
1272 } else {
1274 = QQmlContextData::createRefCounted(componentContext);
1275 ctxt->setContextObject(cacheItem);
1276 cacheItem->contextData = ctxt;
1277
1279 ctxt = initProxy(cacheItem);
1280
1281 cp->incubateObject(
1282 cacheItem->incubationTask,
1283 cacheItem->delegate,
1284 m_context->engine(),
1285 ctxt,
1287 }
1288 }
1289
1290 if (index == m_compositor.count(group) - 1)
1292
1293 // Remove the temporary reference count.
1294 cacheItem->scriptRef -= 1;
1295 if (cacheItem->object && (!cacheItem->incubationTask || isDoneIncubating(cacheItem->incubationTask->status())))
1296 return cacheItem->object;
1297
1298 if (cacheItem->objectRef > 0)
1299 cacheItem->releaseObject();
1300
1301 if (!cacheItem->isReferenced()) {
1302 removeCacheItem(cacheItem);
1303 delete cacheItem;
1304 }
1305
1306 return nullptr;
1307}
1308
1309/*
1310 If asynchronous is true or the component is being loaded asynchronously due
1311 to an ancestor being loaded asynchronously, object() may return 0. In this
1312 case createdItem() will be emitted when the object is available. The object
1313 at this stage does not have any references, so object() must be called again
1314 to ensure a reference is held. Any call to object() which returns a valid object
1315 must be matched by a call to release() in order to destroy the object.
1316*/
1318{
1319 Q_D(QQmlDelegateModel);
1320 if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
1321 qWarning() << "DelegateModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
1322 return nullptr;
1323 }
1324
1325 return d->object(d->m_compositorGroup, index, incubationMode);
1326}
1327
1329{
1330 Q_D(QQmlDelegateModel);
1331 if (d->m_compositor.count(d->m_compositorGroup) <= index)
1332 return QQmlIncubator::Null;
1333 Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
1334 if (!it->inCache())
1335 return QQmlIncubator::Null;
1336
1337 if (auto incubationTask = d->m_cache.at(it.cacheIndex())->incubationTask)
1338 return incubationTask->status();
1339
1340 return QQmlIncubator::Ready;
1341}
1342
1344{
1345 Compositor::iterator it = m_compositor.find(group, index);
1346 if (QQmlAdaptorModel *model = it.list<QQmlAdaptorModel>()) {
1347 QString role = name;
1348 int dot = name.indexOf(QLatin1Char('.'));
1349 if (dot > 0)
1350 role = name.left(dot);
1351 QVariant value = model->value(it.modelIndex(), role);
1352 while (dot > 0) {
1353 QObject *obj = qvariant_cast<QObject*>(value);
1354 if (!obj)
1355 return QVariant();
1356 const int from = dot + 1;
1357 dot = name.indexOf(QLatin1Char('.'), from);
1358 value = obj->property(QStringView{name}.mid(from, dot - from).toUtf8());
1359 }
1360 return value;
1361 }
1362 return QVariant();
1363}
1364
1366{
1367 Q_D(QQmlDelegateModel);
1368 return d->variantValue(d->m_compositorGroup, index, role);
1369}
1370
1372{
1373 Q_D(const QQmlDelegateModel);
1375 return cacheItem->groupIndex(d->m_compositorGroup);
1376 return -1;
1377}
1378
1380{
1381 Q_D(QQmlDelegateModel);
1382 d->m_adaptorModel.replaceWatchedRoles(d->m_watchedRoles, roles);
1383 d->m_watchedRoles = roles;
1384}
1385
1387 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1388{
1390 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1391 itemsInserted(inserts);
1392 emitChanges();
1393}
1394
1396 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1397{
1399 m_compositor.clearFlags(from, count, group, groupFlags, &removes);
1400 itemsRemoved(removes);
1401 emitChanges();
1402}
1403
1405 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1406{
1409
1410 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1411 itemsInserted(inserts);
1412 const int removeFlags = ~groupFlags & Compositor::GroupMask;
1413
1414 from = m_compositor.find(from.group, from.index[from.group]);
1415 m_compositor.clearFlags(from, count, group, removeFlags, &removes);
1416 itemsRemoved(removes);
1417 emitChanges();
1418}
1419
1421{
1422 Q_D(QQmlDelegateModel);
1423 if (e->type() == QEvent::UpdateRequest) {
1424 d->m_waitingToFetchMore = false;
1425 d->m_adaptorModel.fetchMore();
1426 } else if (e->type() == QEvent::User) {
1427 d->m_incubatorCleanupScheduled = false;
1428 qDeleteAll(d->m_finishedIncubating);
1429 d->m_finishedIncubating.clear();
1430 }
1432}
1433
1435{
1436 if (!m_delegate)
1437 return;
1438
1439 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
1440
1441 for (const Compositor::Change &change : changes) {
1442 for (int i = 1; i < m_groupCount; ++i) {
1443 if (change.inGroup(i)) {
1444 translatedChanges[i].append(QQmlChangeSet::Change(change.index[i], change.count));
1445 }
1446 }
1447 }
1448
1449 for (int i = 1; i < m_groupCount; ++i)
1451}
1452
1453void QQmlDelegateModel::_q_itemsChanged(int index, int count, const QVector<int> &roles)
1454{
1455 Q_D(QQmlDelegateModel);
1456 if (count <= 0 || !d->m_complete)
1457 return;
1458
1459 if (d->m_adaptorModel.notify(d->m_cache, index, count, roles)) {
1461 d->m_compositor.listItemsChanged(&d->m_adaptorModel, index, count, &changes);
1462 d->itemsChanged(changes);
1463 d->emitChanges();
1464 }
1465}
1466
1467static void incrementIndexes(QQmlDelegateModelItem *cacheItem, int count, const int *deltas)
1468{
1469 if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1470 for (int i = 1; i < count; ++i)
1471 incubationTask->index[i] += deltas[i];
1472 }
1473 if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
1474 for (int i = 1; i < qMin<int>(count, Compositor::MaximumGroupCount); ++i)
1475 attached->m_currentIndex[i] += deltas[i];
1476 }
1477}
1478
1480 const QVector<Compositor::Insert> &inserts,
1481 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedInserts,
1482 QHash<int, QList<QQmlDelegateModelItem *> > *movedItems)
1483{
1484 int cacheIndex = 0;
1485
1486 int inserted[Compositor::MaximumGroupCount];
1487 for (int i = 1; i < m_groupCount; ++i)
1488 inserted[i] = 0;
1489
1490 for (const Compositor::Insert &insert : inserts) {
1491 for (; cacheIndex < insert.cacheIndex(); ++cacheIndex)
1492 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1493
1494 for (int i = 1; i < m_groupCount; ++i) {
1495 if (insert.inGroup(i)) {
1496 (*translatedInserts)[i].append(
1497 QQmlChangeSet::Change(insert.index[i], insert.count, insert.moveId));
1498 inserted[i] += insert.count;
1499 }
1500 }
1501
1502 if (!insert.inCache())
1503 continue;
1504
1505 if (movedItems && insert.isMove()) {
1506 QList<QQmlDelegateModelItem *> items = movedItems->take(insert.moveId);
1507 Q_ASSERT(items.size() == insert.count);
1508 m_cache = m_cache.mid(0, insert.cacheIndex())
1509 + items + m_cache.mid(insert.cacheIndex());
1510 }
1511 if (insert.inGroup()) {
1512 for (int offset = 0; cacheIndex < insert.cacheIndex() + insert.count;
1513 ++cacheIndex, ++offset) {
1514 QQmlDelegateModelItem *cacheItem = m_cache.at(cacheIndex);
1515 cacheItem->groups |= insert.flags & Compositor::GroupMask;
1516
1517 if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1518 for (int i = 1; i < m_groupCount; ++i)
1519 incubationTask->index[i] = cacheItem->groups & (1 << i)
1520 ? insert.index[i] + offset
1521 : insert.index[i];
1522 }
1523 if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
1524 for (int i = 1; i < m_groupCount; ++i)
1525 attached->m_currentIndex[i] = cacheItem->groups & (1 << i)
1526 ? insert.index[i] + offset
1527 : insert.index[i];
1528 }
1529 }
1530 } else {
1531 cacheIndex = insert.cacheIndex() + insert.count;
1532 }
1533 }
1534 for (const QList<QQmlDelegateModelItem *> cache = m_cache; cacheIndex < cache.size(); ++cacheIndex)
1535 incrementIndexes(cache.at(cacheIndex), m_groupCount, inserted);
1536}
1537
1539{
1540 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1541 itemsInserted(inserts, &translatedInserts);
1542 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1543 if (!m_delegate)
1544 return;
1545
1546 for (int i = 1; i < m_groupCount; ++i)
1548}
1549
1550void QQmlDelegateModel::_q_itemsInserted(int index, int count)
1551{
1552
1553 Q_D(QQmlDelegateModel);
1554 if (count <= 0 || !d->m_complete)
1555 return;
1556
1557 d->m_count += count;
1558
1559 const QList<QQmlDelegateModelItem *> cache = d->m_cache;
1560 for (int i = 0, c = cache.size(); i < c; ++i) {
1562 // layout change triggered by changing the modelIndex might have
1563 // already invalidated this item in d->m_cache and deleted it.
1564 if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
1565 continue;
1566
1567 if (item->modelIndex() >= index) {
1568 const int newIndex = item->modelIndex() + count;
1569 const int row = newIndex;
1570 const int column = 0;
1571 item->setModelIndex(newIndex, row, column);
1572 }
1573 }
1574
1576 d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
1577 d->itemsInserted(inserts);
1578 d->emitChanges();
1579}
1580
1581//### This method should be split in two. It will remove delegates, and it will re-render the list.
1582// When e.g. QQmlListModel::remove is called, the removal of the delegates should be done on
1583// QAbstractItemModel::rowsAboutToBeRemoved, and the re-rendering on
1584// QAbstractItemModel::rowsRemoved. Currently both are done on the latter signal. The problem is
1585// that the destruction of an item will emit a changed signal that ends up at the delegate, which
1586// in turn will try to load the data from the model (which should have already freed it), resulting
1587// in a use-after-free. See QTBUG-59256.
1589 const QVector<Compositor::Remove> &removes,
1590 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves,
1591 QHash<int, QList<QQmlDelegateModelItem *> > *movedItems)
1592{
1593 int cacheIndex = 0;
1594 int removedCache = 0;
1595
1596 int removed[Compositor::MaximumGroupCount];
1597 for (int i = 1; i < m_groupCount; ++i)
1598 removed[i] = 0;
1599
1600 for (const Compositor::Remove &remove : removes) {
1601 for (; cacheIndex < remove.cacheIndex() && cacheIndex < m_cache.size(); ++cacheIndex)
1602 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1603
1604 for (int i = 1; i < m_groupCount; ++i) {
1605 if (remove.inGroup(i)) {
1606 (*translatedRemoves)[i].append(
1607 QQmlChangeSet::Change(remove.index[i], remove.count, remove.moveId));
1608 removed[i] -= remove.count;
1609 }
1610 }
1611
1612 if (!remove.inCache())
1613 continue;
1614
1615 if (movedItems && remove.isMove()) {
1616 movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex(), remove.count));
1620 } else {
1621 for (; cacheIndex < remove.cacheIndex() + remove.count - removedCache; ++cacheIndex) {
1622 QQmlDelegateModelItem *cacheItem = m_cache.at(cacheIndex);
1623 if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
1624 QObject *object = cacheItem->object;
1625 cacheItem->destroyObject();
1626 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
1627 emitDestroyingPackage(package);
1628 else
1629 emitDestroyingItem(object);
1630 cacheItem->scriptRef -= 1;
1631 }
1632 if (!cacheItem->isReferenced() && !remove.inGroup(Compositor::Persisted)) {
1633 m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1634 m_cache.removeAt(cacheIndex);
1635 delete cacheItem;
1636 --cacheIndex;
1637 ++removedCache;
1638 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1639 } else if (remove.groups() == cacheItem->groups) {
1640 cacheItem->groups = 0;
1641 if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1642 for (int i = 1; i < m_groupCount; ++i)
1643 incubationTask->index[i] = -1;
1644 }
1645 if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
1646 for (int i = 1; i < m_groupCount; ++i)
1647 attached->m_currentIndex[i] = -1;
1648 }
1649 } else {
1650 if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1651 if (!cacheItem->isObjectReferenced()) {
1652 releaseIncubator(cacheItem->incubationTask);
1653 cacheItem->incubationTask = nullptr;
1654 if (cacheItem->object) {
1655 QObject *object = cacheItem->object;
1656 cacheItem->destroyObject();
1657 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
1658 emitDestroyingPackage(package);
1659 else
1660 emitDestroyingItem(object);
1661 }
1662 cacheItem->scriptRef -= 1;
1663 } else {
1664 for (int i = 1; i < m_groupCount; ++i) {
1665 if (remove.inGroup(i))
1666 incubationTask->index[i] = remove.index[i];
1667 }
1668 }
1669 }
1670 if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
1671 for (int i = 1; i < m_groupCount; ++i) {
1672 if (remove.inGroup(i))
1673 attached->m_currentIndex[i] = remove.index[i];
1674 }
1675 }
1676 cacheItem->groups &= ~remove.flags;
1677 }
1678 }
1679 }
1680 }
1681
1682 for (const QList<QQmlDelegateModelItem *> cache = m_cache; cacheIndex < cache.size(); ++cacheIndex)
1683 incrementIndexes(cache.at(cacheIndex), m_groupCount, removed);
1684}
1685
1687{
1688 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1689 itemsRemoved(removes, &translatedRemoves);
1690 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1691 if (!m_delegate)
1692 return;
1693
1694 for (int i = 1; i < m_groupCount; ++i)
1696}
1697
1698void QQmlDelegateModel::_q_itemsRemoved(int index, int count)
1699{
1700 Q_D(QQmlDelegateModel);
1701 if (count <= 0|| !d->m_complete)
1702 return;
1703
1704 d->m_count -= count;
1705 Q_ASSERT(d->m_count >= 0);
1706 const QList<QQmlDelegateModelItem *> cache = d->m_cache;
1707 //Prevents items being deleted in remove loop
1709 item->referenceObject();
1710
1711 for (int i = 0, c = cache.size(); i < c; ++i) {
1713 // layout change triggered by removal of a previous item might have
1714 // already invalidated this item in d->m_cache and deleted it
1715 if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
1716 continue;
1717
1718 if (item->modelIndex() >= index + count) {
1719 const int newIndex = item->modelIndex() - count;
1720 const int row = newIndex;
1721 const int column = 0;
1722 item->setModelIndex(newIndex, row, column);
1723 } else if (item->modelIndex() >= index) {
1724 item->setModelIndex(-1, -1, -1);
1725 }
1726 }
1727 //Release items which are referenced before the loop
1729 item->releaseObject();
1730
1732 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
1733 d->itemsRemoved(removes);
1734
1735 d->emitChanges();
1736}
1737
1739 const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1740{
1742
1743 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1744 itemsRemoved(removes, &translatedRemoves, &movedItems);
1745
1746 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1747 itemsInserted(inserts, &translatedInserts, &movedItems);
1748 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1749 Q_ASSERT(movedItems.isEmpty());
1750 if (!m_delegate)
1751 return;
1752
1753 for (int i = 1; i < m_groupCount; ++i) {
1755 translatedRemoves.at(i),
1756 translatedInserts.at(i));
1757 }
1758}
1759
1760void QQmlDelegateModel::_q_itemsMoved(int from, int to, int count)
1761{
1762 Q_D(QQmlDelegateModel);
1763 if (count <= 0 || !d->m_complete)
1764 return;
1765
1766 const int minimum = qMin(from, to);
1767 const int maximum = qMax(from, to) + count;
1768 const int difference = from > to ? count : -count;
1769
1770 const QList<QQmlDelegateModelItem *> cache = d->m_cache;
1771 for (int i = 0, c = cache.size(); i < c; ++i) {
1773 // layout change triggered by changing the modelIndex might have
1774 // already invalidated this item in d->m_cache and deleted it.
1775 if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
1776 continue;
1777
1778 if (item->modelIndex() >= from && item->modelIndex() < from + count) {
1779 const int newIndex = item->modelIndex() - from + to;
1780 const int row = newIndex;
1781 const int column = 0;
1782 item->setModelIndex(newIndex, row, column);
1783 } else if (item->modelIndex() >= minimum && item->modelIndex() < maximum) {
1784 const int newIndex = item->modelIndex() + difference;
1785 const int row = newIndex;
1786 const int column = 0;
1787 item->setModelIndex(newIndex, row, column);
1788 }
1789 }
1790
1793 d->m_compositor.listItemsMoved(&d->m_adaptorModel, from, to, count, &removes, &inserts);
1794 d->itemsMoved(removes, inserts);
1795 d->emitChanges();
1796}
1797
1799{
1800 Q_Q(QQmlDelegateModel);
1801 emit q->modelUpdated(changeSet, reset);
1802 if (changeSet.difference() != 0)
1803 emit q->countChanged();
1804}
1805
1807{
1808 Q_Q(QQmlDelegateModel);
1809 if (!m_complete)
1810 return;
1811
1812 if (m_transaction) {
1813 qmlWarning(q) << QQmlDelegateModel::tr("The delegates of a DelegateModel cannot be changed within onUpdated.");
1814 return;
1815 }
1816
1817 if (remove) {
1818 for (int i = 1; i < m_groupCount; ++i) {
1820 0, m_compositor.count(Compositor::Group(i)));
1821 }
1822 }
1823 if (add) {
1824 for (int i = 1; i < m_groupCount; ++i) {
1826 0, m_compositor.count(Compositor::Group(i)));
1827 }
1828 }
1829 emitChanges();
1830}
1831
1833{
1835 return;
1836
1837 m_transaction = true;
1839 for (int i = 1; i < m_groupCount; ++i)
1841 m_transaction = false;
1842
1843 const bool reset = m_reset;
1844 m_reset = false;
1845 for (int i = 1; i < m_groupCount; ++i)
1847
1848 // emitChanges may alter m_cache and delete items
1850 attachedObjects.reserve(m_cache.length());
1851 for (const QQmlDelegateModelItem *cacheItem : std::as_const(m_cache))
1852 attachedObjects.append(cacheItem->attached);
1853
1854 for (const QPointer<QQmlDelegateModelAttached> &attached : std::as_const(attachedObjects)) {
1855 if (attached && attached->m_cacheItem)
1856 attached->emitChanges();
1857 }
1858}
1859
1860void QQmlDelegateModel::_q_modelAboutToBeReset()
1861{
1862 auto aim = static_cast<QAbstractItemModel *>(sender());
1863 auto oldRoleNames = aim->roleNames();
1864 // this relies on the fact that modelAboutToBeReset must be followed
1865 // by a modelReset signal before any further modelAboutToBeReset can occur
1866 QObject::connect(aim, &QAbstractItemModel::modelReset, this, [&, oldRoleNames](){
1867 auto aim = static_cast<QAbstractItemModel *>(sender());
1868 if (oldRoleNames == aim->roleNames()) {
1869 // if the rolenames stayed the same (most common case), then we don't have
1870 // to throw away all the setup that we did
1871 handleModelReset();
1872 } else {
1873 // If they did change, we give up and just start from scratch via setMode
1875 // but we still have to call handleModelReset, otherwise views will
1876 // not refresh
1877 handleModelReset();
1878 }
1880}
1881
1882void QQmlDelegateModel::handleModelReset()
1883{
1884 Q_D(QQmlDelegateModel);
1885 if (!d->m_delegate)
1886 return;
1887
1888 int oldCount = d->m_count;
1889 d->m_adaptorModel.rootIndex = QModelIndex();
1890
1891 if (d->m_complete) {
1892 d->m_count = d->adaptorModelCount();
1893
1894 const QList<QQmlDelegateModelItem *> cache = d->m_cache;
1896 item->referenceObject();
1897
1898 for (int i = 0, c = cache.size(); i < c; ++i) {
1900 // layout change triggered by changing the modelIndex might have
1901 // already invalidated this item in d->m_cache and deleted it.
1902 if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
1903 continue;
1904
1905 if (item->modelIndex() != -1)
1906 item->setModelIndex(-1, -1, -1);
1907 }
1908
1910 item->releaseObject();
1913 if (oldCount)
1914 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
1915 if (d->m_count)
1916 d->m_compositor.listItemsInserted(&d->m_adaptorModel, 0, d->m_count, &inserts);
1917 d->itemsMoved(removes, inserts);
1918 d->m_reset = true;
1919
1920 if (d->m_adaptorModel.canFetchMore())
1921 d->m_adaptorModel.fetchMore();
1922
1923 d->emitChanges();
1924 }
1926}
1927
1928void QQmlDelegateModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
1929{
1930 Q_D(QQmlDelegateModel);
1931 if (parent == d->m_adaptorModel.rootIndex)
1932 _q_itemsInserted(begin, end - begin + 1);
1933}
1934
1935void QQmlDelegateModel::_q_rowsAboutToBeRemoved(const QModelIndex &parent, int begin, int end)
1936{
1937 Q_D(QQmlDelegateModel);
1938 if (!d->m_adaptorModel.rootIndex.isValid())
1939 return;
1940 const QModelIndex index = d->m_adaptorModel.rootIndex;
1941 if (index.parent() == parent && index.row() >= begin && index.row() <= end) {
1942 const int oldCount = d->m_count;
1943 d->m_count = 0;
1944 d->disconnectFromAbstractItemModel();
1945 d->m_adaptorModel.invalidateModel();
1946
1947 if (d->m_complete && oldCount > 0) {
1949 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
1950 d->itemsRemoved(removes);
1951 d->emitChanges();
1952 }
1953 }
1954}
1955
1956void QQmlDelegateModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
1957{
1958 Q_D(QQmlDelegateModel);
1959 if (parent == d->m_adaptorModel.rootIndex)
1960 _q_itemsRemoved(begin, end - begin + 1);
1961}
1962
1963void QQmlDelegateModel::_q_rowsMoved(
1964 const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
1965 const QModelIndex &destinationParent, int destinationRow)
1966{
1967 Q_D(QQmlDelegateModel);
1968 const int count = sourceEnd - sourceStart + 1;
1969 if (destinationParent == d->m_adaptorModel.rootIndex && sourceParent == d->m_adaptorModel.rootIndex) {
1970 _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow - count, count);
1971 } else if (sourceParent == d->m_adaptorModel.rootIndex) {
1972 _q_itemsRemoved(sourceStart, count);
1973 } else if (destinationParent == d->m_adaptorModel.rootIndex) {
1974 _q_itemsInserted(destinationRow, count);
1975 }
1976}
1977
1978void QQmlDelegateModel::_q_columnsInserted(const QModelIndex &parent, int begin, int end)
1979{
1980 Q_D(QQmlDelegateModel);
1981 Q_UNUSED(end);
1982 if (parent == d->m_adaptorModel.rootIndex && begin == 0) {
1983 // mark all items as changed
1984 _q_itemsChanged(0, d->m_count, QVector<int>());
1985 }
1986}
1987
1988void QQmlDelegateModel::_q_columnsRemoved(const QModelIndex &parent, int begin, int end)
1989{
1990 Q_D(QQmlDelegateModel);
1991 Q_UNUSED(end);
1992 if (parent == d->m_adaptorModel.rootIndex && begin == 0) {
1993 // mark all items as changed
1994 _q_itemsChanged(0, d->m_count, QVector<int>());
1995 }
1996}
1997
1998void QQmlDelegateModel::_q_columnsMoved(const QModelIndex &parent, int start, int end,
1999 const QModelIndex &destination, int column)
2000{
2001 Q_D(QQmlDelegateModel);
2002 Q_UNUSED(end);
2003 if ((parent == d->m_adaptorModel.rootIndex && start == 0)
2004 || (destination == d->m_adaptorModel.rootIndex && column == 0)) {
2005 // mark all items as changed
2006 _q_itemsChanged(0, d->m_count, QVector<int>());
2007 }
2008}
2009
2010void QQmlDelegateModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles)
2011{
2012 Q_D(QQmlDelegateModel);
2013 if (begin.parent() == d->m_adaptorModel.rootIndex)
2014 _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, roles);
2015}
2016
2017bool QQmlDelegateModel::isDescendantOf(const QPersistentModelIndex& desc, const QList< QPersistentModelIndex >& parents) const
2018{
2019 for (int i = 0, c = parents.size(); i < c; ++i) {
2020 for (QPersistentModelIndex parent = desc; parent.isValid(); parent = parent.parent()) {
2021 if (parent == parents[i])
2022 return true;
2023 }
2024 }
2025
2026 return false;
2027}
2028
2029void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
2030{
2031 Q_D(QQmlDelegateModel);
2032 if (!d->m_complete)
2033 return;
2034
2036 if (!parents.isEmpty() && d->m_adaptorModel.rootIndex.isValid() && !isDescendantOf(d->m_adaptorModel.rootIndex, parents)) {
2037 return;
2038 }
2039
2040 // mark all items as changed
2041 _q_itemsChanged(0, d->m_count, QVector<int>());
2042
2044 // Ignored
2045 } else {
2046 // We don't know what's going on, so reset the model
2047 handleModelReset();
2048 }
2049}
2050
2052{
2054 cacheItem->attached = new QQmlDelegateModelAttached(cacheItem, obj);
2055 return cacheItem->attached;
2056 }
2057 return new QQmlDelegateModelAttached(obj);
2058}
2059
2060bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups)
2061{
2062 if (!m_context || !m_context->isValid())
2063 return false;
2064
2066 if (!cacheItem)
2067 return false;
2068 if (!object.isObject())
2069 return false;
2070
2071 QV4::ExecutionEngine *v4 = object.as<QV4::Object>()->engine();
2072 QV4::Scope scope(v4);
2073 QV4::ScopedObject o(scope, object);
2074 if (!o)
2075 return false;
2076
2078 QV4::ScopedValue propertyName(scope);
2079 QV4::ScopedValue v(scope);
2080 while (1) {
2081 propertyName = it.nextPropertyNameAsString(v);
2082 if (propertyName->isNull())
2083 break;
2084 cacheItem->setValue(
2085 propertyName->toQStringNoThrow(),
2087 }
2088
2089 cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
2090
2091 // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
2092 itemsInserted(QVector<Compositor::Insert>(1, Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag)));
2093
2094 m_cache.insert(before.cacheIndex(), cacheItem);
2095 m_compositor.insert(before, nullptr, 0, 1, cacheItem->groups);
2096
2097 return true;
2098}
2099
2100//============================================================================
2101
2104 : model(model)
2105 , groupCount(groupNames.size() + 1)
2106 , v4Engine(engine)
2108 , groupNames(groupNames)
2109{
2110}
2111
2113{
2114 if (metaObject)
2116}
2117
2119{
2120 QMetaObjectBuilder builder;
2121 builder.setFlags(DynamicMetaObject);
2122 builder.setClassName(QQmlDelegateModelAttached::staticMetaObject.className());
2123 builder.setSuperClass(&QQmlDelegateModelAttached::staticMetaObject);
2124
2125 int notifierId = 0;
2126 for (int i = 0; i < groupNames.size(); ++i, ++notifierId) {
2127 QString propertyName = QLatin1String("in") + groupNames.at(i);
2128 propertyName.replace(2, 1, propertyName.at(2).toUpper());
2129 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
2130 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
2131 propertyName.toUtf8(), "bool", notifierId);
2132 propertyBuilder.setWritable(true);
2133 }
2134 for (int i = 0; i < groupNames.size(); ++i, ++notifierId) {
2135 const QString propertyName = groupNames.at(i) + QLatin1String("Index");
2136 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
2137 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
2138 propertyName.toUtf8(), "int", notifierId);
2139 propertyBuilder.setWritable(true);
2140 }
2141
2143}
2144
2146{
2147 QV4::Scope scope(v4Engine);
2148
2149 QV4::ScopedObject proto(scope, v4Engine->newObject());
2150 proto->defineAccessorProperty(QStringLiteral("model"), QQmlDelegateModelItem::get_model, nullptr);
2152 QV4::ScopedString s(scope);
2153 QV4::ScopedProperty p(scope);
2154
2155 s = v4Engine->newString(QStringLiteral("isUnresolved"));
2159 p->setSetter(nullptr);
2161
2162 s = v4Engine->newString(QStringLiteral("inItems"));
2166
2167 s = v4Engine->newString(QStringLiteral("inPersistedItems"));
2171
2172 s = v4Engine->newString(QStringLiteral("itemsIndex"));
2175
2176 s = v4Engine->newString(QStringLiteral("persistedItemsIndex"));
2178 p->setSetter(nullptr);
2180
2181 for (int i = 2; i < groupNames.size(); ++i) {
2182 QString propertyName = QLatin1String("in") + groupNames.at(i);
2183 propertyName.replace(2, 1, propertyName.at(2).toUpper());
2184 s = v4Engine->newString(propertyName);
2188 }
2189 for (int i = 2; i < groupNames.size(); ++i) {
2190 const QString propertyName = groupNames.at(i) + QLatin1String("Index");
2191 s = v4Engine->newString(propertyName);
2193 p->setSetter(nullptr);
2195 }
2196 modelItemProto.set(v4Engine, proto);
2197}
2198
2200{
2201 int groupFlags = 0;
2202 for (const QString &groupName : groups) {
2203 int index = groupNames.indexOf(groupName);
2204 if (index != -1)
2205 groupFlags |= 2 << index;
2206 }
2207 return groupFlags;
2208}
2209
2211{
2212 int groupFlags = 0;
2213 QV4::Scope scope(v4Engine);
2214
2215 QV4::ScopedString s(scope, groups);
2216 if (s) {
2217 const QString groupName = s->toQString();
2218 int index = groupNames.indexOf(groupName);
2219 if (index != -1)
2220 groupFlags |= 2 << index;
2221 return groupFlags;
2222 }
2223
2225 if (array) {
2226 QV4::ScopedValue v(scope);
2227 uint arrayLength = array->getLength();
2228 for (uint i = 0; i < arrayLength; ++i) {
2229 v = array->get(i);
2230 const QString groupName = v->toQString();
2231 int index = groupNames.indexOf(groupName);
2232 if (index != -1)
2233 groupFlags |= 2 << index;
2234 }
2235 }
2236 return groupFlags;
2237}
2238
2240{
2241 QV4::Scope scope(b);
2243 if (!o)
2244 return b->engine()->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
2245 if (!o->d()->item->metaType->model)
2247
2248 return o->d()->item->get();
2249}
2250
2252{
2253 QV4::Scope scope(b);
2255 if (!o)
2256 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
2257
2259 for (int i = 1; i < o->d()->item->metaType->groupCount; ++i) {
2260 if (o->d()->item->groups & (1 << i))
2261 groups.append(o->d()->item->metaType->groupNames.at(i - 1));
2262 }
2263
2264 return scope.engine->fromVariant(groups);
2265}
2266
2268{
2269 QV4::Scope scope(b);
2271 if (!o)
2272 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
2273
2274 if (!argc)
2276
2277 if (!o->d()->item->metaType->model)
2279 QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->d()->item->metaType->model);
2280
2281 const int groupFlags = model->m_cacheMetaType->parseGroups(argv[0]);
2282 const int cacheIndex = model->m_cache.indexOf(o->d()->item);
2283 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
2284 model->setGroups(it, 1, Compositor::Cache, groupFlags);
2285 return QV4::Encode::undefined();
2286}
2287
2289{
2290 return QV4::Encode(bool(thisItem->groups & (1 << flag)));
2291}
2292
2294{
2295 if (!cacheItem->metaType->model)
2296 return QV4::Encode::undefined();
2297
2299
2300 bool member = arg.toBoolean();
2301 uint groupFlag = (1 << flag);
2302 if (member == ((cacheItem->groups & groupFlag) != 0))
2303 return QV4::Encode::undefined();
2304
2305 const int cacheIndex = model->m_cache.indexOf(cacheItem);
2306 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
2307 if (member)
2308 model->addGroups(it, 1, Compositor::Cache, groupFlag);
2309 else
2310 model->removeGroups(it, 1, Compositor::Cache, groupFlag);
2311 return QV4::Encode::undefined();
2312}
2313
2315{
2316 return QV4::Encode((int)thisItem->groupIndex(Compositor::Group(flag)));
2317}
2318
2320{
2321 if (!contextData)
2322 return;
2323
2325 ctxt = ctxt->nextChild()) {
2326 if (ctxt->contextObject() == childContextObject)
2327 ctxt->setContextObject(nullptr);
2328 }
2329}
2330
2331
2332//---------------------------------------------------------------------------
2333
2335
2337{
2338 item->Dispose();
2339 Object::destroy();
2340}
2341
2342
2346 int modelIndex, int row, int column)
2347 : v4(metaType->v4Engine)
2348 , metaType(metaType)
2349 , contextData(nullptr)
2350 , object(nullptr)
2351 , attached(nullptr)
2352 , incubationTask(nullptr)
2353 , delegate(nullptr)
2354 , poolTime(0)
2355 , objectRef(0)
2356 , scriptRef(0)
2357 , groups(0)
2358 , index(modelIndex)
2359 , row(row)
2360 , column(column)
2361{
2362 if (accessor->propertyCache) {
2363 // The property cache in the accessor is common for all the model
2364 // items in the model it wraps. It describes available model roles,
2365 // together with revisioned properties like row, column and index, all
2366 // which should be available in the delegate. We assign this cache to the
2367 // model item so that the QML engine can use the revision information
2368 // when resolving the properties (rather than falling back to just
2369 // inspecting the QObject in the model item directly).
2370 QQmlData::get(this, true)->propertyCache = accessor->propertyCache;
2371 }
2372}
2373
2375{
2376 Q_ASSERT(scriptRef == 0);
2377 Q_ASSERT(objectRef == 0);
2378 Q_ASSERT(!object);
2379
2380 if (incubationTask) {
2381 if (metaType->model)
2383 else
2384 delete incubationTask;
2385 }
2386}
2387
2389{
2390 --scriptRef;
2391 if (isReferenced())
2392 return;
2393
2394 if (metaType->model) {
2396 model->removeCacheItem(this);
2397 }
2398 delete this;
2399}
2400
2401void QQmlDelegateModelItem::setModelIndex(int idx, int newRow, int newColumn, bool alwaysEmit)
2402{
2403 const int prevIndex = index;
2404 const int prevRow = row;
2405 const int prevColumn = column;
2406
2407 index = idx;
2408 row = newRow;
2409 column = newColumn;
2410
2411 if (idx != prevIndex || alwaysEmit)
2413 if (row != prevRow || alwaysEmit)
2414 emit rowChanged();
2415 if (column != prevColumn || alwaysEmit)
2416 emit columnChanged();
2417}
2418
2420{
2421 Q_ASSERT(object);
2423
2424 QQmlData *data = QQmlData::get(object);
2425 Q_ASSERT(data);
2426 if (data->ownContext) {
2427 data->ownContext->clearContext();
2428 if (data->ownContext->contextObject() == object)
2429 data->ownContext->setContextObject(nullptr);
2430 data->ownContext = nullptr;
2431 data->context = nullptr;
2432 }
2433 /* QTBUG-87228: when destroying object at the application exit, the deferred
2434 * parent by setting it to QCoreApplication instance if it's nullptr, so
2435 * deletion won't work. Not to leak memory, make sure our object has a that
2436 * the parent claims the object at the end of the lifetime. When not at the
2437 * application exit, normal event loop will handle the deferred deletion
2438 * earlier.
2439 */
2440 if (object->parent() == nullptr)
2441 object->setParent(QCoreApplication::instance());
2442 object->deleteLater();
2443
2444 if (attached) {
2445 attached->m_cacheItem = nullptr;
2446 attached = nullptr;
2447 }
2448
2450 object = nullptr;
2451}
2452
2454{
2455 QQmlData *d = QQmlData::get(object);
2456 if (!d)
2457 return nullptr;
2458
2460 if (!context || !context->isValid())
2461 return nullptr;
2462
2463 if (QObject *extraObject = context->extraObject())
2464 return qobject_cast<QQmlDelegateModelItem *>(extraObject);
2465
2466 for (context = context->parent(); context; context = context->parent()) {
2467 if (QObject *extraObject = context->extraObject())
2468 return qobject_cast<QQmlDelegateModelItem *>(extraObject);
2469 if (QQmlDelegateModelItem *cacheItem = qobject_cast<QQmlDelegateModelItem *>(
2470 context->contextObject())) {
2471 return cacheItem;
2472 }
2473 }
2474 return nullptr;
2475}
2476
2478{
2481 : nullptr) {
2482 return model->m_compositor.find(Compositor::Cache, model->m_cache.indexOf(this)).index[group];
2483 }
2484 return -1;
2485}
2486
2487//---------------------------------------------------------------------------
2488
2491 : metaType(metaType)
2493 , memberPropertyOffset(QQmlDelegateModelAttached::staticMetaObject.propertyCount())
2494 , indexPropertyOffset(QQmlDelegateModelAttached::staticMetaObject.propertyCount() + metaType->groupNames.size())
2495{
2496 // Don't reference count the meta-type here as that would create a circular reference.
2497 // Instead we rely the fact that the meta-type's reference count can't reach 0 without first
2498 // destroying all delegates with attached objects.
2499 *static_cast<QMetaObject *>(this) = *metaObject;
2500}
2501
2503{
2504 ::free(metaObject);
2505}
2506
2508{
2509 release();
2510}
2511
2513{
2515 if (call == QMetaObject::ReadProperty) {
2516 if (_id >= indexPropertyOffset) {
2517 Compositor::Group group = Compositor::Group(_id - indexPropertyOffset + 1);
2518 *static_cast<int *>(arguments[0]) = attached->m_currentIndex[group];
2519 return -1;
2520 } else if (_id >= memberPropertyOffset) {
2521 Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
2522 *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
2523 return -1;
2524 }
2525 } else if (call == QMetaObject::WriteProperty) {
2526 if (_id >= memberPropertyOffset) {
2527 if (!metaType->model)
2528 return -1;
2530 Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
2531 const int groupFlag = 1 << group;
2532 const bool member = attached->m_cacheItem->groups & groupFlag;
2533 if (member && !*static_cast<bool *>(arguments[0])) {
2534 Compositor::iterator it = model->m_compositor.find(
2535 group, attached->m_currentIndex[group]);
2536 model->removeGroups(it, 1, group, groupFlag);
2537 } else if (!member && *static_cast<bool *>(arguments[0])) {
2538 for (int i = 1; i < metaType->groupCount; ++i) {
2539 if (attached->m_cacheItem->groups & (1 << i)) {
2540 Compositor::iterator it = model->m_compositor.find(
2541 Compositor::Group(i), attached->m_currentIndex[i]);
2542 model->addGroups(it, 1, Compositor::Group(i), groupFlag);
2543 break;
2544 }
2545 }
2546 }
2547 return -1;
2548 }
2549 }
2550 return attached->qt_metacall(call, _id, arguments);
2551}
2552
2554 : m_cacheItem(nullptr)
2555 , m_previousGroups(0)
2556{
2558}
2559
2562 : m_cacheItem(cacheItem)
2563 , m_previousGroups(cacheItem->groups)
2564{
2567 // Let m_previousIndex be equal to m_currentIndex
2568 std::copy(std::begin(m_currentIndex), std::end(m_currentIndex), std::begin(m_previousIndex));
2569
2570 if (!cacheItem->metaType->metaObject)
2571 cacheItem->metaType->initializeMetaObject();
2572
2574 cacheItem->metaType->metaObject->addref();
2575}
2576
2578{
2579 if (QQDMIncubationTask *incubationTask = m_cacheItem->incubationTask) {
2580 for (int i = 1; i < qMin<int>(m_cacheItem->metaType->groupCount, Compositor::MaximumGroupCount); ++i)
2581 m_currentIndex[i] = incubationTask->index[i];
2582 } else {
2584 Compositor::iterator it = model->m_compositor.find(
2585 Compositor::Cache, model->m_cache.indexOf(m_cacheItem));
2586 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
2587 m_currentIndex[i] = it.index[i];
2588 }
2589}
2590
2592{
2593 setInGroup(QQmlListCompositor::Persisted, inPersisted);
2594}
2595
2597{
2598 if (!m_cacheItem)
2599 return false;
2600 const uint groupFlag = (1 << QQmlListCompositor::Persisted);
2601 return m_cacheItem->groups & groupFlag;
2602}
2603
2605{
2606 if (!m_cacheItem)
2607 return -1;
2609}
2610
2611void QQmlDelegateModelAttached::setInGroup(QQmlListCompositor::Group group, bool inGroup)
2612{
2614 return;
2616 const uint groupFlag = (1 << group);
2617 if (inGroup == bool(m_cacheItem->groups & groupFlag))
2618 return;
2619
2620 const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
2621 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
2622 if (inGroup)
2623 model->addGroups(it, 1, Compositor::Cache, groupFlag);
2624 else
2625 model->removeGroups(it, 1, Compositor::Cache, groupFlag);
2626 // signal emission happens in add-/removeGroups
2627}
2628
2630{
2632}
2633
2635{
2636 if (!m_cacheItem)
2637 return false;
2638 const uint groupFlag = (1 << QQmlListCompositor::Default);
2639 return m_cacheItem->groups & groupFlag;
2640}
2641
2643{
2644 if (!m_cacheItem)
2645 return -1;
2647}
2648
2658{
2659 return m_cacheItem ? m_cacheItem->metaType->model : nullptr;
2660}
2661
2671{
2673
2674 if (!m_cacheItem)
2675 return groups;
2676 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
2677 if (m_cacheItem->groups & (1 << i))
2678 groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
2679 }
2680 return groups;
2681}
2682
2684{
2685 if (!m_cacheItem)
2686 return;
2687
2689
2690 const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
2691 const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
2692 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
2693 model->setGroups(it, 1, Compositor::Cache, groupFlags);
2694}
2695
2709{
2710 if (!m_cacheItem)
2711 return false;
2712
2713 return m_cacheItem->groups & Compositor::UnresolvedFlag;
2714}
2715
2757{
2758 const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
2760
2761 int indexChanges = 0;
2762 const int groupCount = m_cacheItem->metaType->groupCount;
2763 for (int i = 1; i < groupCount; ++i) {
2764 if (m_previousIndex[i] != m_currentIndex[i]) {
2766 indexChanges |= (1 << i);
2767 }
2768 }
2769
2770 // Don't access m_cacheItem anymore once we've started sending signals.
2771 // We don't own it and someone might delete it.
2772
2773 int notifierId = 0;
2774 const QMetaObject *meta = metaObject();
2775 for (int i = 1; i < groupCount; ++i, ++notifierId) {
2776 if (groupChanges & (1 << i))
2777 QMetaObject::activate(this, meta, notifierId, nullptr);
2778 }
2779 for (int i = 1; i < groupCount; ++i, ++notifierId) {
2780 if (indexChanges & (1 << i))
2781 QMetaObject::activate(this, meta, notifierId, nullptr);
2782 }
2783
2784 if (groupChanges)
2786}
2787
2788//============================================================================
2789
2791{
2792 Q_ASSERT(!model);
2793 model = m;
2794 group = g;
2795}
2796
2798{
2800 IS_SIGNAL_CONNECTED(q, QQmlDelegateModelGroup, changed, (const QJSValue &,const QJSValue &));
2801}
2802
2804{
2806 if (isChangedConnected() && !changeSet.isEmpty()) {
2808 qdmEngineData(v4)->array(v4, changeSet.removes())),
2810 qdmEngineData(v4)->array(v4, changeSet.inserts())));
2811 }
2812 if (changeSet.difference() != 0)
2813 emit q->countChanged();
2814}
2815
2817{
2818 for (QQmlDelegateModelGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2819 it->emitModelUpdated(changeSet, reset);
2820 changeSet.clear();
2821}
2822
2823typedef QQmlDelegateModelGroupEmitterList::iterator GroupEmitterListIt;
2824
2826{
2827 for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
2828 it->createdPackage(index, package);
2829}
2830
2832{
2833 for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
2834 it->initPackage(index, package);
2835}
2836
2838{
2839 for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
2840 it->destroyingPackage(package);
2841}
2842
2881{
2882}
2883
2887{
2889 d->name = name;
2890 d->setModel(model, Compositor::Group(index));
2891}
2892
2894{
2895}
2896
2906{
2907 Q_D(const QQmlDelegateModelGroup);
2908 return d->name;
2909}
2910
2912{
2914 if (d->model)
2915 return;
2916 if (d->name != name) {
2917 d->name = name;
2918 emit nameChanged();
2919 }
2920}
2921
2929{
2930 Q_D(const QQmlDelegateModelGroup);
2931 if (!d->model)
2932 return 0;
2933 return QQmlDelegateModelPrivate::get(d->model)->m_compositor.count(d->group);
2934}
2935
2943{
2944 Q_D(const QQmlDelegateModelGroup);
2945 return d->defaultInclude;
2946}
2947
2949{
2951 if (d->defaultInclude != include) {
2952 d->defaultInclude = include;
2953
2954 if (d->model) {
2955 if (include)
2957 else
2959 }
2961 }
2962}
2963
2989{
2991 if (!d->model)
2992 return QJSValue();
2993
2995 if (!model->m_context || !model->m_context->isValid()) {
2996 return QJSValue();
2997 } else if (index < 0 || index >= model->m_compositor.count(d->group)) {
2998 qmlWarning(this) << tr("get: index out of range");
2999 return QJSValue();
3000 }
3001
3002 Compositor::iterator it = model->m_compositor.find(d->group, index);
3003 QQmlDelegateModelItem *cacheItem = it->inCache()
3004 ? model->m_cache.at(it.cacheIndex())
3005 : 0;
3006
3007 if (!cacheItem) {
3008 cacheItem = model->m_adaptorModel.createItem(
3009 model->m_cacheMetaType, it.modelIndex());
3010 if (!cacheItem)
3011 return QJSValue();
3012 cacheItem->groups = it->flags;
3013
3014 model->m_cache.insert(it.cacheIndex(), cacheItem);
3015 model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
3016 }
3017
3018 if (model->m_cacheMetaType->modelItemProto.isUndefined())
3019 model->m_cacheMetaType->initializePrototype();
3020 QV4::ExecutionEngine *v4 = model->m_cacheMetaType->v4Engine;
3021 QV4::Scope scope(v4);
3022 ++cacheItem->scriptRef;
3024 QV4::ScopedObject p(scope, model->m_cacheMetaType->modelItemProto.value());
3025 o->setPrototypeOf(p);
3026
3027 return QJSValuePrivate::fromReturnedValue(o->asReturnedValue());
3028}
3029
3030bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::Value &value, int *index, Compositor::Group *group) const
3031{
3032 if (value.isNumber()) {
3033 *index = value.toInt32();
3034 return true;
3035 }
3036
3037 if (!value.isObject())
3038 return false;
3039
3041 QV4::Scope scope(v4);
3043
3044 if (object) {
3045 QQmlDelegateModelItem * const cacheItem = object->d()->item;
3046 if (QQmlDelegateModelPrivate *model = cacheItem->metaType->model
3048 : nullptr) {
3049 *index = model->m_cache.indexOf(cacheItem);
3050 *group = Compositor::Cache;
3051 return true;
3052 }
3053 }
3054 return false;
3055}
3056
3075{
3078
3079 int index = model->m_compositor.count(d->group);
3080 Compositor::Group group = d->group;
3081
3082 if (args->length() == 0)
3083 return;
3084
3085 int i = 0;
3086 QV4::Scope scope(args->v4engine());
3087 QV4::ScopedValue v(scope, (*args)[i]);
3088 if (d->parseIndex(v, &index, &group)) {
3089 if (index < 0 || index > model->m_compositor.count(group)) {
3090 qmlWarning(this) << tr("insert: index out of range");
3091 return;
3092 }
3093 if (++i == args->length())
3094 return;
3095 v = (*args)[i];
3096 }
3097
3098 Compositor::insert_iterator before = index < model->m_compositor.count(group)
3099 ? model->m_compositor.findInsertPosition(group, index)
3100 : model->m_compositor.end();
3101
3102 int groups = 1 << d->group;
3103 if (++i < args->length()) {
3104 QV4::ScopedValue val(scope, (*args)[i]);
3105 groups |= model->m_cacheMetaType->parseGroups(val);
3106 }
3107
3108 if (v->as<QV4::ArrayObject>()) {
3109 return;
3110 } else if (v->as<QV4::Object>()) {
3111 model->insert(before, v, groups);
3112 model->emitChanges();
3113 }
3114}
3115
3134{
3136 if (!d->model)
3137 return;
3138
3139 if (args->length() == 0)
3140 return;
3141
3143
3144 int index = model->m_compositor.count(d->group);
3145 Compositor::Group group = d->group;
3146
3147 int i = 0;
3148 QV4::Scope scope(args->v4engine());
3149 QV4::ScopedValue v(scope, (*args)[i]);
3150 if (d->parseIndex(v, &index, &group))
3151 ++i;
3152
3153 if (i < args->length() && index >= 0 && index <= model->m_compositor.count(group)) {
3154 v = (*args)[i];
3155 if (v->as<QV4::Object>()) {
3156 int groups = 1 << d->group;
3157 if (++i < args->length()) {
3158 QV4::ScopedValue val(scope, (*args)[i]);
3159 groups |= model->m_cacheMetaType->parseGroups(val);
3160 }
3161
3162 Compositor::insert_iterator before = index < model->m_compositor.count(group)
3163 ? model->m_compositor.findInsertPosition(group, index)
3164 : model->m_compositor.end();
3165
3166 index = before.index[d->group];
3167 group = d->group;
3168
3169 if (!model->insert(before, v, groups)) {
3170 return;
3171 }
3172 }
3173 }
3174 if (index < 0 || index >= model->m_compositor.count(group)) {
3175 qmlWarning(this) << tr("create: index out of range");
3176 return;
3177 }
3178
3180 if (object) {
3182 Compositor::iterator it = model->m_compositor.find(group, index);
3183 model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
3184 model->itemsInserted(inserts);
3185 model->m_cache.at(it.cacheIndex())->releaseObject();
3186 }
3187
3188 args->setReturnValue(QV4::QObjectWrapper::wrap(args->v4engine(), object));
3189 model->emitChanges();
3190}
3191
3209{
3211 if (!d->model)
3212 return;
3213
3215
3216 if (args->length() < 2)
3217 return;
3218
3219 int from = -1;
3220 int to = -1;
3221 Compositor::Group fromGroup = d->group;
3222 Compositor::Group toGroup = d->group;
3223
3224 QV4::Scope scope(args->v4engine());
3225 QV4::ScopedValue v(scope, (*args)[0]);
3226 if (d->parseIndex(v, &from, &fromGroup)) {
3227 if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
3228 qmlWarning(this) << tr("resolve: from index out of range");
3229 return;
3230 }
3231 } else {
3232 qmlWarning(this) << tr("resolve: from index invalid");
3233 return;
3234 }
3235
3236 v = (*args)[1];
3237 if (d->parseIndex(v, &to, &toGroup)) {
3238 if (to < 0 || to >= model->m_compositor.count(toGroup)) {
3239 qmlWarning(this) << tr("resolve: to index out of range");
3240 return;
3241 }
3242 } else {
3243 qmlWarning(this) << tr("resolve: to index invalid");
3244 return;
3245 }
3246
3247 Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
3248 Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
3249
3250 if (!fromIt->isUnresolved()) {
3251 qmlWarning(this) << tr("resolve: from is not an unresolved item");
3252 return;
3253 }
3254 if (!toIt->list) {
3255 qmlWarning(this) << tr("resolve: to is not a model item");
3256 return;
3257 }
3258
3259 const int unresolvedFlags = fromIt->flags;
3260 const int resolvedFlags = toIt->flags;
3261 const int resolvedIndex = toIt.modelIndex();
3262 void * const resolvedList = toIt->list;
3263
3264 QQmlDelegateModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex());
3265 cacheItem->groups &= ~Compositor::UnresolvedFlag;
3266
3267 if (toIt.cacheIndex() > fromIt.cacheIndex())
3268 toIt.decrementIndexes(1, unresolvedFlags);
3269 if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
3270 from += 1;
3271
3272 model->itemsMoved(
3273 QVector<Compositor::Remove>(1, Compositor::Remove(fromIt, 1, unresolvedFlags, 0)),
3274 QVector<Compositor::Insert>(1, Compositor::Insert(toIt, 1, unresolvedFlags, 0)));
3275 model->itemsInserted(
3276 QVector<Compositor::Insert>(1, Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag)));
3277 toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
3278 model->itemsRemoved(QVector<Compositor::Remove>(1, Compositor::Remove(toIt, 1, resolvedFlags)));
3279
3280 model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
3281 model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
3282
3283 if (resolvedFlags & Compositor::CacheFlag)
3284 model->m_compositor.insert(
3285 Compositor::Cache, toIt.cacheIndex(), resolvedList,
3286 resolvedIndex, 1, Compositor::CacheFlag);
3287
3288 Q_ASSERT(model->m_cache.size() == model->m_compositor.count(Compositor::Cache));
3289
3290 if (!cacheItem->isReferenced()) {
3291 Q_ASSERT(toIt.cacheIndex() == model->m_cache.indexOf(cacheItem));
3292 model->m_cache.removeAt(toIt.cacheIndex());
3293 model->m_compositor.clearFlags(
3294 Compositor::Cache, toIt.cacheIndex(), 1, Compositor::CacheFlag);
3295 delete cacheItem;
3296 Q_ASSERT(model->m_cache.size() == model->m_compositor.count(Compositor::Cache));
3297 } else {
3298 cacheItem->resolveIndex(model->m_adaptorModel, resolvedIndex);
3299 if (cacheItem->attached)
3300 cacheItem->attached->emitUnresolvedChanged();
3301 }
3302
3303 model->emitChanges();
3304}
3305
3313{
3315 if (!d->model)
3316 return;
3317 Compositor::Group group = d->group;
3318 int index = -1;
3319 int count = 1;
3320
3321 if (args->length() == 0)
3322 return;
3323
3324 int i = 0;
3325 QV4::Scope scope(args->v4engine());
3326 QV4::ScopedValue v(scope, (*args)[0]);
3327 if (!d->parseIndex(v, &index, &group)) {
3328 qmlWarning(this) << tr("remove: invalid index");
3329 return;
3330 }
3331
3332 if (++i < args->length()) {
3333 v = (*args)[i];
3334 if (v->isNumber())
3335 count = v->toInt32();
3336 }
3337
3339 if (index < 0 || index >= model->m_compositor.count(group)) {
3340 qmlWarning(this) << tr("remove: index out of range");
3341 } else if (count != 0) {
3342 Compositor::iterator it = model->m_compositor.find(group, index);
3343 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
3344 qmlWarning(this) << tr("remove: invalid count");
3345 } else {
3346 model->removeGroups(it, count, d->group, 1 << d->group);
3347 }
3348 }
3349}
3350
3352 QQmlV4Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
3353{
3354 if (!model || !QQmlDelegateModelPrivate::get(model)->m_cacheMetaType)
3355 return false;
3356
3357 if (args->length() < 2)
3358 return false;
3359
3360 int i = 0;
3361 QV4::Scope scope(args->v4engine());
3362 QV4::ScopedValue v(scope, (*args)[i]);
3363 if (!parseIndex(v, index, group))
3364 return false;
3365
3366 v = (*args)[++i];
3367 if (v->isNumber()) {
3368 *count = v->toInt32();
3369
3370 if (++i == args->length())
3371 return false;
3372 v = (*args)[i];
3373 }
3374
3376
3377 return true;
3378}
3379
3387{
3389 Compositor::Group group = d->group;
3390 int index = -1;
3391 int count = 1;
3392 int groups = 0;
3393
3394 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
3395 return;
3396
3398 if (index < 0 || index >= model->m_compositor.count(group)) {
3399 qmlWarning(this) << tr("addGroups: index out of range");
3400 } else if (count != 0) {
3401 Compositor::iterator it = model->m_compositor.find(group, index);
3402 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
3403 qmlWarning(this) << tr("addGroups: invalid count");
3404 } else {
3405 model->addGroups(it, count, d->group, groups);
3406 }
3407 }
3408}
3409
3417{
3419 Compositor::Group group = d->group;
3420 int index = -1;
3421 int count = 1;
3422 int groups = 0;
3423
3424 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
3425 return;
3426
3428 if (index < 0 || index >= model->m_compositor.count(group)) {
3429 qmlWarning(this) << tr("removeGroups: index out of range");
3430 } else if (count != 0) {
3431 Compositor::iterator it = model->m_compositor.find(group, index);
3432 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
3433 qmlWarning(this) << tr("removeGroups: invalid count");
3434 } else {
3435 model->removeGroups(it, count, d->group, groups);
3436 }
3437 }
3438}
3439
3448{
3450 Compositor::Group group = d->group;
3451 int index = -1;
3452 int count = 1;
3453 int groups = 0;
3454
3455 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
3456 return;
3457
3459 if (index < 0 || index >= model->m_compositor.count(group)) {
3460 qmlWarning(this) << tr("setGroups: index out of range");
3461 } else if (count != 0) {
3462 Compositor::iterator it = model->m_compositor.find(group, index);
3463 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
3464 qmlWarning(this) << tr("setGroups: invalid count");
3465 } else {
3466 model->setGroups(it, count, d->group, groups);
3467 }
3468 }
3469}
3470
3483{
3485
3486 if (args->length() < 2)
3487 return;
3488
3489 Compositor::Group fromGroup = d->group;
3490 Compositor::Group toGroup = d->group;
3491 int from = -1;
3492 int to = -1;
3493 int count = 1;
3494
3495 QV4::Scope scope(args->v4engine());
3496 QV4::ScopedValue v(scope, (*args)[0]);
3497 if (!d->parseIndex(v, &from, &fromGroup)) {
3498 qmlWarning(this) << tr("move: invalid from index");
3499 return;
3500 }
3501
3502 v = (*args)[1];
3503 if (!d->parseIndex(v, &to, &toGroup)) {
3504 qmlWarning(this) << tr("move: invalid to index");
3505 return;
3506 }
3507
3508 if (args->length() > 2) {
3509 v = (*args)[2];
3510 if (v->isNumber())
3511 count = v->toInt32();
3512 }
3513
3515
3516 if (count < 0) {
3517 qmlWarning(this) << tr("move: invalid count");
3518 } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
3519 qmlWarning(this) << tr("move: from index out of range");
3520 } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
3521 qmlWarning(this) << tr("move: to index out of range");
3522 } else if (count > 0) {
3525
3526 model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
3527 model->itemsMoved(removes, inserts);
3528 model->emitChanges();
3529 }
3530
3531}
3532
3545//============================================================================
3546
3549 , m_model(model)
3550 , m_part(part)
3551 , m_compositorGroup(Compositor::Cache)
3552 , m_inheritGroup(true)
3553{
3555 if (d->m_cacheMetaType) {
3557 m_compositorGroup = Compositor::Default;
3558 } else {
3559 d->m_pendingParts.insert(this);
3560 }
3561}
3562
3564{
3565}
3566
3568{
3569 if (m_inheritGroup)
3570 return m_model->filterGroup();
3571 return m_filterGroup;
3572}
3573
3575{
3576 if (QQmlDelegateModelPrivate::get(m_model)->m_transaction) {
3577 qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged");
3578 return;
3579 }
3580
3581 if (m_filterGroup != group || m_inheritGroup) {
3582 m_filterGroup = group;
3583 m_inheritGroup = false;
3585
3587 }
3588}
3589
3591{
3592 if (!m_inheritGroup) {
3593 m_inheritGroup = true;
3596 }
3597}
3598
3600{
3602 if (!model->m_cacheMetaType)
3603 return;
3604
3605 if (m_inheritGroup) {
3606 if (m_filterGroup == model->m_filterGroup)
3607 return;
3608 m_filterGroup = model->m_filterGroup;
3609 }
3610
3611 QQmlListCompositor::Group previousGroup = m_compositorGroup;
3612 m_compositorGroup = Compositor::Default;
3613 QQmlDelegateModelGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
3614 for (int i = 1; i < model->m_groupCount; ++i) {
3615 if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
3616 m_compositorGroup = Compositor::Group(i);
3617 break;
3618 }
3619 }
3620
3621 QQmlDelegateModelGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
3622 if (m_compositorGroup != previousGroup) {
3625 model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
3626
3627 QQmlChangeSet changeSet;
3628 changeSet.move(removes, inserts);
3629 if (!changeSet.isEmpty())
3630 emit modelUpdated(changeSet, false);
3631
3632 if (changeSet.difference() != 0)
3634 }
3635}
3636
3638 Compositor::Group group, const QQmlChangeSet &changeSet)
3639{
3640 if (!m_inheritGroup)
3641 return;
3642
3643 m_compositorGroup = group;
3644 QQmlDelegateModelGroupPrivate::get(QQmlDelegateModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
3645
3646 if (!changeSet.isEmpty())
3647 emit modelUpdated(changeSet, false);
3648
3649 if (changeSet.difference() != 0)
3651
3653}
3654
3656{
3658 return model->m_delegate
3659 ? model->m_compositor.count(m_compositorGroup)
3660 : 0;
3661}
3662
3664{
3665 return m_model->isValid();
3666}
3667
3669{
3671
3672 if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
3673 qWarning() << "DelegateModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
3674 return nullptr;
3675 }
3676
3677 QObject *object = model->object(m_compositorGroup, index, incubationMode);
3678
3679 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object)) {
3680 QObject *part = package->part(m_part);
3681 if (!part)
3682 return nullptr;
3683 m_packaged.insert(part, package);
3684 return part;
3685 }
3686
3687 model->release(object);
3688 if (!model->m_delegateValidated) {
3689 if (object)
3690 qmlWarning(model->m_delegate) << tr("Delegate component must be Package type.");
3691 model->m_delegateValidated = true;
3692 }
3693
3694 return nullptr;
3695}
3696
3697QQmlInstanceModel::ReleaseFlags QQmlPartsModel::release(QObject *item, ReusableFlag)
3698{
3699 QQmlInstanceModel::ReleaseFlags flags;
3700
3701 auto it = m_packaged.find(item);
3702 if (it != m_packaged.end()) {
3703 QQuickPackage *package = *it;
3705 flags = model->release(package);
3706 m_packaged.erase(it);
3707 if (!m_packaged.contains(item))
3708 flags &= ~Referenced;
3709 if (flags & Destroyed)
3711 }
3712 return flags;
3713}
3714
3716{
3717 return QQmlDelegateModelPrivate::get(m_model)->variantValue(m_compositorGroup, index, role);
3718}
3719
3721{
3723 model->m_adaptorModel.replaceWatchedRoles(m_watchedRoles, roles);
3724 m_watchedRoles = roles;
3725}
3726
3728{
3730 Compositor::iterator it = model->m_compositor.find(model->m_compositorGroup, index);
3731 if (!it->inCache())
3732 return QQmlIncubator::Null;
3733
3734 if (auto incubationTask = model->m_cache.at(it.cacheIndex())->incubationTask)
3735 return incubationTask->status();
3736
3737 return QQmlIncubator::Ready;
3738}
3739
3741{
3742 auto it = m_packaged.find(item);
3743 if (it != m_packaged.end()) {
3745 return cacheItem->groupIndex(m_compositorGroup);
3746 }
3747 return -1;
3748}
3749
3751{
3752 emit createdItem(index, package->part(m_part));
3753}
3754
3756{
3757 if (m_modelUpdatePending)
3758 m_pendingPackageInitializations << index;
3759 else
3760 emit initItem(index, package->part(m_part));
3761}
3762
3764{
3765 QObject *item = package->part(m_part);
3766 Q_ASSERT(!m_packaged.contains(item));
3768}
3769
3771{
3772 m_modelUpdatePending = false;
3773 emit modelUpdated(changeSet, reset);
3774 if (changeSet.difference() != 0)
3776
3778 QVector<int> pendingPackageInitializations;
3779 qSwap(pendingPackageInitializations, m_pendingPackageInitializations);
3780 for (int index : pendingPackageInitializations) {
3781 if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup))
3782 continue;
3783 QObject *object = model->object(m_compositorGroup, index, QQmlIncubator::Asynchronous);
3784 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
3785 emit initItem(index, package->part(m_part));
3786 model->release(object);
3787 }
3788}
3789
3791{
3792 // Currently, the only way for a view to reuse items is to call release()
3793 // in the model class with the second argument explicitly set to
3794 // QQmlReuseableDelegateModelItemsPool::Reusable. If the released item is
3795 // no longer referenced, it will be added to the pool. Reusing of items can
3796 // be specified per item, in case certain items cannot be recycled. A
3797 // QQmlDelegateModelItem knows which delegate its object was created from.
3798 // So when we are about to create a new item, we first check if the pool
3799 // contains an item based on the same delegate from before. If so, we take
3800 // it out of the pool (instead of creating a new item), and update all its
3801 // context properties and attached properties.
3802
3803 // When a view is recycling items, it should call drain() regularly. As
3804 // there is currently no logic to 'hibernate' items in the pool, they are
3805 // only meant to rest there for a short while, ideally only from the time
3806 // e.g a row is unloaded on one side of the view, and until a new row is
3807 // loaded on the opposite side. Between these times, the application will
3808 // see the item as fully functional and 'alive' (just not visible on
3809 // screen). Since this time is supposed to be short, we don't take any
3810 // action to notify the application about it, since we don't want to
3811 // trigger any bindings that can disturb performance.
3812
3813 // A recommended time for calling drain() is each time a view has finished
3814 // loading e.g a new row or column. If there are more items in the pool
3815 // after that, it means that the view most likely doesn't need them anytime
3816 // soon. Those items should be destroyed to reduce resource consumption.
3817
3818 // Depending on if a view is a list or a table, it can sometimes be
3819 // performant to keep items in the pool for a bit longer than one "row
3820 // out/row in" cycle. E.g for a table, if the number of visible rows in a
3821 // view is much larger than the number of visible columns. In that case, if
3822 // you flick out a row, and then flick in a column, you would throw away a
3823 // lot of items in the pool if completely draining it. The reason is that
3824 // unloading a row places more items in the pool than what ends up being
3825 // recycled when loading a new column. And then, when you next flick in a
3826 // new row, you would need to load all those drained items again from
3827 // scratch. For that reason, you can specify a maxPoolTime to the
3828 // drainReusableItemsPool() that allows you to keep items in the pool for a
3829 // bit longer, effectively keeping more items in circulation. A recommended
3830 // maxPoolTime would be equal to the number of dimensions in the view,
3831 // which means 1 for a list view and 2 for a table view. If you specify 0,
3832 // all items will be drained.
3833
3834 Q_ASSERT(!modelItem->incubationTask);
3835 Q_ASSERT(!modelItem->isObjectReferenced());
3836 Q_ASSERT(modelItem->object);
3837 Q_ASSERT(modelItem->delegate);
3838
3839 modelItem->poolTime = 0;
3840 m_reusableItemsPool.append(modelItem);
3841
3842 qCDebug(lcItemViewDelegateRecycling)
3843 << "item:" << modelItem
3844 << "delegate:" << modelItem->delegate
3845 << "index:" << modelItem->modelIndex()
3846 << "row:" << modelItem->modelRow()
3847 << "column:" << modelItem->modelColumn()
3848 << "pool size:" << m_reusableItemsPool.size();
3849}
3850
3852{
3853 // Find the oldest item in the pool that was made from the same delegate as
3854 // the given argument, remove it from the pool, and return it.
3855 for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end(); ++it) {
3856 if ((*it)->delegate != delegate)
3857 continue;
3858 auto modelItem = *it;
3859 m_reusableItemsPool.erase(it);
3860
3861 qCDebug(lcItemViewDelegateRecycling)
3862 << "item:" << modelItem
3863 << "delegate:" << delegate
3864 << "old index:" << modelItem->modelIndex()
3865 << "old row:" << modelItem->modelRow()
3866 << "old column:" << modelItem->modelColumn()
3867 << "new index:" << newIndexHint
3868 << "pool size:" << m_reusableItemsPool.size();
3869
3870 return modelItem;
3871 }
3872
3873 qCDebug(lcItemViewDelegateRecycling)
3874 << "no available item for delegate:" << delegate
3875 << "new index:" << newIndexHint
3876 << "pool size:" << m_reusableItemsPool.size();
3877
3878 return nullptr;
3879}
3880
3881void QQmlReusableDelegateModelItemsPool::drain(int maxPoolTime, std::function<void(QQmlDelegateModelItem *cacheItem)> releaseItem)
3882{
3883 // Rather than releasing all pooled items upon a call to this function, each
3884 // item has a poolTime. The poolTime specifies for how many loading cycles an item
3885 // has been resting in the pool. And for each invocation of this function, poolTime
3886 // will increase. If poolTime is equal to, or exceeds, maxPoolTime, it will be removed
3887 // from the pool and released. This way, the view can tweak a bit for how long
3888 // items should stay in "circulation", even if they are not recycled right away.
3889 qCDebug(lcItemViewDelegateRecycling) << "pool size before drain:" << m_reusableItemsPool.size();
3890
3891 for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end();) {
3892 auto modelItem = *it;
3893 modelItem->poolTime++;
3894 if (modelItem->poolTime <= maxPoolTime) {
3895 ++it;
3896 } else {
3897 it = m_reusableItemsPool.erase(it);
3898 releaseItem(modelItem);
3899 }
3900 }
3901
3902 qCDebug(lcItemViewDelegateRecycling) << "pool size after drain:" << m_reusableItemsPool.size();
3903}
3904
3905//============================================================================
3906
3908{
3910
3911 static QV4::Heap::QQmlDelegateModelGroupChange *create(QV4::ExecutionEngine *e) {
3912 return e->memoryManager->allocate<QQmlDelegateModelGroupChange>();
3913 }
3914
3915 static QV4::ReturnedValue method_get_index(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
3916 QV4::Scope scope(b);
3918 if (!that)
3920 return QV4::Encode(that->d()->change.index);
3921 }
3922 static QV4::ReturnedValue method_get_count(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
3923 QV4::Scope scope(b);
3925 if (!that)
3927 return QV4::Encode(that->d()->change.count);
3928 }
3929 static QV4::ReturnedValue method_get_moveId(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
3930 QV4::Scope scope(b);
3932 if (!that)
3934 if (that->d()->change.moveId < 0)
3936 return QV4::Encode(that->d()->change.moveId);
3937 }
3938};
3939
3941
3943{
3946public:
3948 {
3949 return engine->memoryManager->allocate<QQmlDelegateModelGroupChangeArray>(changes);
3950 }
3951
3952 quint32 count() const { return d()->changes->size(); }
3953 const QQmlChangeSet::Change &at(int index) const { return d()->changes->at(index); }
3954
3955 static QV4::ReturnedValue virtualGet(const QV4::Managed *m, QV4::PropertyKey id, const QV4::Value *receiver, bool *hasProperty)
3956 {
3957 if (id.isArrayIndex()) {
3958 uint index = id.asArrayIndex();
3960 QV4::ExecutionEngine *v4 = static_cast<const QQmlDelegateModelGroupChangeArray *>(m)->engine();
3961 QV4::Scope scope(v4);
3963
3964 if (index >= array->count()) {
3965 if (hasProperty)
3966 *hasProperty = false;
3968 }
3969
3970 const QQmlChangeSet::Change &change = array->at(index);
3971
3972 QV4::ScopedObject changeProto(scope, qdmEngineData(v4)->changeProto.value());
3974 object->setPrototypeOf(changeProto);
3975 object->d()->change = change;
3976
3977 if (hasProperty)
3978 *hasProperty = true;
3979 return object.asReturnedValue();
3980 }
3981
3984
3985 if (id == array->engine()->id_length()->propertyKey()) {
3986 if (hasProperty)
3987 *hasProperty = true;
3988 return QV4::Encode(array->count());
3989 }
3990
3991 return Object::virtualGet(m, id, receiver, hasProperty);
3992 }
3993};
3994
3996{
3997 Object::init();
3998 this->changes = new QVector<QQmlChangeSet::Change>(changes);
3999 QV4::Scope scope(internalClass->engine);
4000 QV4::ScopedObject o(scope, this);
4001 o->setArrayType(QV4::Heap::ArrayData::Custom);
4002}
4003
4005
4007{
4008 QV4::Scope scope(v4);
4009
4010 QV4::ScopedObject proto(scope, v4->newObject());
4011 proto->defineAccessorProperty(QStringLiteral("index"), QQmlDelegateModelGroupChange::method_get_index, nullptr);
4012 proto->defineAccessorProperty(QStringLiteral("count"), QQmlDelegateModelGroupChange::method_get_count, nullptr);
4013 proto->defineAccessorProperty(QStringLiteral("moveId"), QQmlDelegateModelGroupChange::method_get_moveId, nullptr);
4014 changeProto.set(v4, proto);
4015}
4016
4018{
4019}
4020
4022 const QVector<QQmlChangeSet::Change> &changes)
4023{
4024 QV4::Scope scope(v4);
4026 return o.asReturnedValue();
4027}
4028
4030
4031#include "moc_qqmldelegatemodel_p_p.cpp"
4032
4033#include "moc_qqmldelegatemodel_p.cpp"
[qjs-as-container]
void modelAboutToBeReset(QPrivateSignal)
LayoutChangeHint
This enum describes the way the model changes layout.
void modelReset(QPrivateSignal)
virtual QHash< int, QByteArray > roleNames() const
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Returns the index of the data in row and column with parent.
QChar toUpper() const noexcept
Returns the uppercase equivalent if the character is lowercase or titlecase; otherwise returns the ch...
Definition qchar.h:449
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
\inmodule QtCore
Definition qcoreevent.h:45
@ UpdateRequest
Definition qcoreevent.h:113
\inmodule QtCore
Definition qhash.h:818
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:926
void insert(N *n)
Insert object into the list.
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the list.
iterator begin()
Returns an STL-style interator pointing to the first item in the list.
QV4::ExecutionEngine * handle() const
Definition qjsengine.h:292
static QJSValue fromReturnedValue(QV4::ReturnedValue d)
Definition qjsvalue_p.h:189
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
void removeAt(qsizetype i)
Definition qlist.h:573
iterator erase(const_iterator begin, const_iterator end)
Definition qlist.h:882
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:471
qsizetype length() const noexcept
Definition qlist.h:388
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
const_iterator constBegin() const noexcept
Definition qlist.h:615
QList< T > mid(qsizetype pos, qsizetype len=-1) const
Definition qlist.h:968
void append(parameter_type t)
Definition qlist.h:441
void setSuperClass(const QMetaObject *meta)
Sets the superclass meta object of the class being constructed by this meta object builder to meta.
QMetaObject * toMetaObject() const
Converts this meta object builder into a concrete QMetaObject.
QMetaMethodBuilder addSignal(const QByteArray &signature)
Adds a new signal to this class with the specified signature.
void setFlags(MetaObjectFlags)
Sets the flags of the class being constructed by this meta object builder.
QMetaPropertyBuilder addProperty(const QByteArray &name, const QByteArray &type, int notifierId=-1)
Adds a new readable/writable property to this class with the specified name and type.
void setClassName(const QByteArray &name)
Sets the name of the class being constructed by this meta object builder.
void setWritable(bool value)
Sets this property to writable if value is true.
\inmodule QtCore
Definition qmetatype.h:320
\inmodule QtCore
iterator find(const Key &key)
Definition qhash.h:1904
bool contains(const Key &key) const noexcept
Definition qhash.h:1567
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1930
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1830
QDynamicMetaObjectData * metaObject
Definition qobject.h:77
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
\inmodule QtCore
Definition qobject.h:90
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:311
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
Definition qobject.cpp:2521
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1363
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3099
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
\inmodule QtCore
Definition qpointer.h:18
T * data() const
Definition qpointer.h:56
QPointer< QObject > proxiedObject
QQmlRefPointer< QQmlContextData > proxyContext
void statusChanged(Status) override
Called when the status of the incubator changes.
void setInitialState(QObject *) override
Called after the object is first created, but before property bindings are evaluated and,...
int index[QQmlListCompositor::MaximumGroupCount]
QQmlDelegateModelItem * incubating
QQmlDelegateModelPrivate * vdm
void initializeRequiredProperties(QQmlDelegateModelItem *modelItemToIncubate, QObject *object)
virtual QQmlComponent * delegate(QQmlAdaptorModel *adaptorModel, int row, int column=0) const =0
QQmlPropertyCache::ConstPtr propertyCache
bool notify(const QList< QQmlDelegateModelItem * > &items, int index, int count, const QVector< int > &roles) const
QAbstractItemModel * aim()
bool canFetchMore() const
QQmlDelegateModelItem * createItem(const QQmlRefPointer< QQmlDelegateModelItemMetaType > &metaType, int index)
bool hasProxyObject() const
QQmlAnyBinding is an abstraction over the various bindings in QML.
void installOn(const QQmlProperty &target, InterceptorMode mode=IgnoreInterceptors)
The QQmlChangeSet class stores an ordered list of notifications about changes to a linear data set.
const QVector< Change > & removes() const
void remove(int index, int count)
Appends a notification that count items were removed at index.
void change(int index, int count)
Appends a notification that count items were changed at index.
int difference() const
void move(int from, int to, int count, int moveId)
Appends a notification that count items were moved from one index to another.
void insert(int index, int count)
Appends a notification that count items were inserted at index.
const QVector< Change > & inserts() const
bool isEmpty() const
static QQmlComponentPrivate * get(QQmlComponent *c)
static QQmlProperty removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties *requiredProperties, QQmlEngine *engine, bool *wasInRequiredProperties=nullptr)
The QQmlComponent class encapsulates a QML component definition.
QQmlContext * creationContext() const
Returns the QQmlContext the component was created in.
QList< QQmlError > errors() const
Returns the list of errors that occurred during the last compile or create operation.
void setContextObject(QObject *contextObject)
static QQmlRefPointer< QQmlContextData > get(QQmlContext *context)
static QQmlRefPointer< QQmlContextData > createChild(const QQmlRefPointer< QQmlContextData > &parent)
QQmlRefPointer< QQmlContextData > childContexts() const
static QQmlRefPointer< QQmlContextData > createRefCounted(const QQmlRefPointer< QQmlContextData > &parent)
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
bool isValid() const
Returns whether the context is valid.
QQmlEngine * engine() const
Return the context's QQmlEngine, or \nullptr if the context has no QQmlEngine or the QQmlEngine was d...
QQmlPropertyCache::ConstPtr propertyCache
Definition qqmldata_p.h:195
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
QQmlDelegateModelAttachedMetaObject(QQmlDelegateModelItemMetaType *metaType, QMetaObject *metaObject)
int metaCall(QObject *, QMetaObject::Call, int _id, void **) override
void setGroups(const QStringList &groups)
void emitChanges()
\qmlattachedproperty bool QtQml.Models::DelegateModel::inItems
int m_previousIndex[QQmlListCompositor::MaximumGroupCount]
int m_currentIndex[QQmlListCompositor::MaximumGroupCount]
void setInPersistedItems(bool inPersisted)
QQmlDelegateModelAttached(QObject *parent)
QQmlDelegateModelItem * m_cacheItem
QV4::ReturnedValue array(QV4::ExecutionEngine *engine, const QVector< QQmlChangeSet::Change > &changes)
QQmlDelegateModelEngineData(QV4::ExecutionEngine *v4)
bool parseIndex(const QV4::Value &value, int *index, Compositor::Group *group) const
void createdPackage(int index, QQuickPackage *package)
QPointer< QQmlDelegateModel > model
static QQmlDelegateModelGroupPrivate * get(QQmlDelegateModelGroup *group)
bool parseGroupArgs(QQmlV4Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
void initPackage(int index, QQuickPackage *package)
QQmlDelegateModelGroupEmitterList emitters
void destroyingPackage(QQuickPackage *package)
void setModel(QQmlDelegateModel *model, Compositor::Group group)
void emitChanges(QV4::ExecutionEngine *engine)
void resolve(QQmlV4Function *)
\qmlmethod QtQml.Models::DelegateModelGroup::resolve(int from, int to)
void setName(const QString &name)
bool defaultInclude() const
\qmlproperty bool QtQml.Models::DelegateModelGroup::includeByDefault
void insert(QQmlV4Function *)
\qmlmethod QtQml.Models::DelegateModelGroup::insert(int index, jsdict data, array groups = undefined)...
void setGroups(QQmlV4Function *)
\qmlmethod QtQml.Models::DelegateModelGroup::setGroups(int index, int count, stringlist groups)
void addGroups(QQmlV4Function *)
\qmlmethod QtQml.Models::DelegateModelGroup::addGroups(int index, int count, stringlist groups)
void remove(QQmlV4Function *)
\qmlmethod QtQml.Models::DelegateModelGroup::remove(int index, int count)
Q_INVOKABLE QJSValue get(int index)
\qmlmethod object QtQml.Models::DelegateModelGroup::get(int index)
void removeGroups(QQmlV4Function *)
\qmlmethod QtQml.Models::DelegateModelGroup::removeGroups(int index, int count, stringlist groups)
void setDefaultInclude(bool include)
void create(QQmlV4Function *)
\qmlmethod QtQml.Models::DelegateModelGroup::create(int index) \qmlmethod QtQml.Models::DelegateModel...
void move(QQmlV4Function *)
\qmlmethod QtQml.Models::DelegateModelGroup::move(var from, var to, int count)
QQmlDelegateModelGroup(QObject *parent=nullptr)
\qmltype DelegateModelGroup \instantiates QQmlDelegateModelGroup \inqmlmodule QtQml....
QV4::ExecutionEngine *const v4Engine
QPointer< QQmlDelegateModel > model
QQmlDelegateModelItemMetaType(QV4::ExecutionEngine *engine, QQmlDelegateModel *model, const QStringList &groupNames)
QQmlDelegateModelAttachedMetaObject * metaObject
int parseGroups(const QStringList &groupNames) const
QQDMIncubationTask * incubationTask
static QV4::ReturnedValue set_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg)
void childContextObjectDestroyed(QObject *childContextObject)
virtual void setValue(const QString &role, const QVariant &value)
QPointer< QQmlDelegateModelAttached > attached
static QV4::ReturnedValue get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &)
static QV4::ReturnedValue get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg)
static QV4::ReturnedValue get_groups(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
int groupIndex(Compositor::Group group)
virtual bool resolveIndex(const QQmlAdaptorModel &, int)
static QQmlDelegateModelItem * dataForObject(QObject *object)
static QV4::ReturnedValue get_model(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
virtual void setModelIndex(int idx, int newRow, int newColumn, bool alwaysEmit=false)
QQmlDelegateModelItem(const QQmlRefPointer< QQmlDelegateModelItemMetaType > &metaType, QQmlAdaptorModel::Accessors *accessor, int modelIndex, int row, int column)
QQmlRefPointer< QQmlContextData > contextData
static QV4::ReturnedValue set_groups(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
QQmlRefPointer< QQmlDelegateModelItemMetaType > const metaType
QQmlDelegateModelParts(QQmlDelegateModel *parent)
QList< QQmlPartsModel * > models
void setInitialState(QQDMIncubationTask *incubationTask, QObject *o)
void removeCacheItem(QQmlDelegateModelItem *cacheItem)
QVariant variantValue(Compositor::Group group, int index, const QString &name)
void emitCreatedPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package)
QList< QQDMIncubationTask * > m_finishedIncubating
QQmlDelegateModelItemMetaType * m_cacheMetaType
QList< QQmlDelegateModelItem * > m_cache
QQmlDelegateModel::ReleaseFlags release(QObject *object, QQmlInstanceModel::ReusableFlag reusable=QQmlInstanceModel::NotReusable)
QQmlDelegateModelParts * m_parts
static qsizetype group_count(QQmlListProperty< QQmlDelegateModelGroup > *property)
QQmlAbstractDelegateComponent * m_delegateChooser
QPointer< QQmlContext > m_context
void emitCreatedItem(QQDMIncubationTask *incubationTask, QObject *item)
void emitInitItem(QQDMIncubationTask *incubationTask, QObject *item)
static void group_append(QQmlListProperty< QQmlDelegateModelGroup > *property, QQmlDelegateModelGroup *group)
QQmlStrongJSQObjectReference< QQmlComponent > m_delegate
void emitDestroyingItem(QObject *item)
void addCacheItem(QQmlDelegateModelItem *item, Compositor::iterator it)
void reuseItem(QQmlDelegateModelItem *item, int newModelIndex, int newGroups)
void drainReusableItemsPool(int maxPoolTime)
QQmlDelegateModelGroup * m_persistedItems
static QQmlDelegateModelGroup * group_at(QQmlListProperty< QQmlDelegateModelGroup > *property, qsizetype index)
void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override
QObject * object(Compositor::Group group, int index, QQmlIncubator::IncubationMode incubationMode)
void destroyCacheItem(QQmlDelegateModelItem *cacheItem)
void itemsRemoved(const QVector< Compositor::Remove > &removes, QVarLengthArray< QVector< QQmlChangeSet::Change >, Compositor::MaximumGroupCount > *translatedRemoves, QHash< int, QList< QQmlDelegateModelItem * > > *movedItems=nullptr)
void setGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
bool insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups)
void itemsInserted(const QVector< Compositor::Insert > &inserts, QVarLengthArray< QVector< QQmlChangeSet::Change >, Compositor::MaximumGroupCount > *translatedInserts, QHash< int, QList< QQmlDelegateModelItem * > > *movedItems=nullptr)
QQmlDelegateModelPrivate(QQmlContext *)
Encapsulates a model and delegate.
void delegateChanged(bool add=true, bool remove=true)
QQmlDelegateModelGroup * m_items
void releaseIncubator(QQDMIncubationTask *incubationTask)
void incubatorStatusChanged(QQDMIncubationTask *incubationTask, QQmlIncubator::Status status)
void emitInitPackage(QQDMIncubationTask *incubationTask, QQuickPackage *package)
void addGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
void emitDestroyingPackage(QQuickPackage *package)
QQmlComponent * resolveDelegate(int index)
QQmlDelegateModelGroup * m_groups[Compositor::MaximumGroupCount]
void itemsChanged(const QVector< Compositor::Change > &changes)
void removeGroups(Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
QQmlReusableDelegateModelItemsPool m_reusableItemsPool
void itemsMoved(const QVector< Compositor::Remove > &removes, const QVector< Compositor::Insert > &inserts)
QQmlListCompositor::Group m_compositorGroup
static QQmlDelegateModelPrivate * get(QQmlDelegateModel *m)
void setModel(const QVariant &)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void filterGroupChanged()
Q_INVOKABLE QVariant modelIndex(int idx) const
\qmlmethod QModelIndex QtQml.Models::DelegateModel::modelIndex(int index)
QQmlDelegateModelGroup * items
\qmlproperty DelegateModelGroup QtQml.Models::DelegateModel::items
void setDelegate(QQmlComponent *)
int count() const override
\qmlproperty int QtQml.Models::DelegateModel::count
void classBegin() override
Invoked after class creation, but before any properties have been set.
void drainReusableItemsPool(int maxPoolTime) override
QVariant variantValue(int index, const QString &role) override
bool event(QEvent *) override
This virtual function receives events to an object and should return true if the event e was recogniz...
QString filterGroup() const
\qmlproperty string QtQml.Models::DelegateModel::filterOnGroup
int indexOf(QObject *object, QObject *objectContext) const override
void setRootIndex(const QVariant &root)
void setFilterGroup(const QString &group)
const QAbstractItemModel * abstractItemModel() const override
Q_INVOKABLE QVariant parentModelIndex() const
\qmlmethod QModelIndex QtQml.Models::DelegateModel::parentModelIndex()
QObject * parts
\qmlproperty object QtQml.Models::DelegateModel::parts
static QQmlDelegateModelAttached * qmlAttachedProperties(QObject *obj)
bool isValid() const override
QQmlListProperty< QQmlDelegateModelGroup > groups
\qmlproperty list<DelegateModelGroup> QtQml.Models::DelegateModel::groups
void setWatchedRoles(const QList< QByteArray > &roles) override
QQmlDelegateModelGroup * persistedItems
\qmlproperty DelegateModelGroup QtQml.Models::DelegateModel::persistedItems
QQmlComponent * delegate
QQmlIncubator::Status incubationStatus(int index) override
ReleaseFlags release(QObject *object, ReusableFlag reusableFlag=NotReusable) override
void cancel(int index) override
static QQmlEnginePrivate * get(QQmlEngine *e)
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
static QQmlIncubatorPrivate * get(QQmlIncubator *incubator)
QList< QQmlError > errors() const
Return the list of errors encountered while incubating the object.
void clear()
Clears the incubator.
bool isError() const
Returns true if the incubator's status() is Error.
IncubationMode
Specifies the mode the incubator operates in.
void forceCompletion()
Force any in-progress incubation to finish synchronously.
Status status() const
Return the current status of the incubator.
Status
Specifies the status of the QQmlIncubator.
IncubationMode incubationMode() const
Return the incubation mode passed to the QQmlIncubator constructor.
void createdItem(int index, QObject *object)
void modelUpdated(const QQmlChangeSet &changeSet, bool reset)
void destroyingItem(QObject *object)
void initItem(int index, QObject *object)
void setRemoveGroups(int groups)
iterator find(Group group, int index)
Returns an iterator representing the item at index in a group.
void transition(Group from, Group to, QVector< QQmlChangeSet::Change > *removes, QVector< QQmlChangeSet::Change > *inserts)
void setDefaultGroup(Group group)
int count(Group group) const
Returns the number of items that belong to a group.
void clearFlags(Group fromGroup, int from, int count, Group group, uint flags, QVector< Remove > *removals=nullptr)
Clears the given flags flags on count items belonging to group starting at the position from.
void setFlags(Group fromGroup, int from, int count, Group group, int flags, QVector< Insert > *inserts=nullptr)
Sets the given flags flags on count items belonging to group starting at the position identified by f...
void clearDefaultGroup(Group group)
void insert(Group group, int before, void *list, int index, int count, uint flags, QVector< Insert > *inserts=nullptr)
Inserts a range of count indexes starting at index from a list with the given flags into a group at i...
The QQmlListProperty class allows applications to expose list-like properties of QObject-derived clas...
Definition qqmllist.h:24
QObject * object() const
void emitModelUpdated(const QQmlChangeSet &changeSet, bool reset) override
QVariant variantValue(int index, const QString &role) override
int count() const override
void filterGroupChanged()
void setFilterGroup(const QString &group)
QQmlIncubator::Status incubationStatus(int index) override
int indexOf(QObject *item, QObject *objectContext) const override
void destroyingPackage(QQuickPackage *package) override
void setWatchedRoles(const QList< QByteArray > &roles) override
QQmlPartsModel(QQmlDelegateModel *model, const QString &part, QObject *parent=nullptr)
\qmlsignal QtQml.Models::DelegateModelGroup::changed(array removed, array inserted)
ReleaseFlags release(QObject *item, ReusableFlag reusable=NotReusable) override
void createdPackage(int index, QQuickPackage *package) override
void initPackage(int index, QQuickPackage *package) override
QString filterGroup() const
bool isValid() const override
The QQmlProperty class abstracts accessing properties on objects created from QML.
int index() const
Return the Qt metaobject index of the property.
QML_ANONYMOUSQObject * object
void addref() const
void release() const
void reset(T *t=nullptr)
void drain(int maxPoolTime, std::function< void(QQmlDelegateModelItem *cacheItem)> releaseItem)
void insertItem(QQmlDelegateModelItem *modelItem)
QQmlDelegateModelItem * takeItem(const QQmlComponent *delegate, int newIndexHint)
QObject * part(const QString &=QString())
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
iterator erase(const_iterator i)
Definition qset.h:145
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
QByteArray toUtf8() const &
Definition qstring.h:563
ObjectType::Data * allocate(Args &&... args)
Definition qv4mm_p.h:199
void set(ExecutionEngine *engine, const Value &value)
const T & at(qsizetype idx) const
void append(const T &t)
void push_back(const T &t)
void reserve(qsizetype sz)
\inmodule QtCore
Definition qvariant.h:64
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:531
qSwap(pi, e)
qDeleteAll(list.begin(), list.end())
double e
QCache< int, Employee > cache
[0]
QSet< QString >::iterator it
auto mo
[7]
QList< QVariant > arguments
Combined button and popup list for selecting options.
\qmltype Particle \inqmlmodule QtQuick.Particles
quint64 ReturnedValue
@ Attr_NotConfigurable
@ Attr_NotEnumerable
@ Attr_Accessor
@ SingleShotConnection
QVector3D minimum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW
Definition qssgutils_p.h:52
QVector3D maximum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW
Definition qssgutils_p.h:53
static int arrayLength(const QString &rawType)
Definition provider.cpp:52
static void * context
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char * destination
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static QV4::ExecutionEngine * v4Engine(QV4::Value *d)
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
@ DynamicMetaObject
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLsizei GLuint * groups
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLuint object
[3]
GLfloat GLfloat f
GLboolean GLuint group
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLuint name
GLenum GLenum GLsizei void GLsizei void * column
GLhandleARB obj
[2]
GLboolean reset
const GLubyte * c
GLuint GLfloat * val
GLenum array
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
static qreal dot(const QPointF &a, const QPointF &b)
static void add(QPainterPath &path, const QWingedEdge &list, int edge, QPathEdge::Traversal traversal)
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:71
static QQmlRefPointer< QQmlContextData > initProxy(QQmlDelegateModelItem *cacheItem)
static bool isDoneIncubating(QQmlIncubator::Status status)
static void incrementIndexes(QQmlDelegateModelItem *cacheItem, int count, const int *deltas)
QQmlDelegateModelGroupEmitterList::iterator GroupEmitterListIt
QT_BEGIN_NAMESPACE typedef QQmlListCompositor Compositor
#define qmlobject_connect(Sender, SenderType, Signal, Receiver, ReceiverType, Method)
Connect Signal of Sender to Method of Receiver.
void QQml_setParent_noEvent(QObject *object, QObject *parent)
Makes the object a child of parent.
#define IS_SIGNAL_CONNECTED(Sender, SenderType, Name, Arguments)
Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me)
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
SSL_CTX int(*) void arg)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
#define tr(X)
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define emit
#define Q_UNUSED(x)
@ desc
unsigned int quint32
Definition qtypes.h:45
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
#define V4_DEFINE_EXTENSION(dataclass, datafunction)
Definition qv4engine_p.h:38
#define V4_NEEDS_DESTROY
#define THROW_TYPE_ERROR()
#define RETURN_UNDEFINED()
#define DEFINE_OBJECT_VTABLE(classname)
#define V4_OBJECT2(DataClass, superClass)
const char property[13]
Definition qwizard.cpp:101
const char className[16]
[1]
Definition qwizard.cpp:100
QSqlQueryModel * model
[16]
settings remove("monkey")
obj metaObject() -> className()
QObject::connect nullptr
QGraphicsItem * item
QList< QTreeWidgetItem * > items
QNetworkProxy proxy
[0]
view create()
QJSValueList args
QJSValue global
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:17
qsizetype lastIndexOf(const AT &t, qsizetype from=-1) const noexcept
Definition qlist.h:962
\inmodule QtCore
const QMetaObject * superClass() const
Returns the meta-object of the superclass, or \nullptr if there is no such object.
static void activate(QObject *sender, int signal_index, void **argv)
Definition qobject.cpp:4057
const QQmlChangeSet::Change & at(int index) const
static QV4::Heap::QQmlDelegateModelGroupChangeArray * create(QV4::ExecutionEngine *engine, const QVector< QQmlChangeSet::Change > &changes)
static QV4::ReturnedValue virtualGet(const QV4::Managed *m, QV4::PropertyKey id, const QV4::Value *receiver, bool *hasProperty)
static QV4::ReturnedValue method_get_index(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
static QV4::ReturnedValue method_get_moveId(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
static QV4::Heap::QQmlDelegateModelGroupChange * create(QV4::ExecutionEngine *e)
static QV4::ReturnedValue method_get_count(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
static ReturnedValue virtualCall(const QV4::FunctionObject *that, const Value *thisObject, const Value *argv, int argc)
static Heap::DelegateModelGroupFunction * create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue(*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
static constexpr ReturnedValue undefined()
MemoryManager * memoryManager
ExecutionContext * rootContext() const
Heap::String * newString(const QString &s=QString())
QV4::ReturnedValue fromVariant(const QVariant &)
Heap::Object * newObject()
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols=true)
ReturnedValue throwTypeError()
void init(const QVector< QQmlChangeSet::Change > &changes)
QVector< QQmlChangeSet::Change > * changes
ExecutionEngine * engine() const
static ReturnedValue wrap(ExecutionEngine *engine, QObject *object)
ExecutionEngine * engine
constexpr ReturnedValue asReturnedValue() const
static constexpr Value undefinedValue()
Definition qv4value_p.h:191
const T * as() const
Definition qv4value_p.h:132
QString toQStringNoThrow() const
Definition qv4value.cpp:122
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent