Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
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
53 QVector<QQmlChangeSet::Change> *changes;
54};
55
56
57}
58
60{
62
65 QV4::ReturnedValue (*code)(QQmlDelegateModelItem *, uint, const QV4::Value &))
66 {
67 return engine->memoryManager->allocate<DelegateModelGroupFunction>(engine, flag, code);
68 }
69
70 static ReturnedValue virtualCall(const QV4::FunctionObject *that, const Value *thisObject, const Value *argv, int argc)
71 {
72 QV4::Scope scope(that->engine());
75 if (!o)
76 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
77
78 QV4::ScopedValue v(scope, argc ? argv[0] : Value::undefinedValue());
79 return f->d()->code(o->d()->item, f->d()->flag, v);
80 }
81};
82
83void Heap::DelegateModelGroupFunction::init(
86{
87 QV4::Heap::FunctionObject::init(engine, QStringLiteral("DelegateModelGroupFunction"));
88 this->flag = flag;
89 this->code = code;
90}
91
92}
93
95
96
97
109
111
112
114{
115 prop.setWritable(false);
116}
117
119{
120 QQmlDelegateModelParts *parts = static_cast<QQmlDelegateModelParts *>(object());
122 parts->model, QString::fromUtf8(name(id)), parts);
123 parts->models.append(m);
124 return QVariant::fromValue(static_cast<QObject *>(m));
125}
126
132
133//---------------------------------------------------------------------------
134
138
160 : m_delegateChooser(nullptr)
161 , m_cacheMetaType(nullptr)
162 , m_context(ctxt)
163 , m_parts(nullptr)
164 , m_filterGroup(QStringLiteral("items"))
165 , m_count(0)
166 , m_groupCount(Compositor::MinimumGroupCount)
167 , m_compositorGroup(Compositor::Cache)
168 , m_complete(false)
169 , m_delegateValidated(false)
170 , m_reset(false)
171 , m_transaction(false)
172 , m_incubatorCleanupScheduled(false)
173 , m_waitingToFetchMore(false)
174 , m_cacheItems(nullptr)
175 , m_items(nullptr)
176 , m_persistedItems(nullptr)
177{
178}
179
190
192{
193 // QQmlDelegateModel currently only support list models.
194 // So even if a model is a table model, only the first
195 // column will be used.
196 return m_adaptorModel.rowCount();
197}
198
207
209{
211 m_compositor.setRemoveGroups(Compositor::GroupMask & ~Compositor::PersistedFlag);
212
213 m_items = new QQmlDelegateModelGroup(QStringLiteral("items"), q, Compositor::Default, q);
215 m_persistedItems = new QQmlDelegateModelGroup(QStringLiteral("persistedItems"), q, Compositor::Persisted, q);
216 QQmlDelegateModelGroupPrivate::get(m_items)->emitters.insert(this);
217}
218
223
225: QQmlInstanceModel(*(new QQmlDelegateModelPrivate(ctxt)), parent)
226{
228 d->init();
229}
230
232{
234 d->disconnectFromAbstractItemModel();
235 d->m_adaptorModel.setObject(nullptr);
236
237 for (QQmlDelegateModelItem *cacheItem : std::as_const(d->m_cache)) {
238 if (cacheItem->object) {
239 delete cacheItem->object;
240
241 cacheItem->object = nullptr;
242 cacheItem->contextData.reset();
243 cacheItem->scriptRef -= 1;
244 } else if (cacheItem->incubationTask) {
245 // Both the incubationTask and the object may hold a scriptRef,
246 // but if both are present, only one scriptRef is held in total.
247 cacheItem->scriptRef -= 1;
248 }
249
250 cacheItem->groups &= ~Compositor::UnresolvedFlag;
251 cacheItem->objectRef = 0;
252
253 if (cacheItem->incubationTask) {
254 d->releaseIncubator(cacheItem->incubationTask);
255 cacheItem->incubationTask->vdm = nullptr;
256 cacheItem->incubationTask = nullptr;
257 }
258
259 if (!cacheItem->isReferenced())
260 delete cacheItem;
261 }
262}
263
264
266{
268 if (!d->m_context)
269 d->m_context = qmlContext(this);
270}
271
273{
275 d->m_complete = true;
276
277 int defaultGroups = 0;
278 QStringList groupNames;
279 groupNames.append(QStringLiteral("items"));
280 groupNames.append(QStringLiteral("persistedItems"));
281 if (QQmlDelegateModelGroupPrivate::get(d->m_items)->defaultInclude)
282 defaultGroups |= Compositor::DefaultFlag;
283 if (QQmlDelegateModelGroupPrivate::get(d->m_persistedItems)->defaultInclude)
284 defaultGroups |= Compositor::PersistedFlag;
285 for (int i = Compositor::MinimumGroupCount; i < d->m_groupCount; ++i) {
286 QString name = d->m_groups[i]->name();
287 if (name.isEmpty()) {
288 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
289 --d->m_groupCount;
290 --i;
291 } else if (name.at(0).isUpper()) {
292 qmlWarning(d->m_groups[i]) << QQmlDelegateModelGroup::tr("Group names must start with a lower case letter");
293 d->m_groups[i] = d->m_groups[d->m_groupCount - 1];
294 --d->m_groupCount;
295 --i;
296 } else {
297 groupNames.append(name);
298
300 group->setModel(this, Compositor::Group(i));
301 if (group->defaultInclude)
302 defaultGroups |= (1 << i);
303 }
304 }
305
306 d->m_cacheMetaType = new QQmlDelegateModelItemMetaType(
307 d->m_context->engine()->handle(), this, groupNames);
308
309 d->m_compositor.setGroupCount(d->m_groupCount);
310 d->m_compositor.setDefaultGroups(defaultGroups);
311 d->updateFilterGroup();
312
313 while (!d->m_pendingParts.isEmpty())
314 static_cast<QQmlPartsModel *>(d->m_pendingParts.first())->updateFilterGroup();
315
316 QVector<Compositor::Insert> inserts;
317 d->m_count = d->adaptorModelCount();
318 d->m_compositor.append(
319 &d->m_adaptorModel,
320 0,
321 d->m_count,
322 defaultGroups | Compositor::AppendFlag | Compositor::PrependFlag,
323 &inserts);
324 d->itemsInserted(inserts);
325 d->emitChanges();
326 d->requestMoreIfNecessary();
327}
328
345{
346 Q_D(const QQmlDelegateModel);
347 return d->m_adaptorModel.model();
348}
349
351{
354 return;
355
356 auto aim = m_adaptorModel.aim();
357
358 QObject::connect(aim, &QAbstractItemModel::rowsInserted, q, &QQmlDelegateModel::_q_rowsInserted);
359 QObject::connect(aim, &QAbstractItemModel::rowsRemoved, q, &QQmlDelegateModel::_q_rowsRemoved);
360 QObject::connect(aim, &QAbstractItemModel::rowsAboutToBeRemoved, q, &QQmlDelegateModel::_q_rowsAboutToBeRemoved);
361 QObject::connect(aim, &QAbstractItemModel::columnsInserted, q, &QQmlDelegateModel::_q_columnsInserted);
362 QObject::connect(aim, &QAbstractItemModel::columnsRemoved, q, &QQmlDelegateModel::_q_columnsRemoved);
363 QObject::connect(aim, &QAbstractItemModel::columnsMoved, q, &QQmlDelegateModel::_q_columnsMoved);
364 QObject::connect(aim, &QAbstractItemModel::dataChanged, q, &QQmlDelegateModel::_q_dataChanged);
365 QObject::connect(aim, &QAbstractItemModel::rowsMoved, q, &QQmlDelegateModel::_q_rowsMoved);
366 QObject::connect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset);
367 QObject::connect(aim, &QAbstractItemModel::layoutChanged, q, &QQmlDelegateModel::_q_layoutChanged);
368}
369
371{
374 return;
375
376 auto aim = m_adaptorModel.aim();
377
378 QObject::disconnect(aim, &QAbstractItemModel::rowsInserted, q, &QQmlDelegateModel::_q_rowsInserted);
379 QObject::disconnect(aim, &QAbstractItemModel::rowsAboutToBeRemoved, q, &QQmlDelegateModel::_q_rowsAboutToBeRemoved);
380 QObject::disconnect(aim, &QAbstractItemModel::rowsRemoved, q, &QQmlDelegateModel::_q_rowsRemoved);
381 QObject::disconnect(aim, &QAbstractItemModel::columnsInserted, q, &QQmlDelegateModel::_q_columnsInserted);
382 QObject::disconnect(aim, &QAbstractItemModel::columnsRemoved, q, &QQmlDelegateModel::_q_columnsRemoved);
383 QObject::disconnect(aim, &QAbstractItemModel::columnsMoved, q, &QQmlDelegateModel::_q_columnsMoved);
384 QObject::disconnect(aim, &QAbstractItemModel::dataChanged, q, &QQmlDelegateModel::_q_dataChanged);
385 QObject::disconnect(aim, &QAbstractItemModel::rowsMoved, q, &QQmlDelegateModel::_q_rowsMoved);
386 QObject::disconnect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset);
387 QObject::disconnect(aim, &QAbstractItemModel::layoutChanged, q, &QQmlDelegateModel::_q_layoutChanged);
388}
389
391{
393
394 if (d->m_complete)
395 _q_itemsRemoved(0, d->m_count);
396
397 d->disconnectFromAbstractItemModel();
398 d->m_adaptorModel.setModel(model);
399 d->connectToAbstractItemModel();
400
401 d->m_adaptorModel.replaceWatchedRoles(QList<QByteArray>(), d->m_watchedRoles);
402 for (int i = 0; d->m_parts && i < d->m_parts->models.size(); ++i) {
403 d->m_adaptorModel.replaceWatchedRoles(
404 QList<QByteArray>(), d->m_parts->models.at(i)->watchedRoles());
405 }
406
407 if (d->m_complete) {
408 _q_itemsInserted(0, d->adaptorModelCount());
409 d->requestMoreIfNecessary();
410 }
411}
412
421{
422 Q_D(const QQmlDelegateModel);
423 return d->m_delegate;
424}
425
427{
429 if (d->m_transaction) {
430 qmlWarning(this) << tr("The delegate of a DelegateModel cannot be changed within onUpdated.");
431 return;
432 }
433 if (d->m_delegate == delegate)
434 return;
435 if (d->m_complete)
436 _q_itemsRemoved(0, d->m_count);
437 d->m_delegate.setObject(delegate, this);
438 d->m_delegateValidated = false;
439 if (d->m_delegateChooser)
440 QObject::disconnect(d->m_delegateChooserChanged);
441
442 d->m_delegateChooser = nullptr;
443 if (delegate) {
445 qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
446 if (adc) {
447 d->m_delegateChooser = adc;
448 d->m_delegateChooserChanged = connect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this,
449 [d](){ d->delegateChanged(); });
450 }
451 }
452 if (d->m_complete) {
453 _q_itemsInserted(0, d->adaptorModelCount());
454 d->requestMoreIfNecessary();
455 }
457}
458
488{
489 Q_D(const QQmlDelegateModel);
490 return QVariant::fromValue(QModelIndex(d->m_adaptorModel.rootIndex));
491}
492
494{
496
497 QModelIndex modelIndex = qvariant_cast<QModelIndex>(root);
498 const bool changed = d->m_adaptorModel.rootIndex != modelIndex;
499 if (changed || !d->m_adaptorModel.isValid()) {
500 const int oldCount = d->m_count;
501 d->m_adaptorModel.rootIndex = modelIndex;
502 if (!d->m_adaptorModel.isValid() && d->m_adaptorModel.aim()) {
503 // The previous root index was invalidated, so we need to reconnect the model.
504 d->disconnectFromAbstractItemModel();
505 d->m_adaptorModel.setModel(d->m_adaptorModel.list.list());
506 d->connectToAbstractItemModel();
507 }
508 if (d->m_adaptorModel.canFetchMore())
509 d->m_adaptorModel.fetchMore();
510 if (d->m_complete) {
511 const int newCount = d->adaptorModelCount();
512 if (oldCount)
513 _q_itemsRemoved(0, oldCount);
514 if (newCount)
515 _q_itemsInserted(0, newCount);
516 }
517 if (changed)
519 }
520}
521
535{
536 Q_D(const QQmlDelegateModel);
537 return d->m_adaptorModel.modelIndex(idx);
538}
539
553{
554 Q_D(const QQmlDelegateModel);
555 return d->m_adaptorModel.parentModelIndex();
556}
557
563{
564 Q_D(const QQmlDelegateModel);
565 if (!d->m_delegate)
566 return 0;
567 return d->m_compositor.count(d->m_compositorGroup);
568}
569
570QQmlDelegateModel::ReleaseFlags QQmlDelegateModelPrivate::release(QObject *object, QQmlInstanceModel::ReusableFlag reusableFlag)
571{
572 if (!object)
573 return QQmlDelegateModel::ReleaseFlags{};
574
576 if (!cacheItem)
577 return QQmlDelegateModel::ReleaseFlags{};
578
579 if (!cacheItem->releaseObject())
581
582 if (reusableFlag == QQmlInstanceModel::Reusable) {
583 removeCacheItem(cacheItem);
585 emit q_func()->itemPooled(cacheItem->index, cacheItem->object);
587 }
588
589 destroyCacheItem(cacheItem);
591}
592
594{
595 emitDestroyingItem(cacheItem->object);
596 cacheItem->destroyObject();
597 if (cacheItem->incubationTask) {
598 releaseIncubator(cacheItem->incubationTask);
599 cacheItem->incubationTask = nullptr;
600 }
601 cacheItem->Dispose();
602}
603
604/*
605 Returns ReleaseStatus flags.
606*/
607QQmlDelegateModel::ReleaseFlags QQmlDelegateModel::release(QObject *item, QQmlInstanceModel::ReusableFlag reusableFlag)
608{
610 QQmlInstanceModel::ReleaseFlags stat = d->release(item, reusableFlag);
611 return stat;
612}
613
614// Cancel a requested async item
616{
618 if (index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
619 qWarning() << "DelegateModel::cancel: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
620 return;
621 }
622
623 Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
624 QQmlDelegateModelItem *cacheItem = it->inCache() ? d->m_cache.at(it.cacheIndex()) : 0;
625 if (cacheItem) {
626 if (cacheItem->incubationTask && !cacheItem->isObjectReferenced()) {
627 d->releaseIncubator(cacheItem->incubationTask);
628 cacheItem->incubationTask = nullptr;
629
630 if (cacheItem->object) {
631 QObject *object = cacheItem->object;
632 cacheItem->destroyObject();
633 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
634 d->emitDestroyingPackage(package);
635 else
636 d->emitDestroyingItem(object);
637 }
638
639 cacheItem->scriptRef -= 1;
640 }
641 if (!cacheItem->isReferenced()) {
642 d->m_compositor.clearFlags(
643 Compositor::Cache, it.cacheIndex(), 1, Compositor::CacheFlag);
644 d->m_cache.removeAt(it.cacheIndex());
645 delete cacheItem;
646 Q_ASSERT(d->m_cache.size() == d->m_compositor.count(Compositor::Cache));
647 }
648 }
649}
650
652 QQmlListProperty<QQmlDelegateModelGroup> *property, QQmlDelegateModelGroup *group)
653{
654 QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
655 if (d->m_complete)
656 return;
657 if (d->m_groupCount == Compositor::MaximumGroupCount) {
658 qmlWarning(d->q_func()) << QQmlDelegateModel::tr("The maximum number of supported DelegateModelGroups is 8");
659 return;
660 }
661 d->m_groups[d->m_groupCount] = group;
662 d->m_groupCount += 1;
663}
664
666 QQmlListProperty<QQmlDelegateModelGroup> *property)
667{
668 QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
669 return d->m_groupCount - 1;
670}
671
673 QQmlListProperty<QQmlDelegateModelGroup> *property, qsizetype index)
674{
675 QQmlDelegateModelPrivate *d = static_cast<QQmlDelegateModelPrivate *>(property->data);
676 return index >= 0 && index < d->m_groupCount - 1
677 ? d->m_groups[index + 1]
678 : nullptr;
679}
680
709QQmlListProperty<QQmlDelegateModelGroup> QQmlDelegateModel::groups()
710{
712 return QQmlListProperty<QQmlDelegateModelGroup>(
713 this,
714 d,
718 nullptr, nullptr, nullptr);
719}
720
728{
730 return d->m_items;
731}
732
751{
753 return d->m_persistedItems;
754}
755
767{
768 Q_D(const QQmlDelegateModel);
769 return d->m_filterGroup;
770}
771
773{
775
776 if (d->m_transaction) {
777 qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged");
778 return;
779 }
780
781 if (d->m_filterGroup != group) {
782 d->m_filterGroup = group;
783 d->updateFilterGroup();
785 }
786}
787
792
794{
796 if (!m_cacheMetaType)
797 return;
798
800 m_compositorGroup = Compositor::Default;
801 for (int i = 1; i < m_groupCount; ++i) {
802 if (m_filterGroup == m_cacheMetaType->groupNames.at(i - 1)) {
803 m_compositorGroup = Compositor::Group(i);
804 break;
805 }
806 }
807
809 if (m_compositorGroup != previousGroup) {
810 QVector<QQmlChangeSet::Change> removes;
811 QVector<QQmlChangeSet::Change> inserts;
812 m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
813
814 QQmlChangeSet changeSet;
815 changeSet.move(removes, inserts);
816 emit q->modelUpdated(changeSet, false);
817
818 if (changeSet.difference() != 0)
819 emit q->countChanged();
820
821 if (m_parts) {
822 auto partsCopy = m_parts->models; // deliberate; this may alter m_parts
823 for (QQmlPartsModel *model : std::as_const(partsCopy))
824 model->updateFilterGroup(m_compositorGroup, changeSet);
825 }
826 }
827}
828
858{
860 if (!d->m_parts)
861 d->m_parts = new QQmlDelegateModelParts(this);
862 return d->m_parts;
863}
864
866{
867 Q_D(const QQmlDelegateModel);
868 return d->m_adaptorModel.adaptsAim() ? d->m_adaptorModel.aim() : nullptr;
869}
870
872{
873 for (int i = 1; i < m_groupCount; ++i)
874 QQmlDelegateModelGroupPrivate::get(m_groups[i])->createdPackage(incubationTask->index[i], package);
875}
876
878{
879 for (int i = 1; i < m_groupCount; ++i)
880 QQmlDelegateModelGroupPrivate::get(m_groups[i])->initPackage(incubationTask->index[i], package);
881}
882
884{
885 for (int i = 1; i < m_groupCount; ++i)
886 QQmlDelegateModelGroupPrivate::get(m_groups[i])->destroyingPackage(package);
887}
888
890{
891 return status == QQmlIncubator::Ready || status == QQmlIncubator::Error;
892}
893
895{
896 // QQmlObjectCreator produces a private internal context.
897 // We can always attach the extra object there.
898 QQmlData *d = QQmlData::get(object);
899 if (auto contextData = d ? d->context : nullptr)
900 contextData->setExtraObject(modelItemToIncubate);
901
902 Q_ASSERT(modelItemToIncubate->delegate);
903 const bool isBound = QQmlComponentPrivate::get(modelItemToIncubate->delegate)->isBound();
904
905 auto incubatorPriv = QQmlIncubatorPrivate::get(this);
906 if (incubatorPriv->hadTopLevelRequiredProperties()) {
907 // If we have required properties, we clear the context object
908 // so that the model role names are not polluting the context.
909 // Unless the context is bound, in which case we have never set the context object.
910 if (incubating && !isBound) {
913 }
914 if (proxyContext) {
916 }
917
918 // Retrieve the metaObject before the potential return so that the accessors have a chance
919 // to perform some finalization in case they produce a dynamic metaobject. Here we know for
920 // sure that we are using required properties.
921 const QMetaObject *qmlMetaObject = modelItemToIncubate->metaObject();
922
923 if (incubatorPriv->requiredProperties()->empty())
924 return;
925 RequiredProperties *requiredProperties = incubatorPriv->requiredProperties();
926
927 // if a required property was not in the model, it might still be a static property of the
928 // QQmlDelegateModelItem or one of its derived classes this is the case for index, row,
929 // column, model and more
930 // the most derived subclasses of QQmlDelegateModelItem are QQmlDMAbstractItemModelData and
931 // QQmlDMObjectData at depth 2, so 4 should be plenty
932 QVarLengthArray<QPair<const QMetaObject *, QObject *>, 4> mos;
933 // we first check the dynamic meta object for properties originating from the model
934 // contains abstractitemmodelproperties
935 mos.push_back(qMakePair(qmlMetaObject, modelItemToIncubate));
936 auto delegateModelItemSubclassMO = qmlMetaObject->superClass();
937 mos.push_back(qMakePair(delegateModelItemSubclassMO, modelItemToIncubate));
938
939 while (strcmp(delegateModelItemSubclassMO->className(),
940 modelItemToIncubate->staticMetaObject.className())) {
941 delegateModelItemSubclassMO = delegateModelItemSubclassMO->superClass();
942 mos.push_back(qMakePair(delegateModelItemSubclassMO, modelItemToIncubate));
943 }
944 if (proxiedObject)
945 mos.push_back(qMakePair(proxiedObject->metaObject(), proxiedObject));
946
947 QQmlEngine *engine = QQmlEnginePrivate::get(incubatorPriv->enginePriv);
949 QV4::Scope scope(v4);
950
951 for (const auto &metaObjectAndObject : mos) {
952 const QMetaObject *mo = metaObjectAndObject.first;
953 QObject *itemOrProxy = metaObjectAndObject.second;
955
956 for (int i = mo->propertyOffset(); i < mo->propertyCount() + mo->propertyOffset(); ++i) {
957 auto prop = mo->property(i);
958 if (!prop.name())
959 continue;
960 const QString propName = QString::fromUtf8(prop.name());
961 bool wasInRequired = false;
963 object, propName, requiredProperties,
964 engine, &wasInRequired);
965 if (wasInRequired) {
966 QQmlAnyBinding binding;
967 binding = new QQmlPropertyToPropertyBinding(
968 engine, itemOrProxy, i, targetProp.object(), targetProp.index());
969 binding.installOn(targetProp);
970 }
971 }
972 }
973 } else {
974 if (!isBound)
975 modelItemToIncubate->contextData->setContextObject(modelItemToIncubate);
976 if (proxiedObject)
978
979 // Retrieve the metaObject() once so that the accessors have a chance to perform some
980 // finalization in case they produce a dynamic metaobject. For example, they might be
981 // inclined to create a propertyCache now because there are no required properties and any
982 // revisioned properties should be hidden after all. Here is the first time we know for
983 // sure whether we are using context properties.
984 modelItemToIncubate->metaObject();
985 }
986}
987
989{
990 if (vdm) {
992 } else if (isDoneIncubating(status)) {
994 // The model was deleted from under our feet, cleanup ourselves
995 delete incubating->object;
996 incubating->object = nullptr;
1000 }
1001}
1002
1004{
1005 Q_Q(QQmlDelegateModel);
1006 if (!incubationTask->isError())
1007 incubationTask->clear();
1008 m_finishedIncubating.append(incubationTask);
1012 }
1013}
1014
1016{
1017 Q_ASSERT(item->object);
1018
1019 // Update/reset which groups the item belongs to
1020 item->groups = newGroups;
1021
1022 // Update context property index (including row and column) on the delegate
1023 // item, and inform the application about it. For a list, the row is the same
1024 // as the index, and the column is always 0. We set alwaysEmit to true, to
1025 // force all bindings to be reevaluated, even if the index didn't change.
1026 const bool alwaysEmit = true;
1027 item->setModelIndex(newModelIndex, newModelIndex, 0, alwaysEmit);
1028
1029 // Notify the application that all 'dynamic'/role-based context data has
1030 // changed as well (their getter function will use the updated index).
1031 auto const itemAsList = QList<QQmlDelegateModelItem *>() << item;
1032 auto const updateAllRoles = QVector<int>();
1033 m_adaptorModel.notify(itemAsList, newModelIndex, 1, updateAllRoles);
1034
1035 if (QQmlDelegateModelAttached *att = static_cast<QQmlDelegateModelAttached *>(
1036 qmlAttachedPropertiesObject<QQmlDelegateModel>(item->object, false))) {
1037 // Update currentIndex of the attached DelegateModel object
1038 // to the index the item has in the cache.
1039 att->resetCurrentIndex();
1040 // emitChanges will emit both group-, and index changes to the application
1041 att->emitChanges();
1042 }
1043
1044 // Inform the view that the item is recycled. This will typically result
1045 // in the view updating its own attached delegate item properties.
1046 emit q_func()->itemReused(newModelIndex, item->object);
1047}
1048
1050{
1051 m_reusableItemsPool.drain(maxPoolTime, [this](QQmlDelegateModelItem *cacheItem){ destroyCacheItem(cacheItem); });
1052}
1053
1055{
1056 d_func()->drainReusableItemsPool(maxPoolTime);
1057}
1058
1060{
1061 return d_func()->m_reusableItemsPool.size();
1062}
1063
1065{
1066 if (!m_delegateChooser)
1067 return m_delegate;
1068
1069 QQmlComponent *delegate = nullptr;
1071
1072 do {
1073 delegate = chooser->delegate(&m_adaptorModel, index);
1074 chooser = qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
1075 } while (chooser);
1076
1077 return delegate;
1078}
1079
1081{
1082 m_cache.insert(it.cacheIndex(), item);
1083 m_compositor.setFlags(it, 1, Compositor::CacheFlag);
1084 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1085}
1086
1088{
1089 int cidx = m_cache.lastIndexOf(cacheItem);
1090 if (cidx >= 0) {
1091 m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag);
1092 m_cache.removeAt(cidx);
1093 }
1094 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1095}
1096
1098{
1099 if (!isDoneIncubating(status))
1100 return;
1101
1102 const QList<QQmlError> incubationTaskErrors = incubationTask->errors();
1103
1104 QQmlDelegateModelItem *cacheItem = incubationTask->incubating;
1105 cacheItem->incubationTask = nullptr;
1106 incubationTask->incubating = nullptr;
1107 releaseIncubator(incubationTask);
1108
1109 if (status == QQmlIncubator::Ready) {
1110 cacheItem->referenceObject();
1111 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
1112 emitCreatedPackage(incubationTask, package);
1113 else
1114 emitCreatedItem(incubationTask, cacheItem->object);
1115 cacheItem->releaseObject();
1116 } else if (status == QQmlIncubator::Error) {
1117 qmlInfo(m_delegate, incubationTaskErrors + m_delegate->errors()) << "Cannot create delegate";
1118 }
1119
1120 if (!cacheItem->isObjectReferenced()) {
1121 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
1122 emitDestroyingPackage(package);
1123 else
1124 emitDestroyingItem(cacheItem->object);
1125 delete cacheItem->object;
1126 cacheItem->object = nullptr;
1127 cacheItem->scriptRef -= 1;
1128 cacheItem->contextData.reset();
1129
1130 if (!cacheItem->isReferenced()) {
1131 removeCacheItem(cacheItem);
1132 delete cacheItem;
1133 }
1134 }
1135}
1136
1141
1143{
1144 QQmlDelegateModelItem *cacheItem = incubationTask->incubating;
1145 incubationTask->initializeRequiredProperties(incubationTask->incubating, o);
1146 cacheItem->object = o;
1147
1148 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
1149 emitInitPackage(incubationTask, package);
1150 else
1151 emitInitItem(incubationTask, cacheItem->object);
1152}
1153
1154static QQmlRefPointer<QQmlContextData> initProxy(QQmlDelegateModelItem *cacheItem)
1155{
1157 = qobject_cast<QQmlAdaptorModelProxyInterface *>(cacheItem);
1158 if (!proxy)
1159 return cacheItem->contextData;
1160
1161 QQmlRefPointer<QQmlContextData> ctxt = QQmlContextData::createChild(cacheItem->contextData);
1162 QObject *proxied = proxy->proxiedObject();
1163 cacheItem->incubationTask->proxiedObject = proxied;
1164 cacheItem->incubationTask->proxyContext = ctxt;
1165 ctxt->setContextObject(cacheItem);
1166 // We don't own the proxied object. We need to clear it if it goes away.
1169 return ctxt;
1170}
1171
1173{
1174 if (!m_delegate || index < 0 || index >= m_compositor.count(group)) {
1175 qWarning() << "DelegateModel::item: index out range" << index << m_compositor.count(group);
1176 return nullptr;
1177 } else if (!m_context || !m_context->isValid()) {
1178 return nullptr;
1179 }
1180
1181 Compositor::iterator it = m_compositor.find(group, index);
1182 const auto flags = it->flags;
1183 const auto modelIndex = it.modelIndex();
1184
1185 QQmlDelegateModelItem *cacheItem = it->inCache() ? m_cache.at(it.cacheIndex()) : 0;
1186
1187 if (!cacheItem || !cacheItem->delegate) {
1188 QQmlComponent *delegate = resolveDelegate(modelIndex);
1189 if (!delegate)
1190 return nullptr;
1191
1192 if (!cacheItem) {
1193 cacheItem = m_reusableItemsPool.takeItem(delegate, index);
1194 if (cacheItem) {
1195 // Move the pooled item back into the cache, update
1196 // all related properties, and return the object (which
1197 // has already been incubated, otherwise it wouldn't be in the pool).
1198 addCacheItem(cacheItem, it);
1199 reuseItem(cacheItem, index, flags);
1200 cacheItem->referenceObject();
1201
1202 if (index == m_compositor.count(group) - 1)
1204 return cacheItem->object;
1205 }
1206
1207 // Since we could't find an available item in the pool, we create a new one
1208 cacheItem = m_adaptorModel.createItem(m_cacheMetaType, modelIndex);
1209 if (!cacheItem)
1210 return nullptr;
1211
1212 cacheItem->groups = flags;
1213 addCacheItem(cacheItem, it);
1214 }
1215
1216 cacheItem->delegate = delegate;
1217 }
1218
1219 // Bump the reference counts temporarily so neither the content data or the delegate object
1220 // are deleted if incubatorStatusChanged() is called synchronously.
1221 cacheItem->scriptRef += 1;
1222 cacheItem->referenceObject();
1223
1224 if (cacheItem->incubationTask) {
1225 bool sync = (incubationMode == QQmlIncubator::Synchronous || incubationMode == QQmlIncubator::AsynchronousIfNested);
1226 if (sync && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) {
1227 // previously requested async - now needed immediately
1228 cacheItem->incubationTask->forceCompletion();
1229 }
1230 } else if (!cacheItem->object) {
1231 QQmlContext *creationContext = cacheItem->delegate->creationContext();
1232
1233 cacheItem->scriptRef += 1;
1234
1235 cacheItem->incubationTask = new QQDMIncubationTask(this, incubationMode);
1236 cacheItem->incubationTask->incubating = cacheItem;
1237 cacheItem->incubationTask->clear();
1238
1239 for (int i = 1; i < m_groupCount; ++i)
1240 cacheItem->incubationTask->index[i] = it.index[i];
1241
1242 const QQmlRefPointer<QQmlContextData> componentContext
1243 = QQmlContextData::get(creationContext ? creationContext : m_context.data());
1244 QQmlComponentPrivate *cp = QQmlComponentPrivate::get(cacheItem->delegate);
1245
1246 if (cp->isBound()) {
1247 cacheItem->contextData = componentContext;
1248
1249 // Ignore return value of initProxy. We want to know the proxy when assigning required
1250 // properties, but we don't want it to pollute our context. The context is bound.
1252 initProxy(cacheItem);
1253
1254 cp->incubateObject(
1255 cacheItem->incubationTask,
1256 cacheItem->delegate,
1257 m_context->engine(),
1258 componentContext,
1260 } else {
1261 QQmlRefPointer<QQmlContextData> ctxt
1262 = QQmlContextData::createRefCounted(componentContext);
1263 ctxt->setContextObject(cacheItem);
1264 cacheItem->contextData = ctxt;
1265
1267 ctxt = initProxy(cacheItem);
1268
1269 cp->incubateObject(
1270 cacheItem->incubationTask,
1271 cacheItem->delegate,
1272 m_context->engine(),
1273 ctxt,
1275 }
1276 }
1277
1278 if (index == m_compositor.count(group) - 1)
1280
1281 // Remove the temporary reference count.
1282 cacheItem->scriptRef -= 1;
1283 if (cacheItem->object && (!cacheItem->incubationTask || isDoneIncubating(cacheItem->incubationTask->status())))
1284 return cacheItem->object;
1285
1286 if (cacheItem->objectRef > 0)
1287 cacheItem->releaseObject();
1288
1289 if (!cacheItem->isReferenced()) {
1290 removeCacheItem(cacheItem);
1291 delete cacheItem;
1292 }
1293
1294 return nullptr;
1295}
1296
1297/*
1298 If asynchronous is true or the component is being loaded asynchronously due
1299 to an ancestor being loaded asynchronously, object() may return 0. In this
1300 case createdItem() will be emitted when the object is available. The object
1301 at this stage does not have any references, so object() must be called again
1302 to ensure a reference is held. Any call to object() which returns a valid object
1303 must be matched by a call to release() in order to destroy the object.
1304*/
1306{
1307 Q_D(QQmlDelegateModel);
1308 if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) {
1309 qWarning() << "DelegateModel::item: index out range" << index << d->m_compositor.count(d->m_compositorGroup);
1310 return nullptr;
1311 }
1312
1313 return d->object(d->m_compositorGroup, index, incubationMode);
1314}
1315
1317{
1318 Q_D(QQmlDelegateModel);
1319 if (d->m_compositor.count(d->m_compositorGroup) <= index)
1320 return QQmlIncubator::Null;
1321 Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index);
1322 if (!it->inCache())
1323 return QQmlIncubator::Null;
1324
1325 if (auto incubationTask = d->m_cache.at(it.cacheIndex())->incubationTask)
1326 return incubationTask->status();
1327
1328 return QQmlIncubator::Ready;
1329}
1330
1332{
1333 Compositor::iterator it = m_compositor.find(group, index);
1334 if (QQmlAdaptorModel *model = it.list<QQmlAdaptorModel>()) {
1335 QString role = name;
1336 int dot = name.indexOf(QLatin1Char('.'));
1337 if (dot > 0)
1338 role = name.left(dot);
1339 QVariant value = model->value(it.modelIndex(), role);
1340 while (dot > 0) {
1341 QObject *obj = qvariant_cast<QObject*>(value);
1342 if (!obj)
1343 return QVariant();
1344 const int from = dot + 1;
1345 dot = name.indexOf(QLatin1Char('.'), from);
1346 value = obj->property(QStringView{name}.mid(from, dot - from).toUtf8());
1347 }
1348 return value;
1349 }
1350 return QVariant();
1351}
1352
1354{
1355 Q_D(QQmlDelegateModel);
1356 return d->variantValue(d->m_compositorGroup, index, role);
1357}
1358
1360{
1361 Q_D(const QQmlDelegateModel);
1363 return cacheItem->groupIndex(d->m_compositorGroup);
1364 return -1;
1365}
1366
1367void QQmlDelegateModel::setWatchedRoles(const QList<QByteArray> &roles)
1368{
1369 Q_D(QQmlDelegateModel);
1370 d->m_adaptorModel.replaceWatchedRoles(d->m_watchedRoles, roles);
1371 d->m_watchedRoles = roles;
1372}
1373
1375 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1376{
1377 QVector<Compositor::Insert> inserts;
1378 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1379 itemsInserted(inserts);
1380 emitChanges();
1381}
1382
1384 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1385{
1386 QVector<Compositor::Remove> removes;
1387 m_compositor.clearFlags(from, count, group, groupFlags, &removes);
1388 itemsRemoved(removes);
1389 emitChanges();
1390}
1391
1393 Compositor::iterator from, int count, Compositor::Group group, int groupFlags)
1394{
1395 QVector<Compositor::Remove> removes;
1396 QVector<Compositor::Insert> inserts;
1397
1398 m_compositor.setFlags(from, count, group, groupFlags, &inserts);
1399 itemsInserted(inserts);
1400 const int removeFlags = ~groupFlags & Compositor::GroupMask;
1401
1402 from = m_compositor.find(from.group, from.index[from.group]);
1403 m_compositor.clearFlags(from, count, group, removeFlags, &removes);
1404 itemsRemoved(removes);
1405 emitChanges();
1406}
1407
1409{
1410 Q_D(QQmlDelegateModel);
1411 if (e->type() == QEvent::UpdateRequest) {
1412 d->m_waitingToFetchMore = false;
1413 d->m_adaptorModel.fetchMore();
1414 } else if (e->type() == QEvent::User) {
1415 d->m_incubatorCleanupScheduled = false;
1416 qDeleteAll(d->m_finishedIncubating);
1417 d->m_finishedIncubating.clear();
1418 }
1419 return QQmlInstanceModel::event(e);
1420}
1421
1422void QQmlDelegateModelPrivate::itemsChanged(const QVector<Compositor::Change> &changes)
1423{
1424 if (!m_delegate)
1425 return;
1426
1427 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedChanges(m_groupCount);
1428
1429 for (const Compositor::Change &change : changes) {
1430 for (int i = 1; i < m_groupCount; ++i) {
1431 if (change.inGroup(i)) {
1432 translatedChanges[i].append(QQmlChangeSet::Change(change.index[i], change.count));
1433 }
1434 }
1435 }
1436
1437 for (int i = 1; i < m_groupCount; ++i)
1438 QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.change(translatedChanges.at(i));
1439}
1440
1441void QQmlDelegateModel::_q_itemsChanged(int index, int count, const QVector<int> &roles)
1442{
1443 Q_D(QQmlDelegateModel);
1444 if (count <= 0 || !d->m_complete)
1445 return;
1446
1447 if (d->m_adaptorModel.notify(d->m_cache, index, count, roles)) {
1448 QVector<Compositor::Change> changes;
1449 d->m_compositor.listItemsChanged(&d->m_adaptorModel, index, count, &changes);
1450 d->itemsChanged(changes);
1451 d->emitChanges();
1452 }
1453 const bool needToCheckDelegateChoiceInvalidation = d->m_delegateChooser && !roles.isEmpty();
1454 if (!needToCheckDelegateChoiceInvalidation)
1455 return;
1456
1457 // here, we only really can handle AIM based models, because only there
1458 // we can do something sensible with roles
1459 if (!d->m_adaptorModel.adaptsAim())
1460 return;
1461
1462 const auto aim = d->m_adaptorModel.aim();
1463 const auto choiceRole = d->m_delegateChooser->role().toUtf8();
1464 const auto &roleNames = aim->roleNames();
1465 auto it = std::find_if(roles.begin(), roles.end(), [&](int role) {
1466 return roleNames[role] == choiceRole;
1467 });
1468 if (it == roles.end())
1469 return;
1470
1471 // Compare handleModelReset - we're doing a more localized version
1472
1473 /* A role change affecting the DelegateChoice is equivalent to removing all
1474 affected items (including invalidating their cache entries) and afterwards
1475 reinserting them.
1476 */
1477 QVector<Compositor::Remove> removes;
1478 QVector<Compositor::Insert> inserts;
1479 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
1480 const QList<QQmlDelegateModelItem *> cache = d->m_cache;
1482 item->referenceObject();
1483 for (const auto& removed: removes) {
1484 if (!d->m_cache.isSharedWith(cache))
1485 break;
1486 QQmlDelegateModelItem *item = cache.value(removed.cacheIndex(), nullptr);
1487 if (!d->m_cache.contains(item))
1488 continue;
1489 if (item->modelIndex() != -1)
1490 item->setModelIndex(-1, -1, -1);
1491 }
1493 item->releaseObject();
1494 d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
1495 d->itemsMoved(removes, inserts);
1496 d->emitChanges();
1497}
1498
1499static void incrementIndexes(QQmlDelegateModelItem *cacheItem, int count, const int *deltas)
1500{
1501 if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1502 for (int i = 1; i < count; ++i)
1503 incubationTask->index[i] += deltas[i];
1504 }
1505 if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
1506 for (int i = 1; i < qMin<int>(count, Compositor::MaximumGroupCount); ++i)
1507 attached->m_currentIndex[i] += deltas[i];
1508 }
1509}
1510
1512 const QVector<Compositor::Insert> &inserts,
1513 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedInserts,
1514 QHash<int, QList<QQmlDelegateModelItem *> > *movedItems)
1515{
1516 int cacheIndex = 0;
1517
1518 int inserted[Compositor::MaximumGroupCount];
1519 for (int i = 1; i < m_groupCount; ++i)
1520 inserted[i] = 0;
1521
1522 for (const Compositor::Insert &insert : inserts) {
1523 for (; cacheIndex < insert.cacheIndex(); ++cacheIndex)
1524 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, inserted);
1525
1526 for (int i = 1; i < m_groupCount; ++i) {
1527 if (insert.inGroup(i)) {
1528 (*translatedInserts)[i].append(
1529 QQmlChangeSet::Change(insert.index[i], insert.count, insert.moveId));
1530 inserted[i] += insert.count;
1531 }
1532 }
1533
1534 if (!insert.inCache())
1535 continue;
1536
1537 if (movedItems && insert.isMove()) {
1538 QList<QQmlDelegateModelItem *> items = movedItems->take(insert.moveId);
1539 Q_ASSERT(items.size() == insert.count);
1540 m_cache = m_cache.mid(0, insert.cacheIndex())
1541 + items + m_cache.mid(insert.cacheIndex());
1542 }
1543 if (insert.inGroup()) {
1544 for (int offset = 0; cacheIndex < insert.cacheIndex() + insert.count;
1545 ++cacheIndex, ++offset) {
1546 QQmlDelegateModelItem *cacheItem = m_cache.at(cacheIndex);
1547 cacheItem->groups |= insert.flags & Compositor::GroupMask;
1548
1549 if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1550 for (int i = 1; i < m_groupCount; ++i)
1551 incubationTask->index[i] = cacheItem->groups & (1 << i)
1552 ? insert.index[i] + offset
1553 : insert.index[i];
1554 }
1555 if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
1556 for (int i = 1; i < m_groupCount; ++i)
1557 attached->m_currentIndex[i] = cacheItem->groups & (1 << i)
1558 ? insert.index[i] + offset
1559 : insert.index[i];
1560 }
1561 }
1562 } else {
1563 cacheIndex = insert.cacheIndex() + insert.count;
1564 }
1565 }
1566 for (const QList<QQmlDelegateModelItem *> cache = m_cache; cacheIndex < cache.size(); ++cacheIndex)
1567 incrementIndexes(cache.at(cacheIndex), m_groupCount, inserted);
1568}
1569
1570void QQmlDelegateModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts)
1571{
1572 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1573 itemsInserted(inserts, &translatedInserts);
1574 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1575 if (!m_delegate)
1576 return;
1577
1578 for (int i = 1; i < m_groupCount; ++i)
1579 QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.insert(translatedInserts.at(i));
1580}
1581
1582void QQmlDelegateModel::_q_itemsInserted(int index, int count)
1583{
1584
1585 Q_D(QQmlDelegateModel);
1586 if (count <= 0 || !d->m_complete)
1587 return;
1588
1589 d->m_count += count;
1590
1591 const QList<QQmlDelegateModelItem *> cache = d->m_cache;
1592 for (int i = 0, c = cache.size(); i < c; ++i) {
1594 // layout change triggered by changing the modelIndex might have
1595 // already invalidated this item in d->m_cache and deleted it.
1596 if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
1597 continue;
1598
1599 if (item->modelIndex() >= index) {
1600 const int newIndex = item->modelIndex() + count;
1601 const int row = newIndex;
1602 const int column = 0;
1603 item->setModelIndex(newIndex, row, column);
1604 }
1605 }
1606
1607 QVector<Compositor::Insert> inserts;
1608 d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
1609 d->itemsInserted(inserts);
1610 d->emitChanges();
1611}
1612
1613//### This method should be split in two. It will remove delegates, and it will re-render the list.
1614// When e.g. QQmlListModel::remove is called, the removal of the delegates should be done on
1615// QAbstractItemModel::rowsAboutToBeRemoved, and the re-rendering on
1616// QAbstractItemModel::rowsRemoved. Currently both are done on the latter signal. The problem is
1617// that the destruction of an item will emit a changed signal that ends up at the delegate, which
1618// in turn will try to load the data from the model (which should have already freed it), resulting
1619// in a use-after-free. See QTBUG-59256.
1621 const QVector<Compositor::Remove> &removes,
1622 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves,
1623 QHash<int, QList<QQmlDelegateModelItem *> > *movedItems)
1624{
1625 int cacheIndex = 0;
1626 int removedCache = 0;
1627
1628 int removed[Compositor::MaximumGroupCount];
1629 for (int i = 1; i < m_groupCount; ++i)
1630 removed[i] = 0;
1631
1632 for (const Compositor::Remove &remove : removes) {
1633 for (; cacheIndex < remove.cacheIndex() && cacheIndex < m_cache.size(); ++cacheIndex)
1634 incrementIndexes(m_cache.at(cacheIndex), m_groupCount, removed);
1635
1636 for (int i = 1; i < m_groupCount; ++i) {
1637 if (remove.inGroup(i)) {
1638 (*translatedRemoves)[i].append(
1639 QQmlChangeSet::Change(remove.index[i], remove.count, remove.moveId));
1640 removed[i] -= remove.count;
1641 }
1642 }
1643
1644 if (!remove.inCache())
1645 continue;
1646
1647 if (movedItems && remove.isMove()) {
1648 movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex(), remove.count));
1652 } else {
1653 for (; cacheIndex < remove.cacheIndex() + remove.count - removedCache; ++cacheIndex) {
1654 QQmlDelegateModelItem *cacheItem = m_cache.at(cacheIndex);
1655 if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object) {
1656 QObject *object = cacheItem->object;
1657 cacheItem->destroyObject();
1658 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
1659 emitDestroyingPackage(package);
1660 else
1661 emitDestroyingItem(object);
1662 cacheItem->scriptRef -= 1;
1663 }
1664 if (!cacheItem->isReferenced() && !remove.inGroup(Compositor::Persisted)) {
1665 m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
1666 m_cache.removeAt(cacheIndex);
1667 delete cacheItem;
1668 --cacheIndex;
1669 ++removedCache;
1670 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1671 } else if (remove.groups() == cacheItem->groups) {
1672 cacheItem->groups = 0;
1673 if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1674 for (int i = 1; i < m_groupCount; ++i)
1675 incubationTask->index[i] = -1;
1676 }
1677 if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
1678 for (int i = 1; i < m_groupCount; ++i)
1679 attached->m_currentIndex[i] = -1;
1680 }
1681 } else {
1682 if (QQDMIncubationTask *incubationTask = cacheItem->incubationTask) {
1683 if (!cacheItem->isObjectReferenced()) {
1684 releaseIncubator(cacheItem->incubationTask);
1685 cacheItem->incubationTask = nullptr;
1686 if (cacheItem->object) {
1687 QObject *object = cacheItem->object;
1688 cacheItem->destroyObject();
1689 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
1690 emitDestroyingPackage(package);
1691 else
1692 emitDestroyingItem(object);
1693 }
1694 cacheItem->scriptRef -= 1;
1695 } else {
1696 for (int i = 1; i < m_groupCount; ++i) {
1697 if (remove.inGroup(i))
1698 incubationTask->index[i] = remove.index[i];
1699 }
1700 }
1701 }
1702 if (QQmlDelegateModelAttached *attached = cacheItem->attached) {
1703 for (int i = 1; i < m_groupCount; ++i) {
1704 if (remove.inGroup(i))
1705 attached->m_currentIndex[i] = remove.index[i];
1706 }
1707 }
1708 cacheItem->groups &= ~remove.flags;
1709 }
1710 }
1711 }
1712 }
1713
1714 for (const QList<QQmlDelegateModelItem *> cache = m_cache; cacheIndex < cache.size(); ++cacheIndex)
1715 incrementIndexes(cache.at(cacheIndex), m_groupCount, removed);
1716}
1717
1718void QQmlDelegateModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes)
1719{
1720 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1721 itemsRemoved(removes, &translatedRemoves);
1722 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1723 if (!m_delegate)
1724 return;
1725
1726 for (int i = 1; i < m_groupCount; ++i)
1727 QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.remove(translatedRemoves.at(i));
1728}
1729
1730void QQmlDelegateModel::_q_itemsRemoved(int index, int count)
1731{
1732 Q_D(QQmlDelegateModel);
1733 if (count <= 0|| !d->m_complete)
1734 return;
1735
1736 d->m_count -= count;
1737 Q_ASSERT(d->m_count >= 0);
1738 const QList<QQmlDelegateModelItem *> cache = d->m_cache;
1739 //Prevents items being deleted in remove loop
1741 item->referenceObject();
1742
1743 for (int i = 0, c = cache.size(); i < c; ++i) {
1745 // layout change triggered by removal of a previous item might have
1746 // already invalidated this item in d->m_cache and deleted it
1747 if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
1748 continue;
1749
1750 if (item->modelIndex() >= index + count) {
1751 const int newIndex = item->modelIndex() - count;
1752 const int row = newIndex;
1753 const int column = 0;
1754 item->setModelIndex(newIndex, row, column);
1755 } else if (item->modelIndex() >= index) {
1756 item->setModelIndex(-1, -1, -1);
1757 }
1758 }
1759 //Release items which are referenced before the loop
1761 item->releaseObject();
1762
1763 QVector<Compositor::Remove> removes;
1764 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
1765 d->itemsRemoved(removes);
1766
1767 d->emitChanges();
1768}
1769
1771 const QVector<Compositor::Remove> &removes, const QVector<Compositor::Insert> &inserts)
1772{
1773 QHash<int, QList<QQmlDelegateModelItem *> > movedItems;
1774
1775 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount);
1776 itemsRemoved(removes, &translatedRemoves, &movedItems);
1777
1778 QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount);
1779 itemsInserted(inserts, &translatedInserts, &movedItems);
1780 Q_ASSERT(m_cache.size() == m_compositor.count(Compositor::Cache));
1781 Q_ASSERT(movedItems.isEmpty());
1782 if (!m_delegate)
1783 return;
1784
1785 for (int i = 1; i < m_groupCount; ++i) {
1787 translatedRemoves.at(i),
1788 translatedInserts.at(i));
1789 }
1790}
1791
1792void QQmlDelegateModel::_q_itemsMoved(int from, int to, int count)
1793{
1794 Q_D(QQmlDelegateModel);
1795 if (count <= 0 || !d->m_complete)
1796 return;
1797
1798 const int minimum = qMin(from, to);
1799 const int maximum = qMax(from, to) + count;
1800 const int difference = from > to ? count : -count;
1801
1802 const QList<QQmlDelegateModelItem *> cache = d->m_cache;
1803 for (int i = 0, c = cache.size(); i < c; ++i) {
1805 // layout change triggered by changing the modelIndex might have
1806 // already invalidated this item in d->m_cache and deleted it.
1807 if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
1808 continue;
1809
1810 if (item->modelIndex() >= from && item->modelIndex() < from + count) {
1811 const int newIndex = item->modelIndex() - from + to;
1812 const int row = newIndex;
1813 const int column = 0;
1814 item->setModelIndex(newIndex, row, column);
1815 } else if (item->modelIndex() >= minimum && item->modelIndex() < maximum) {
1816 const int newIndex = item->modelIndex() + difference;
1817 const int row = newIndex;
1818 const int column = 0;
1819 item->setModelIndex(newIndex, row, column);
1820 }
1821 }
1822
1823 QVector<Compositor::Remove> removes;
1824 QVector<Compositor::Insert> inserts;
1825 d->m_compositor.listItemsMoved(&d->m_adaptorModel, from, to, count, &removes, &inserts);
1826 d->itemsMoved(removes, inserts);
1827 d->emitChanges();
1828}
1829
1831{
1832 Q_Q(QQmlDelegateModel);
1833 emit q->modelUpdated(changeSet, reset);
1834 if (changeSet.difference() != 0)
1835 emit q->countChanged();
1836}
1837
1839{
1840 Q_Q(QQmlDelegateModel);
1841 if (!m_complete)
1842 return;
1843
1844 if (m_transaction) {
1845 qmlWarning(q) << QQmlDelegateModel::tr("The delegates of a DelegateModel cannot be changed within onUpdated.");
1846 return;
1847 }
1848
1849 if (remove) {
1850 for (int i = 1; i < m_groupCount; ++i) {
1851 QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.remove(
1852 0, m_compositor.count(Compositor::Group(i)));
1853 }
1854 }
1855 if (add) {
1856 for (int i = 1; i < m_groupCount; ++i) {
1857 QQmlDelegateModelGroupPrivate::get(m_groups[i])->changeSet.insert(
1858 0, m_compositor.count(Compositor::Group(i)));
1859 }
1860 }
1861 emitChanges();
1862}
1863
1865{
1867 return;
1868
1869 m_transaction = true;
1871 for (int i = 1; i < m_groupCount; ++i)
1873 m_transaction = false;
1874
1875 const bool reset = m_reset;
1876 m_reset = false;
1877 for (int i = 1; i < m_groupCount; ++i)
1879
1880 // emitChanges may alter m_cache and delete items
1881 QVarLengthArray<QPointer<QQmlDelegateModelAttached>> attachedObjects;
1882 attachedObjects.reserve(m_cache.length());
1883 for (const QQmlDelegateModelItem *cacheItem : std::as_const(m_cache))
1884 attachedObjects.append(cacheItem->attached);
1885
1886 for (const QPointer<QQmlDelegateModelAttached> &attached : std::as_const(attachedObjects)) {
1887 if (attached && attached->m_cacheItem)
1888 attached->emitChanges();
1889 }
1890}
1891
1892void QQmlDelegateModel::_q_modelAboutToBeReset()
1893{
1894 auto aim = static_cast<QAbstractItemModel *>(sender());
1895 auto oldRoleNames = aim->roleNames();
1896 // this relies on the fact that modelAboutToBeReset must be followed
1897 // by a modelReset signal before any further modelAboutToBeReset can occur
1898 QObject::connect(aim, &QAbstractItemModel::modelReset, this, [&, oldRoleNames](){
1899 auto aim = static_cast<QAbstractItemModel *>(sender());
1900 if (oldRoleNames == aim->roleNames()) {
1901 // if the rolenames stayed the same (most common case), then we don't have
1902 // to throw away all the setup that we did
1903 handleModelReset();
1904 } else {
1905 // If they did change, we give up and just start from scratch via setMode
1907 // but we still have to call handleModelReset, otherwise views will
1908 // not refresh
1909 handleModelReset();
1910 }
1912}
1913
1914void QQmlDelegateModel::handleModelReset()
1915{
1916 Q_D(QQmlDelegateModel);
1917 if (!d->m_delegate)
1918 return;
1919
1920 int oldCount = d->m_count;
1921 d->m_adaptorModel.rootIndex = QModelIndex();
1922
1923 if (d->m_complete) {
1924 d->m_count = d->adaptorModelCount();
1925
1926 const QList<QQmlDelegateModelItem *> cache = d->m_cache;
1928 item->referenceObject();
1929
1930 for (int i = 0, c = cache.size(); i < c; ++i) {
1932 // layout change triggered by changing the modelIndex might have
1933 // already invalidated this item in d->m_cache and deleted it.
1934 if (!d->m_cache.isSharedWith(cache) && !d->m_cache.contains(item))
1935 continue;
1936
1937 if (item->modelIndex() != -1)
1938 item->setModelIndex(-1, -1, -1);
1939 }
1940
1942 item->releaseObject();
1943 QVector<Compositor::Remove> removes;
1944 QVector<Compositor::Insert> inserts;
1945 if (oldCount)
1946 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
1947 if (d->m_count)
1948 d->m_compositor.listItemsInserted(&d->m_adaptorModel, 0, d->m_count, &inserts);
1949 d->itemsMoved(removes, inserts);
1950 d->m_reset = true;
1951
1952 if (d->m_adaptorModel.canFetchMore())
1953 d->m_adaptorModel.fetchMore();
1954
1955 d->emitChanges();
1956 }
1958}
1959
1960void QQmlDelegateModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
1961{
1962 Q_D(QQmlDelegateModel);
1963 if (parent == d->m_adaptorModel.rootIndex)
1964 _q_itemsInserted(begin, end - begin + 1);
1965}
1966
1967void QQmlDelegateModel::_q_rowsAboutToBeRemoved(const QModelIndex &parent, int begin, int end)
1968{
1969 Q_D(QQmlDelegateModel);
1970 if (!d->m_adaptorModel.rootIndex.isValid())
1971 return;
1972 const QModelIndex index = d->m_adaptorModel.rootIndex;
1973 if (index.parent() == parent && index.row() >= begin && index.row() <= end) {
1974 const int oldCount = d->m_count;
1975 d->m_count = 0;
1976 d->disconnectFromAbstractItemModel();
1977 d->m_adaptorModel.invalidateModel();
1978
1979 if (d->m_complete && oldCount > 0) {
1980 QVector<Compositor::Remove> removes;
1981 d->m_compositor.listItemsRemoved(&d->m_adaptorModel, 0, oldCount, &removes);
1982 d->itemsRemoved(removes);
1983 d->emitChanges();
1984 }
1985 }
1986}
1987
1988void QQmlDelegateModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end)
1989{
1990 Q_D(QQmlDelegateModel);
1991 if (parent == d->m_adaptorModel.rootIndex)
1992 _q_itemsRemoved(begin, end - begin + 1);
1993}
1994
1995void QQmlDelegateModel::_q_rowsMoved(
1996 const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
1997 const QModelIndex &destinationParent, int destinationRow)
1998{
1999 Q_D(QQmlDelegateModel);
2000 const int count = sourceEnd - sourceStart + 1;
2001 if (destinationParent == d->m_adaptorModel.rootIndex && sourceParent == d->m_adaptorModel.rootIndex) {
2002 _q_itemsMoved(sourceStart, sourceStart > destinationRow ? destinationRow : destinationRow - count, count);
2003 } else if (sourceParent == d->m_adaptorModel.rootIndex) {
2004 _q_itemsRemoved(sourceStart, count);
2005 } else if (destinationParent == d->m_adaptorModel.rootIndex) {
2006 _q_itemsInserted(destinationRow, count);
2007 }
2008}
2009
2010void QQmlDelegateModel::_q_columnsInserted(const QModelIndex &parent, int begin, int end)
2011{
2012 Q_D(QQmlDelegateModel);
2013 Q_UNUSED(end);
2014 if (parent == d->m_adaptorModel.rootIndex && begin == 0) {
2015 // mark all items as changed
2016 _q_itemsChanged(0, d->m_count, QVector<int>());
2017 }
2018}
2019
2020void QQmlDelegateModel::_q_columnsRemoved(const QModelIndex &parent, int begin, int end)
2021{
2022 Q_D(QQmlDelegateModel);
2023 Q_UNUSED(end);
2024 if (parent == d->m_adaptorModel.rootIndex && begin == 0) {
2025 // mark all items as changed
2026 _q_itemsChanged(0, d->m_count, QVector<int>());
2027 }
2028}
2029
2030void QQmlDelegateModel::_q_columnsMoved(const QModelIndex &parent, int start, int end,
2031 const QModelIndex &destination, int column)
2032{
2033 Q_D(QQmlDelegateModel);
2034 Q_UNUSED(end);
2035 if ((parent == d->m_adaptorModel.rootIndex && start == 0)
2036 || (destination == d->m_adaptorModel.rootIndex && column == 0)) {
2037 // mark all items as changed
2038 _q_itemsChanged(0, d->m_count, QVector<int>());
2039 }
2040}
2041
2042void QQmlDelegateModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles)
2043{
2044 Q_D(QQmlDelegateModel);
2045 if (begin.parent() == d->m_adaptorModel.rootIndex)
2046 _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, roles);
2047}
2048
2049bool QQmlDelegateModel::isDescendantOf(const QPersistentModelIndex& desc, const QList< QPersistentModelIndex >& parents) const
2050{
2051 for (int i = 0, c = parents.size(); i < c; ++i) {
2052 for (QPersistentModelIndex parent = desc; parent.isValid(); parent = parent.parent()) {
2053 if (parent == parents[i])
2054 return true;
2055 }
2056 }
2057
2058 return false;
2059}
2060
2061void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
2062{
2063 Q_D(QQmlDelegateModel);
2064 if (!d->m_complete)
2065 return;
2066
2068 if (!parents.isEmpty() && d->m_adaptorModel.rootIndex.isValid() && !isDescendantOf(d->m_adaptorModel.rootIndex, parents)) {
2069 return;
2070 }
2071
2072 // mark all items as changed
2073 _q_itemsChanged(0, d->m_count, QVector<int>());
2074
2076 // Ignored
2077 } else {
2078 // We don't know what's going on, so reset the model
2079 handleModelReset();
2080 }
2081}
2082
2084{
2086 cacheItem->attached = new QQmlDelegateModelAttached(cacheItem, obj);
2087 return cacheItem->attached;
2088 }
2089 return new QQmlDelegateModelAttached(obj);
2090}
2091
2093QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups)
2094{
2095 if (!m_context || !m_context->isValid())
2097
2099 if (!cacheItem)
2101 if (!object.isObject())
2103
2104 QV4::ExecutionEngine *v4 = object.as<QV4::Object>()->engine();
2105 QV4::Scope scope(v4);
2106 QV4::ScopedObject o(scope, object);
2107 if (!o)
2109
2111 QV4::ScopedValue propertyName(scope);
2112 QV4::ScopedValue v(scope);
2113 const auto oldCache = m_cache;
2114 while (1) {
2115 propertyName = it.nextPropertyNameAsString(v);
2116 if (propertyName->isNull())
2117 break;
2118 cacheItem->setValue(
2119 propertyName->toQStringNoThrow(),
2121 }
2122 const bool cacheModified = !m_cache.isSharedWith(oldCache);
2123 if (cacheModified)
2125
2126 cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
2127
2128 // Must be before the new object is inserted into the cache or its indexes will be adjusted too.
2129 itemsInserted(QVector<Compositor::Insert>(1, Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag)));
2130
2131 m_cache.insert(before.cacheIndex(), cacheItem);
2132 m_compositor.insert(before, nullptr, 0, 1, cacheItem->groups);
2133
2135}
2136
2137//============================================================================
2138
2141 : model(model)
2142 , groupCount(groupNames.size() + 1)
2143 , v4Engine(engine)
2145 , groupNames(groupNames)
2146{
2147}
2148
2154
2156{
2157 QMetaObjectBuilder builder;
2158 builder.setFlags(DynamicMetaObject);
2159 builder.setClassName(QQmlDelegateModelAttached::staticMetaObject.className());
2160 builder.setSuperClass(&QQmlDelegateModelAttached::staticMetaObject);
2161
2162 int notifierId = 0;
2163 for (int i = 0; i < groupNames.size(); ++i, ++notifierId) {
2164 QString propertyName = QLatin1String("in") + groupNames.at(i);
2165 propertyName.replace(2, 1, propertyName.at(2).toUpper());
2166 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
2167 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
2168 propertyName.toUtf8(), "bool", notifierId);
2169 propertyBuilder.setWritable(true);
2170 }
2171 for (int i = 0; i < groupNames.size(); ++i, ++notifierId) {
2172 const QString propertyName = groupNames.at(i) + QLatin1String("Index");
2173 builder.addSignal("__" + propertyName.toUtf8() + "Changed()");
2174 QMetaPropertyBuilder propertyBuilder = builder.addProperty(
2175 propertyName.toUtf8(), "int", notifierId);
2176 propertyBuilder.setWritable(true);
2177 }
2178
2180}
2181
2183{
2184 QV4::Scope scope(v4Engine);
2185
2186 QV4::ScopedObject proto(scope, v4Engine->newObject());
2189 QV4::ScopedString s(scope);
2190 QV4::ScopedProperty p(scope);
2191
2192 s = v4Engine->newString(QStringLiteral("isUnresolved"));
2196 p->setSetter(nullptr);
2198
2199 s = v4Engine->newString(QStringLiteral("inItems"));
2203
2204 s = v4Engine->newString(QStringLiteral("inPersistedItems"));
2208
2209 s = v4Engine->newString(QStringLiteral("itemsIndex"));
2212
2213 s = v4Engine->newString(QStringLiteral("persistedItemsIndex"));
2215 p->setSetter(nullptr);
2217
2218 for (int i = 2; i < groupNames.size(); ++i) {
2219 QString propertyName = QLatin1String("in") + groupNames.at(i);
2220 propertyName.replace(2, 1, propertyName.at(2).toUpper());
2221 s = v4Engine->newString(propertyName);
2225 }
2226 for (int i = 2; i < groupNames.size(); ++i) {
2227 const QString propertyName = groupNames.at(i) + QLatin1String("Index");
2228 s = v4Engine->newString(propertyName);
2230 p->setSetter(nullptr);
2232 }
2233 modelItemProto.set(v4Engine, proto);
2234}
2235
2237{
2238 int groupFlags = 0;
2239 for (const QString &groupName : groups) {
2240 int index = groupNames.indexOf(groupName);
2241 if (index != -1)
2242 groupFlags |= 2 << index;
2243 }
2244 return groupFlags;
2245}
2246
2248{
2249 int groupFlags = 0;
2250 QV4::Scope scope(v4Engine);
2251
2252 QV4::ScopedString s(scope, groups);
2253 if (s) {
2254 const QString groupName = s->toQString();
2255 int index = groupNames.indexOf(groupName);
2256 if (index != -1)
2257 groupFlags |= 2 << index;
2258 return groupFlags;
2259 }
2260
2262 if (array) {
2263 QV4::ScopedValue v(scope);
2264 uint arrayLength = array->getLength();
2265 for (uint i = 0; i < arrayLength; ++i) {
2266 v = array->get(i);
2267 const QString groupName = v->toQString();
2268 int index = groupNames.indexOf(groupName);
2269 if (index != -1)
2270 groupFlags |= 2 << index;
2271 }
2272 }
2273 return groupFlags;
2274}
2275
2277{
2278 QV4::Scope scope(b);
2280 if (!o)
2281 return b->engine()->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
2282 if (!o->d()->item->metaType->model)
2284
2285 return o->d()->item->get();
2286}
2287
2289{
2290 QV4::Scope scope(b);
2292 if (!o)
2293 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
2294
2296 for (int i = 1; i < o->d()->item->metaType->groupCount; ++i) {
2297 if (o->d()->item->groups & (1 << i))
2298 groups.append(o->d()->item->metaType->groupNames.at(i - 1));
2299 }
2300
2301 return scope.engine->fromVariant(groups);
2302}
2303
2305{
2306 QV4::Scope scope(b);
2308 if (!o)
2309 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
2310
2311 if (!argc)
2313
2314 if (!o->d()->item->metaType->model)
2316 QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->d()->item->metaType->model);
2317
2318 const int groupFlags = model->m_cacheMetaType->parseGroups(argv[0]);
2319 const int cacheIndex = model->m_cache.indexOf(o->d()->item);
2320 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
2321 model->setGroups(it, 1, Compositor::Cache, groupFlags);
2322 return QV4::Encode::undefined();
2323}
2324
2326{
2327 return QV4::Encode(bool(thisItem->groups & (1 << flag)));
2328}
2329
2331{
2332 if (!cacheItem->metaType->model)
2333 return QV4::Encode::undefined();
2334
2335 QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(cacheItem->metaType->model);
2336
2337 bool member = arg.toBoolean();
2338 uint groupFlag = (1 << flag);
2339 if (member == ((cacheItem->groups & groupFlag) != 0))
2340 return QV4::Encode::undefined();
2341
2342 const int cacheIndex = model->m_cache.indexOf(cacheItem);
2343 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
2344 if (member)
2345 model->addGroups(it, 1, Compositor::Cache, groupFlag);
2346 else
2347 model->removeGroups(it, 1, Compositor::Cache, groupFlag);
2348 return QV4::Encode::undefined();
2349}
2350
2352{
2353 return QV4::Encode((int)thisItem->groupIndex(Compositor::Group(flag)));
2354}
2355
2357{
2358 if (!contextData)
2359 return;
2360
2361 for (QQmlRefPointer<QQmlContextData> ctxt = contextData->childContexts(); ctxt;
2362 ctxt = ctxt->nextChild()) {
2363 if (ctxt->contextObject() == childContextObject)
2364 ctxt->setContextObject(nullptr);
2365 }
2366}
2367
2368
2369//---------------------------------------------------------------------------
2370
2372
2374{
2375 item->Dispose();
2376 Object::destroy();
2377}
2378
2379
2381 const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
2383 int modelIndex, int row, int column)
2384 : v4(metaType->v4Engine)
2385 , metaType(metaType)
2386 , contextData(nullptr)
2387 , object(nullptr)
2388 , attached(nullptr)
2389 , incubationTask(nullptr)
2390 , delegate(nullptr)
2391 , poolTime(0)
2392 , objectRef(0)
2393 , scriptRef(0)
2394 , groups(0)
2395 , index(modelIndex)
2396 , row(row)
2397 , column(column)
2398{
2399 if (accessor->propertyCache) {
2400 // The property cache in the accessor is common for all the model
2401 // items in the model it wraps. It describes available model roles,
2402 // together with revisioned properties like row, column and index, all
2403 // which should be available in the delegate. We assign this cache to the
2404 // model item so that the QML engine can use the revision information
2405 // when resolving the properties (rather than falling back to just
2406 // inspecting the QObject in the model item directly).
2407 QQmlData::get(this, true)->propertyCache = accessor->propertyCache;
2408 }
2409}
2410
2412{
2413 Q_ASSERT(scriptRef == 0);
2414 Q_ASSERT(objectRef == 0);
2415 Q_ASSERT(!object);
2416
2417 if (incubationTask) {
2418 if (metaType->model)
2420 else
2421 delete incubationTask;
2422 }
2423}
2424
2426{
2427 --scriptRef;
2428 if (isReferenced())
2429 return;
2430
2431 if (metaType->model) {
2433 model->removeCacheItem(this);
2434 }
2435 delete this;
2436}
2437
2438void QQmlDelegateModelItem::setModelIndex(int idx, int newRow, int newColumn, bool alwaysEmit)
2439{
2440 const int prevIndex = index;
2441 const int prevRow = row;
2442 const int prevColumn = column;
2443
2444 index = idx;
2445 row = newRow;
2446 column = newColumn;
2447
2448 if (idx != prevIndex || alwaysEmit)
2450 if (row != prevRow || alwaysEmit)
2451 emit rowChanged();
2452 if (column != prevColumn || alwaysEmit)
2453 emit columnChanged();
2454}
2455
2457{
2458 Q_ASSERT(object);
2460
2461 QQmlData *data = QQmlData::get(object);
2462 Q_ASSERT(data);
2463 if (data->ownContext) {
2464 data->ownContext->clearContext();
2465 if (data->ownContext->contextObject() == object)
2466 data->ownContext->setContextObject(nullptr);
2467 data->ownContext = nullptr;
2468 data->context = nullptr;
2469 }
2470 /* QTBUG-87228: when destroying object at the application exit, the deferred
2471 * parent by setting it to QCoreApplication instance if it's nullptr, so
2472 * deletion won't work. Not to leak memory, make sure our object has a that
2473 * the parent claims the object at the end of the lifetime. When not at the
2474 * application exit, normal event loop will handle the deferred deletion
2475 * earlier.
2476 */
2477 if (object->parent() == nullptr)
2478 object->setParent(QCoreApplication::instance());
2479 object->deleteLater();
2480
2481 if (attached) {
2482 attached->m_cacheItem = nullptr;
2483 attached = nullptr;
2484 }
2485
2487 object = nullptr;
2488}
2489
2491{
2492 QQmlData *d = QQmlData::get(object);
2493 if (!d)
2494 return nullptr;
2495
2496 QQmlRefPointer<QQmlContextData> context = d->context;
2497 if (!context || !context->isValid())
2498 return nullptr;
2499
2500 if (QObject *extraObject = context->extraObject())
2501 return qobject_cast<QQmlDelegateModelItem *>(extraObject);
2502
2503 for (context = context->parent(); context; context = context->parent()) {
2504 if (QObject *extraObject = context->extraObject())
2505 return qobject_cast<QQmlDelegateModelItem *>(extraObject);
2506 if (QQmlDelegateModelItem *cacheItem = qobject_cast<QQmlDelegateModelItem *>(
2507 context->contextObject())) {
2508 return cacheItem;
2509 }
2510 }
2511 return nullptr;
2512}
2513
2515{
2518 : nullptr) {
2519 return model->m_compositor.find(Compositor::Cache, model->m_cache.indexOf(this)).index[group];
2520 }
2521 return -1;
2522}
2523
2524//---------------------------------------------------------------------------
2525
2528 : metaType(metaType)
2530 , memberPropertyOffset(QQmlDelegateModelAttached::staticMetaObject.propertyCount())
2531 , indexPropertyOffset(QQmlDelegateModelAttached::staticMetaObject.propertyCount() + metaType->groupNames.size())
2532{
2533 // Don't reference count the meta-type here as that would create a circular reference.
2534 // Instead we rely the fact that the meta-type's reference count can't reach 0 without first
2535 // destroying all delegates with attached objects.
2536 *static_cast<QMetaObject *>(this) = *metaObject;
2537}
2538
2543
2548
2550{
2552 if (call == QMetaObject::ReadProperty) {
2553 if (_id >= indexPropertyOffset) {
2554 Compositor::Group group = Compositor::Group(_id - indexPropertyOffset + 1);
2555 *static_cast<int *>(arguments[0]) = attached->m_currentIndex[group];
2556 return -1;
2557 } else if (_id >= memberPropertyOffset) {
2558 Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
2559 *static_cast<bool *>(arguments[0]) = attached->m_cacheItem->groups & (1 << group);
2560 return -1;
2561 }
2562 } else if (call == QMetaObject::WriteProperty) {
2563 if (_id >= memberPropertyOffset) {
2564 if (!metaType->model)
2565 return -1;
2567 Compositor::Group group = Compositor::Group(_id - memberPropertyOffset + 1);
2568 const int groupFlag = 1 << group;
2569 const bool member = attached->m_cacheItem->groups & groupFlag;
2570 if (member && !*static_cast<bool *>(arguments[0])) {
2571 Compositor::iterator it = model->m_compositor.find(
2572 group, attached->m_currentIndex[group]);
2573 model->removeGroups(it, 1, group, groupFlag);
2574 } else if (!member && *static_cast<bool *>(arguments[0])) {
2575 for (int i = 1; i < metaType->groupCount; ++i) {
2576 if (attached->m_cacheItem->groups & (1 << i)) {
2577 Compositor::iterator it = model->m_compositor.find(
2578 Compositor::Group(i), attached->m_currentIndex[i]);
2579 model->addGroups(it, 1, Compositor::Group(i), groupFlag);
2580 break;
2581 }
2582 }
2583 }
2584 return -1;
2585 }
2586 }
2587 return attached->qt_metacall(call, _id, arguments);
2588}
2589
2591 : m_cacheItem(nullptr)
2592 , m_previousGroups(0)
2593{
2595}
2596
2598 QQmlDelegateModelItem *cacheItem, QObject *parent)
2599 : m_cacheItem(cacheItem)
2600 , m_previousGroups(cacheItem->groups)
2601{
2604 // Let m_previousIndex be equal to m_currentIndex
2605 std::copy(std::begin(m_currentIndex), std::end(m_currentIndex), std::begin(m_previousIndex));
2606
2607 if (!cacheItem->metaType->metaObject)
2608 cacheItem->metaType->initializeMetaObject();
2609
2610 QObjectPrivate::get(this)->metaObject = cacheItem->metaType->metaObject;
2611 cacheItem->metaType->metaObject->addref();
2612}
2613
2615{
2616 if (QQDMIncubationTask *incubationTask = m_cacheItem->incubationTask) {
2617 for (int i = 1; i < qMin<int>(m_cacheItem->metaType->groupCount, Compositor::MaximumGroupCount); ++i)
2618 m_currentIndex[i] = incubationTask->index[i];
2619 } else {
2621 Compositor::iterator it = model->m_compositor.find(
2622 Compositor::Cache, model->m_cache.indexOf(m_cacheItem));
2623 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i)
2624 m_currentIndex[i] = it.index[i];
2625 }
2626}
2627
2629{
2630 setInGroup(QQmlListCompositor::Persisted, inPersisted);
2631}
2632
2634{
2635 if (!m_cacheItem)
2636 return false;
2637 const uint groupFlag = (1 << QQmlListCompositor::Persisted);
2638 return m_cacheItem->groups & groupFlag;
2639}
2640
2647
2648void QQmlDelegateModelAttached::setInGroup(QQmlListCompositor::Group group, bool inGroup)
2649{
2651 return;
2653 const uint groupFlag = (1 << group);
2654 if (inGroup == bool(m_cacheItem->groups & groupFlag))
2655 return;
2656
2657 const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
2658 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
2659 if (inGroup)
2660 model->addGroups(it, 1, Compositor::Cache, groupFlag);
2661 else
2662 model->removeGroups(it, 1, Compositor::Cache, groupFlag);
2663 // signal emission happens in add-/removeGroups
2664}
2665
2667{
2669}
2670
2672{
2673 if (!m_cacheItem)
2674 return false;
2675 const uint groupFlag = (1 << QQmlListCompositor::Default);
2676 return m_cacheItem->groups & groupFlag;
2677}
2678
2680{
2681 if (!m_cacheItem)
2682 return -1;
2684}
2685
2698
2708{
2710
2711 if (!m_cacheItem)
2712 return groups;
2713 for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
2714 if (m_cacheItem->groups & (1 << i))
2715 groups.append(m_cacheItem->metaType->groupNames.at(i - 1));
2716 }
2717 return groups;
2718}
2719
2721{
2722 if (!m_cacheItem)
2723 return;
2724
2726
2727 const int groupFlags = model->m_cacheMetaType->parseGroups(groups);
2728 const int cacheIndex = model->m_cache.indexOf(m_cacheItem);
2729 Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
2730 model->setGroups(it, 1, Compositor::Cache, groupFlags);
2731}
2732
2746{
2747 if (!m_cacheItem)
2748 return false;
2749
2750 return m_cacheItem->groups & Compositor::UnresolvedFlag;
2751}
2752
2794{
2795 const int groupChanges = m_previousGroups ^ m_cacheItem->groups;
2797
2798 int indexChanges = 0;
2799 const int groupCount = m_cacheItem->metaType->groupCount;
2800 for (int i = 1; i < groupCount; ++i) {
2801 if (m_previousIndex[i] != m_currentIndex[i]) {
2803 indexChanges |= (1 << i);
2804 }
2805 }
2806
2807 // Don't access m_cacheItem anymore once we've started sending signals.
2808 // We don't own it and someone might delete it.
2809
2810 int notifierId = 0;
2811 const QMetaObject *meta = metaObject();
2812 for (int i = 1; i < groupCount; ++i, ++notifierId) {
2813 if (groupChanges & (1 << i))
2814 QMetaObject::activate(this, meta, notifierId, nullptr);
2815 }
2816 for (int i = 1; i < groupCount; ++i, ++notifierId) {
2817 if (indexChanges & (1 << i))
2818 QMetaObject::activate(this, meta, notifierId, nullptr);
2819 }
2820
2821 if (groupChanges)
2823}
2824
2825//============================================================================
2826
2828{
2829 Q_ASSERT(!model);
2830 model = m;
2831 group = g;
2832}
2833
2839
2841{
2843 if (isChangedConnected() && !changeSet.isEmpty()) {
2845 qdmEngineData(v4)->array(v4, changeSet.removes())),
2847 qdmEngineData(v4)->array(v4, changeSet.inserts())));
2848 }
2849 if (changeSet.difference() != 0)
2850 emit q->countChanged();
2851}
2852
2854{
2855 for (QQmlDelegateModelGroupEmitterList::iterator it = emitters.begin(); it != emitters.end(); ++it)
2856 it->emitModelUpdated(changeSet, reset);
2857 changeSet.clear();
2858}
2859
2860typedef QQmlDelegateModelGroupEmitterList::iterator GroupEmitterListIt;
2861
2863{
2864 for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
2865 it->createdPackage(index, package);
2866}
2867
2869{
2870 for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
2871 it->initPackage(index, package);
2872}
2873
2875{
2876 for (GroupEmitterListIt it = emitters.begin(), end = emitters.end(); it != end; ++it)
2877 it->destroyingPackage(package);
2878}
2879
2920
2922 const QString &name, QQmlDelegateModel *model, int index, QObject *parent)
2923 : QQmlDelegateModelGroup(parent)
2924{
2926 d->name = name;
2927 d->setModel(model, Compositor::Group(index));
2928}
2929
2933
2943{
2944 Q_D(const QQmlDelegateModelGroup);
2945 return d->name;
2946}
2947
2949{
2951 if (d->model)
2952 return;
2953 if (d->name != name) {
2954 d->name = name;
2955 emit nameChanged();
2956 }
2957}
2958
2966{
2967 Q_D(const QQmlDelegateModelGroup);
2968 if (!d->model)
2969 return 0;
2970 return QQmlDelegateModelPrivate::get(d->model)->m_compositor.count(d->group);
2971}
2972
2980{
2981 Q_D(const QQmlDelegateModelGroup);
2982 return d->defaultInclude;
2983}
2984
2986{
2988 if (d->defaultInclude != include) {
2989 d->defaultInclude = include;
2990
2991 if (d->model) {
2992 if (include)
2993 QQmlDelegateModelPrivate::get(d->model)->m_compositor.setDefaultGroup(d->group);
2994 else
2995 QQmlDelegateModelPrivate::get(d->model)->m_compositor.clearDefaultGroup(d->group);
2996 }
2998 }
2999}
3000
3026{
3028 if (!d->model)
3029 return QJSValue();
3030
3032 if (!model->m_context || !model->m_context->isValid()) {
3033 return QJSValue();
3034 } else if (index < 0 || index >= model->m_compositor.count(d->group)) {
3035 qmlWarning(this) << tr("get: index out of range");
3036 return QJSValue();
3037 }
3038
3039 Compositor::iterator it = model->m_compositor.find(d->group, index);
3040 QQmlDelegateModelItem *cacheItem = it->inCache()
3041 ? model->m_cache.at(it.cacheIndex())
3042 : 0;
3043
3044 if (!cacheItem) {
3045 cacheItem = model->m_adaptorModel.createItem(
3046 model->m_cacheMetaType, it.modelIndex());
3047 if (!cacheItem)
3048 return QJSValue();
3049 cacheItem->groups = it->flags;
3050
3051 model->m_cache.insert(it.cacheIndex(), cacheItem);
3052 model->m_compositor.setFlags(it, 1, Compositor::CacheFlag);
3053 }
3054
3055 if (model->m_cacheMetaType->modelItemProto.isUndefined())
3056 model->m_cacheMetaType->initializePrototype();
3057 QV4::ExecutionEngine *v4 = model->m_cacheMetaType->v4Engine;
3058 QV4::Scope scope(v4);
3059 ++cacheItem->scriptRef;
3061 QV4::ScopedObject p(scope, model->m_cacheMetaType->modelItemProto.value());
3062 o->setPrototypeOf(p);
3063
3064 return QJSValuePrivate::fromReturnedValue(o->asReturnedValue());
3065}
3066
3067bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::Value &value, int *index, Compositor::Group *group) const
3068{
3069 if (value.isNumber()) {
3070 *index = value.toInt32();
3071 return true;
3072 }
3073
3074 if (!value.isObject())
3075 return false;
3076
3078 QV4::Scope scope(v4);
3080
3081 if (object) {
3082 QQmlDelegateModelItem * const cacheItem = object->d()->item;
3083 if (QQmlDelegateModelPrivate *model = cacheItem->metaType->model
3084 ? QQmlDelegateModelPrivate::get(cacheItem->metaType->model)
3085 : nullptr) {
3086 *index = model->m_cache.indexOf(cacheItem);
3087 *group = Compositor::Cache;
3088 return true;
3089 }
3090 }
3091 return false;
3092}
3093
3112{
3115
3116 int index = model->m_compositor.count(d->group);
3117 Compositor::Group group = d->group;
3118
3119 if (args->length() == 0)
3120 return;
3121
3122 int i = 0;
3123 QV4::Scope scope(args->v4engine());
3124 QV4::ScopedValue v(scope, (*args)[i]);
3125 if (d->parseIndex(v, &index, &group)) {
3126 if (index < 0 || index > model->m_compositor.count(group)) {
3127 qmlWarning(this) << tr("insert: index out of range");
3128 return;
3129 }
3130 if (++i == args->length())
3131 return;
3132 v = (*args)[i];
3133 }
3134
3135 if (v->as<QV4::ArrayObject>())
3136 return;
3137
3138 int groups = 1 << d->group;
3139 if (++i < args->length()) {
3140 QV4::ScopedValue val(scope, (*args)[i]);
3141 groups |= model->m_cacheMetaType->parseGroups(val);
3142 }
3143
3144 if (v->as<QV4::Object>()) {
3146 do {
3147 Compositor::insert_iterator before = index < model->m_compositor.count(group)
3148 ? model->m_compositor.findInsertPosition(group, index)
3149 : model->m_compositor.end();
3150 insertionResult = model->insert(before, v, groups);
3151 } while (insertionResult == QQmlDelegateModelPrivate::InsertionResult::Retry);
3153 model->emitChanges();
3154 }
3155}
3156
3175{
3177 if (!d->model)
3178 return;
3179
3180 if (args->length() == 0)
3181 return;
3182
3184
3185 int index = model->m_compositor.count(d->group);
3186 Compositor::Group group = d->group;
3187
3188 int i = 0;
3189 QV4::Scope scope(args->v4engine());
3190 QV4::ScopedValue v(scope, (*args)[i]);
3191 if (d->parseIndex(v, &index, &group))
3192 ++i;
3193
3194 if (i < args->length() && index >= 0 && index <= model->m_compositor.count(group)) {
3195 v = (*args)[i];
3196 if (v->as<QV4::Object>()) {
3197 int groups = 1 << d->group;
3198 if (++i < args->length()) {
3199 QV4::ScopedValue val(scope, (*args)[i]);
3200 groups |= model->m_cacheMetaType->parseGroups(val);
3201 }
3202
3204 do {
3205 Compositor::insert_iterator before = index < model->m_compositor.count(group)
3206 ? model->m_compositor.findInsertPosition(group, index)
3207 : model->m_compositor.end();
3208
3209 index = before.index[d->group];
3210 group = d->group;
3211
3212 insertionResult = model->insert(before, v, groups);
3213 } while (insertionResult == QQmlDelegateModelPrivate::InsertionResult::Retry);
3215 return;
3216 }
3217 }
3218 if (index < 0 || index >= model->m_compositor.count(group)) {
3219 qmlWarning(this) << tr("create: index out of range");
3220 return;
3221 }
3222
3224 if (object) {
3225 QVector<Compositor::Insert> inserts;
3226 Compositor::iterator it = model->m_compositor.find(group, index);
3227 model->m_compositor.setFlags(it, 1, d->group, Compositor::PersistedFlag, &inserts);
3228 model->itemsInserted(inserts);
3229 model->m_cache.at(it.cacheIndex())->releaseObject();
3230 }
3231
3232 args->setReturnValue(QV4::QObjectWrapper::wrap(args->v4engine(), object));
3233 model->emitChanges();
3234}
3235
3253{
3255 if (!d->model)
3256 return;
3257
3259
3260 if (args->length() < 2)
3261 return;
3262
3263 int from = -1;
3264 int to = -1;
3265 Compositor::Group fromGroup = d->group;
3266 Compositor::Group toGroup = d->group;
3267
3268 QV4::Scope scope(args->v4engine());
3269 QV4::ScopedValue v(scope, (*args)[0]);
3270 if (d->parseIndex(v, &from, &fromGroup)) {
3271 if (from < 0 || from >= model->m_compositor.count(fromGroup)) {
3272 qmlWarning(this) << tr("resolve: from index out of range");
3273 return;
3274 }
3275 } else {
3276 qmlWarning(this) << tr("resolve: from index invalid");
3277 return;
3278 }
3279
3280 v = (*args)[1];
3281 if (d->parseIndex(v, &to, &toGroup)) {
3282 if (to < 0 || to >= model->m_compositor.count(toGroup)) {
3283 qmlWarning(this) << tr("resolve: to index out of range");
3284 return;
3285 }
3286 } else {
3287 qmlWarning(this) << tr("resolve: to index invalid");
3288 return;
3289 }
3290
3291 Compositor::iterator fromIt = model->m_compositor.find(fromGroup, from);
3292 Compositor::iterator toIt = model->m_compositor.find(toGroup, to);
3293
3294 if (!fromIt->isUnresolved()) {
3295 qmlWarning(this) << tr("resolve: from is not an unresolved item");
3296 return;
3297 }
3298 if (!toIt->list) {
3299 qmlWarning(this) << tr("resolve: to is not a model item");
3300 return;
3301 }
3302
3303 const int unresolvedFlags = fromIt->flags;
3304 const int resolvedFlags = toIt->flags;
3305 const int resolvedIndex = toIt.modelIndex();
3306 void * const resolvedList = toIt->list;
3307
3308 QQmlDelegateModelItem *cacheItem = model->m_cache.at(fromIt.cacheIndex());
3309 cacheItem->groups &= ~Compositor::UnresolvedFlag;
3310
3311 if (toIt.cacheIndex() > fromIt.cacheIndex())
3312 toIt.decrementIndexes(1, unresolvedFlags);
3313 if (!toIt->inGroup(fromGroup) || toIt.index[fromGroup] > from)
3314 from += 1;
3315
3316 model->itemsMoved(
3317 QVector<Compositor::Remove>(1, Compositor::Remove(fromIt, 1, unresolvedFlags, 0)),
3318 QVector<Compositor::Insert>(1, Compositor::Insert(toIt, 1, unresolvedFlags, 0)));
3319 model->itemsInserted(
3320 QVector<Compositor::Insert>(1, Compositor::Insert(toIt, 1, (resolvedFlags & ~unresolvedFlags) | Compositor::CacheFlag)));
3321 toIt.incrementIndexes(1, resolvedFlags | unresolvedFlags);
3322 model->itemsRemoved(QVector<Compositor::Remove>(1, Compositor::Remove(toIt, 1, resolvedFlags)));
3323
3324 model->m_compositor.setFlags(toGroup, to, 1, unresolvedFlags & ~Compositor::UnresolvedFlag);
3325 model->m_compositor.clearFlags(fromGroup, from, 1, unresolvedFlags);
3326
3327 if (resolvedFlags & Compositor::CacheFlag)
3328 model->m_compositor.insert(
3329 Compositor::Cache, toIt.cacheIndex(), resolvedList,
3330 resolvedIndex, 1, Compositor::CacheFlag);
3331
3332 Q_ASSERT(model->m_cache.size() == model->m_compositor.count(Compositor::Cache));
3333
3334 if (!cacheItem->isReferenced()) {
3335 Q_ASSERT(toIt.cacheIndex() == model->m_cache.indexOf(cacheItem));
3336 model->m_cache.removeAt(toIt.cacheIndex());
3337 model->m_compositor.clearFlags(
3338 Compositor::Cache, toIt.cacheIndex(), 1, Compositor::CacheFlag);
3339 delete cacheItem;
3340 Q_ASSERT(model->m_cache.size() == model->m_compositor.count(Compositor::Cache));
3341 } else {
3342 cacheItem->resolveIndex(model->m_adaptorModel, resolvedIndex);
3343 if (cacheItem->attached)
3344 cacheItem->attached->emitUnresolvedChanged();
3345 }
3346
3347 model->emitChanges();
3348}
3349
3357{
3359 if (!d->model)
3360 return;
3361 Compositor::Group group = d->group;
3362 int index = -1;
3363 int count = 1;
3364
3365 if (args->length() == 0)
3366 return;
3367
3368 int i = 0;
3369 QV4::Scope scope(args->v4engine());
3370 QV4::ScopedValue v(scope, (*args)[0]);
3371 if (!d->parseIndex(v, &index, &group)) {
3372 qmlWarning(this) << tr("remove: invalid index");
3373 return;
3374 }
3375
3376 if (++i < args->length()) {
3377 v = (*args)[i];
3378 if (v->isNumber())
3379 count = v->toInt32();
3380 }
3381
3383 if (index < 0 || index >= model->m_compositor.count(group)) {
3384 qmlWarning(this) << tr("remove: index out of range");
3385 } else if (count != 0) {
3386 Compositor::iterator it = model->m_compositor.find(group, index);
3387 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
3388 qmlWarning(this) << tr("remove: invalid count");
3389 } else {
3390 model->removeGroups(it, count, d->group, 1 << d->group);
3391 }
3392 }
3393}
3394
3396 QQmlV4FunctionPtr args, Compositor::Group *group, int *index, int *count, int *groups) const
3397{
3398 if (!model || !QQmlDelegateModelPrivate::get(model)->m_cacheMetaType)
3399 return false;
3400
3401 if (args->length() < 2)
3402 return false;
3403
3404 int i = 0;
3405 QV4::Scope scope(args->v4engine());
3406 QV4::ScopedValue v(scope, (*args)[i]);
3407 if (!parseIndex(v, index, group))
3408 return false;
3409
3410 v = (*args)[++i];
3411 if (v->isNumber()) {
3412 *count = v->toInt32();
3413
3414 if (++i == args->length())
3415 return false;
3416 v = (*args)[i];
3417 }
3418
3419 *groups = QQmlDelegateModelPrivate::get(model)->m_cacheMetaType->parseGroups(v);
3420
3421 return true;
3422}
3423
3431{
3433 Compositor::Group group = d->group;
3434 int index = -1;
3435 int count = 1;
3436 int groups = 0;
3437
3438 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
3439 return;
3440
3442 if (index < 0 || index >= model->m_compositor.count(group)) {
3443 qmlWarning(this) << tr("addGroups: index out of range");
3444 } else if (count != 0) {
3445 Compositor::iterator it = model->m_compositor.find(group, index);
3446 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
3447 qmlWarning(this) << tr("addGroups: invalid count");
3448 } else {
3449 model->addGroups(it, count, d->group, groups);
3450 }
3451 }
3452}
3453
3461{
3463 Compositor::Group group = d->group;
3464 int index = -1;
3465 int count = 1;
3466 int groups = 0;
3467
3468 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
3469 return;
3470
3472 if (index < 0 || index >= model->m_compositor.count(group)) {
3473 qmlWarning(this) << tr("removeGroups: index out of range");
3474 } else if (count != 0) {
3475 Compositor::iterator it = model->m_compositor.find(group, index);
3476 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
3477 qmlWarning(this) << tr("removeGroups: invalid count");
3478 } else {
3479 model->removeGroups(it, count, d->group, groups);
3480 }
3481 }
3482}
3483
3492{
3494 Compositor::Group group = d->group;
3495 int index = -1;
3496 int count = 1;
3497 int groups = 0;
3498
3499 if (!d->parseGroupArgs(args, &group, &index, &count, &groups))
3500 return;
3501
3503 if (index < 0 || index >= model->m_compositor.count(group)) {
3504 qmlWarning(this) << tr("setGroups: index out of range");
3505 } else if (count != 0) {
3506 Compositor::iterator it = model->m_compositor.find(group, index);
3507 if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) {
3508 qmlWarning(this) << tr("setGroups: invalid count");
3509 } else {
3510 model->setGroups(it, count, d->group, groups);
3511 }
3512 }
3513}
3514
3527{
3529
3530 if (args->length() < 2)
3531 return;
3532
3533 Compositor::Group fromGroup = d->group;
3534 Compositor::Group toGroup = d->group;
3535 int from = -1;
3536 int to = -1;
3537 int count = 1;
3538
3539 QV4::Scope scope(args->v4engine());
3540 QV4::ScopedValue v(scope, (*args)[0]);
3541 if (!d->parseIndex(v, &from, &fromGroup)) {
3542 qmlWarning(this) << tr("move: invalid from index");
3543 return;
3544 }
3545
3546 v = (*args)[1];
3547 if (!d->parseIndex(v, &to, &toGroup)) {
3548 qmlWarning(this) << tr("move: invalid to index");
3549 return;
3550 }
3551
3552 if (args->length() > 2) {
3553 v = (*args)[2];
3554 if (v->isNumber())
3555 count = v->toInt32();
3556 }
3557
3559
3560 if (count < 0) {
3561 qmlWarning(this) << tr("move: invalid count");
3562 } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) {
3563 qmlWarning(this) << tr("move: from index out of range");
3564 } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) {
3565 qmlWarning(this) << tr("move: to index out of range");
3566 } else if (count > 0) {
3567 QVector<Compositor::Remove> removes;
3568 QVector<Compositor::Insert> inserts;
3569
3570 model->m_compositor.move(fromGroup, from, toGroup, to, count, d->group, &removes, &inserts);
3571 model->itemsMoved(removes, inserts);
3572 model->emitChanges();
3573 }
3574
3575}
3576
3589//============================================================================
3590
3592 : QQmlInstanceModel(*new QObjectPrivate, parent)
3593 , m_model(model)
3594 , m_part(part)
3595 , m_compositorGroup(Compositor::Cache)
3596 , m_inheritGroup(true)
3597{
3599 if (d->m_cacheMetaType) {
3600 QQmlDelegateModelGroupPrivate::get(d->m_groups[1])->emitters.insert(this);
3601 m_compositorGroup = Compositor::Default;
3602 } else {
3603 d->m_pendingParts.insert(this);
3604 }
3605}
3606
3610
3612{
3613 if (m_inheritGroup)
3614 return m_model->filterGroup();
3615 return m_filterGroup;
3616}
3617
3619{
3620 if (QQmlDelegateModelPrivate::get(m_model)->m_transaction) {
3621 qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged");
3622 return;
3623 }
3624
3625 if (m_filterGroup != group || m_inheritGroup) {
3626 m_filterGroup = group;
3627 m_inheritGroup = false;
3629
3631 }
3632}
3633
3635{
3636 if (!m_inheritGroup) {
3637 m_inheritGroup = true;
3640 }
3641}
3642
3644{
3646 if (!model->m_cacheMetaType)
3647 return;
3648
3649 if (m_inheritGroup) {
3650 if (m_filterGroup == model->m_filterGroup)
3651 return;
3652 m_filterGroup = model->m_filterGroup;
3653 }
3654
3655 QQmlListCompositor::Group previousGroup = m_compositorGroup;
3656 m_compositorGroup = Compositor::Default;
3657 QQmlDelegateModelGroupPrivate::get(model->m_groups[Compositor::Default])->emitters.insert(this);
3658 for (int i = 1; i < model->m_groupCount; ++i) {
3659 if (m_filterGroup == model->m_cacheMetaType->groupNames.at(i - 1)) {
3660 m_compositorGroup = Compositor::Group(i);
3661 break;
3662 }
3663 }
3664
3665 QQmlDelegateModelGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this);
3666 if (m_compositorGroup != previousGroup) {
3667 QVector<QQmlChangeSet::Change> removes;
3668 QVector<QQmlChangeSet::Change> inserts;
3669 model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts);
3670
3671 QQmlChangeSet changeSet;
3672 changeSet.move(removes, inserts);
3673 if (!changeSet.isEmpty())
3674 emit modelUpdated(changeSet, false);
3675
3676 if (changeSet.difference() != 0)
3678 }
3679}
3680
3682 Compositor::Group group, const QQmlChangeSet &changeSet)
3683{
3684 if (!m_inheritGroup)
3685 return;
3686
3687 m_compositorGroup = group;
3688 QQmlDelegateModelGroupPrivate::get(QQmlDelegateModelPrivate::get(m_model)->m_groups[m_compositorGroup])->emitters.insert(this);
3689
3690 if (!changeSet.isEmpty())
3691 emit modelUpdated(changeSet, false);
3692
3693 if (changeSet.difference() != 0)
3695
3697}
3698
3700{
3702 return model->m_delegate
3703 ? model->m_compositor.count(m_compositorGroup)
3704 : 0;
3705}
3706
3708{
3709 return m_model->isValid();
3710}
3711
3713{
3715
3716 if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup)) {
3717 qWarning() << "DelegateModel::item: index out range" << index << model->m_compositor.count(m_compositorGroup);
3718 return nullptr;
3719 }
3720
3721 QObject *object = model->object(m_compositorGroup, index, incubationMode);
3722
3723 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object)) {
3724 QObject *part = package->part(m_part);
3725 if (!part)
3726 return nullptr;
3727 m_packaged.insert(part, package);
3728 return part;
3729 }
3730
3731 model->release(object);
3732 if (!model->m_delegateValidated) {
3733 if (object)
3734 qmlWarning(model->m_delegate) << tr("Delegate component must be Package type.");
3735 model->m_delegateValidated = true;
3736 }
3737
3738 return nullptr;
3739}
3740
3741QQmlInstanceModel::ReleaseFlags QQmlPartsModel::release(QObject *item, ReusableFlag)
3742{
3743 QQmlInstanceModel::ReleaseFlags flags;
3744
3745 auto it = m_packaged.find(item);
3746 if (it != m_packaged.end()) {
3747 QQuickPackage *package = *it;
3749 flags = model->release(package);
3750 m_packaged.erase(it);
3751 if (!m_packaged.contains(item))
3752 flags &= ~Referenced;
3753 if (flags & Destroyed)
3754 QQmlDelegateModelPrivate::get(m_model)->emitDestroyingPackage(package);
3755 }
3756 return flags;
3757}
3758
3760{
3761 return QQmlDelegateModelPrivate::get(m_model)->variantValue(m_compositorGroup, index, role);
3762}
3763
3764void QQmlPartsModel::setWatchedRoles(const QList<QByteArray> &roles)
3765{
3767 model->m_adaptorModel.replaceWatchedRoles(m_watchedRoles, roles);
3768 m_watchedRoles = roles;
3769}
3770
3772{
3774 Compositor::iterator it = model->m_compositor.find(model->m_compositorGroup, index);
3775 if (!it->inCache())
3776 return QQmlIncubator::Null;
3777
3778 if (auto incubationTask = model->m_cache.at(it.cacheIndex())->incubationTask)
3779 return incubationTask->status();
3780
3781 return QQmlIncubator::Ready;
3782}
3783
3785{
3786 auto it = m_packaged.find(item);
3787 if (it != m_packaged.end()) {
3789 return cacheItem->groupIndex(m_compositorGroup);
3790 }
3791 return -1;
3792}
3793
3795{
3796 emit createdItem(index, package->part(m_part));
3797}
3798
3800{
3801 if (m_modelUpdatePending)
3802 m_pendingPackageInitializations << index;
3803 else
3804 emit initItem(index, package->part(m_part));
3805}
3806
3808{
3809 QObject *item = package->part(m_part);
3810 Q_ASSERT(!m_packaged.contains(item));
3812}
3813
3815{
3816 m_modelUpdatePending = false;
3817 emit modelUpdated(changeSet, reset);
3818 if (changeSet.difference() != 0)
3820
3822 QVector<int> pendingPackageInitializations;
3823 qSwap(pendingPackageInitializations, m_pendingPackageInitializations);
3824 for (int index : pendingPackageInitializations) {
3825 if (!model->m_delegate || index < 0 || index >= model->m_compositor.count(m_compositorGroup))
3826 continue;
3827 QObject *object = model->object(m_compositorGroup, index, QQmlIncubator::Asynchronous);
3828 if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(object))
3829 emit initItem(index, package->part(m_part));
3830 model->release(object);
3831 }
3832}
3833
3835{
3836 // Currently, the only way for a view to reuse items is to call release()
3837 // in the model class with the second argument explicitly set to
3838 // QQmlReuseableDelegateModelItemsPool::Reusable. If the released item is
3839 // no longer referenced, it will be added to the pool. Reusing of items can
3840 // be specified per item, in case certain items cannot be recycled. A
3841 // QQmlDelegateModelItem knows which delegate its object was created from.
3842 // So when we are about to create a new item, we first check if the pool
3843 // contains an item based on the same delegate from before. If so, we take
3844 // it out of the pool (instead of creating a new item), and update all its
3845 // context properties and attached properties.
3846
3847 // When a view is recycling items, it should call drain() regularly. As
3848 // there is currently no logic to 'hibernate' items in the pool, they are
3849 // only meant to rest there for a short while, ideally only from the time
3850 // e.g a row is unloaded on one side of the view, and until a new row is
3851 // loaded on the opposite side. Between these times, the application will
3852 // see the item as fully functional and 'alive' (just not visible on
3853 // screen). Since this time is supposed to be short, we don't take any
3854 // action to notify the application about it, since we don't want to
3855 // trigger any bindings that can disturb performance.
3856
3857 // A recommended time for calling drain() is each time a view has finished
3858 // loading e.g a new row or column. If there are more items in the pool
3859 // after that, it means that the view most likely doesn't need them anytime
3860 // soon. Those items should be destroyed to reduce resource consumption.
3861
3862 // Depending on if a view is a list or a table, it can sometimes be
3863 // performant to keep items in the pool for a bit longer than one "row
3864 // out/row in" cycle. E.g for a table, if the number of visible rows in a
3865 // view is much larger than the number of visible columns. In that case, if
3866 // you flick out a row, and then flick in a column, you would throw away a
3867 // lot of items in the pool if completely draining it. The reason is that
3868 // unloading a row places more items in the pool than what ends up being
3869 // recycled when loading a new column. And then, when you next flick in a
3870 // new row, you would need to load all those drained items again from
3871 // scratch. For that reason, you can specify a maxPoolTime to the
3872 // drainReusableItemsPool() that allows you to keep items in the pool for a
3873 // bit longer, effectively keeping more items in circulation. A recommended
3874 // maxPoolTime would be equal to the number of dimensions in the view,
3875 // which means 1 for a list view and 2 for a table view. If you specify 0,
3876 // all items will be drained.
3877
3878 Q_ASSERT(!modelItem->incubationTask);
3879 Q_ASSERT(!modelItem->isObjectReferenced());
3880 Q_ASSERT(modelItem->object);
3881 Q_ASSERT(modelItem->delegate);
3882
3883 modelItem->poolTime = 0;
3884 m_reusableItemsPool.append(modelItem);
3885
3886 qCDebug(lcItemViewDelegateRecycling)
3887 << "item:" << modelItem
3888 << "delegate:" << modelItem->delegate
3889 << "index:" << modelItem->modelIndex()
3890 << "row:" << modelItem->modelRow()
3891 << "column:" << modelItem->modelColumn()
3892 << "pool size:" << m_reusableItemsPool.size();
3893}
3894
3896{
3897 // Find the oldest item in the pool that was made from the same delegate as
3898 // the given argument, remove it from the pool, and return it.
3899 for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end(); ++it) {
3900 if ((*it)->delegate != delegate)
3901 continue;
3902 auto modelItem = *it;
3903 m_reusableItemsPool.erase(it);
3904
3905 qCDebug(lcItemViewDelegateRecycling)
3906 << "item:" << modelItem
3907 << "delegate:" << delegate
3908 << "old index:" << modelItem->modelIndex()
3909 << "old row:" << modelItem->modelRow()
3910 << "old column:" << modelItem->modelColumn()
3911 << "new index:" << newIndexHint
3912 << "pool size:" << m_reusableItemsPool.size();
3913
3914 return modelItem;
3915 }
3916
3917 qCDebug(lcItemViewDelegateRecycling)
3918 << "no available item for delegate:" << delegate
3919 << "new index:" << newIndexHint
3920 << "pool size:" << m_reusableItemsPool.size();
3921
3922 return nullptr;
3923}
3924
3925void QQmlReusableDelegateModelItemsPool::drain(int maxPoolTime, std::function<void(QQmlDelegateModelItem *cacheItem)> releaseItem)
3926{
3927 // Rather than releasing all pooled items upon a call to this function, each
3928 // item has a poolTime. The poolTime specifies for how many loading cycles an item
3929 // has been resting in the pool. And for each invocation of this function, poolTime
3930 // will increase. If poolTime is equal to, or exceeds, maxPoolTime, it will be removed
3931 // from the pool and released. This way, the view can tweak a bit for how long
3932 // items should stay in "circulation", even if they are not recycled right away.
3933 qCDebug(lcItemViewDelegateRecycling) << "pool size before drain:" << m_reusableItemsPool.size();
3934
3935 for (auto it = m_reusableItemsPool.begin(); it != m_reusableItemsPool.end();) {
3936 auto modelItem = *it;
3937 modelItem->poolTime++;
3938 if (modelItem->poolTime <= maxPoolTime) {
3939 ++it;
3940 } else {
3941 it = m_reusableItemsPool.erase(it);
3942 releaseItem(modelItem);
3943 }
3944 }
3945
3946 qCDebug(lcItemViewDelegateRecycling) << "pool size after drain:" << m_reusableItemsPool.size();
3947}
3948
3949//============================================================================
3950
3952{
3954
3955 static QV4::Heap::QQmlDelegateModelGroupChange *create(QV4::ExecutionEngine *e) {
3956 return e->memoryManager->allocate<QQmlDelegateModelGroupChange>();
3957 }
3958
3959 static QV4::ReturnedValue method_get_index(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
3960 QV4::Scope scope(b);
3962 if (!that)
3964 return QV4::Encode(that->d()->change.index);
3965 }
3966 static QV4::ReturnedValue method_get_count(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
3967 QV4::Scope scope(b);
3969 if (!that)
3971 return QV4::Encode(that->d()->change.count);
3972 }
3973 static QV4::ReturnedValue method_get_moveId(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) {
3974 QV4::Scope scope(b);
3976 if (!that)
3978 if (that->d()->change.moveId < 0)
3980 return QV4::Encode(that->d()->change.moveId);
3981 }
3982};
3983
3985
3987{
3990public:
3991 static QV4::Heap::QQmlDelegateModelGroupChangeArray *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes)
3992 {
3993 return engine->memoryManager->allocate<QQmlDelegateModelGroupChangeArray>(changes);
3994 }
3995
3996 quint32 count() const { return d()->changes->size(); }
3997 const QQmlChangeSet::Change &at(int index) const { return d()->changes->at(index); }
3998
3999 static QV4::ReturnedValue virtualGet(const QV4::Managed *m, QV4::PropertyKey id, const QV4::Value *receiver, bool *hasProperty)
4000 {
4001 if (id.isArrayIndex()) {
4002 uint index = id.asArrayIndex();
4004 QV4::ExecutionEngine *v4 = static_cast<const QQmlDelegateModelGroupChangeArray *>(m)->engine();
4005 QV4::Scope scope(v4);
4007
4008 if (index >= array->count()) {
4009 if (hasProperty)
4010 *hasProperty = false;
4011 return QV4::Value::undefinedValue().asReturnedValue();
4012 }
4013
4014 const QQmlChangeSet::Change &change = array->at(index);
4015
4016 QV4::ScopedObject changeProto(scope, qdmEngineData(v4)->changeProto.value());
4018 object->setPrototypeOf(changeProto);
4019 object->d()->change = change;
4020
4021 if (hasProperty)
4022 *hasProperty = true;
4023 return object.asReturnedValue();
4024 }
4025
4028
4029 if (id == array->engine()->id_length()->propertyKey()) {
4030 if (hasProperty)
4031 *hasProperty = true;
4032 return QV4::Encode(array->count());
4033 }
4034
4035 return Object::virtualGet(m, id, receiver, hasProperty);
4036 }
4037};
4038
4039void QV4::Heap::QQmlDelegateModelGroupChangeArray::init(const QVector<QQmlChangeSet::Change> &changes)
4040{
4041 Object::init();
4042 this->changes = new QVector<QQmlChangeSet::Change>(changes);
4043 QV4::Scope scope(internalClass->engine);
4044 QV4::ScopedObject o(scope, this);
4045 o->setArrayType(QV4::Heap::ArrayData::Custom);
4046}
4047
4049
4060
4064
4066 const QVector<QQmlChangeSet::Change> &changes)
4067{
4068 QV4::Scope scope(v4);
4070 return o.asReturnedValue();
4071}
4072
4074
4075#include "moc_qqmldelegatemodel_p_p.cpp"
4076
4077#include "moc_qqmldelegatemodel_p.cpp"
[qjs-as-container]
void rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow, QPrivateSignal)
void modelAboutToBeReset(QPrivateSignal)
void columnsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after columns have been removed from the model.
LayoutChangeHint
This enum describes the way the model changes layout.
void modelReset(QPrivateSignal)
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles=QList< int >())
This signal is emitted whenever the data in an existing item changes.
void layoutChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted just before rows are removed from the model.
virtual QHash< int, QByteArray > roleNames() const
void rowsInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after rows have been inserted into the model.
void columnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn, QPrivateSignal)
void columnsInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after columns have been inserted into the model.
void rowsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted after rows have been removed from the model.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Returns the index of the data in row and column with parent.
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
Type type() const
Returns the event type.
Definition qcoreevent.h:304
\inmodule QtCore
Definition qhash.h:820
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:298
static QJSValue fromReturnedValue(QV4::ReturnedValue d)
Definition qjsvalue_p.h:197
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
qsizetype size() const noexcept
Definition qlist.h:397
void removeAt(qsizetype i)
Definition qlist.h:590
bool isSharedWith(const QList< T > &other) const
Definition qlist.h:429
iterator erase(const_iterator begin, const_iterator end)
Definition qlist.h:889
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:488
qsizetype length() const noexcept
Definition qlist.h:399
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
const_iterator constBegin() const noexcept
Definition qlist.h:632
QList< T > mid(qsizetype pos, qsizetype len=-1) const
Definition qlist.h:975
void append(parameter_type t)
Definition qlist.h:458
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:341
\inmodule QtCore
iterator find(const Key &key)
Definition qhash.h:2021
bool contains(const Key &key) const noexcept
Definition qhash.h:1658
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:2034
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1922
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
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:2658
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:1389
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
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:2435
T * data() const noexcept
Definition qpointer.h:73
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 complex property bindings are evaluated and,...
int index[QQmlListCompositor::MaximumGroupCount]
QQmlDelegateModelItem * incubating
QQmlDelegateModelPrivate * vdm
void initializeRequiredProperties(QQmlDelegateModelItem *modelItemToIncubate, QObject *object)
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
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.
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.
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...
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(QQmlV4FunctionPtr 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 setName(const QString &name)
bool defaultInclude() const
\qmlproperty bool QtQml.Models::DelegateModelGroup::includeByDefault
void resolve(QQmlV4FunctionPtr)
\qmlmethod QtQml.Models::DelegateModelGroup::resolve(int from, int to)
void addGroups(QQmlV4FunctionPtr)
\qmlmethod QtQml.Models::DelegateModelGroup::addGroups(int index, int count, stringlist groups)
void setGroups(QQmlV4FunctionPtr)
\qmlmethod QtQml.Models::DelegateModelGroup::setGroups(int index, int count, stringlist groups)
Q_INVOKABLE QJSValue get(int index)
\qmlmethod object QtQml.Models::DelegateModelGroup::get(int index)
void create(QQmlV4FunctionPtr)
\qmlmethod QtQml.Models::DelegateModelGroup::create(int index) \qmlmethod QtQml.Models::DelegateModel...
void insert(QQmlV4FunctionPtr)
\qmlmethod QtQml.Models::DelegateModelGroup::insert(int index, jsdict data, array groups = undefined)...
void move(QQmlV4FunctionPtr)
\qmlmethod QtQml.Models::DelegateModelGroup::move(var from, var to, int count)
void remove(QQmlV4FunctionPtr)
\qmlmethod QtQml.Models::DelegateModelGroup::remove(int index, int count)
void setDefaultInclude(bool include)
void removeGroups(QQmlV4FunctionPtr)
\qmlmethod QtQml.Models::DelegateModelGroup::removeGroups(int index, int count, stringlist groups)
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)
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)
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)
InsertionResult insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups)
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)
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.
QObject * object() const
Return the incubated object if the status is Ready, otherwise 0.
bool isError() const
Returns true if the incubator's status() is Error.
IncubationMode
Specifies the mode the incubator operates in.
Status status() const
Return the current status of the incubator.
Status
Specifies the status of the QQmlIncubator.
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)
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 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...
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.
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:78
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:129
QString left(qsizetype n) const &
Definition qstring.h:363
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
QByteArray toUtf8() const &
Definition qstring.h:634
ObjectType::Data * allocate(Args &&... args)
Definition qv4mm_p.h:298
void set(ExecutionEngine *engine, const Value &value)
\inmodule QtCore
Definition qvariant.h:65
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:536
qDeleteAll(list.begin(), list.end())
QCache< int, Employee > cache
[0]
QSet< QString >::iterator it
auto mo
[7]
QList< QVariant > arguments
QVector3D minimum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW
Definition qssgutils_p.h:54
QVector3D maximum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW
Definition qssgutils_p.h:55
Combined button and popup list for selecting options.
Scoped< FunctionObject > ScopedFunctionObject
quint64 ReturnedValue
Scoped< String > ScopedString
@ Attr_NotConfigurable
@ Attr_NotEnumerable
@ Attr_Accessor
@ SingleShotConnection
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:166
#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
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]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLboolean GLuint group
GLbitfield flags
GLuint start
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLuint name
GLenum GLenum GLsizei void GLsizei void * column
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLboolean reset
const GLubyte * c
GLuint GLfloat * val
GLenum array
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLfloat GLfloat p
[1]
QT_BEGIN_NAMESPACE 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:75
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
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)
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
Definition qswap.h:20
#define tr(X)
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define emit
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
#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
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18
qsizetype lastIndexOf(const AT &t, qsizetype from=-1) const noexcept
Definition qlist.h:969
\inmodule QtCore
static void activate(QObject *sender, int signal_index, void **argv)
Definition qobject.cpp:4193
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::ExecutionEngine *engine, uint flag, QV4::ReturnedValue(*code)(QQmlDelegateModelItem *, uint, const QV4::Value &))
static constexpr ReturnedValue undefined()
MemoryManager * memoryManager
QV4::ReturnedValue fromVariant(const QVariant &)
Heap::Object * newObject()
Heap::String * newString(char16_t c)
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
void defineAccessorProperty(const QString &name, VTable::Call getter, VTable::Call setter)
void insertMember(StringOrSymbol *s, const Value &v, PropertyAttributes attributes=Attr_Data)
static ReturnedValue wrap(ExecutionEngine *engine, QObject *object)
ExecutionEngine * engine
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