aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2023-08-15 11:40:32 +0200
committerUlf Hermann <ulf.hermann@qt.io>2023-08-22 09:12:56 +0200
commit603fb28d1d1500752782d5d138c262fccb50f0f9 (patch)
tree8cee39c7ee196ac673158fbf58a6c5cb2d16dd2f /src
parent139d45c062ce6061b96f7ffe206babde4b596a98 (diff)
QQmlBind: handle top-level attached properties
While top-level attached properties are formally deferred in QQmlBind, QQmlBind is not really interested in them. Top-level attached properties cannot be generalized grouped properties, after all. Therefore, populate the attached objects the usual way when encountering them. Pick-to: 6.6 6.5 Fixes: QTBUG-116049 Change-Id: I18e8759ea52fd91fadf80b2cc69b5054f7cea23a Reviewed-by: Sami Shalayel <sami.shalayel@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> Reviewed-by: Semih Yavuz <semih.yavuz@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp10
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h4
-rw-r--r--src/qml/types/qqmlbind.cpp101
3 files changed, 90 insertions, 25 deletions
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index ea31ff0b56..42bac5d1d1 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -290,6 +290,16 @@ void QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
}
}
+void QQmlObjectCreator::populateDeferredInstance(
+ QObject *outerObject, int deferredIndex, int index, QObject *instance,
+ QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding)
+{
+ doPopulateDeferred(outerObject, deferredIndex, [&]() {
+ populateInstance(index, instance, bindingTarget, valueTypeProperty, binding);
+ });
+}
+
void QQmlObjectCreator::finalizePopulateDeferred()
{
phase = ObjectsCreated;
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 0a2f1ecda9..0e73feeac4 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -120,6 +120,10 @@ public:
void beginPopulateDeferred(const QQmlRefPointer<QQmlContextData> &context);
void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
const QV4::CompiledData::Binding *binding);
+ void populateDeferredInstance(QObject *outerObject, int deferredIndex,
+ int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding = nullptr);
void finalizePopulateDeferred();
bool finalize(QQmlInstantiationInterrupt &interrupt);
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 8bfe9d4c4e..cdca6e89d4 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -3,28 +3,29 @@
#include "qqmlbind_p.h"
-#include <private/qqmlnullablevalue_p.h>
-#include <private/qqmlproperty_p.h>
+#include <private/qqmlanybinding_p.h>
#include <private/qqmlbinding_p.h>
+#include <private/qqmlcomponent_p.h>
#include <private/qqmlmetatype_p.h>
+#include <private/qqmlnullablevalue_p.h>
+#include <private/qqmlproperty_p.h>
#include <private/qqmlvmemetaobject_p.h>
#include <private/qv4persistent_p.h>
+#include <private/qv4qmlcontext_p.h>
+#include <private/qv4resolvedtypereference_p.h>
-#include <qqmlengine.h>
-#include <qqmlcontext.h>
-#include <qqmlproperty.h>
-#include <qqmlpropertymap.h>
-#include <qqmlinfo.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmlproperty.h>
+#include <QtQml/qqmlpropertymap.h>
+
+#include <QtCore/private/qobject_p.h>
-#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
-#include <QtCore/qtimer.h>
+#include <QtCore/qfile.h>
#include <QtCore/qloggingcategory.h>
-#include <private/qqmlanybinding_p.h>
-#include <private/qv4qmlcontext_p.h>
-#include <private/qqmlcomponent_p.h>
-
-#include <private/qobject_p.h>
+#include <QtCore/qtimer.h>
QT_BEGIN_NAMESPACE
@@ -736,6 +737,20 @@ static QQmlAnyBinding createBinding(
return QQmlAnyBinding();
}
+static void initCreator(
+ QQmlData::DeferredData *deferredData,
+ const QQmlRefPointer<QQmlContextData> &contextData,
+ QQmlComponentPrivate::ConstructionState *immediateState)
+{
+ if (!immediateState->hasCreator()) {
+ immediateState->setCompletePending(true);
+ immediateState->initCreator(
+ deferredData->context->parent(), deferredData->compilationUnit,
+ contextData);
+ immediateState->creator()->beginPopulateDeferred(deferredData->context);
+ }
+}
+
void QQmlBindPrivate::decodeBinding(
QQmlBind *q, const QString &propertyPrefix,
QQmlData::DeferredData *deferredData,
@@ -744,12 +759,54 @@ void QQmlBindPrivate::decodeBinding(
{
const QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
= deferredData->compilationUnit;
- const QString propertyName = propertyPrefix
- + compilationUnit->stringAt(binding->propertyNameIndex);
+ const QString propertySuffix = compilationUnit->stringAt(binding->propertyNameIndex);
+ const QString propertyName = propertyPrefix + propertySuffix;
switch (binding->type()) {
- case QV4::CompiledData::Binding::Type_GroupProperty:
- case QV4::CompiledData::Binding::Type_AttachedProperty: {
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ if (propertyPrefix.isEmpty()) {
+ // Top-level attached properties cannot be generalized grouped properties.
+ // Treat them as regular properties.
+ // ... unless we're not supposed to handle regular properties. Then ignore them.
+ if (!immediateState)
+ return;
+
+ Q_ASSERT(compilationUnit->stringAt(compilationUnit->objectAt(binding->value.objectIndex)
+ ->inheritedTypeNameIndex).isEmpty());
+
+ const QV4::ResolvedTypeReference *typeReference
+ = compilationUnit->resolvedType(binding->propertyNameIndex);
+ Q_ASSERT(typeReference);
+ QQmlType attachedType = typeReference->type();
+ if (!attachedType.isValid()) {
+ const QQmlTypeNameCache::Result result
+ = deferredData->context->imports()->query(propertySuffix);
+ if (!result.isValid()) {
+ qmlWarning(q).nospace()
+ << "Unknown name " << propertySuffix << ". The binding is ignored.";
+ return;
+ }
+ attachedType = result.type;
+ }
+
+ QQmlContext *context = qmlContext(q);
+ QObject *attachedObject = qmlAttachedPropertiesObject(
+ q, attachedType.attachedPropertiesFunction(
+ QQmlEnginePrivate::get(context->engine())));
+ if (!attachedObject) {
+ qmlWarning(q).nospace() <<"Could not create attached properties object '"
+ << attachedType.typeName() << "'";
+ return;
+ }
+
+ initCreator(deferredData, QQmlContextData::get(context), immediateState);
+ immediateState->creator()->populateDeferredInstance(
+ q, deferredData->deferredIdx, binding->value.objectIndex, attachedObject,
+ attachedObject, /*value type property*/ nullptr, binding);
+ return;
+ }
+ Q_FALLTHROUGH();
+ case QV4::CompiledData::Binding::Type_GroupProperty: {
const QString pre = propertyName + u'.';
const QV4::CompiledData::Object *subObj
= compilationUnit->objectAt(binding->value.objectIndex);
@@ -776,13 +833,7 @@ void QQmlBindPrivate::decodeBinding(
QQmlProperty property = QQmlPropertyPrivate::create(
q, propertyName, contextData, QQmlPropertyPrivate::InitFlag::AllowSignal);
if (property.isValid()) {
- if (!immediateState->hasCreator()) {
- immediateState->setCompletePending(true);
- immediateState->initCreator(
- deferredData->context->parent(), deferredData->compilationUnit,
- contextData);
- immediateState->creator()->beginPopulateDeferred(deferredData->context);
- }
+ initCreator(deferredData, contextData, immediateState);
immediateState->creator()->populateDeferredBinding(
property, deferredData->deferredIdx, binding);
} else {