960 const QQmlProperty &prop,
const QV4::CompiledData::Binding *binding,
961 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
962 const QQmlRefPointer<QQmlContextData> &contextData,
963 QObject *scopeObject)
965 switch (binding->type()) {
966 case QV4::CompiledData::Binding::Type_Translation:
967 case QV4::CompiledData::Binding::Type_TranslationById:
968 return QQmlAnyBinding::createTranslationBinding(prop, compilationUnit, binding, scopeObject);
969 case QV4::CompiledData::Binding::Type_Script: {
970 const QQmlBinding::Identifier id = binding->value.compiledScriptIndex;
971 if (id == QQmlBinding::Invalid) {
972 return QQmlAnyBinding::createFromCodeString(
973 prop, compilationUnit->bindingValueAsString(binding), scopeObject,
974 contextData, compilationUnit->finalUrlString(), binding->location.line());
976 QV4::Scope scope(contextData->engine()->handle());
977 QV4::Scoped<QV4::QmlContext> qmlCtxt(
978 scope, QV4::QmlContext::create(
979 scope.engine->rootContext(), contextData, scopeObject));
980 return QQmlAnyBinding::createFromFunction(
981 prop, compilationUnit->runtimeFunctions.at(id), scopeObject, contextData,
987 return QQmlAnyBinding();
1005 QQmlBind *q,
const QString &propertyPrefix,
1006 QQmlData::DeferredData *deferredData,
1007 const QV4::CompiledData::Binding *binding,
1008 QQmlComponentPrivate::ConstructionState *immediateState)
1010 const QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
1011 = deferredData->compilationUnit;
1012 QString propertySuffix = compilationUnit->stringAt(binding->propertyNameIndex);
1013 if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerExpression)
1014 || binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject)) {
1015 propertySuffix = *QQmlSignalNames::anyHandlerNameToSignalName(propertySuffix);
1016 }
else if (binding->hasFlag(QV4::CompiledData::Binding::IsPropertyObserver)) {
1017 propertySuffix = *QQmlSignalNames::changedHandlerNameToPropertyName(propertySuffix);
1019 const QString propertyName = propertyPrefix + propertySuffix;
1021 switch (binding->type()) {
1022 case QV4::CompiledData::Binding::Type_AttachedProperty:
1023 if (propertyPrefix.isEmpty()) {
1027 if (!immediateState)
1030 Q_ASSERT(compilationUnit->stringAt(compilationUnit->objectAt(binding->value.objectIndex)
1031 ->inheritedTypeNameIndex).isEmpty());
1033 const QV4::ResolvedTypeReference *typeReference
1034 = compilationUnit->resolvedType(binding->propertyNameIndex);
1035 Q_ASSERT(typeReference);
1036 QQmlType attachedType = typeReference->type();
1037 if (!attachedType.isValid()) {
1038 if (QQmlTypeLoader *typeLoader = compilationUnit->engine->typeLoader()) {
1039 const QQmlTypeNameCache::Result result
1040 = deferredData->context->imports()->query(propertySuffix, typeLoader);
1041 if (!result.isValid()) {
1042 qmlWarning(q).nospace()
1043 <<
"Unknown name " << propertySuffix <<
". The binding is ignored.";
1046 attachedType = result.type;
1050 QQmlContext *context = qmlContext(q);
1051 QObject *attachedObject = qmlAttachedPropertiesObject(
1052 q, attachedType.attachedPropertiesFunction(QQmlTypeLoader::get(context->engine())));
1053 if (!attachedObject) {
1054 qmlWarning(q).nospace() <<
"Could not create attached properties object '"
1055 << attachedType.typeName() <<
"'";
1059 initCreator(deferredData, QQmlContextData::get(context), immediateState);
1060 immediateState->creator()->populateDeferredInstance(
1061 q, deferredData->deferredIdx, binding->value.objectIndex, attachedObject,
1062 attachedObject,
nullptr, binding);
1066 case QV4::CompiledData::Binding::Type_GroupedProperty: {
1067 const QString pre = propertyName + u'.';
1068 const QV4::CompiledData::Object *subObj
1069 = compilationUnit->objectAt(binding->value.objectIndex);
1070 const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
1071 for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding)
1072 decodeBinding(q, pre, deferredData, subBinding, immediateState);
1079 QQmlBindEntry entry;
1080 QQmlContext *context = qmlContext(q);
1081 const QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
1082 entry.prop = QQmlPropertyPrivate::create(
nullptr, propertyName, contextData,
1083 QQmlPropertyPrivate::InitFlag::AllowId);
1084 if (!entry.prop.isValid()) {
1087 if (!immediateState)
1090 QQmlProperty property = QQmlPropertyPrivate::create(
1091 q, propertyName, contextData, QQmlPropertyPrivate::InitFlag::AllowSignal);
1092 if (property.isValid()) {
1093 initCreator(deferredData, contextData, immediateState);
1094 immediateState->creator()->populateDeferredBinding(
1095 property, deferredData->deferredIdx, binding);
1097 qmlWarning(q).nospace() <<
"Unknown name " << propertyName
1098 <<
". The binding is ignored.";
1104 case GeneralizedGroup:
1106 case ObjectPropertyValue:
1107 warnIgnoredProperties(q);
1108 objectPropertyValueData.~ObjectPropertyValueData();
1111 new (&generalizedGroupData) GeneralizedGroupData;
1112 mode = GeneralizedGroup;
1116 const auto setVariant = [&entry](QV4::PersistentValue value) {
1117 entry.currentKind = entry.current.setVariant(value, entry.currentKind);
1120 const auto setBinding = [&entry](QQmlAnyBinding binding) {
1121 entry.currentKind = entry.current.set(binding, entry.currentKind);
1124 switch (binding->type()) {
1125 case QV4::CompiledData::Binding::Type_AttachedProperty:
1126 case QV4::CompiledData::Binding::Type_GroupedProperty:
1129 case QV4::CompiledData::Binding::Type_Translation:
1130 case QV4::CompiledData::Binding::Type_TranslationById:
1131 case QV4::CompiledData::Binding::Type_Script:
1133 if (!generalizedGroupData.delayedValues)
1134 createDelayedValues();
1135 const QString delayedName = QString::number(generalizedGroupData.entries.size());
1136 generalizedGroupData.delayedValues->insert(delayedName, QVariant());
1137 QQmlProperty bindingTarget
1138 = QQmlProperty(generalizedGroupData.delayedValues.get(), delayedName);
1139 Q_ASSERT(bindingTarget.isValid());
1140 QQmlAnyBinding anyBinding = createBinding(
1141 bindingTarget, binding, compilationUnit, contextData, q);
1142 anyBinding.installOn(bindingTarget);
1144 setBinding(createBinding(entry.prop, binding, compilationUnit, contextData, q));
1147 case QV4::CompiledData::Binding::Type_String:
1148 setVariant(QV4::PersistentValue(
1149 compilationUnit->engine,
1150 compilationUnit->runtimeStrings[binding->stringIndex]->asReturnedValue()));
1152 case QV4::CompiledData::Binding::Type_Number:
1153 setVariant(QV4::PersistentValue(
1154 compilationUnit->engine,
1155 QV4::Encode(compilationUnit->bindingValueAsNumber(binding))));
1157 case QV4::CompiledData::Binding::Type_Boolean:
1158 setVariant(QV4::PersistentValue(compilationUnit->engine, QV4::Encode(binding->value.b)));
1160 case QV4::CompiledData::Binding::Type_Null:
1161 setVariant(QV4::PersistentValue(compilationUnit->engine, QV4::Encode::null()));
1163 case QV4::CompiledData::Binding::Type_Object:
1166 if (!immediateState)
1168 auto v4 = compilationUnit->engine;
1171 const QQmlProperty &property = entry.prop;
1172 QObject *bindingTargetObject = property.object();
1175 int objectToBeCreated = binding->value.objectIndex;
1177 auto context = qmlContext(bindingTargetObject);
1178 auto contextData = QQmlContextData::get(context);
1179 initCreator(deferredData, contextData, immediateState);
1180 QObject *newObject = immediateState->creator()->createObjectInContext(objectToBeCreated, bindingTargetObject, contextData);
1181 setVariant(QV4::PersistentValue(v4, QV4::QObjectWrapper::wrap(v4, newObject)));
1184 case QV4::CompiledData::Binding::Type_Invalid:
1188 generalizedGroupData.entries.append(std::move(entry));
1240void QQmlBindPrivate::buildBindEntries(QQmlBind *q, QQmlComponentPrivate::DeferredState *deferredState)
1242 QQmlData *data = QQmlData::get(q);
1243 if (data && !data->deferredData.isEmpty()) {
1244 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
1245 for (QQmlData::DeferredData *deferredData : data->deferredData) {
1246 QMultiHash<
int,
const QV4::CompiledData::Binding *> *bindings = &deferredData->bindings;
1247 if (deferredState) {
1248 QQmlComponentPrivate::ConstructionState constructionState;
1249 for (
auto it = bindings->cbegin(); it != bindings->cend(); ++it)
1250 decodeBinding(q, QString(), deferredData, *it, &constructionState);
1253 if (constructionState.hasCreator()) {
1254 ++ep->inProgressCreations;
1255 constructionState.creator()->finalizePopulateDeferred();
1256 constructionState.appendCreatorErrors();
1257 deferredState->push_back(std::move(constructionState));
1260 for (
auto it = bindings->cbegin(); it != bindings->cend(); ++it)
1261 decodeBinding(q, QString(), deferredData, *it,
nullptr);
1265 if (deferredState) {
1266 data->releaseDeferredData();
1267 if (!deferredState->empty())
1268 QQmlComponentPrivate::completeDeferred(ep, deferredState);
1312 switch (entry->currentKind) {
1313 case QQmlBindEntryKind::V4Value: {
1314 auto propPriv = QQmlPropertyPrivate::get(entry->prop);
1315 QQmlVMEMetaObject *vmemo =
1316 QQmlVMEMetaObject::get(propPriv->object, propPriv->engine->handle());
1318 return QV4::RuntimeHelpers::strictEqual(
1320 QV4::Value::fromReturnedValue(vmemo->vmeProperty(propPriv->core.coreIndex())),
1321 *entry->current.v4Value.valueRef());
1323 case QQmlBindEntryKind::Variant: {
1324 const QV4::PersistentValue &v4Value = entry->current.v4Value;
1325 QMetaType propMetaType = entry->prop.propertyMetaType();
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337 QVariant valueAsVariant = v4Value.engine()->toVariant(*v4Value.valueRef(),
1339 if (propMetaType.flags() & QMetaType::IsQmlList) {
1342 QList<QObject *> expectedObjectList;
1343 QQmlListProperty<QObject> expectedAsListProp(
nullptr, &expectedObjectList);
1344 QQmlPropertyPrivate::convertToQQmlListProperty(&expectedAsListProp, propMetaType, valueAsVariant);
1346 QVariant actualValue = entry->prop.read();
1348 QQmlListReference* listReference = get_if<QQmlListReference>(&actualValue);
1349 Q_ASSERT(listReference);
1350 auto actualObjectList = QQmlListReferencePrivate::get(listReference)->property.toList<QList<QObject *>>();
1351 return std::equal(expectedObjectList.constBegin(), expectedObjectList.constEnd(),
1352 actualObjectList.constBegin(), actualObjectList.constEnd());
1354 }
else if (QMetaType varMetaType = valueAsVariant.metaType(); varMetaType != propMetaType) {
1355 QVariant converted = QQmlPropertyPrivate::convertToWriteTargetType(
1356 valueAsVariant, propMetaType);
1357 if (converted.isValid())
1358 valueAsVariant = std::move(converted);
1360 return valueAsVariant
1361 == entry->prop.read();
1363 case QQmlBindEntryKind::Binding:
1364 return entry->current.binding == QQmlAnyBinding::ofProperty(entry->prop);
1365 case QQmlBindEntryKind::None:
1374 if (!entry->prop.isValid() || (entry->currentKind == QQmlBindEntryKind::None))
1376 if (!entry->prop.object())
1386 switch (entry->previousKind) {
1387 case QQmlBindEntryKind::Binding:
1389 QQmlAnyBinding p = std::move(entry->previous.binding);
1391 p.installOn(entry->prop);
1394 case QQmlBindEntryKind::V4Value:
1396 QQmlAnyBinding::takeFrom(entry->prop);
1397 auto propPriv = QQmlPropertyPrivate::get(entry->prop);
1398 QQmlVMEMetaObject *vmemo =
1399 QQmlVMEMetaObject::get(propPriv->object, propPriv->engine->handle());
1401 vmemo->setVMEProperty(propPriv->core.coreIndex(),
1402 *entry->previous.v4Value.valueRef());
1406 case QQmlBindEntryKind::Variant:
1408 QQmlAnyBinding::takeFrom(entry->prop);
1409 const QV4::PersistentValue &v4Value = entry->previous.v4Value;
1410 entry->prop.write(v4Value.engine()->toVariant(
1411 *v4Value.valueRef(), entry->prop.propertyMetaType()));
1415 case QQmlBindEntryKind::None:
1422 if (entry->previousKind == QQmlBindEntryKind::None) {
1424 QQmlAnyBinding prevBind = QQmlAnyBinding::takeFrom(entry->prop);
1426 entry->previousKind = entry->previous.set(std::move(prevBind), entry->previousKind);
1429 auto propPriv = QQmlPropertyPrivate::get(entry->prop);
1430 auto propData = propPriv->core;
1431 if (!propPriv->valueTypeData.isValid() && propData.isVarProperty()) {
1432 QQmlVMEMetaObject *vmemo =
1433 QQmlVMEMetaObject::get(propPriv->object, propPriv->engine->handle());
1435 auto retVal = vmemo->vmeProperty(propData.coreIndex());
1436 entry->previousKind = entry->previous.set(
1437 QV4::PersistentValue(vmemo->engine(), retVal), entry->previousKind);
1438 }
else if (entry->prop.propertyMetaType().flags() & QMetaType::IsQmlList) {
1439 using namespace QV4;
1440 ExecutionEngine *v4 = qmlEngine(q_func())->handle();
1441 entry->previousKind = entry->previous.setVariant(
1442 QV4::PersistentValue(v4, QV4::QmlListWrapper::createOwned(v4, entry->prop)),
1443 entry->previousKind);
1447 entry->previousKind = entry->previous.set(
1448 propPriv->engine->handle(), entry->prop.read(), entry->previousKind);
1455 QQmlPropertyPrivate::removeBinding(entry->prop, QQmlPropertyPrivate::OverrideSticky);