Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmlbinding.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmlbinding_p.h"
5
6#include "qqmlcontext.h"
7#include "qqmldata_p.h"
8
9#include <private/qqmldebugserviceinterfaces_p.h>
10#include <private/qqmldebugconnector_p.h>
11
12#include <private/qqmlprofiler_p.h>
13#include <private/qqmlexpression_p.h>
14#include <private/qqmlscriptstring_p.h>
15#include <private/qqmlbuiltinfunctions_p.h>
16#include <private/qqmlvmemetaobject_p.h>
17#include <private/qqmlvaluetypewrapper_p.h>
18#include <private/qv4qmlcontext_p.h>
19#include <private/qv4qobjectwrapper_p.h>
20#include <private/qv4variantobject_p.h>
21#include <private/qv4jscall_p.h>
22#include <private/qjsvalue_p.h>
23
24#include <qtqml_tracepoints_p.h>
25
26#include <QVariant>
27#include <QtCore/qdebug.h>
28#include <QVector>
29
31
32Q_TRACE_POINT(qtqml, QQmlBinding_entry, const QQmlEngine *engine, const QString &function, const QString &fileName, int line, int column)
33Q_TRACE_POINT(qtqml, QQmlBinding_exit)
34
36{
37 QQmlBinding *b = newBinding(property);
38
39 if (ctxt && !ctxt->isValid())
40 return b;
41
42 const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
43 if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid()))
44 return b;
45
47 QV4::Function *runtimeFunction = nullptr;
48
49 QQmlRefPointer<QQmlContextData> ctxtdata = QQmlContextData::get(scriptPrivate->context);
50 QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
51 if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit()) {
52 url = ctxtdata->urlString();
53 if (scriptPrivate->bindingId != QQmlBinding::Invalid)
54 runtimeFunction = ctxtdata->typeCompilationUnit()->runtimeFunctions.at(scriptPrivate->bindingId);
55 }
56
57 b->setNotifyOnValueChanged(true);
58 b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
59 b->setScopeObject(obj ? obj : scriptPrivate->scope);
60
61 QV4::ExecutionEngine *v4 = b->engine()->handle();
62 if (runtimeFunction) {
63 QV4::Scope scope(v4);
64 QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxtdata, b->scopeObject()));
65 b->setupFunction(qmlContext, runtimeFunction);
66 } else {
67 QString code = scriptPrivate->script;
68 b->createQmlBinding(b->context(), b->scopeObject(), code, url, scriptPrivate->lineNumber);
69 }
70
71 return b;
72}
73
75{
76 if (m_sourceLocation)
77 return *m_sourceLocation;
79}
80
82{
83 if (m_sourceLocation)
84 delete m_sourceLocation;
85 m_sourceLocation = new QQmlSourceLocation(location);
86}
87
88
91 const QQmlRefPointer<QQmlContextData> &ctxt, const QString &url, quint16 lineNumber)
92{
93 QQmlBinding *b = newBinding(property);
94
95 b->setNotifyOnValueChanged(true);
96 b->QQmlJavaScriptExpression::setContext(ctxt);
97 b->setScopeObject(obj);
98
99 b->createQmlBinding(ctxt, obj, str, url, lineNumber);
100
101 return b;
102}
103
106 const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope)
107{
108 return create(property ? property->propType() : QMetaType(), function, obj, ctxt, scope);
109}
110
112 const QQmlRefPointer<QQmlContextData> &ctxt,
114{
115 QQmlBinding *b = newBinding(propertyType);
116
117 b->setNotifyOnValueChanged(true);
118 b->QQmlJavaScriptExpression::setContext(ctxt);
119 b->setScopeObject(obj);
120
121 Q_ASSERT(scope);
122 b->setupFunction(scope, function);
123
124 return b;
125}
126
128{
129 delete m_sourceLocation;
130}
131
132void QQmlBinding::update(QQmlPropertyData::WriteFlags flags)
133{
134 if (!enabledFlag() || !hasValidContext())
135 return;
136
137 // Check that the target has not been deleted
139 return;
140
141 // Check for a binding update loop
142 if (Q_UNLIKELY(updatingFlag())) {
143 const QQmlPropertyData *d = nullptr;
145 getPropertyData(&d, &vtd);
146 Q_ASSERT(d);
149 return;
150 }
151 setUpdatingFlag(true);
152
154
156 QV4::Scope scope(qmlEngine->handle());
157
158 if (canUseAccessor())
160
161 Q_TRACE_SCOPE(QQmlBinding, qmlEngine, function() ? function()->name()->toQString() : QString(),
164 doUpdate(watcher, flags, scope);
165
166 if (!watcher.wasDeleted())
167 setUpdatingFlag(false);
168}
169
171{
173 int argc = 0;
174 const QV4::Value *argv = nullptr;
175 const QV4::Value *thisObject = nullptr;
176 QV4::BoundFunction *b = nullptr;
177 if ((b = static_cast<QV4::BoundFunction *>(m_boundFunction.valueRef()))) {
178 QV4::Heap::MemberData *args = b->boundArgs();
179 if (args) {
180 argc = args->values.size;
181 argv = args->values.data();
182 }
183 thisObject = &b->d()->boundThis;
184 }
185 QV4::Scope scope(v4);
186 QV4::JSCallData jsCall(thisObject, argv, argc);
187
188 return QQmlJavaScriptExpression::evaluate(jsCall.callData(scope), isUndefined);
189}
190
191template<int StaticPropType>
193{
194protected:
195 // Returns true if successful, false if an error description was set on expression
196 Q_ALWAYS_INLINE bool write(void *result, QMetaType type, bool isUndefined,
197 QQmlPropertyData::WriteFlags flags) override final
198 {
199 const QQmlPropertyData *pd;
201 getPropertyData(&pd, &vpd);
202 Q_ASSERT(pd);
203
204 if (isUndefined || vpd.isValid())
205 return slowWrite(*pd, vpd, result, type, isUndefined, flags);
206
207 if ((StaticPropType == QMetaType::UnknownType && pd->propType() == type)
208 || StaticPropType == type.id()) {
210 return pd->writeProperty(targetObject(), result, flags);
211 }
212
213 // If the type didn't match, we need to do JavaScript conversion. This should be rare.
214 return write(engine()->handle()->metaTypeToJS(type, result), isUndefined, flags);
215 }
216
217 // Returns true if successful, false if an error description was set on expression
218 Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined,
219 QQmlPropertyData::WriteFlags flags) override final
220 {
222
223 const QQmlPropertyData *pd;
225 getPropertyData(&pd, &vpd);
226 Q_ASSERT(pd);
227
228 int propertyType = StaticPropType; // If the binding is specialized to a type, the if and switch below will be constant-folded.
229 if (propertyType == QMetaType::UnknownType)
230 propertyType = pd->propType().id();
231
232 if (Q_LIKELY(!isUndefined && !vpd.isValid())) {
233 switch (propertyType) {
234 case QMetaType::Bool:
235 if (result.isBoolean())
236 return doStore<bool>(result.booleanValue(), pd, flags);
237 else
238 return doStore<bool>(result.toBoolean(), pd, flags);
239 case QMetaType::Int:
240 if (result.isInteger())
241 return doStore<int>(result.integerValue(), pd, flags);
242 else if (result.isNumber()) {
243 return doStore<int>(result.toInt32(), pd, flags);
244 }
245 break;
246 case QMetaType::Double:
247 if (result.isNumber())
248 return doStore<double>(result.asDouble(), pd, flags);
249 break;
250 case QMetaType::Float:
251 if (result.isNumber())
252 return doStore<float>(result.asDouble(), pd, flags);
253 break;
254 case QMetaType::QString:
255 if (result.isString())
256 return doStore<QString>(result.toQStringNoThrow(), pd, flags);
257 break;
258 default:
260 if (vtw->d()->metaType() == pd->propType()) {
261 return vtw->write(m_target.data(), pd->coreIndex());
262 }
263 }
264 break;
265 }
266 }
267
268 return slowWrite(*pd, vpd, result, isUndefined, flags);
269 }
270
271 template <typename T>
272 Q_ALWAYS_INLINE bool doStore(T value, const QQmlPropertyData *pd, QQmlPropertyData::WriteFlags flags) const
273 {
274 void *o = &value;
275 return pd->writeProperty(targetObject(), o, flags);
276 }
277};
278
279class QQmlTranslationBinding : public GenericBinding<QMetaType::QString>, public QPropertyObserver {
280public:
281 QQmlTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
283 {
284 setCompilationUnit(compilationUnit);
285 setSource(QQmlEnginePrivate::get(compilationUnit->engine)->translationLanguage);
286 }
287
288 virtual QString bindingValue() const = 0;
289
291 { static_cast<QQmlTranslationBinding *>(observer)->update(); }
292
294 QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) override final
295 {
296 if (watcher.wasDeleted())
297 return;
298
299 if (!isAddedToObject() || hasError())
300 return;
301
302 const QString result = this->bindingValue();
303
305
306 const QQmlPropertyData *pd;
308 getPropertyData(&pd, &vpd);
309 Q_ASSERT(pd);
310 if (pd->propType().id() == QMetaType::QString) {
311 doStore(result, pd, flags);
312 } else {
313 QV4::ScopedString value(scope, scope.engine->newString(result));
314 slowWrite(*pd, vpd, value, /*isUndefined*/false, flags);
315 }
316 }
317
318 bool hasDependencies() const override final { return true; }
319};
320
322{
323 const QV4::CompiledData::Binding *m_binding;
324
325public:
327 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
329 : QQmlTranslationBinding(compilationUnit), m_binding(binding)
330 {
331 }
332
333 QString bindingValue() const override
334 {
335 return this->m_compilationUnit->bindingValueAsString(m_binding);
336 }
337
338 QQmlSourceLocation sourceLocation() const override final
339 {
340 return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line(),
341 m_binding->valueLocation.column());
342 }
343};
344
346{
347 QQmlTranslation m_translationData;
348
349 quint16 m_line;
350 quint16 m_column;
351
352public:
354 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
355 const QQmlTranslation &translationData, quint16 line, quint16 column)
356 : QQmlTranslationBinding(compilationUnit),
357 m_translationData(translationData),
358 m_line(line),
359 m_column(column)
360 {
361 }
362
363 virtual QString bindingValue() const override { return m_translationData.translate(); }
364
365 QQmlSourceLocation sourceLocation() const override final
366 {
367 return QQmlSourceLocation(m_compilationUnit->fileName(), m_line, m_column);
368 }
369};
370
372 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
373 const QV4::CompiledData::Binding *binding, QObject *obj,
374 const QQmlRefPointer<QQmlContextData> &ctxt)
375{
377
378 b->setNotifyOnValueChanged(true);
379 b->QQmlJavaScriptExpression::setContext(ctxt);
380 b->setScopeObject(obj);
381#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
382 if (QQmlDebugTranslationService *service
383 = QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
384 service->foundTranslationBinding(
385 TranslationBindingInformation::create(unit, binding, b->scopeObject(), ctxt));
386 }
387#endif
388 return b;
389}
390
392 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit,
393 const QQmlRefPointer<QQmlContextData> &ctxt, const QString &propertyName,
394 const QQmlTranslation &translationData, const QQmlSourceLocation &location, QObject *obj)
395{
397 unit, translationData, location.column, location.line);
398
399 b->setNotifyOnValueChanged(true);
400 b->QQmlJavaScriptExpression::setContext(ctxt);
401 b->setScopeObject(obj);
402
403#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
404 QString originString;
405 if (QQmlDebugTranslationService *service =
406 QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
407 service->foundTranslationBinding({ unit, b->scopeObject(), ctxt,
408
409 propertyName, translationData,
410
411 location.line, location.column });
412 }
413#else
414 Q_UNUSED(propertyName)
415#endif
416 return b;
417}
418
420 const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, const void *result,
421 QMetaType resultType, bool isUndefined, QQmlPropertyData::WriteFlags flags)
422{
423 // The logic in this method is obscure. It follows what the other slowWrite does, minus the type
424 // conversions and the checking for binding functions. If you're writing a C++ type, and
425 // you're passing a binding function wrapped into QJSValue, you probably want it to be assigned.
426
427 if (hasError())
428 return false;
429
431 const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
433
434 if (core.isVarProperty()) {
436 Q_ASSERT(vmemo);
437 vmemo->setVMEProperty(core.coreIndex(),
438 qmlEngine->handle()->metaTypeToJS(resultType, result));
439 } else if (isUndefined && core.isResettable()) {
440 void *args[] = { nullptr };
442 } else if (isUndefined && metaType == QMetaType::fromType<QVariant>()) {
444 m_target.data(), core, valueTypeData, QVariant(), context(), flags);
445 } else if (metaType == QMetaType::fromType<QJSValue>()) {
447 m_target.data(), core, valueTypeData,
448 QVariant(resultType, result), context(), flags);
449 } else if (isUndefined) {
450 const char *name = metaType.name();
451 const QString typeName = name
453 : QStringLiteral("[unknown property type]");
455 QStringLiteral("Unable to assign [undefined] to ") + typeName);
456 return false;
458 m_target.data(), core, valueTypeData, QVariant(resultType, result),
459 context(), flags)) {
460 if (watcher.wasDeleted())
461 return true;
462 handleWriteError(result, resultType, metaType);
463 return false;
464 }
465
466 return true;
467}
468
470 const QQmlPropertyData &valueTypeData,
471 const QV4::Value &result,
472 bool isUndefined, QQmlPropertyData::WriteFlags flags)
473{
474 const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
475 const int type = metaType.id();
476
478
480 bool isVarProperty = core.isVarProperty();
481
482 if (isUndefined) {
483 } else if (core.isQList()) {
484 if (core.propType().flags() & QMetaType::IsQmlList)
486 else
488 } else if (result.isNull() && core.isQObject()) {
489 value = QVariant::fromValue((QObject *)nullptr);
490 } else if (core.propType() == QMetaType::fromType<QList<QUrl>>()) {
491 const QVariant resultVariant
494 ? QQmlPropertyPrivate::urlSequence(resultVariant, context())
495 : QQmlPropertyPrivate::urlSequence(resultVariant));
496 } else if (!isVarProperty && metaType != QMetaType::fromType<QJSValue>()) {
498 }
499
500 if (hasError()) {
501 return false;
502 } else if (isVarProperty) {
504 if (f && f->isBinding()) {
505 // we explicitly disallow this case to avoid confusion. Users can still store one
506 // in an array in a var property if they need to, but the common case is user error.
507 delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
508 return false;
509 }
510
512 Q_ASSERT(vmemo);
513 vmemo->setVMEProperty(core.coreIndex(), result);
514 } else if (isUndefined
515 && (valueTypeData.isValid() ? valueTypeData.isResettable() : core.isResettable())) {
517 m_target.data(), core, valueTypeData, context(), flags);
518 } else if (isUndefined && type == QMetaType::QVariant) {
520 } else if (metaType == QMetaType::fromType<QJSValue>()) {
522 if (f && f->isBinding()) {
523 delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
524 return false;
525 }
527 m_target.data(), core, valueTypeData,
529 context(), flags);
530 } else if (isUndefined) {
531 const char *name = QMetaType(type).name();
532 const QLatin1String typeName(name ? name : "[unknown property type]");
533 delayedError()->setErrorDescription(QLatin1String("Unable to assign [undefined] to ")
534 + typeName);
535 return false;
536 } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) {
537 if (f->isBinding())
538 delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
539 else
540 delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
541 return false;
542 } else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, value, context(), flags)) {
543
544 if (watcher.wasDeleted())
545 return true;
546 handleWriteError(value.constData(), value.metaType(), metaType);
547 return false;
548 }
549
550 return true;
551}
552
553void QQmlBinding::handleWriteError(const void *result, QMetaType resultType, QMetaType metaType)
554{
555 const char *valueType = nullptr;
556 const char *propertyType = nullptr;
557
558 if (resultType.flags() & QMetaType::PointerToQObject) {
559 if (QObject *o = *(QObject *const *)result) {
560 valueType = o->metaObject()->className();
561 QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(metaType);
562 if (!propertyMetaObject.isNull())
563 propertyType = propertyMetaObject.className();
564 }
565 } else if (resultType.isValid()) {
566 if (resultType == QMetaType::fromType<std::nullptr_t>()
567 || resultType == QMetaType::fromType<void *>()) {
568 valueType = "null";
569 } else {
570 valueType = resultType.name();
571 }
572 }
573
574 if (!valueType)
575 valueType = "undefined";
576 if (!propertyType)
577 propertyType = metaType.name();
578 if (!propertyType)
579 propertyType = "[unknown property type]";
580
581 delayedError()->setErrorDescription(QStringLiteral("Unable to assign ")
582 + QString::fromUtf8(valueType)
583 + QStringLiteral(" to ")
584 + QString::fromUtf8(propertyType));
585}
586
588{
592
593 bool isUndefined = false;
594
595 QV4::Scope scope(qmlEngine->handle());
597
599
601}
602
607
609{
610 update();
611}
612
613void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
614{
615 const bool wasEnabled = enabledFlag();
619
620 if (e && !wasEnabled)
621 update(flags);
622}
623
625{
626 return QStringLiteral("function() { [native code] }");
627}
628
629QVector<QQmlProperty> QQmlBinding::dependencies() const
630{
631 QVector<QQmlProperty> dependencies;
632 if (!m_target.data())
633 return dependencies;
634
635 for (QQmlJavaScriptExpressionGuard *guard = activeGuards.first(); guard; guard = activeGuards.next(guard)) {
636 if (guard->signalIndex() == -1) // guard's sender is a QQmlNotifier, not a QObject*.
637 continue;
638
639 QObject *senderObject = guard->senderAsObject();
640 if (!senderObject)
641 continue;
642
643 const QMetaObject *senderMeta = senderObject->metaObject();
644 if (!senderMeta)
645 continue;
646
647 for (int i = 0; i < senderMeta->propertyCount(); i++) {
648 QMetaProperty property = senderMeta->property(i);
649 if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) {
650 dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(property.name())));
651 }
652 }
653 }
654
655 for (auto trigger = qpropertyChangeTriggers; trigger; trigger = trigger->next) {
656 QMetaProperty prop = trigger->property();
657 if (prop.isValid())
658 dependencies.push_back(QQmlProperty(trigger->target, QString::fromUtf8(prop.name())));
659 }
660
661 return dependencies;
662}
663
668
669void QQmlBinding::doUpdate(const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope)
670{
671 auto ep = QQmlEnginePrivate::get(scope.engine);
672 ep->referenceScarceResources();
673
674 bool error = false;
675 auto canWrite = [&]() { return !watcher.wasDeleted() && isAddedToObject() && !hasError(); };
676 const QV4::Function *v4Function = function();
677 if (v4Function && v4Function->kind == QV4::Function::AotCompiled && !hasBoundFunction()) {
678 const auto returnType = v4Function->aotCompiledFunction.types[0];
679 if (returnType == QMetaType::fromType<QVariant>()) {
681 const bool isUndefined = !evaluate(&result, returnType);
682 if (canWrite())
683 error = !write(result.data(), result.metaType(), isUndefined, flags);
684 } else {
685 const auto size = returnType.sizeOf();
686 if (Q_LIKELY(size > 0)) {
687 Q_ALLOCA_VAR(void, result, size);
688 if (returnType.flags() & QMetaType::NeedsConstruction)
689 returnType.construct(result);
690 const bool isUndefined = !evaluate(result, returnType);
691 if (canWrite())
692 error = !write(result, returnType, isUndefined, flags);
693 if (returnType.flags() & QMetaType::NeedsDestruction)
694 returnType.destruct(result);
695 } else if (canWrite()) {
697 }
698 }
699 } else {
700 bool isUndefined = false;
701 QV4::ScopedValue result(scope, evaluate(&isUndefined));
702 if (canWrite())
703 error = !write(result, isUndefined, flags);
704 }
705
706 if (!watcher.wasDeleted()) {
707
708 if (error) {
711 }
712
713 if (hasError()) {
714 if (!delayedError()->addError(ep)) ep->warning(this->error(engine()));
715 } else {
716 clearError();
717 }
718 }
719
720 ep->dereferenceScarceResources();
721}
722
724{
725 QQmlMetaObject targetMetaObject;
726
727public:
729 : targetMetaObject(QQmlPropertyPrivate::rawMetaObjectForType(propertyType))
730 {}
731
732protected:
733 Q_ALWAYS_INLINE bool write(void *result, QMetaType type, bool isUndefined,
734 QQmlPropertyData::WriteFlags flags) override final
735 {
736 const QQmlPropertyData *pd;
737 QQmlPropertyData vtpd;
738 getPropertyData(&pd, &vtpd);
739 if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
740 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
741
742 // Check if the result is a QObject:
743 QObject *resultObject = nullptr;
744 QQmlMetaObject resultMo;
745 const auto typeFlags = type.flags();
746 if (!result || ((typeFlags & QMetaType::IsPointer) && !*static_cast<void **>(result))) {
747 // Special case: we can always write a nullptr. Don't bother checking anything else.
748 return pd->writeProperty(targetObject(), &resultObject, flags);
749 } else if (typeFlags & QMetaType::PointerToQObject) {
750 resultObject = *static_cast<QObject **>(result);
751 if (!resultObject)
752 return pd->writeProperty(targetObject(), &resultObject, flags);
753 if (QQmlData *ddata = QQmlData::get(resultObject, false))
754 resultMo = ddata->propertyCache;
755 if (resultMo.isNull())
756 resultMo = resultObject->metaObject();
757 } else if (type == QMetaType::fromType<QVariant>()) {
758 const QVariant value = *static_cast<QVariant *>(result);
760 if (resultMo.isNull())
761 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
762 resultObject = *static_cast<QObject *const *>(value.constData());
763 } else {
764 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
765 }
766
767 return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
768 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
769 });
770 }
771
772 Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined,
773 QQmlPropertyData::WriteFlags flags) override final
774 {
775 const QQmlPropertyData *pd;
776 QQmlPropertyData vtpd;
777 getPropertyData(&pd, &vtpd);
778 if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
779 return slowWrite(*pd, vtpd, result, isUndefined, flags);
780
781 // Check if the result is a QObject:
782 QObject *resultObject = nullptr;
783 QQmlMetaObject resultMo;
784 if (result.isNull()) {
785 // Special case: we can always write a nullptr. Don't bother checking anything else.
786 return pd->writeProperty(targetObject(), &resultObject, flags);
787 } else if (auto wrapper = result.as<QV4::QObjectWrapper>()) {
788 resultObject = wrapper->object();
789 if (!resultObject)
790 return pd->writeProperty(targetObject(), &resultObject, flags);
791 if (QQmlData *ddata = QQmlData::get(resultObject, false))
792 resultMo = ddata->propertyCache;
793 if (resultMo.isNull()) {
794 resultMo = resultObject->metaObject();
795 }
796 } else if (auto variant = result.as<QV4::VariantObject>()) {
797 const QVariant value = variant->d()->data();
799 if (resultMo.isNull())
800 return slowWrite(*pd, vtpd, result, isUndefined, flags);
801 resultObject = *static_cast<QObject *const *>(value.constData());
802 } else {
803 return slowWrite(*pd, vtpd, result, isUndefined, flags);
804 }
805
806 return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
807 return slowWrite(*pd, vtpd, result, isUndefined, flags);
808 });
809 }
810
811private:
813
814 template<typename SlowWrite>
815 bool compareAndSet(const QQmlMetaObject &resultMo, QObject *resultObject, const QQmlPropertyData *pd,
816 QQmlPropertyData::WriteFlags flags, const SlowWrite &slowWrite) const
817 {
818 if (QQmlMetaObject::canConvert(resultMo, targetMetaObject)) {
819 return pd->writeProperty(targetObject(), &resultObject, flags);
820 } else if (!resultObject && QQmlMetaObject::canConvert(targetMetaObject, resultMo)) {
821 // In the case of a null QObject, we assign the null if there is
822 // any change that the null variant type could be up or down cast to
823 // the property type.
824 return pd->writeProperty(targetObject(), &resultObject, flags);
825 } else {
826 return slowWrite();
827 }
828 }
829};
830
831QQmlBinding *QQmlBinding::newBinding(const QQmlPropertyData *property)
832{
833 return newBinding(property ? property->propType() : QMetaType());
834}
835
836QQmlBinding *QQmlBinding::newBinding(QMetaType propertyType)
837{
838 if (propertyType.flags() & QMetaType::PointerToQObject)
839 return new QObjectPointerBinding(propertyType);
840
841 switch (propertyType.id()) {
842 case QMetaType::Bool:
843 return new GenericBinding<QMetaType::Bool>;
844 case QMetaType::Int:
845 return new GenericBinding<QMetaType::Int>;
846 case QMetaType::Double:
847 return new GenericBinding<QMetaType::Double>;
848 case QMetaType::Float:
849 return new GenericBinding<QMetaType::Float>;
850 case QMetaType::QString:
851 return new GenericBinding<QMetaType::QString>;
852 default:
853 return new GenericBinding<QMetaType::UnknownType>;
854 }
855}
856
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
static N * next(N *v)
bool isEmpty() const
N * first() const
QV4::ExecutionEngine * handle() const
Definition qjsengine.h:298
static QJSValue fromReturnedValue(QV4::ReturnedValue d)
Definition qjsvalue_p.h:197
qsizetype size() const noexcept
Definition qlist.h:397
pointer data()
Definition qlist.h:431
\inmodule QtCore
const char * name() const
Returns this property's name.
bool isValid() const
Returns true if this property is valid (readable); otherwise returns false.
\inmodule QtCore
Definition qmetatype.h:341
static constexpr QMetaType fromType()
Definition qmetatype.h:2642
constexpr TypeFlags flags() const
Definition qmetatype.h:2658
int id(int=0) const
Definition qmetatype.h:475
@ NeedsDestruction
Definition qmetatype.h:401
@ PointerToQObject
Definition qmetatype.h:406
@ NeedsConstruction
Definition qmetatype.h:400
constexpr const char * name() const
Definition qmetatype.h:2680
friend class QVariant
Definition qmetatype.h:796
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
\inmodule QtCore
Definition qobject.h:103
QPropertyBindingPrivate * binding
Definition qproperty.h:252
void setSource(const Property &property)
Definition qproperty.h:267
static void printBindingLoopError(const QQmlProperty &prop)
QTaggedPointer< QObject, TargetTags > m_target
QObject * targetObject() const
void getPropertyData(const QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const
QVector< QQmlProperty > dependencies() const
virtual bool hasDependencies() const
QVariant evaluate()
~QQmlBinding() override
void refresh() override
static QQmlBinding * createTranslationBinding(const QQmlRefPointer< QV4::ExecutableCompilationUnit > &unit, const QV4::CompiledData::Binding *binding, QObject *obj, const QQmlRefPointer< QQmlContextData > &ctxt)
QQmlSourceLocation sourceLocation() const override
void update(QQmlPropertyData::WriteFlags flags=QQmlPropertyData::DontRemoveBinding)
QString expression() const override
void setSourceLocation(const QQmlSourceLocation &location)
void expressionChanged() override
virtual void doUpdate(const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope)
void setEnabled(bool, QQmlPropertyData::WriteFlags flags=QQmlPropertyData::DontRemoveBinding) override
static QQmlBinding * create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *)
bool slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags)
virtual bool write(const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags)=0
bool hasBoundFunction() const
static QQmlRefPointer< QQmlContextData > get(QQmlContext *context)
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
static bool wasDeleted(const QObject *)
Definition qqmldata_p.h:312
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
void setErrorObject(QObject *object)
void setErrorLocation(const QQmlSourceLocation &sourceLocation)
void setErrorDescription(const QString &description)
static QQmlEnginePrivate * get(QQmlEngine *e)
void referenceScarceResources()
void dereferenceScarceResources()
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
void setCompilationUnit(const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit)
QV4::ReturnedValue evaluate(bool *isUndefined)
QForwardFieldList< QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next, GuardTag > activeGuards
QQmlRefPointer< QQmlContextData > context() const
virtual QQmlSourceLocation sourceLocation() const
static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
bool isResettable() const
bool isVarProperty() const
bool writeProperty(QObject *target, void *value, WriteFlags flags) const
QMetaType propType() const
static bool resolveUrlsOnAssignment()
static QQmlMetaObject rawMetaObjectForType(QMetaType metaType)
static QQmlProperty restore(QObject *, const QQmlPropertyData &, const QQmlPropertyData *, const QQmlRefPointer< QQmlContextData > &)
static QList< QUrl > urlSequence(const QVariant &value)
bool writeValueProperty(const QVariant &, QQmlPropertyData::WriteFlags)
static bool resetValueProperty(QObject *, const QQmlPropertyData &, const QQmlPropertyData &valueTypeData, const QQmlRefPointer< QQmlContextData > &, QQmlPropertyData::WriteFlags flags={})
The QQmlProperty class abstracts accessing properties on objects created from QML.
The QQmlScriptString class encapsulates a script and its context.
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
QString translate() const
static QQmlVMEMetaObject * get(QObject *o)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
T * data() const noexcept
Value * valueRef() const
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
Private d
Definition qvariant.h:672
QString str
[2]
Combined button and popup list for selecting options.
quint64 ReturnedValue
Scoped< String > ScopedString
#define Q_UNLIKELY(x)
#define Q_NEVER_INLINE
#define Q_LIKELY(x)
#define Q_ALWAYS_INLINE
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
const char * typeName
GLint location
GLboolean GLboolean GLboolean b
GLuint64 GLenum void * handle
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLfloat GLfloat f
GLenum type
GLbitfield flags
GLuint name
GLenum GLenum GLsizei void GLsizei void * column
GLhandleARB obj
[2]
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
QQmlEngine * qmlEngine(const QObject *obj)
Definition qqml.cpp:80
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define Q_UNUSED(x)
#define Q_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
#define Q_TRACE_POINT(provider, tracepoint,...)
Definition qtrace_p.h:232
unsigned short quint16
Definition qtypes.h:48
#define Q_ALLOCA_VAR(type, name, size)
Definition qv4alloca_p.h:36
const char property[13]
Definition qwizard.cpp:101
QFutureWatcher< int > watcher
QUrl url("example.com")
[constructor-url-reference]
QVariant variant
[1]
view create()
QJSValueList args
QJSEngine engine
[0]
static Q_CORE_EXPORT QMetaMethod signal(const QMetaObject *m, int signal_index)
\inmodule QtCore
static int metacall(QObject *, Call, int, void **)
static constexpr ReturnedValue undefined()
ExecutionContext * rootContext() const
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols=true)
QV4::ReturnedValue metaTypeToJS(QMetaType type, const void *data)
QVarLengthArray< QMetaType, 4 > types
AOTCompiledFunction aotCompiledFunction
static Heap::QmlContext * create(QV4::ExecutionContext *parent, QQmlRefPointer< QQmlContextData > context, QObject *scopeObject)
ExecutionEngine * engine
const T * as() const
Definition qv4value_p.h:132
uchar data[MaxInternalSize]
Definition qvariant.h:112
TriggerList * next
void wrapper()