aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels/qqmldelegatemodel.cpp
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2019-08-15 10:03:57 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2019-09-12 09:19:25 +0200
commit0cc6d2a8ac895c592ccdc430ad08bd399e19ba19 (patch)
tree97107dcc00ab69b7ba885ad95ef2a411e5285e8b /src/qmlmodels/qqmldelegatemodel.cpp
parent1909f99aac4a14d70ffcc004fc9e16c154485c25 (diff)
Support required properties in model delegates
If a delegates declares a required property of a given name, and that name exists as a role in the model, we set the property accordingly. The same holds true for the special properties that come from the QQmlDelegateModel like "index" and "model". All roles are still injected into scope and thus accessible; changing this in Qt5 would be tedious or even impossible while still maintaining backwardscompatibility with delegates that do not use required properties. Change-Id: I4f388ba549c42f1ff9822bdb3b8357c4d45e4b66 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
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);