37QQmlBinding *QQmlBinding::create(
const QQmlPropertyData *property,
const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt)
39 QQmlBinding *b = newBinding(property);
41 if (ctxt && !ctxt->isValid())
44 const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
45 if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid()))
49 QV4::Function *runtimeFunction =
nullptr;
51 QQmlRefPointer<QQmlContextData> ctxtdata = QQmlContextData::get(scriptPrivate->context);
52 QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
53 if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit()) {
54 url = ctxtdata->urlString();
55 if (scriptPrivate->bindingId != QQmlBinding::Invalid)
56 runtimeFunction = ctxtdata->typeCompilationUnit()->runtimeFunctions.at(scriptPrivate->bindingId);
59 b->setNotifyOnValueChanged(
true);
60 b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
61 b->setScopeObject(obj ? obj : scriptPrivate->scope);
63 QV4::ExecutionEngine *v4 = b->engine()->handle();
64 if (runtimeFunction) {
66 QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxtdata, b->scopeObject()));
67 b->setupFunction(qmlContext, runtimeFunction);
69 QString code = scriptPrivate->script;
70 b->createQmlBinding(b->context(), b->scopeObject(), code, url, scriptPrivate->lineNumber);
91QQmlBinding *QQmlBinding::create(
92 const QQmlPropertyData *property,
const QString &str, QObject *obj,
93 const QQmlRefPointer<QQmlContextData> &ctxt,
const QString &url, quint16 lineNumber)
95 QQmlBinding *b = newBinding(property);
97 b->setNotifyOnValueChanged(
true);
98 b->QQmlJavaScriptExpression::setContext(ctxt);
99 b->setScopeObject(obj);
101 b->createQmlBinding(ctxt, obj, str, url, lineNumber);
113QQmlBinding *QQmlBinding::create(QMetaType propertyType, QV4::Function *function, QObject *obj,
114 const QQmlRefPointer<QQmlContextData> &ctxt,
115 QV4::ExecutionContext *scope)
117 QQmlBinding *b = newBinding(propertyType);
119 b->setNotifyOnValueChanged(
true);
120 b->QQmlJavaScriptExpression::setContext(ctxt);
121 b->setScopeObject(obj);
124 b->setupFunction(scope, function);
134void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
136 if (!enabledFlag() || !hasValidContext())
140 if (QQmlData::wasDeleted(targetObject()))
144 if (Q_UNLIKELY(updatingFlag())) {
145 const QQmlPropertyData *d =
nullptr;
146 QQmlPropertyData vtd;
147 getPropertyData(&d, &vtd);
149 QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), *d, &vtd,
nullptr);
150 printBindingLoopError(p);
153 setUpdatingFlag(
true);
155 DeleteWatcher watcher(
this);
157 QQmlEngine *qmlEngine = engine();
158 QV4::Scope scope(qmlEngine->handle());
160 if (canUseAccessor())
161 flags.setFlag(QQmlPropertyData::BypassInterceptor);
163 Q_TRACE_SCOPE(QQmlBinding, qmlEngine, function() ? function()->name()->toQString() : QString(),
164 sourceLocation().sourceFile, sourceLocation().line, sourceLocation().column);
165 QQmlBindingProfiler prof(QQmlEnginePrivate::get(qmlEngine)->profiler, function());
166 doUpdate(watcher, flags, scope);
168 if (!watcher.wasDeleted())
169 setUpdatingFlag(
false);
178QV4::ReturnedValue QQmlBinding::evaluate(
bool *isUndefined)
180 QV4::ExecutionEngine *v4 = engine()->handle();
182 const QV4::Value *argv =
nullptr;
183 const QV4::Value *thisObject =
nullptr;
184 QV4::BoundFunction *b =
nullptr;
185 if ((b =
static_cast<QV4::BoundFunction *>(m_boundFunction.valueRef()))) {
186 QV4::Heap::MemberData *args = b->boundArgs();
188 argc = args->values.size;
189 argv = args->values.data();
191 thisObject = &b->d()->boundThis;
193 QV4::Scope scope(v4);
194 QV4::JSCallData jsCall(thisObject, argv, argc);
196 return QQmlJavaScriptExpression::evaluate(jsCall.callData(scope), isUndefined);
381QQmlBinding *QQmlBinding::createTranslationBinding(
382 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
383 const QV4::CompiledData::Binding *binding, QObject *obj,
384 const QQmlRefPointer<QQmlContextData> &ctxt)
386 QQmlTranslationBinding *b =
new QQmlTranslationBindingFromBinding(unit, binding);
388 b->setNotifyOnValueChanged(
true);
389 b->QQmlJavaScriptExpression::setContext(ctxt);
390 b->setScopeObject(obj);
391#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
392 if (QQmlDebugTranslationService *service
393 = QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
394 service->foundTranslationBinding(
395 TranslationBindingInformation::create(unit, binding, b->scopeObject(), ctxt));
401QQmlBinding *QQmlBinding::createTranslationBinding(
402 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
403 const QQmlRefPointer<QQmlContextData> &ctxt,
const QString &propertyName,
404 const QQmlTranslation &translationData,
const QQmlSourceLocation &location, QObject *obj)
406 QQmlTranslationBinding *b =
new QQmlTranslationBindingFromTranslationInfo(
407 unit, translationData, location.column, location.line);
409 b->setNotifyOnValueChanged(
true);
410 b->QQmlJavaScriptExpression::setContext(ctxt);
411 b->setScopeObject(obj);
413#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
414 if (QQmlDebugTranslationService *service =
415 QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
416 service->foundTranslationBinding({ unit, b->scopeObject(), ctxt,
418 propertyName, translationData,
420 location.line, location.column });
423 Q_UNUSED(propertyName)
428bool QQmlBinding::slowWrite(
429 const QQmlPropertyData &core,
const QQmlPropertyData &valueTypeData,
const void *result,
430 QMetaType resultType,
bool isUndefined, QQmlPropertyData::WriteFlags flags)
439 QQmlEngine *qmlEngine = engine();
440 const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
441 QQmlJavaScriptExpression::DeleteWatcher watcher(
this);
443 if (QQmlVMEMetaObject *vmemo = core.isVarProperty()
444 ? QQmlVMEMetaObject::get(m_target.data(), qmlEngine->handle())
446 QV4::Scope scope(qmlEngine->handle());
447 QV4::ScopedValue value(scope, qmlEngine->handle()->metaTypeToJS(resultType, result));
448 vmemo->setVMEProperty(core.coreIndex(),
450 }
else if (isUndefined && core.isResettable()) {
451 void *args[] = {
nullptr };
452 QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex(), args);
453 }
else if (isUndefined && metaType == QMetaType::fromType<QVariant>()) {
454 QQmlPropertyPrivate::writeValueProperty(
455 m_target.data(), core, valueTypeData, QVariant(), context(), flags);
456 }
else if (metaType == QMetaType::fromType<QJSValue>()) {
457 QQmlPropertyPrivate::writeValueProperty(
458 m_target.data(), core, valueTypeData,
459 QVariant(resultType, result), context(), flags);
460 }
else if (isUndefined) {
461 const char *name = metaType.name();
462 const QString typeName = name
463 ? QString::fromUtf8(name)
464 : QStringLiteral(
"[unknown property type]");
465 delayedError()->setErrorDescription(
466 QStringLiteral(
"Unable to assign [undefined] to ") + typeName);
468 }
else if (!QQmlPropertyPrivate::writeValueProperty(
469 m_target.data(), core, valueTypeData, QVariant(resultType, result),
471 if (watcher.wasDeleted())
473 handleWriteError(result, resultType, metaType);
480Q_NEVER_INLINE
bool QQmlBinding::slowWrite(
const QQmlPropertyData &core,
481 const QQmlPropertyData &valueTypeData,
482 const QV4::Value &result,
483 bool isUndefined, QQmlPropertyData::WriteFlags flags)
485 const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
486 const int type = metaType.id();
488 QQmlJavaScriptExpression::DeleteWatcher watcher(
this);
494 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data(), engine()->handle());
495 const bool isVarProperty = core.isVarProperty() && vmemo;
498 }
else if (core.isQList()) {
499 if (core.propType().flags() & QMetaType::IsQmlList)
500 value = QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QObject*>>());
502 value = QV4::ExecutionEngine::toVariant(result, core.propType());
503 }
else if (result.isNull() && core.isQObject()) {
504 value = QVariant::fromValue((QObject *)
nullptr);
505 }
else if (core.propType() == QMetaType::fromType<QList<QUrl>>()) {
506 const QVariant resultVariant
507 = QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QUrl>>());
508 value = QVariant::fromValue(QQmlPropertyPrivate::resolveUrlsOnAssignment()
509 ? QQmlPropertyPrivate::urlSequence(resultVariant, context())
510 : QQmlPropertyPrivate::urlSequence(resultVariant));
511 }
else if (!isVarProperty && metaType != QMetaType::fromType<QJSValue>()) {
512 value = QV4::ExecutionEngine::toVariant(result, metaType);
517 }
else if (isVarProperty) {
518 const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
519 if (f && f->isBinding()) {
522 delayedError()->setErrorDescription(QLatin1String(
"Invalid use of Qt.binding() in a binding declaration."));
527 vmemo->setVMEProperty(core.coreIndex(), result);
528 }
else if (isUndefined
529 && (valueTypeData.isValid() ? valueTypeData.isResettable() : core.isResettable())) {
530 QQmlPropertyPrivate::resetValueProperty(
531 m_target.data(), core, valueTypeData, context(), flags);
532 }
else if (isUndefined && type == QMetaType::QVariant) {
533 QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant(), context(), flags);
534 }
else if (metaType == QMetaType::fromType<QJSValue>()) {
535 const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
536 if (f && f->isBinding()) {
537 delayedError()->setErrorDescription(QLatin1String(
"Invalid use of Qt.binding() in a binding declaration."));
540 QQmlPropertyPrivate::writeValueProperty(
541 m_target.data(), core, valueTypeData,
542 QVariant::fromValue(QJSValuePrivate::fromReturnedValue(result.asReturnedValue())),
544 }
else if (isUndefined) {
545 const char *name = QMetaType(type).name();
546 const QLatin1String typeName(name ? name :
"[unknown property type]");
547 delayedError()->setErrorDescription(QLatin1String(
"Unable to assign [undefined] to ")
550 }
else if (
const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
551 f && !f->as<QV4::QQmlTypeWrapper>()) {
553 delayedError()->setErrorDescription(QLatin1String(
"Invalid use of Qt.binding() in a binding declaration."));
555 delayedError()->setErrorDescription(QLatin1String(
"Unable to assign a function to a property of any type other than var."));
557 }
else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, value, context(), flags)) {
559 if (watcher.wasDeleted())
561 handleWriteError(value.constData(), value.metaType(), metaType);
602QVariant QQmlBinding::evaluate()
604 QQmlEngine *qmlEngine = engine();
605 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine);
606 ep->referenceScarceResources();
608 bool isUndefined =
false;
610 QV4::Scope scope(qmlEngine->handle());
611 QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
613 ep->dereferenceScarceResources();
615 return QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QObject*> >());
644QList<QQmlProperty> QQmlBinding::dependencies()
const
646 QList<QQmlProperty> dependencies;
647 if (!m_target.data())
650 for (QQmlJavaScriptExpressionGuard *guard = activeGuards.first(); guard; guard = activeGuards.next(guard)) {
651 if (guard->signalIndex() == -1)
654 QObject *senderObject = guard->senderAsObject();
658 const QMetaObject *senderMeta = senderObject->metaObject();
662 for (
int i = 0; i < senderMeta->propertyCount(); i++) {
663 QMetaProperty property = senderMeta->property(i);
664 if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) {
665 dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(property.name())));
670 for (
auto trigger = qpropertyChangeTriggers; trigger; trigger = trigger->next) {
671 QMetaProperty prop = trigger->property();
673 dependencies.push_back(QQmlProperty(trigger->target, QString::fromUtf8(prop.name())));
684void QQmlBinding::doUpdate(
const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope)
687 auto ep = QQmlEnginePrivate::get(scope.engine);
688 ep->referenceScarceResources();
691 auto canWrite = [&]() {
return !watcher.wasDeleted() && isAddedToObject() && !hasError(); };
692 const QV4::Function *v4Function = function();
693 if (v4Function && v4Function->kind == QV4::Function::AotCompiled && !hasBoundFunction()) {
694 const auto returnType = v4Function->aotCompiledFunction.types[0];
695 if (returnType == QMetaType::fromType<QVariant>()) {
697 const bool isUndefined = !evaluate(&result, returnType);
699 error = !write(result.data(), result.metaType(), isUndefined, flags);
701 const auto size = returnType.sizeOf();
702 if (Q_LIKELY(size > 0)) {
703 Q_ALLOCA_VAR(
void, result, size);
704 if (returnType.flags() & QMetaType::NeedsConstruction)
705 returnType.construct(result);
706 const bool isUndefined = !evaluate(result, returnType);
708 error = !write(result, returnType, isUndefined, flags);
709 if (returnType.flags() & QMetaType::NeedsDestruction)
710 returnType.destruct(result);
711 }
else if (canWrite()) {
712 error = !write(QV4::Value::undefined(),
true, flags);
716 bool isUndefined =
false;
717 QV4::ScopedValue result(scope, evaluate(&isUndefined));
719 error = !write(result, isUndefined, flags);
722 if (!watcher.wasDeleted()) {
725 delayedError()->setErrorLocation(sourceLocation());
726 delayedError()->setErrorObject(m_target.data());
730 if (!delayedError()->addError(ep)) ep->warning(
this->error(engine()));
736 ep->dereferenceScarceResources();
741 QBiPointer<
const QtPrivate::QMetaTypeInterface,
const QMetaObject> targetMeta;
743 const QMetaObject *targetMetaObject() {
748 if (targetMeta.isT2())
749 return targetMeta.asT2();
751 const QMetaObject *metaObject = QQmlPropertyPrivate::rawMetaObjectForType(
752 QMetaType(targetMeta.asT1())).metaObject();
755 targetMeta = metaObject;
765 QQmlPropertyData::WriteFlags flags)
override final
767 const QQmlPropertyData *pd;
768 QQmlPropertyData vtpd;
769 getPropertyData(&pd, &vtpd);
770 if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
771 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
774 QObject *resultObject =
nullptr;
775 QQmlMetaObject resultMo;
776 const auto typeFlags = type.flags();
777 if (!result || ((typeFlags & QMetaType::IsPointer) && !*
static_cast<
void **>(result))) {
779 return pd->writeProperty(targetObject(), &resultObject, flags);
780 }
else if (typeFlags & QMetaType::PointerToQObject) {
781 resultObject = *
static_cast<QObject **>(result);
783 return pd->writeProperty(targetObject(), &resultObject, flags);
784 if (QQmlData *ddata = QQmlData::get(resultObject,
false))
785 resultMo = ddata->propertyCache;
786 if (resultMo.isNull())
787 resultMo = resultObject->metaObject();
788 }
else if (type == QMetaType::fromType<QVariant>()) {
789 const QVariant value = *
static_cast<QVariant *>(result);
790 resultMo = QQmlPropertyPrivate::rawMetaObjectForType(value.metaType());
791 if (resultMo.isNull())
792 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
793 resultObject = *
static_cast<QObject *
const *>(value.constData());
795 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
798 return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
799 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
804 QQmlPropertyData::WriteFlags flags)
override final
806 const QQmlPropertyData *pd;
807 QQmlPropertyData vtpd;
808 getPropertyData(&pd, &vtpd);
809 if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
810 return slowWrite(*pd, vtpd, result, isUndefined, flags);
813 QObject *resultObject =
nullptr;
814 QQmlMetaObject resultMo;
815 if (result.isNull()) {
817 return pd->writeProperty(targetObject(), &resultObject, flags);
818 }
else if (
auto wrapper = result.as<QV4::QObjectWrapper>()) {
819 resultObject = wrapper->object();
821 return pd->writeProperty(targetObject(), &resultObject, flags);
822 if (QQmlData *ddata = QQmlData::get(resultObject,
false))
823 resultMo = ddata->propertyCache;
824 if (resultMo.isNull()) {
825 resultMo = resultObject->metaObject();
827 }
else if (
auto variant = result.as<QV4::VariantObject>()) {
828 const QVariant value = variant->d()->data();
829 resultMo = QQmlPropertyPrivate::rawMetaObjectForType(value.metaType());
830 if (resultMo.isNull())
831 return slowWrite(*pd, vtpd, result, isUndefined, flags);
832 resultObject = *
static_cast<QObject *
const *>(value.constData());
834 return slowWrite(*pd, vtpd, result, isUndefined, flags);
837 return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
838 return slowWrite(*pd, vtpd, result, isUndefined, flags);
845 template<
typename SlowWrite>
846 bool compareAndSet(
const QQmlMetaObject &resultMo, QObject *resultObject,
const QQmlPropertyData *pd,
847 QQmlPropertyData::WriteFlags flags,
const SlowWrite &slowWrite)
849 const QMetaObject *propertyMo = targetMetaObject();
853 if (QQmlMetaObject::canConvert(resultMo, propertyMo)) {
854 return pd->writeProperty(targetObject(), &resultObject, flags);
855 }
else if (!resultObject && QQmlMetaObject::canConvert(propertyMo, resultMo)) {
859 return pd->writeProperty(targetObject(), &resultObject, flags);