38QQmlBinding *QQmlBinding::create(
const QQmlPropertyData *property,
const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt)
40 QQmlBinding *b = newBinding(property);
42 if (ctxt && !ctxt->isValid())
45 const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
46 if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid()))
50 QV4::Function *runtimeFunction =
nullptr;
52 QQmlRefPointer<QQmlContextData> ctxtdata = QQmlContextData::get(scriptPrivate->context);
53 QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
54 if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit()) {
55 url = ctxtdata->urlString();
56 if (scriptPrivate->bindingId != QQmlBinding::Invalid)
57 runtimeFunction = ctxtdata->typeCompilationUnit()->runtimeFunctions.at(scriptPrivate->bindingId);
60 b->setNotifyOnValueChanged(
true);
61 b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
62 b->setScopeObject(obj ? obj : scriptPrivate->scope);
64 QV4::ExecutionEngine *v4 = b->engine()->handle();
65 if (runtimeFunction) {
67 QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxtdata, b->scopeObject()));
68 b->setupFunction(qmlContext, runtimeFunction);
70 QString code = scriptPrivate->script;
71 b->createQmlBinding(b->context(), b->scopeObject(), code, url, scriptPrivate->lineNumber);
92QQmlBinding *QQmlBinding::create(
93 const QQmlPropertyData *property,
const QString &str, QObject *obj,
94 const QQmlRefPointer<QQmlContextData> &ctxt,
const QString &url, quint16 lineNumber)
96 QQmlBinding *b = newBinding(property);
98 b->setNotifyOnValueChanged(
true);
99 b->QQmlJavaScriptExpression::setContext(ctxt);
100 b->setScopeObject(obj);
102 b->createQmlBinding(ctxt, obj, str, url, lineNumber);
114QQmlBinding *QQmlBinding::create(QMetaType propertyType, QV4::Function *function, QObject *obj,
115 const QQmlRefPointer<QQmlContextData> &ctxt,
116 QV4::ExecutionContext *scope)
118 QQmlBinding *b = newBinding(propertyType);
120 b->setNotifyOnValueChanged(
true);
121 b->QQmlJavaScriptExpression::setContext(ctxt);
122 b->setScopeObject(obj);
125 b->setupFunction(scope, function);
135void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
137 if (!enabledFlag() || !hasValidContext())
141 if (QQmlData::wasDeleted(targetObject()))
145 if (Q_UNLIKELY(updatingFlag())) {
146 const QQmlPropertyData *d =
nullptr;
147 QQmlPropertyData vtd;
148 getPropertyData(&d, &vtd);
150 QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), *d, &vtd,
nullptr);
151 printBindingLoopError(p);
154 setUpdatingFlag(
true);
156 DeleteWatcher watcher(
this);
158 QQmlEngine *qmlEngine = engine();
159 QV4::Scope scope(qmlEngine->handle());
161 if (canUseAccessor())
162 flags.setFlag(QQmlPropertyData::BypassInterceptor);
164 Q_TRACE_SCOPE(QQmlBinding, qmlEngine, function() ? function()->name()->toQString() : QString(),
165 sourceLocation().sourceFile, sourceLocation().line, sourceLocation().column);
166 QQmlBindingProfiler prof(QQmlEnginePrivate::get(qmlEngine)->profiler, function());
167 doUpdate(watcher, flags, scope);
169 if (!watcher.wasDeleted())
170 setUpdatingFlag(
false);
179QV4::ReturnedValue QQmlBinding::evaluate(
bool *isUndefined)
181 QV4::ExecutionEngine *v4 = engine()->handle();
183 const QV4::Value *argv =
nullptr;
184 const QV4::Value *thisObject =
nullptr;
185 QV4::BoundFunction *b =
nullptr;
186 if ((b =
static_cast<QV4::BoundFunction *>(m_boundFunction.valueRef()))) {
187 QV4::Heap::MemberData *args = b->boundArgs();
189 argc = args->values.size;
190 argv = args->values.data();
192 thisObject = &b->d()->boundThis;
194 QV4::Scope scope(v4);
195 QV4::JSCallData jsCall(thisObject, argv, argc);
197 return QQmlJavaScriptExpression::evaluate(jsCall.callData(scope), isUndefined);
382QQmlBinding *QQmlBinding::createTranslationBinding(
383 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
384 const QV4::CompiledData::Binding *binding, QObject *obj,
385 const QQmlRefPointer<QQmlContextData> &ctxt)
387 QQmlTranslationBinding *b =
new QQmlTranslationBindingFromBinding(unit, binding);
389 b->setNotifyOnValueChanged(
true);
390 b->QQmlJavaScriptExpression::setContext(ctxt);
391 b->setScopeObject(obj);
392#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
393 if (QQmlDebugTranslationService *service
394 = QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
395 service->foundTranslationBinding(
396 TranslationBindingInformation::create(unit, binding, b->scopeObject(), ctxt));
402QQmlBinding *QQmlBinding::createTranslationBinding(
403 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
404 const QQmlRefPointer<QQmlContextData> &ctxt,
const QString &propertyName,
405 const QQmlTranslation &translationData,
const QQmlSourceLocation &location, QObject *obj)
407 QQmlTranslationBinding *b =
new QQmlTranslationBindingFromTranslationInfo(
408 unit, translationData, location.column, location.line);
410 b->setNotifyOnValueChanged(
true);
411 b->QQmlJavaScriptExpression::setContext(ctxt);
412 b->setScopeObject(obj);
414#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
415 if (QQmlDebugTranslationService *service =
416 QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
417 service->foundTranslationBinding({ unit, b->scopeObject(), ctxt,
419 propertyName, translationData,
421 location.line, location.column });
424 Q_UNUSED(propertyName)
443bool QQmlBinding::slowWrite(
444 const QQmlPropertyData &core,
const QQmlPropertyData &valueTypeData,
const void *result,
445 QMetaType resultType,
bool isUndefined, QQmlPropertyData::WriteFlags flags)
454 QQmlEngine *qmlEngine = engine();
455 const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
456 QQmlJavaScriptExpression::DeleteWatcher watcher(
this);
458 if (QQmlVMEMetaObject *vmemo = core.isVarProperty()
459 ? QQmlVMEMetaObject::get(m_target.data(), qmlEngine->handle())
461 QV4::Scope scope(qmlEngine->handle());
462 QV4::ScopedValue value(scope, qmlEngine->handle()->metaTypeToJS(resultType, result));
463 vmemo->setVMEProperty(core.coreIndex(),
465 }
else if (isUndefined && core.isResettable()) {
466 void *args[] = {
nullptr };
467 QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex(), args);
468 }
else if (isUndefined && QQmlMetaType::canLosslesslyHoldUndefined(metaType)) {
469 QQmlPropertyPrivate::writeValueProperty(
470 m_target.data(), core, valueTypeData, undefinedAs(metaType), context(), flags);
471 }
else if (metaType == QMetaType::fromType<QJSValue>()) {
472 QQmlPropertyPrivate::writeValueProperty(
473 m_target.data(), core, valueTypeData,
474 QVariant(resultType, result), context(), flags);
475 }
else if (isUndefined) {
476 const char *name = metaType.name();
477 const QString typeName = name
478 ? QString::fromUtf8(name)
479 : QStringLiteral(
"[unknown property type]");
480 delayedError()->setErrorDescription(
481 QStringLiteral(
"Unable to assign [undefined] to ") + typeName);
483 }
else if (!QQmlPropertyPrivate::writeValueProperty(
484 m_target.data(), core, valueTypeData, QVariant(resultType, result),
486 if (watcher.wasDeleted())
488 handleWriteError(result, resultType, metaType);
495Q_NEVER_INLINE
bool QQmlBinding::slowWrite(
const QQmlPropertyData &core,
496 const QQmlPropertyData &valueTypeData,
497 const QV4::Value &result,
498 bool isUndefined, QQmlPropertyData::WriteFlags flags)
500 const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
501 const int type = metaType.id();
503 QQmlJavaScriptExpression::DeleteWatcher watcher(
this);
509 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data(), engine()->handle());
510 const bool isVarProperty = core.isVarProperty() && vmemo;
513 }
else if (core.isQList()) {
514 if (core.propType().flags() & QMetaType::IsQmlList)
515 value = QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QObject*>>());
517 value = QV4::ExecutionEngine::toVariant(result, core.propType());
518 }
else if (result.isNull() && core.isQObject()) {
519 value = QVariant::fromValue((QObject *)
nullptr);
520 }
else if (core.propType() == QMetaType::fromType<QList<QUrl>>()) {
521 const QVariant resultVariant
522 = QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QUrl>>());
523 value = QVariant::fromValue(QQmlPropertyPrivate::resolveUrlsOnAssignment()
524 ? QQmlPropertyPrivate::urlSequence(resultVariant, context())
525 : QQmlPropertyPrivate::urlSequence(resultVariant));
526 }
else if (!isVarProperty && metaType != QMetaType::fromType<QJSValue>()) {
527 value = QV4::ExecutionEngine::toVariant(result, metaType);
532 }
else if (isVarProperty) {
533 const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
534 if (f && f->isBinding()) {
537 delayedError()->setErrorDescription(QLatin1String(
"Invalid use of Qt.binding() in a binding declaration."));
542 vmemo->setVMEProperty(core.coreIndex(), result);
543 }
else if (isUndefined
544 && (valueTypeData.isValid() ? valueTypeData.isResettable() : core.isResettable())) {
545 QQmlPropertyPrivate::resetValueProperty(
546 m_target.data(), core, valueTypeData, context(), flags);
547 }
else if (isUndefined && QQmlMetaType::canLosslesslyHoldUndefined(metaType)) {
548 QQmlPropertyPrivate::writeValueProperty(
549 m_target.data(), core, valueTypeData, undefinedAs(metaType), context(), flags);
550 }
else if (metaType == QMetaType::fromType<QJSValue>()) {
551 const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
552 if (f && f->isBinding()) {
553 delayedError()->setErrorDescription(QLatin1String(
"Invalid use of Qt.binding() in a binding declaration."));
556 QQmlPropertyPrivate::writeValueProperty(
557 m_target.data(), core, valueTypeData,
558 QVariant::fromValue(QJSValuePrivate::fromReturnedValue(result.asReturnedValue())),
560 }
else if (isUndefined) {
561 const char *name = QMetaType(type).name();
562 const QLatin1String typeName(name ? name :
"[unknown property type]");
563 delayedError()->setErrorDescription(QLatin1String(
"Unable to assign [undefined] to ")
566 }
else if (
const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
567 f && !f->as<QV4::QQmlTypeWrapper>()) {
569 delayedError()->setErrorDescription(QLatin1String(
"Invalid use of Qt.binding() in a binding declaration."));
571 delayedError()->setErrorDescription(QLatin1String(
"Unable to assign a function to a property of any type other than var."));
573 }
else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, value, context(), flags)) {
575 if (watcher.wasDeleted())
577 handleWriteError(value.constData(), value.metaType(), metaType);
618QVariant QQmlBinding::evaluate()
620 QQmlEngine *qmlEngine = engine();
621 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine);
622 ep->referenceScarceResources();
624 bool isUndefined =
false;
626 QV4::Scope scope(qmlEngine->handle());
627 QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
629 ep->dereferenceScarceResources();
631 return QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QObject*> >());
660QList<QQmlProperty> QQmlBinding::dependencies()
const
662 QList<QQmlProperty> dependencies;
663 if (!m_target.data())
666 for (QQmlJavaScriptExpressionGuard *guard = activeGuards.first(); guard; guard = activeGuards.next(guard)) {
667 if (guard->signalIndex() == -1)
670 QObject *senderObject = guard->senderAsObject();
674 const QMetaObject *senderMeta = senderObject->metaObject();
678 for (
int i = 0; i < senderMeta->propertyCount(); i++) {
679 QMetaProperty property = senderMeta->property(i);
680 if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) {
681 dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(property.name())));
686 for (
auto trigger = qpropertyChangeTriggers; trigger; trigger = trigger->next) {
687 QMetaProperty prop = trigger->property();
689 dependencies.push_back(QQmlProperty(trigger->target, QString::fromUtf8(prop.name())));
700void QQmlBinding::doUpdate(
const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope)
703 auto ep = QQmlEnginePrivate::get(scope.engine);
704 ep->referenceScarceResources();
707 auto canWrite = [&]() {
return !watcher.wasDeleted() && isAddedToObject() && !hasError(); };
708 const QV4::Function *v4Function = function();
709 if (v4Function && v4Function->kind == QV4::Function::AotCompiled && !hasBoundFunction()) {
710 const auto returnType = v4Function->aotCompiledFunction.types[0];
711 if (returnType == QMetaType::fromType<QVariant>()) {
713 const bool isUndefined = !evaluate(&result, returnType);
715 error = !write(result.data(), result.metaType(), isUndefined, flags);
717 const auto size = returnType.sizeOf();
718 if (Q_LIKELY(size > 0)) {
719 Q_ALLOCA_VAR(
void, result, size);
720 if (returnType.flags() & QMetaType::NeedsConstruction)
721 returnType.construct(result);
722 const bool isUndefined = !evaluate(result, returnType);
724 error = !write(result, returnType, isUndefined, flags);
725 if (returnType.flags() & QMetaType::NeedsDestruction)
726 returnType.destruct(result);
727 }
else if (canWrite()) {
728 error = !write(QV4::Value::undefined(),
true, flags);
732 bool isUndefined =
false;
733 QV4::ScopedValue result(scope, evaluate(&isUndefined));
735 error = !write(result, isUndefined, flags);
738 if (!watcher.wasDeleted()) {
741 delayedError()->setErrorLocation(sourceLocation());
742 delayedError()->setErrorObject(m_target.data());
746 if (!delayedError()->addError(ep)) ep->warning(
this->error(engine()));
752 ep->dereferenceScarceResources();
757 QBiPointer<
const QtPrivate::QMetaTypeInterface,
const QMetaObject> targetMeta;
759 const QMetaObject *targetMetaObject() {
764 if (targetMeta.isT2())
765 return targetMeta.asT2();
767 const QMetaObject *metaObject = QQmlPropertyPrivate::rawMetaObjectForType(
768 QMetaType(targetMeta.asT1())).metaObject();
771 targetMeta = metaObject;
781 QQmlPropertyData::WriteFlags flags)
override final
783 const QQmlPropertyData *pd;
784 QQmlPropertyData vtpd;
785 getPropertyData(&pd, &vtpd);
786 if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
787 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
790 QObject *resultObject =
nullptr;
791 QQmlMetaObject resultMo;
792 const auto typeFlags = type.flags();
793 if (!result || ((typeFlags & QMetaType::IsPointer) && !*
static_cast<
void **>(result))) {
795 return pd->writeProperty(targetObject(), &resultObject, flags);
796 }
else if (typeFlags & QMetaType::PointerToQObject) {
797 resultObject = *
static_cast<QObject **>(result);
799 return pd->writeProperty(targetObject(), &resultObject, flags);
800 if (QQmlData *ddata = QQmlData::get(resultObject,
false))
801 resultMo = ddata->propertyCache;
802 if (resultMo.isNull())
803 resultMo = resultObject->metaObject();
804 }
else if (type == QMetaType::fromType<QVariant>()) {
805 const QVariant value = *
static_cast<QVariant *>(result);
806 resultMo = QQmlPropertyPrivate::rawMetaObjectForType(value.metaType());
807 if (resultMo.isNull())
808 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
809 resultObject = *
static_cast<QObject *
const *>(value.constData());
811 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
814 return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
815 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
820 QQmlPropertyData::WriteFlags flags)
override final
822 const QQmlPropertyData *pd;
823 QQmlPropertyData vtpd;
824 getPropertyData(&pd, &vtpd);
825 if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
826 return slowWrite(*pd, vtpd, result, isUndefined, flags);
829 QObject *resultObject =
nullptr;
830 QQmlMetaObject resultMo;
831 if (result.isNull()) {
833 return pd->writeProperty(targetObject(), &resultObject, flags);
834 }
else if (
auto wrapper = result.as<QV4::QObjectWrapper>()) {
835 resultObject = wrapper->object();
837 return pd->writeProperty(targetObject(), &resultObject, flags);
838 if (QQmlData *ddata = QQmlData::get(resultObject,
false))
839 resultMo = ddata->propertyCache;
840 if (resultMo.isNull()) {
841 resultMo = resultObject->metaObject();
843 }
else if (
auto variant = result.as<QV4::VariantObject>()) {
844 const QVariant value = variant->d()->data();
845 resultMo = QQmlPropertyPrivate::rawMetaObjectForType(value.metaType());
846 if (resultMo.isNull())
847 return slowWrite(*pd, vtpd, result, isUndefined, flags);
848 resultObject = *
static_cast<QObject *
const *>(value.constData());
850 return slowWrite(*pd, vtpd, result, isUndefined, flags);
853 return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
854 return slowWrite(*pd, vtpd, result, isUndefined, flags);
861 template<
typename SlowWrite>
862 bool compareAndSet(
const QQmlMetaObject &resultMo, QObject *resultObject,
const QQmlPropertyData *pd,
863 QQmlPropertyData::WriteFlags flags,
const SlowWrite &slowWrite)
865 const QMetaObject *propertyMo = targetMetaObject();
869 if (QQmlMetaObject::canConvert(resultMo, propertyMo)) {
870 return pd->writeProperty(targetObject(), &resultObject, flags);
871 }
else if (!resultObject && QQmlMetaObject::canConvert(propertyMo, resultMo)) {
875 return pd->writeProperty(targetObject(), &resultObject, flags);