diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2023-08-15 11:40:32 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-08-22 09:12:56 +0200 |
commit | 603fb28d1d1500752782d5d138c262fccb50f0f9 (patch) | |
tree | 8cee39c7ee196ac673158fbf58a6c5cb2d16dd2f /src/qml/types/qqmlbind.cpp | |
parent | 139d45c062ce6061b96f7ffe206babde4b596a98 (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/qml/types/qqmlbind.cpp')
-rw-r--r-- | src/qml/types/qqmlbind.cpp | 101 |
1 files changed, 76 insertions, 25 deletions
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 { |