aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels/qqmldelegatemodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlmodels/qqmldelegatemodel.cpp')
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp303
1 files changed, 195 insertions, 108 deletions
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index fcbcec15a1..36efadeed7 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -31,7 +31,7 @@ namespace QV4 {
namespace Heap {
struct DelegateModelGroupFunction : FunctionObject {
- void init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg));
+ void init(ExecutionEngine *engine, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg));
QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg);
uint flag;
@@ -60,9 +60,11 @@ struct DelegateModelGroupFunction : QV4::FunctionObject
{
V4_OBJECT2(DelegateModelGroupFunction, FunctionObject)
- static Heap::DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
+ static Heap::DelegateModelGroupFunction *create(
+ QV4::ExecutionEngine *engine, uint flag,
+ QV4::ReturnedValue (*code)(QQmlDelegateModelItem *, uint, const QV4::Value &))
{
- return scope->engine()->memoryManager->allocate<DelegateModelGroupFunction>(scope, flag, code);
+ return engine->memoryManager->allocate<DelegateModelGroupFunction>(engine, flag, code);
}
static ReturnedValue virtualCall(const QV4::FunctionObject *that, const Value *thisObject, const Value *argv, int argc)
@@ -78,9 +80,11 @@ struct DelegateModelGroupFunction : QV4::FunctionObject
}
};
-void Heap::DelegateModelGroupFunction::init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
+void Heap::DelegateModelGroupFunction::init(
+ QV4::ExecutionEngine *engine, uint flag,
+ QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
{
- QV4::Heap::FunctionObject::init(scope, QStringLiteral("DelegateModelGroupFunction"));
+ QV4::Heap::FunctionObject::init(engine, QStringLiteral("DelegateModelGroupFunction"));
this->flag = flag;
this->code = code;
}
@@ -103,7 +107,7 @@ public:
QV4::PersistentValue changeProto;
};
-V4_DEFINE_EXTENSION(QQmlDelegateModelEngineData, engineData)
+V4_DEFINE_EXTENSION(QQmlDelegateModelEngineData, qdmEngineData)
void QQmlDelegateModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
@@ -351,26 +355,16 @@ void QQmlDelegateModelPrivate::connectToAbstractItemModel()
auto aim = m_adaptorModel.aim();
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsInserted(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_columnsInserted(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- q, QQmlDelegateModel, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- q, QQmlDelegateModel, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- q, QQmlDelegateModel, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- q, QQmlDelegateModel, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(modelReset()),
- q, QQmlDelegateModel, SLOT(_q_modelReset()));
- qmlobject_connect(aim, QAbstractItemModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- q, QQmlDelegateModel, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ QObject::connect(aim, &QAbstractItemModel::rowsInserted, q, &QQmlDelegateModel::_q_rowsInserted);
+ QObject::connect(aim, &QAbstractItemModel::rowsRemoved, q, &QQmlDelegateModel::_q_rowsRemoved);
+ QObject::connect(aim, &QAbstractItemModel::rowsAboutToBeRemoved, q, &QQmlDelegateModel::_q_rowsAboutToBeRemoved);
+ QObject::connect(aim, &QAbstractItemModel::columnsInserted, q, &QQmlDelegateModel::_q_columnsInserted);
+ QObject::connect(aim, &QAbstractItemModel::columnsRemoved, q, &QQmlDelegateModel::_q_columnsRemoved);
+ QObject::connect(aim, &QAbstractItemModel::columnsMoved, q, &QQmlDelegateModel::_q_columnsMoved);
+ QObject::connect(aim, &QAbstractItemModel::dataChanged, q, &QQmlDelegateModel::_q_dataChanged);
+ QObject::connect(aim, &QAbstractItemModel::rowsMoved, q, &QQmlDelegateModel::_q_rowsMoved);
+ QObject::connect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset);
+ QObject::connect(aim, &QAbstractItemModel::layoutChanged, q, &QQmlDelegateModel::_q_layoutChanged);
}
void QQmlDelegateModelPrivate::disconnectFromAbstractItemModel()
@@ -381,26 +375,16 @@ void QQmlDelegateModelPrivate::disconnectFromAbstractItemModel()
auto aim = m_adaptorModel.aim();
- QObject::disconnect(aim, SIGNAL(rowsInserted(QModelIndex,int,int)),
- q, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- q, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- q, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(columnsInserted(QModelIndex,int,int)), q,
- SLOT(_q_columnsInserted(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(columnsRemoved(QModelIndex,int,int)), q,
- SLOT(_q_columnsRemoved(QModelIndex,int,int)));
- QObject::disconnect(aim, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), q,
- SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
- QObject::disconnect(aim, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
- q, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
- QObject::disconnect(aim, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- q, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
- QObject::disconnect(aim, SIGNAL(modelReset()),
- q, SLOT(_q_modelReset()));
- QObject::disconnect(aim, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- q, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ QObject::disconnect(aim, &QAbstractItemModel::rowsInserted, q, &QQmlDelegateModel::_q_rowsInserted);
+ QObject::disconnect(aim, &QAbstractItemModel::rowsAboutToBeRemoved, q, &QQmlDelegateModel::_q_rowsAboutToBeRemoved);
+ QObject::disconnect(aim, &QAbstractItemModel::rowsRemoved, q, &QQmlDelegateModel::_q_rowsRemoved);
+ QObject::disconnect(aim, &QAbstractItemModel::columnsInserted, q, &QQmlDelegateModel::_q_columnsInserted);
+ QObject::disconnect(aim, &QAbstractItemModel::columnsRemoved, q, &QQmlDelegateModel::_q_columnsRemoved);
+ QObject::disconnect(aim, &QAbstractItemModel::columnsMoved, q, &QQmlDelegateModel::_q_columnsMoved);
+ QObject::disconnect(aim, &QAbstractItemModel::dataChanged, q, &QQmlDelegateModel::_q_dataChanged);
+ QObject::disconnect(aim, &QAbstractItemModel::rowsMoved, q, &QQmlDelegateModel::_q_rowsMoved);
+ QObject::disconnect(aim, &QAbstractItemModel::modelAboutToBeReset, q, &QQmlDelegateModel::_q_modelAboutToBeReset);
+ QObject::disconnect(aim, &QAbstractItemModel::layoutChanged, q, &QQmlDelegateModel::_q_layoutChanged);
}
void QQmlDelegateModel::setModel(const QVariant &model)
@@ -461,7 +445,7 @@ void QQmlDelegateModel::setDelegate(QQmlComponent *delegate)
qobject_cast<QQmlAbstractDelegateComponent *>(delegate);
if (adc) {
d->m_delegateChooser = adc;
- d->m_delegateChooserChanged = connect(adc, &QQmlAbstractDelegateComponent::delegateChanged,
+ d->m_delegateChooserChanged = connect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this,
[d](){ d->delegateChanged(); });
}
}
@@ -922,7 +906,7 @@ void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *mod
if (incubatorPriv->hadTopLevelRequiredProperties()) {
// If we have required properties, we clear the context object
// so that the model role names are not polluting the context.
- // Unless the context is bound, in which case we have never set context object.
+ // Unless the context is bound, in which case we have never set the context object.
if (incubating && !isBound) {
Q_ASSERT(incubating->contextData);
incubating->contextData->setContextObject(nullptr);
@@ -931,16 +915,20 @@ void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *mod
proxyContext->setContextObject(nullptr);
}
+ // Retrieve the metaObject before the potential return so that the accessors have a chance
+ // to perform some finalization in case they produce a dynamic metaobject. Here we know for
+ // sure that we are using required properties.
+ const QMetaObject *qmlMetaObject = modelItemToIncubate->metaObject();
+
if (incubatorPriv->requiredProperties()->empty())
return;
RequiredProperties *requiredProperties = incubatorPriv->requiredProperties();
- auto qmlMetaObject = modelItemToIncubate->metaObject();
// if a required property was not in the model, it might still be a static property of the
// QQmlDelegateModelItem or one of its derived classes this is the case for index, row,
// column, model and more
- // the most derived subclass of QQmlDelegateModelItem is QQmlDMAbstractModelData at depth 2,
- // so 4 should be plenty
+ // the most derived subclasses of QQmlDelegateModelItem are QQmlDMAbstractItemModelData and
+ // QQmlDMObjectData at depth 2, so 4 should be plenty
QVarLengthArray<QPair<const QMetaObject *, QObject *>, 4> mos;
// we first check the dynamic meta object for properties originating from the model
// contains abstractitemmodelproperties
@@ -987,6 +975,13 @@ void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *mod
modelItemToIncubate->contextData->setContextObject(modelItemToIncubate);
if (proxiedObject)
proxyContext->setContextObject(proxiedObject);
+
+ // Retrieve the metaObject() once so that the accessors have a chance to perform some
+ // finalization in case they produce a dynamic metaobject. For example, they might be
+ // inclined to create a propertyCache now because there are no required properties and any
+ // revisioned properties should be hidden after all. Here is the first time we know for
+ // sure whether we are using context properties.
+ modelItemToIncubate->metaObject();
}
}
@@ -1203,6 +1198,9 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
addCacheItem(cacheItem, it);
reuseItem(cacheItem, index, flags);
cacheItem->referenceObject();
+
+ if (index == m_compositor.count(group) - 1)
+ requestMoreIfNecessary();
return cacheItem->object;
}
@@ -1285,7 +1283,9 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
if (cacheItem->object && (!cacheItem->incubationTask || isDoneIncubating(cacheItem->incubationTask->status())))
return cacheItem->object;
- cacheItem->releaseObject();
+ if (cacheItem->objectRef > 0)
+ cacheItem->releaseObject();
+
if (!cacheItem->isReferenced()) {
removeCacheItem(cacheItem);
delete cacheItem;
@@ -1450,6 +1450,50 @@ void QQmlDelegateModel::_q_itemsChanged(int index, int count, const QVector<int>
d->itemsChanged(changes);
d->emitChanges();
}
+ const bool needToCheckDelegateChoiceInvalidation = d->m_delegateChooser && !roles.isEmpty();
+ if (!needToCheckDelegateChoiceInvalidation)
+ return;
+
+ // here, we only really can handle AIM based models, because only there
+ // we can do something sensible with roles
+ if (!d->m_adaptorModel.adaptsAim())
+ return;
+
+ const auto aim = d->m_adaptorModel.aim();
+ const auto choiceRole = d->m_delegateChooser->role().toUtf8();
+ const auto &roleNames = aim->roleNames();
+ auto it = std::find_if(roles.begin(), roles.end(), [&](int role) {
+ return roleNames[role] == choiceRole;
+ });
+ if (it == roles.end())
+ return;
+
+ // Compare handleModelReset - we're doing a more localized version
+
+ /* A role change affecting the DelegateChoice is equivalent to removing all
+ affected items (including invalidating their cache entries) and afterwards
+ reinserting them.
+ */
+ QVector<Compositor::Remove> removes;
+ QVector<Compositor::Insert> inserts;
+ d->m_compositor.listItemsRemoved(&d->m_adaptorModel, index, count, &removes);
+ const QList<QQmlDelegateModelItem *> cache = d->m_cache;
+ for (QQmlDelegateModelItem *item : cache)
+ item->referenceObject();
+ for (const auto& removed: removes) {
+ if (!d->m_cache.isSharedWith(cache))
+ break;
+ QQmlDelegateModelItem *item = cache.value(removed.cacheIndex(), nullptr);
+ if (!d->m_cache.contains(item))
+ continue;
+ if (item->modelIndex() != -1)
+ item->setModelIndex(-1, -1, -1);
+ }
+ for (QQmlDelegateModelItem *item : cache)
+ item->releaseObject();
+ d->m_compositor.listItemsInserted(&d->m_adaptorModel, index, count, &inserts);
+ d->itemsMoved(removes, inserts);
+ d->emitChanges();
}
static void incrementIndexes(QQmlDelegateModelItem *cacheItem, int count, const int *deltas)
@@ -1602,8 +1646,8 @@ void QQmlDelegateModelPrivate::itemsRemoved(
if (movedItems && remove.isMove()) {
movedItems->insert(remove.moveId, m_cache.mid(remove.cacheIndex(), remove.count));
- QList<QQmlDelegateModelItem *>::iterator begin = m_cache.begin() + remove.cacheIndex();
- QList<QQmlDelegateModelItem *>::iterator end = begin + remove.count;
+ QList<QQmlDelegateModelItem *>::const_iterator begin = m_cache.constBegin() + remove.cacheIndex();
+ QList<QQmlDelegateModelItem *>::const_iterator end = begin + remove.count;
m_cache.erase(begin, end);
} else {
for (; cacheIndex < remove.cacheIndex() + remove.count - removedCache; ++cacheIndex) {
@@ -1617,7 +1661,7 @@ void QQmlDelegateModelPrivate::itemsRemoved(
emitDestroyingItem(object);
cacheItem->scriptRef -= 1;
}
- if (!cacheItem->isReferenced()) {
+ if (!cacheItem->isReferenced() && !remove.inGroup(Compositor::Persisted)) {
m_compositor.clearFlags(Compositor::Cache, cacheIndex, 1, Compositor::CacheFlag);
m_cache.removeAt(cacheIndex);
delete cacheItem;
@@ -1833,14 +1877,41 @@ void QQmlDelegateModelPrivate::emitChanges()
for (int i = 1; i < m_groupCount; ++i)
QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitModelUpdated(reset);
- auto cacheCopy = m_cache; // deliberate; emitChanges may alter m_cache
- for (QQmlDelegateModelItem *cacheItem : std::as_const(cacheCopy)) {
- if (cacheItem->attached)
- cacheItem->attached->emitChanges();
+ // emitChanges may alter m_cache and delete items
+ QVarLengthArray<QPointer<QQmlDelegateModelAttached>> attachedObjects;
+ attachedObjects.reserve(m_cache.length());
+ for (const QQmlDelegateModelItem *cacheItem : std::as_const(m_cache))
+ attachedObjects.append(cacheItem->attached);
+
+ for (const QPointer<QQmlDelegateModelAttached> &attached : std::as_const(attachedObjects)) {
+ if (attached && attached->m_cacheItem)
+ attached->emitChanges();
}
}
-void QQmlDelegateModel::_q_modelReset()
+void QQmlDelegateModel::_q_modelAboutToBeReset()
+{
+ auto aim = static_cast<QAbstractItemModel *>(sender());
+ auto oldRoleNames = aim->roleNames();
+ // this relies on the fact that modelAboutToBeReset must be followed
+ // by a modelReset signal before any further modelAboutToBeReset can occur
+ QObject::connect(aim, &QAbstractItemModel::modelReset, this, [&, oldRoleNames](){
+ auto aim = static_cast<QAbstractItemModel *>(sender());
+ if (oldRoleNames == aim->roleNames()) {
+ // if the rolenames stayed the same (most common case), then we don't have
+ // to throw away all the setup that we did
+ handleModelReset();
+ } else {
+ // If they did change, we give up and just start from scratch via setMode
+ setModel(QVariant::fromValue(model()));
+ // but we still have to call handleModelReset, otherwise views will
+ // not refresh
+ handleModelReset();
+ }
+ }, Qt::SingleShotConnection);
+}
+
+void QQmlDelegateModel::handleModelReset()
{
Q_D(QQmlDelegateModel);
if (!d->m_delegate)
@@ -2005,7 +2076,7 @@ void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &par
// Ignored
} else {
// We don't know what's going on, so reset the model
- _q_modelReset();
+ handleModelReset();
}
}
@@ -2018,26 +2089,28 @@ QQmlDelegateModelAttached *QQmlDelegateModel::qmlAttachedProperties(QObject *obj
return new QQmlDelegateModelAttached(obj);
}
-bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups)
+QQmlDelegateModelPrivate::InsertionResult
+QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const QV4::Value &object, int groups)
{
if (!m_context || !m_context->isValid())
- return false;
+ return InsertionResult::Error;
QQmlDelegateModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, -1);
if (!cacheItem)
- return false;
+ return InsertionResult::Error;
if (!object.isObject())
- return false;
+ return InsertionResult::Error;
QV4::ExecutionEngine *v4 = object.as<QV4::Object>()->engine();
QV4::Scope scope(v4);
QV4::ScopedObject o(scope, object);
if (!o)
- return false;
+ return InsertionResult::Error;
QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
QV4::ScopedValue propertyName(scope);
QV4::ScopedValue v(scope);
+ const auto oldCache = m_cache;
while (1) {
propertyName = it.nextPropertyNameAsString(v);
if (propertyName->isNull())
@@ -2046,6 +2119,9 @@ bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const
propertyName->toQStringNoThrow(),
QV4::ExecutionEngine::toVariant(v, QMetaType {}));
}
+ const bool cacheModified = !m_cache.isSharedWith(oldCache);
+ if (cacheModified)
+ return InsertionResult::Retry;
cacheItem->groups = groups | Compositor::UnresolvedFlag | Compositor::CacheFlag;
@@ -2055,7 +2131,7 @@ bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const
m_cache.insert(before.cacheIndex(), cacheItem);
m_compositor.insert(before, nullptr, 0, 1, cacheItem->groups);
- return true;
+ return InsertionResult::Success;
}
//============================================================================
@@ -2115,27 +2191,27 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
s = v4Engine->newString(QStringLiteral("isUnresolved"));
QV4::ScopedFunctionObject f(scope);
- QV4::ExecutionContext *global = scope.engine->rootContext();
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, 30, QQmlDelegateModelItem::get_member)));
+ QV4::ExecutionEngine *engine = scope.engine;
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, 30, QQmlDelegateModelItem::get_member)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("inItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("inPersistedItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("itemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("persistedItemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
@@ -2143,14 +2219,14 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
QString propertyName = QLatin1String("in") + groupNames.at(i);
propertyName.replace(2, 1, propertyName.at(2).toUpper());
s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
for (int i = 2; i < groupNames.size(); ++i) {
const QString propertyName = groupNames.at(i) + QLatin1String("Index");
s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::get_index)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
@@ -2720,20 +2796,24 @@ void QQmlDelegateModelAttached::emitChanges()
m_previousGroups = m_cacheItem->groups;
int indexChanges = 0;
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i) {
+ const int groupCount = m_cacheItem->metaType->groupCount;
+ for (int i = 1; i < groupCount; ++i) {
if (m_previousIndex[i] != m_currentIndex[i]) {
m_previousIndex[i] = m_currentIndex[i];
indexChanges |= (1 << i);
}
}
+ // Don't access m_cacheItem anymore once we've started sending signals.
+ // We don't own it and someone might delete it.
+
int notifierId = 0;
const QMetaObject *meta = metaObject();
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
if (groupChanges & (1 << i))
QMetaObject::activate(this, meta, notifierId, nullptr);
}
- for (int i = 1; i < m_cacheItem->metaType->groupCount; ++i, ++notifierId) {
+ for (int i = 1; i < groupCount; ++i, ++notifierId) {
if (indexChanges & (1 << i))
QMetaObject::activate(this, meta, notifierId, nullptr);
}
@@ -2762,9 +2842,9 @@ void QQmlDelegateModelGroupPrivate::emitChanges(QV4::ExecutionEngine *v4)
Q_Q(QQmlDelegateModelGroup);
if (isChangedConnected() && !changeSet.isEmpty()) {
emit q->changed(QJSValuePrivate::fromReturnedValue(
- engineData(v4)->array(v4, changeSet.removes())),
+ qdmEngineData(v4)->array(v4, changeSet.removes())),
QJSValuePrivate::fromReturnedValue(
- engineData(v4)->array(v4, changeSet.inserts())));
+ qdmEngineData(v4)->array(v4, changeSet.inserts())));
}
if (changeSet.difference() != 0)
emit q->countChanged();
@@ -3028,7 +3108,7 @@ bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::Value &value, int *ind
items that are later replaced by actual data.
*/
-void QQmlDelegateModelGroup::insert(QQmlV4Function *args)
+void QQmlDelegateModelGroup::insert(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model);
@@ -3052,9 +3132,8 @@ void QQmlDelegateModelGroup::insert(QQmlV4Function *args)
v = (*args)[i];
}
- Compositor::insert_iterator before = index < model->m_compositor.count(group)
- ? model->m_compositor.findInsertPosition(group, index)
- : model->m_compositor.end();
+ if (v->as<QV4::ArrayObject>())
+ return;
int groups = 1 << d->group;
if (++i < args->length()) {
@@ -3062,11 +3141,16 @@ void QQmlDelegateModelGroup::insert(QQmlV4Function *args)
groups |= model->m_cacheMetaType->parseGroups(val);
}
- if (v->as<QV4::ArrayObject>()) {
- return;
- } else if (v->as<QV4::Object>()) {
- model->insert(before, v, groups);
- model->emitChanges();
+ if (v->as<QV4::Object>()) {
+ auto insertionResult = QQmlDelegateModelPrivate::InsertionResult::Retry;
+ do {
+ Compositor::insert_iterator before = index < model->m_compositor.count(group)
+ ? model->m_compositor.findInsertPosition(group, index)
+ : model->m_compositor.end();
+ insertionResult = model->insert(before, v, groups);
+ } while (insertionResult == QQmlDelegateModelPrivate::InsertionResult::Retry);
+ if (insertionResult == QQmlDelegateModelPrivate::InsertionResult::Success)
+ model->emitChanges();
}
}
@@ -3087,7 +3171,7 @@ void QQmlDelegateModelGroup::insert(QQmlV4Function *args)
group remain instantiated when not referenced by any view.
*/
-void QQmlDelegateModelGroup::create(QQmlV4Function *args)
+void QQmlDelegateModelGroup::create(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
if (!d->model)
@@ -3116,16 +3200,19 @@ void QQmlDelegateModelGroup::create(QQmlV4Function *args)
groups |= model->m_cacheMetaType->parseGroups(val);
}
- Compositor::insert_iterator before = index < model->m_compositor.count(group)
- ? model->m_compositor.findInsertPosition(group, index)
- : model->m_compositor.end();
+ auto insertionResult = QQmlDelegateModelPrivate::InsertionResult::Retry;
+ do {
+ Compositor::insert_iterator before = index < model->m_compositor.count(group)
+ ? model->m_compositor.findInsertPosition(group, index)
+ : model->m_compositor.end();
- index = before.index[d->group];
- group = d->group;
+ index = before.index[d->group];
+ group = d->group;
- if (!model->insert(before, v, groups)) {
+ insertionResult = model->insert(before, v, groups);
+ } while (insertionResult == QQmlDelegateModelPrivate::InsertionResult::Retry);
+ if (insertionResult == QQmlDelegateModelPrivate::InsertionResult::Error)
return;
- }
}
}
if (index < 0 || index >= model->m_compositor.count(group)) {
@@ -3162,7 +3249,7 @@ void QQmlDelegateModelGroup::create(QQmlV4Function *args)
that the previously unresolved item has simply moved.
*/
-void QQmlDelegateModelGroup::resolve(QQmlV4Function *args)
+void QQmlDelegateModelGroup::resolve(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
if (!d->model)
@@ -3266,7 +3353,7 @@ void QQmlDelegateModelGroup::resolve(QQmlV4Function *args)
Removes \a count items starting at \a index from the group.
*/
-void QQmlDelegateModelGroup::remove(QQmlV4Function *args)
+void QQmlDelegateModelGroup::remove(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
if (!d->model)
@@ -3306,7 +3393,7 @@ void QQmlDelegateModelGroup::remove(QQmlV4Function *args)
}
bool QQmlDelegateModelGroupPrivate::parseGroupArgs(
- QQmlV4Function *args, Compositor::Group *group, int *index, int *count, int *groups) const
+ QQmlV4FunctionPtr args, Compositor::Group *group, int *index, int *count, int *groups) const
{
if (!model || !QQmlDelegateModelPrivate::get(model)->m_cacheMetaType)
return false;
@@ -3340,7 +3427,7 @@ bool QQmlDelegateModelGroupPrivate::parseGroupArgs(
Adds \a count items starting at \a index to \a groups.
*/
-void QQmlDelegateModelGroup::addGroups(QQmlV4Function *args)
+void QQmlDelegateModelGroup::addGroups(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
Compositor::Group group = d->group;
@@ -3370,7 +3457,7 @@ void QQmlDelegateModelGroup::addGroups(QQmlV4Function *args)
Removes \a count items starting at \a index from \a groups.
*/
-void QQmlDelegateModelGroup::removeGroups(QQmlV4Function *args)
+void QQmlDelegateModelGroup::removeGroups(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
Compositor::Group group = d->group;
@@ -3401,7 +3488,7 @@ void QQmlDelegateModelGroup::removeGroups(QQmlV4Function *args)
their existing groups and added to \a groups.
*/
-void QQmlDelegateModelGroup::setGroups(QQmlV4Function *args)
+void QQmlDelegateModelGroup::setGroups(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
Compositor::Group group = d->group;
@@ -3436,7 +3523,7 @@ void QQmlDelegateModelGroup::setGroups(QQmlV4Function *args)
reordering you have done via this function.
*/
-void QQmlDelegateModelGroup::move(QQmlV4Function *args)
+void QQmlDelegateModelGroup::move(QQmlV4FunctionPtr args)
{
Q_D(QQmlDelegateModelGroup);
@@ -3926,7 +4013,7 @@ public:
const QQmlChangeSet::Change &change = array->at(index);
- QV4::ScopedObject changeProto(scope, engineData(v4)->changeProto.value());
+ QV4::ScopedObject changeProto(scope, qdmEngineData(v4)->changeProto.value());
QV4::Scoped<QQmlDelegateModelGroupChange> object(scope, QQmlDelegateModelGroupChange::create(v4));
object->setPrototypeOf(changeProto);
object->d()->change = change;