11#include <private/qqmldebugserviceinterfaces_p.h>
12#include <private/qqmldebugconnector_p.h>
14#include <private/qqmlprofiler_p.h>
15#include <private/qqmlexpression_p.h>
16#include <private/qqmlscriptstring_p.h>
17#include <private/qqmlbuiltinfunctions_p.h>
18#include <private/qqmlvmemetaobject_p.h>
19#include <private/qqmlvaluetypewrapper_p.h>
20#include <private/qv4qmlcontext_p.h>
21#include <private/qv4qobjectwrapper_p.h>
22#include <private/qv4variantobject_p.h>
23#include <private/qv4jscall_p.h>
24#include <private/qjsvalue_p.h>
26#include <qtqml_tracepoints_p.h>
29#include <QtCore/qdebug.h>
34Q_TRACE_POINT(qtqml, QQmlBinding_entry,
const QQmlEngine *engine,
const QString &function,
const QString &fileName,
int line,
int column)
35Q_TRACE_POINT(qtqml, QQmlBinding_exit)
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);
76QQmlSourceLocation QQmlBinding::sourceLocation()
const
79 return *m_sourceLocation;
80 return QQmlJavaScriptExpression::sourceLocation();
83void QQmlBinding::setSourceLocation(
const QQmlSourceLocation &location)
86 delete m_sourceLocation;
87 m_sourceLocation =
new QQmlSourceLocation(location);
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);
106QQmlBinding *QQmlBinding::create(
107 const QQmlPropertyData *property, QV4::Function *function, QObject *obj,
108 const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope)
110 return create(property ? property->propType() : QMetaType(), function, obj, ctxt, scope);
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);
129QQmlBinding::~QQmlBinding()
131 delete m_sourceLocation;
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);
172void QQmlBinding::printBindingLoopError(
const QQmlProperty &prop)
174 qmlWarning(prop.object()) << QString(QLatin1String(
"Binding loop detected for property \"%1\":\n%2"))
175 .arg(prop.name(), expressionIdentifier());
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);
199template<
int StaticPropType>
205 QQmlPropertyData::WriteFlags flags)
override final
207 const QQmlPropertyData *pd;
208 QQmlPropertyData vpd;
209 getPropertyData(&pd, &vpd);
212 if (isUndefined || vpd.isValid())
213 return slowWrite(*pd, vpd, result, type, isUndefined, flags);
215 if ((StaticPropType == QMetaType::UnknownType && pd->propType() == type)
216 || StaticPropType == type.id()) {
217 Q_ASSERT(targetObject());
218 return pd->writeProperty(targetObject(), result, flags);
222 QV4::Scope scope(engine()->handle());
223 QV4::ScopedValue value(scope, engine()->handle()->metaTypeToJS(type, result));
224 return write(value, isUndefined, flags);
229 QQmlPropertyData::WriteFlags flags)
override final
231 Q_ASSERT(targetObject());
233 const QQmlPropertyData *pd;
234 QQmlPropertyData vpd;
235 getPropertyData(&pd, &vpd);
238 int propertyType = StaticPropType;
239 if (propertyType == QMetaType::UnknownType)
240 propertyType = pd->propType().id();
242 if (Q_LIKELY(!isUndefined && !vpd.isValid())) {
243 switch (propertyType) {
244 case QMetaType::Bool:
245 if (result.isBoolean())
246 return doStore<
bool>(result.booleanValue(), pd, flags);
248 return doStore<
bool>(result.toBoolean(), pd, flags);
250 if (result.isInteger())
251 return doStore<
int>(result.integerValue(), pd, flags);
252 else if (result.isNumber()) {
253 return doStore<
int>(result.toInt32(), pd, flags);
256 case QMetaType::Double:
257 if (result.isNumber())
258 return doStore<
double>(result.asDouble(), pd, flags);
260 case QMetaType::Float:
261 if (result.isNumber())
262 return doStore<
float>(result.asDouble(), pd, flags);
264 case QMetaType::QString:
265 if (result.isString())
266 return doStore<QString>(result.toQStringNoThrow(), pd, flags);
269 if (
const QV4::QQmlValueTypeWrapper *vtw = result.as<
const QV4::QQmlValueTypeWrapper>()) {
270 if (vtw->d()->metaType() == pd->propType()) {
271 return vtw->write(m_target.data(), pd->coreIndex());
278 return slowWrite(*pd, vpd, result, isUndefined, flags);
281 template <
typename T>
285 return pd->writeProperty(targetObject(), o, flags);
294 setCompilationUnit(compilationUnit);
295 setSource(QQmlEnginePrivate::get(compilationUnit->engine)->translationLanguage);
304 QQmlPropertyData::WriteFlags flags, QV4::Scope &scope)
override final
306 if (watcher.wasDeleted())
309 if (!isAddedToObject() || hasError())
312 const QString result =
this->bindingValue();
314 Q_ASSERT(targetObject());
316 const QQmlPropertyData *pd;
317 QQmlPropertyData vpd;
318 getPropertyData(&pd, &vpd);
320 if (pd->propType().id() == QMetaType::QString) {
321 doStore(result, pd, flags);
323 QV4::ScopedString value(scope, scope.engine->newString(result));
324 slowWrite(*pd, vpd, value,
false, flags);
337 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
345 return this->m_compilationUnit->bindingValueAsString(m_binding);
350 return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line(),
351 m_binding->valueLocation.column());
357 QQmlTranslation m_translationData;
364 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
365 const QQmlTranslation &translationData, quint16 line, quint16 column)
377 return QQmlSourceLocation(m_compilationUnit->fileName(), m_line, m_column);
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 QString originString;
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)
429bool QQmlBinding::slowWrite(
430 const QQmlPropertyData &core,
const QQmlPropertyData &valueTypeData,
const void *result,
431 QMetaType resultType,
bool isUndefined, QQmlPropertyData::WriteFlags flags)
440 QQmlEngine *qmlEngine = engine();
441 const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
442 QQmlJavaScriptExpression::DeleteWatcher watcher(
this);
444 if (core.isVarProperty()) {
445 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data());
447 QV4::Scope scope(qmlEngine->handle());
448 QV4::ScopedValue value(scope, qmlEngine->handle()->metaTypeToJS(resultType, result));
449 vmemo->setVMEProperty(core.coreIndex(),
451 }
else if (isUndefined && core.isResettable()) {
452 void *args[] = {
nullptr };
453 QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex(), args);
454 }
else if (isUndefined && metaType == QMetaType::fromType<QVariant>()) {
455 QQmlPropertyPrivate::writeValueProperty(
456 m_target.data(), core, valueTypeData, QVariant(), context(), flags);
457 }
else if (metaType == QMetaType::fromType<QJSValue>()) {
458 QQmlPropertyPrivate::writeValueProperty(
459 m_target.data(), core, valueTypeData,
460 QVariant(resultType, result), context(), flags);
461 }
else if (isUndefined) {
462 const char *name = metaType.name();
463 const QString typeName = name
464 ? QString::fromUtf8(name)
465 : QStringLiteral(
"[unknown property type]");
466 delayedError()->setErrorDescription(
467 QStringLiteral(
"Unable to assign [undefined] to ") + typeName);
469 }
else if (!QQmlPropertyPrivate::writeValueProperty(
470 m_target.data(), core, valueTypeData, QVariant(resultType, result),
472 if (watcher.wasDeleted())
474 handleWriteError(result, resultType, metaType);
481Q_NEVER_INLINE
bool QQmlBinding::slowWrite(
const QQmlPropertyData &core,
482 const QQmlPropertyData &valueTypeData,
483 const QV4::Value &result,
484 bool isUndefined, QQmlPropertyData::WriteFlags flags)
486 const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
487 const int type = metaType.id();
489 QQmlJavaScriptExpression::DeleteWatcher watcher(
this);
492 bool isVarProperty = core.isVarProperty();
495 }
else if (core.isQList()) {
496 if (core.propType().flags() & QMetaType::IsQmlList)
497 value = QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QObject*>>());
499 value = QV4::ExecutionEngine::toVariant(result, core.propType());
500 }
else if (result.isNull() && core.isQObject()) {
501 value = QVariant::fromValue((QObject *)
nullptr);
502 }
else if (core.propType() == QMetaType::fromType<QList<QUrl>>()) {
503 const QVariant resultVariant
504 = QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QUrl>>());
505 value = QVariant::fromValue(QQmlPropertyPrivate::resolveUrlsOnAssignment()
506 ? QQmlPropertyPrivate::urlSequence(resultVariant, context())
507 : QQmlPropertyPrivate::urlSequence(resultVariant));
508 }
else if (!isVarProperty && metaType != QMetaType::fromType<QJSValue>()) {
509 value = QV4::ExecutionEngine::toVariant(result, metaType);
514 }
else if (isVarProperty) {
515 const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
516 if (f && f->isBinding()) {
519 delayedError()->setErrorDescription(QLatin1String(
"Invalid use of Qt.binding() in a binding declaration."));
523 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data());
525 vmemo->setVMEProperty(core.coreIndex(), result);
526 }
else if (isUndefined
527 && (valueTypeData.isValid() ? valueTypeData.isResettable() : core.isResettable())) {
528 QQmlPropertyPrivate::resetValueProperty(
529 m_target.data(), core, valueTypeData, context(), flags);
530 }
else if (isUndefined && type == QMetaType::QVariant) {
531 QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant(), context(), flags);
532 }
else if (metaType == QMetaType::fromType<QJSValue>()) {
533 const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
534 if (f && f->isBinding()) {
535 delayedError()->setErrorDescription(QLatin1String(
"Invalid use of Qt.binding() in a binding declaration."));
538 QQmlPropertyPrivate::writeValueProperty(
539 m_target.data(), core, valueTypeData,
540 QVariant::fromValue(QJSValuePrivate::fromReturnedValue(result.asReturnedValue())),
542 }
else if (isUndefined) {
543 const char *name = QMetaType(type).name();
544 const QLatin1String typeName(name ? name :
"[unknown property type]");
545 delayedError()->setErrorDescription(QLatin1String(
"Unable to assign [undefined] to ")
548 }
else if (
const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
549 f && !f->as<QV4::QQmlTypeWrapper>()) {
551 delayedError()->setErrorDescription(QLatin1String(
"Invalid use of Qt.binding() in a binding declaration."));
553 delayedError()->setErrorDescription(QLatin1String(
"Unable to assign a function to a property of any type other than var."));
555 }
else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, value, context(), flags)) {
557 if (watcher.wasDeleted())
559 handleWriteError(value.constData(), value.metaType(), metaType);
566void QQmlBinding::handleWriteError(
const void *result, QMetaType resultType, QMetaType metaType)
568 const char *valueType =
nullptr;
569 const char *propertyType =
nullptr;
571 if (resultType.flags() & QMetaType::PointerToQObject) {
572 if (QObject *o = *(QObject *
const *)result) {
573 valueType = o->metaObject()->className();
574 QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(metaType);
575 if (!propertyMetaObject.isNull())
576 propertyType = propertyMetaObject.className();
578 }
else if (resultType.isValid()) {
579 if (resultType == QMetaType::fromType<std::nullptr_t>()
580 || resultType == QMetaType::fromType<
void *>()) {
583 valueType = resultType.name();
588 valueType =
"undefined";
590 propertyType = metaType.name();
592 propertyType =
"[unknown property type]";
594 delayedError()->setErrorDescription(QStringLiteral(
"Unable to assign ")
595 + QString::fromUtf8(valueType)
596 + QStringLiteral(
" to ")
597 + QString::fromUtf8(propertyType));
600QVariant QQmlBinding::evaluate()
602 QQmlEngine *qmlEngine = engine();
603 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine);
604 ep->referenceScarceResources();
606 bool isUndefined =
false;
608 QV4::Scope scope(qmlEngine->handle());
609 QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined));
611 ep->dereferenceScarceResources();
613 return QV4::ExecutionEngine::toVariant(result, QMetaType::fromType<QList<QObject*> >());
616void QQmlBinding::expressionChanged()
621void QQmlBinding::refresh()
626void QQmlBinding::setEnabled(
bool e, QQmlPropertyData::WriteFlags flags)
628 const bool wasEnabled = enabledFlag();
630 setNotifyOnValueChanged(e);
631 updateCanUseAccessor();
633 if (e && !wasEnabled)
637QString QQmlBinding::expression()
const
639 return QStringLiteral(
"function() { [native code] }");
642QList<QQmlProperty> QQmlBinding::dependencies()
const
644 QList<QQmlProperty> dependencies;
645 if (!m_target.data())
648 for (QQmlJavaScriptExpressionGuard *guard = activeGuards.first(); guard; guard = activeGuards.next(guard)) {
649 if (guard->signalIndex() == -1)
652 QObject *senderObject = guard->senderAsObject();
656 const QMetaObject *senderMeta = senderObject->metaObject();
660 for (
int i = 0; i < senderMeta->propertyCount(); i++) {
661 QMetaProperty property = senderMeta->property(i);
662 if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) {
663 dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(property.name())));
668 for (
auto trigger = qpropertyChangeTriggers; trigger; trigger = trigger->next) {
669 QMetaProperty prop = trigger->property();
671 dependencies.push_back(QQmlProperty(trigger->target, QString::fromUtf8(prop.name())));
677bool QQmlBinding::hasDependencies()
const
679 return !activeGuards.isEmpty() || qpropertyChangeTriggers;
682void QQmlBinding::doUpdate(
const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope)
684 auto ep = QQmlEnginePrivate::get(scope.engine);
685 ep->referenceScarceResources();
688 auto canWrite = [&]() {
return !watcher.wasDeleted() && isAddedToObject() && !hasError(); };
689 const QV4::Function *v4Function = function();
690 if (v4Function && v4Function->kind == QV4::Function::AotCompiled && !hasBoundFunction()) {
691 const auto returnType = v4Function->aotCompiledFunction.types[0];
692 if (returnType == QMetaType::fromType<QVariant>()) {
694 const bool isUndefined = !evaluate(&result, returnType);
696 error = !write(result.data(), result.metaType(), isUndefined, flags);
698 const auto size = returnType.sizeOf();
699 if (Q_LIKELY(size > 0)) {
700 Q_ALLOCA_VAR(
void, result, size);
701 if (returnType.flags() & QMetaType::NeedsConstruction)
702 returnType.construct(result);
703 const bool isUndefined = !evaluate(result, returnType);
705 error = !write(result, returnType, isUndefined, flags);
706 if (returnType.flags() & QMetaType::NeedsDestruction)
707 returnType.destruct(result);
708 }
else if (canWrite()) {
709 error = !write(QV4::Value::undefined(),
true, flags);
713 bool isUndefined =
false;
714 QV4::ScopedValue result(scope, evaluate(&isUndefined));
716 error = !write(result, isUndefined, flags);
719 if (!watcher.wasDeleted()) {
722 delayedError()->setErrorLocation(sourceLocation());
723 delayedError()->setErrorObject(m_target.data());
727 if (!delayedError()->addError(ep)) ep->warning(
this->error(engine()));
733 ep->dereferenceScarceResources();
738 QBiPointer<
const QtPrivate::QMetaTypeInterface,
const QMetaObject> targetMeta;
740 const QMetaObject *targetMetaObject() {
745 if (targetMeta.isT2())
746 return targetMeta.asT2();
748 const QMetaObject *metaObject = QQmlPropertyPrivate::rawMetaObjectForType(
749 QMetaType(targetMeta.asT1())).metaObject();
752 targetMeta = metaObject;
762 QQmlPropertyData::WriteFlags flags)
override final
764 const QQmlPropertyData *pd;
765 QQmlPropertyData vtpd;
766 getPropertyData(&pd, &vtpd);
767 if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
768 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
771 QObject *resultObject =
nullptr;
772 QQmlMetaObject resultMo;
773 const auto typeFlags = type.flags();
774 if (!result || ((typeFlags & QMetaType::IsPointer) && !*
static_cast<
void **>(result))) {
776 return pd->writeProperty(targetObject(), &resultObject, flags);
777 }
else if (typeFlags & QMetaType::PointerToQObject) {
778 resultObject = *
static_cast<QObject **>(result);
780 return pd->writeProperty(targetObject(), &resultObject, flags);
781 if (QQmlData *ddata = QQmlData::get(resultObject,
false))
782 resultMo = ddata->propertyCache;
783 if (resultMo.isNull())
784 resultMo = resultObject->metaObject();
785 }
else if (type == QMetaType::fromType<QVariant>()) {
786 const QVariant value = *
static_cast<QVariant *>(result);
787 resultMo = QQmlPropertyPrivate::rawMetaObjectForType(value.metaType());
788 if (resultMo.isNull())
789 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
790 resultObject = *
static_cast<QObject *
const *>(value.constData());
792 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
795 return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
796 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
801 QQmlPropertyData::WriteFlags flags)
override final
803 const QQmlPropertyData *pd;
804 QQmlPropertyData vtpd;
805 getPropertyData(&pd, &vtpd);
806 if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
807 return slowWrite(*pd, vtpd, result, isUndefined, flags);
810 QObject *resultObject =
nullptr;
811 QQmlMetaObject resultMo;
812 if (result.isNull()) {
814 return pd->writeProperty(targetObject(), &resultObject, flags);
815 }
else if (
auto wrapper = result.as<QV4::QObjectWrapper>()) {
816 resultObject = wrapper->object();
818 return pd->writeProperty(targetObject(), &resultObject, flags);
819 if (QQmlData *ddata = QQmlData::get(resultObject,
false))
820 resultMo = ddata->propertyCache;
821 if (resultMo.isNull()) {
822 resultMo = resultObject->metaObject();
824 }
else if (
auto variant = result.as<QV4::VariantObject>()) {
825 const QVariant value = variant->d()->data();
826 resultMo = QQmlPropertyPrivate::rawMetaObjectForType(value.metaType());
827 if (resultMo.isNull())
828 return slowWrite(*pd, vtpd, result, isUndefined, flags);
829 resultObject = *
static_cast<QObject *
const *>(value.constData());
831 return slowWrite(*pd, vtpd, result, isUndefined, flags);
834 return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
835 return slowWrite(*pd, vtpd, result, isUndefined, flags);
842 template<
typename SlowWrite>
843 bool compareAndSet(
const QQmlMetaObject &resultMo, QObject *resultObject,
const QQmlPropertyData *pd,
844 QQmlPropertyData::WriteFlags flags,
const SlowWrite &slowWrite)
846 const QMetaObject *propertyMo = targetMetaObject();
850 if (QQmlMetaObject::canConvert(resultMo, propertyMo)) {
851 return pd->writeProperty(targetObject(), &resultObject, flags);
852 }
else if (!resultObject && QQmlMetaObject::canConvert(propertyMo, resultMo)) {
856 return pd->writeProperty(targetObject(), &resultObject, flags);
863QQmlBinding *QQmlBinding::newBinding(
const QQmlPropertyData *property)
865 return newBinding(property ? property->propType() : QMetaType());
868QQmlBinding *QQmlBinding::newBinding(QMetaType propertyType)
870 if (propertyType.flags() & QMetaType::PointerToQObject)
871 return new QObjectPointerBinding(propertyType);
873 switch (propertyType.id()) {
874 case QMetaType::Bool:
875 return new GenericBinding<QMetaType::Bool>;
877 return new GenericBinding<QMetaType::Int>;
878 case QMetaType::Double:
879 return new GenericBinding<QMetaType::Double>;
880 case QMetaType::Float:
881 return new GenericBinding<QMetaType::Float>;
882 case QMetaType::QString:
883 return new GenericBinding<QMetaType::QString>;
885 return new GenericBinding<QMetaType::UnknownType>;
Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags) override final
Q_ALWAYS_INLINE bool write(void *result, QMetaType type, bool isUndefined, QQmlPropertyData::WriteFlags flags) override final
Q_ALWAYS_INLINE bool doStore(T value, const QQmlPropertyData *pd, QQmlPropertyData::WriteFlags flags) const
QObjectPointerBinding(QMetaType propertyType)
Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags) override final
Q_ALWAYS_INLINE bool write(void *result, QMetaType type, bool isUndefined, QQmlPropertyData::WriteFlags flags) override final
QString bindingValue() const override
QQmlSourceLocation sourceLocation() const override final
QQmlTranslationBindingFromBinding(const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit, const QV4::CompiledData::Binding *binding)
QQmlSourceLocation sourceLocation() const override final
QQmlTranslationBindingFromTranslationInfo(const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit, const QQmlTranslation &translationData, quint16 line, quint16 column)
virtual QString bindingValue() const override
QQmlTranslationBinding(const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit)
void doUpdate(const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) override final
static void onLanguageChange(QPropertyObserver *observer, QUntypedPropertyData *)
virtual QString bindingValue() const =0
bool hasDependencies() const override final
Combined button and popup list for selecting options.