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.cpp81
1 files changed, 78 insertions, 3 deletions
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index 6c80f4a3e5..c37dc114a1 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -48,7 +48,6 @@
#include <private/qqmlchangeset_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
-#include <private/qqmlincubator_p.h>
#include <private/qv4value_p.h>
#include <private/qv4functionobject_p.h>
@@ -887,6 +886,81 @@ static bool isDoneIncubating(QQmlIncubator::Status status)
return status == QQmlIncubator::Ready || status == QQmlIncubator::Error;
}
+PropertyUpdater::PropertyUpdater(QObject *parent) :
+ QObject(parent) {}
+
+void PropertyUpdater::doUpdate()
+{
+ auto sender = QObject::sender();
+ auto mo = sender->metaObject();
+ auto signalIndex = QObject::senderSignalIndex();
+ // start at 0 instead of propertyOffset to handle properties from parent hierarchy
+ for (auto i = 0; i < mo->propertyCount() + mo->propertyOffset(); ++i) {
+ auto property = mo->property(i);
+ if (property.notifySignal().methodIndex() == signalIndex) {
+ // we synchronize between required properties and model rolenames by name
+ // that's why the QQmlProperty and the metaobject property must have the same name
+ QQmlProperty qmlProp(parent(), QString::fromLatin1(property.name()));
+ qmlProp.write(property.read(QObject::sender()));
+ return;
+ }
+ }
+}
+
+void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *modelItemToIncubate, QObject *object)
+{
+ auto incubatorPriv = QQmlIncubatorPrivate::get(this);
+ if (incubatorPriv->hadRequiredProperties()) {
+ 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
+ QVarLengthArray<const QMetaObject *, 4> mos;
+ // we first check the dynamic meta object for properties originating from the model
+ mos.push_back(qmlMetaObject); // contains abstractitemmodelproperties
+ auto delegateModelItemSubclassMO = qmlMetaObject->superClass();
+ mos.push_back(delegateModelItemSubclassMO);
+
+ while (strcmp(delegateModelItemSubclassMO->className(), modelItemToIncubate->staticMetaObject.className())) {
+ delegateModelItemSubclassMO = delegateModelItemSubclassMO->superClass();
+ mos.push_back(delegateModelItemSubclassMO);
+ }
+ if (proxiedObject)
+ mos.push_back(proxiedObject->metaObject());
+
+ auto updater = new PropertyUpdater(object);
+ for (const QMetaObject *mo : mos) {
+ for (int i = mo->propertyOffset(); i < mo->propertyCount() + mo->propertyOffset(); ++i) {
+ auto prop = mo->property(i);
+ if (!prop.name())
+ continue;
+ auto propName = QString::fromUtf8(prop.name());
+ bool wasInRequired = false;
+ QQmlProperty componentProp = QQmlComponentPrivate::removePropertyFromRequired(
+ object, propName, requiredProperties, &wasInRequired);
+ // only write to property if it was actually requested by the component
+ if (wasInRequired && prop.hasNotifySignal()) {
+ QMetaMethod changeSignal = prop.notifySignal();
+ QMetaMethod updateSlot = PropertyUpdater::staticMetaObject.method(PropertyUpdater::staticMetaObject.indexOfSlot("doUpdate()"));
+ QObject::connect(modelItemToIncubate, changeSignal, updater, updateSlot);
+ }
+ if (wasInRequired)
+ componentProp.write(prop.read(modelItemToIncubate));
+ }
+ }
+ } else {
+ modelItemToIncubate->contextData->contextObject = modelItemToIncubate;
+ if (proxiedObject)
+ proxyContext->contextObject = proxiedObject;
+ }
+}
+
void QQDMIncubationTask::statusChanged(Status status)
{
if (vdm) {
@@ -987,6 +1061,7 @@ void QQDMIncubationTask::setInitialState(QObject *o)
void QQmlDelegateModelPrivate::setInitialState(QQDMIncubationTask *incubationTask, QObject *o)
{
QQmlDelegateModelItem *cacheItem = incubationTask->incubating;
+ incubationTask->initializeRequiredProperties(incubationTask->incubating, o);
cacheItem->object = o;
if (QQuickPackage *package = qmlobject_cast<QQuickPackage *>(cacheItem->object))
@@ -1053,7 +1128,6 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
QQmlContextData *ctxt = new QQmlContextData;
ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context.data()));
- ctxt->contextObject = cacheItem;
cacheItem->contextData = ctxt;
if (m_adaptorModel.hasProxyObject()) {
@@ -1062,7 +1136,8 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
ctxt = new QQmlContextData;
ctxt->setParent(cacheItem->contextData, /*stronglyReferencedByParent*/true);
QObject *proxied = proxy->proxiedObject();
- ctxt->contextObject = proxied;
+ cacheItem->incubationTask->proxiedObject = proxied;
+ cacheItem->incubationTask->proxyContext = ctxt;
// We don't own the proxied object. We need to clear it if it goes away.
QObject::connect(proxied, &QObject::destroyed,
cacheItem, &QQmlDelegateModelItem::childContextObjectDestroyed);