Qt 6.x
The Qt SDK
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
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
107{
108 return create(property ? property->propType() : QMetaType(), function, obj, ctxt, scope);
109}
110
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:
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:
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:
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
373 const QV4::CompiledData::Binding *binding, QObject *obj,
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
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#endif
414 return b;
415}
416
418 const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, const void *result,
419 QMetaType resultType, bool isUndefined, QQmlPropertyData::WriteFlags flags)
420{
421 // The logic in this method is obscure. It follows what the other slowWrite does, minus the type
422 // conversions and the checking for binding functions. If you're writing a C++ type, and
423 // you're passing a binding function wrapped into QJSValue, you probably want it to be assigned.
424
425 if (hasError())
426 return false;
427
429 const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
431
432 if (core.isVarProperty()) {
434 Q_ASSERT(vmemo);
435 vmemo->setVMEProperty(core.coreIndex(),
436 qmlEngine->handle()->metaTypeToJS(resultType, result));
437 } else if (isUndefined && core.isResettable()) {
438 void *args[] = { nullptr };
440 } else if (isUndefined && metaType == QMetaType::fromType<QVariant>()) {
442 m_target.data(), core, valueTypeData, QVariant(), context(), flags);
443 } else if (metaType == QMetaType::fromType<QJSValue>()) {
445 m_target.data(), core, valueTypeData,
446 QVariant(resultType, result), context(), flags);
447 } else if (isUndefined) {
448 const char *name = metaType.name();
449 const QString typeName = name
451 : QStringLiteral("[unknown property type]");
453 QStringLiteral("Unable to assign [undefined] to ") + typeName);
454 return false;
456 m_target.data(), core, valueTypeData, QVariant(resultType, result),
457 context(), flags)) {
458 if (watcher.wasDeleted())
459 return true;
460 handleWriteError(result, resultType, metaType);
461 return false;
462 }
463
464 return true;
465}
466
468 const QQmlPropertyData &valueTypeData,
469 const QV4::Value &result,
470 bool isUndefined, QQmlPropertyData::WriteFlags flags)
471{
472 const QMetaType metaType = valueTypeData.isValid() ? valueTypeData.propType() : core.propType();
473 const int type = metaType.id();
474
476
478 bool isVarProperty = core.isVarProperty();
479
480 if (isUndefined) {
481 } else if (core.isQList()) {
482 if (core.propType().flags() & QMetaType::IsQmlList)
484 else
486 } else if (result.isNull() && core.isQObject()) {
487 value = QVariant::fromValue((QObject *)nullptr);
488 } else if (core.propType() == QMetaType::fromType<QList<QUrl>>()) {
489 const QVariant resultVariant
492 ? QQmlPropertyPrivate::urlSequence(resultVariant, context())
493 : QQmlPropertyPrivate::urlSequence(resultVariant));
494 } else if (!isVarProperty && metaType != QMetaType::fromType<QJSValue>()) {
496 }
497
498 if (hasError()) {
499 return false;
500 } else if (isVarProperty) {
502 if (f && f->isBinding()) {
503 // we explicitly disallow this case to avoid confusion. Users can still store one
504 // in an array in a var property if they need to, but the common case is user error.
505 delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
506 return false;
507 }
508
510 Q_ASSERT(vmemo);
511 vmemo->setVMEProperty(core.coreIndex(), result);
512 } else if (isUndefined
513 && (valueTypeData.isValid() ? valueTypeData.isResettable() : core.isResettable())) {
515 m_target.data(), core, valueTypeData, context(), flags);
516 } else if (isUndefined && type == QMetaType::QVariant) {
518 } else if (metaType == QMetaType::fromType<QJSValue>()) {
520 if (f && f->isBinding()) {
521 delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
522 return false;
523 }
525 m_target.data(), core, valueTypeData,
527 context(), flags);
528 } else if (isUndefined) {
529 const char *name = QMetaType(type).name();
530 const QLatin1String typeName(name ? name : "[unknown property type]");
531 delayedError()->setErrorDescription(QLatin1String("Unable to assign [undefined] to ")
532 + typeName);
533 return false;
534 } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) {
535 if (f->isBinding())
536 delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
537 else
538 delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
539 return false;
540 } else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, value, context(), flags)) {
541
542 if (watcher.wasDeleted())
543 return true;
544 handleWriteError(value.constData(), value.metaType(), metaType);
545 return false;
546 }
547
548 return true;
549}
550
551void QQmlBinding::handleWriteError(const void *result, QMetaType resultType, QMetaType metaType)
552{
553 const char *valueType = nullptr;
554 const char *propertyType = nullptr;
555
556 if (resultType.flags() & QMetaType::PointerToQObject) {
557 if (QObject *o = *(QObject *const *)result) {
558 valueType = o->metaObject()->className();
559 QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(metaType);
560 if (!propertyMetaObject.isNull())
561 propertyType = propertyMetaObject.className();
562 }
563 } else if (resultType.isValid()) {
564 if (resultType == QMetaType::fromType<std::nullptr_t>()
565 || resultType == QMetaType::fromType<void *>()) {
566 valueType = "null";
567 } else {
568 valueType = resultType.name();
569 }
570 }
571
572 if (!valueType)
573 valueType = "undefined";
574 if (!propertyType)
575 propertyType = metaType.name();
576 if (!propertyType)
577 propertyType = "[unknown property type]";
578
579 delayedError()->setErrorDescription(QStringLiteral("Unable to assign ")
580 + QString::fromUtf8(valueType)
581 + QStringLiteral(" to ")
582 + QString::fromUtf8(propertyType));
583}
584
586{
590
591 bool isUndefined = false;
592
593 QV4::Scope scope(qmlEngine->handle());
595
597
599}
600
602{
603 update();
604}
605
607{
608 update();
609}
610
611void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags)
612{
613 const bool wasEnabled = enabledFlag();
617
618 if (e && !wasEnabled)
619 update(flags);
620}
621
623{
624 return QStringLiteral("function() { [native code] }");
625}
626
628{
630 if (!m_target.data())
631 return dependencies;
632
633 for (QQmlJavaScriptExpressionGuard *guard = activeGuards.first(); guard; guard = activeGuards.next(guard)) {
634 if (guard->signalIndex() == -1) // guard's sender is a QQmlNotifier, not a QObject*.
635 continue;
636
637 QObject *senderObject = guard->senderAsObject();
638 if (!senderObject)
639 continue;
640
641 const QMetaObject *senderMeta = senderObject->metaObject();
642 if (!senderMeta)
643 continue;
644
645 for (int i = 0; i < senderMeta->propertyCount(); i++) {
646 QMetaProperty property = senderMeta->property(i);
647 if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) {
648 dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(property.name())));
649 }
650 }
651 }
652
653 for (auto trigger = qpropertyChangeTriggers; trigger; trigger = trigger->next) {
654 QMetaProperty prop = trigger->property();
655 if (prop.isValid())
656 dependencies.push_back(QQmlProperty(trigger->target, QString::fromUtf8(prop.name())));
657 }
658
659 return dependencies;
660}
661
663{
665}
666
667void QQmlBinding::doUpdate(const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope)
668{
669 auto ep = QQmlEnginePrivate::get(scope.engine);
670 ep->referenceScarceResources();
671
672 bool error = false;
673 auto canWrite = [&]() { return !watcher.wasDeleted() && isAddedToObject() && !hasError(); };
674 const QV4::Function *v4Function = function();
675 if (v4Function && v4Function->kind == QV4::Function::AotCompiled && !hasBoundFunction()) {
676 const auto returnType = v4Function->aotCompiledFunction->returnType;
677 if (returnType == QMetaType::fromType<QVariant>()) {
678 // It expects uninitialized memory
680 const bool isUndefined = !evaluate(result, returnType);
681 if (canWrite())
682 error = !write(result->data(), result->metaType(), isUndefined, flags);
683 result->~QVariant();
684 } else {
685 const auto size = returnType.sizeOf();
686 if (Q_LIKELY(size > 0)) {
687 Q_ALLOCA_VAR(void, result, size);
688 const bool isUndefined = !evaluate(result, returnType);
689 if (canWrite())
690 error = !write(result, returnType, isUndefined, flags);
691 returnType.destruct(result);
692 } else if (canWrite()) {
694 }
695 }
696 } else {
697 bool isUndefined = false;
698 QV4::ScopedValue result(scope, evaluate(&isUndefined));
699 if (canWrite())
700 error = !write(result, isUndefined, flags);
701 }
702
703 if (!watcher.wasDeleted()) {
704
705 if (error) {
708 }
709
710 if (hasError()) {
711 if (!delayedError()->addError(ep)) ep->warning(this->error(engine()));
712 } else {
713 clearError();
714 }
715 }
716
717 ep->dereferenceScarceResources();
718}
719
721{
722 QQmlMetaObject targetMetaObject;
723
724public:
726 : targetMetaObject(QQmlPropertyPrivate::rawMetaObjectForType(propertyType))
727 {}
728
729protected:
730 Q_ALWAYS_INLINE bool write(void *result, QMetaType type, bool isUndefined,
731 QQmlPropertyData::WriteFlags flags) override final
732 {
733 const QQmlPropertyData *pd;
734 QQmlPropertyData vtpd;
735 getPropertyData(&pd, &vtpd);
736 if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
737 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
738
739 // Check if the result is a QObject:
740 QObject *resultObject = nullptr;
741 QQmlMetaObject resultMo;
742 const auto typeFlags = type.flags();
743 if (!result || ((typeFlags & QMetaType::IsPointer) && !*static_cast<void **>(result))) {
744 // Special case: we can always write a nullptr. Don't bother checking anything else.
745 return pd->writeProperty(targetObject(), &resultObject, flags);
746 } else if (typeFlags & QMetaType::PointerToQObject) {
747 resultObject = *static_cast<QObject **>(result);
748 if (!resultObject)
749 return pd->writeProperty(targetObject(), &resultObject, flags);
750 if (QQmlData *ddata = QQmlData::get(resultObject, false))
751 resultMo = ddata->propertyCache;
752 if (resultMo.isNull())
753 resultMo = resultObject->metaObject();
754 } else if (type == QMetaType::fromType<QVariant>()) {
755 const QVariant value = *static_cast<QVariant *>(result);
757 if (resultMo.isNull())
758 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
759 resultObject = *static_cast<QObject *const *>(value.constData());
760 } else {
761 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
762 }
763
764 return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
765 return slowWrite(*pd, vtpd, result, type, isUndefined, flags);
766 });
767 }
768
769 Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined,
770 QQmlPropertyData::WriteFlags flags) override final
771 {
772 const QQmlPropertyData *pd;
773 QQmlPropertyData vtpd;
774 getPropertyData(&pd, &vtpd);
775 if (Q_UNLIKELY(isUndefined || vtpd.isValid()))
776 return slowWrite(*pd, vtpd, result, isUndefined, flags);
777
778 // Check if the result is a QObject:
779 QObject *resultObject = nullptr;
780 QQmlMetaObject resultMo;
781 if (result.isNull()) {
782 // Special case: we can always write a nullptr. Don't bother checking anything else.
783 return pd->writeProperty(targetObject(), &resultObject, flags);
784 } else if (auto wrapper = result.as<QV4::QObjectWrapper>()) {
785 resultObject = wrapper->object();
786 if (!resultObject)
787 return pd->writeProperty(targetObject(), &resultObject, flags);
788 if (QQmlData *ddata = QQmlData::get(resultObject, false))
789 resultMo = ddata->propertyCache;
790 if (resultMo.isNull()) {
791 resultMo = resultObject->metaObject();
792 }
793 } else if (auto variant = result.as<QV4::VariantObject>()) {
794 const QVariant value = variant->d()->data();
796 if (resultMo.isNull())
797 return slowWrite(*pd, vtpd, result, isUndefined, flags);
798 resultObject = *static_cast<QObject *const *>(value.constData());
799 } else {
800 return slowWrite(*pd, vtpd, result, isUndefined, flags);
801 }
802
803 return compareAndSet(resultMo, resultObject, pd, flags, [&]() {
804 return slowWrite(*pd, vtpd, result, isUndefined, flags);
805 });
806 }
807
808private:
810
811 template<typename SlowWrite>
812 bool compareAndSet(const QQmlMetaObject &resultMo, QObject *resultObject, const QQmlPropertyData *pd,
813 QQmlPropertyData::WriteFlags flags, const SlowWrite &slowWrite) const
814 {
815 if (QQmlMetaObject::canConvert(resultMo, targetMetaObject)) {
816 return pd->writeProperty(targetObject(), &resultObject, flags);
817 } else if (!resultObject && QQmlMetaObject::canConvert(targetMetaObject, resultMo)) {
818 // In the case of a null QObject, we assign the null if there is
819 // any change that the null variant type could be up or down cast to
820 // the property type.
821 return pd->writeProperty(targetObject(), &resultObject, flags);
822 } else {
823 return slowWrite();
824 }
825 }
826};
827
828QQmlBinding *QQmlBinding::newBinding(const QQmlPropertyData *property)
829{
830 return newBinding(property ? property->propType() : QMetaType());
831}
832
833QQmlBinding *QQmlBinding::newBinding(QMetaType propertyType)
834{
835 if (propertyType.flags() & QMetaType::PointerToQObject)
836 return new QObjectPointerBinding(propertyType);
837
838 switch (propertyType.id()) {
839 case QMetaType::Bool:
841 case QMetaType::Int:
843 case QMetaType::Double:
845 case QMetaType::Float:
847 case QMetaType::QString:
849 default:
851 }
852}
853
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:292
static QJSValue fromReturnedValue(QV4::ReturnedValue d)
Definition qjsvalue_p.h:189
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
pointer data()
Definition qlist.h:414
int methodIndex() const
\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:320
static constexpr QMetaType fromType()
Definition qmetatype.h:2612
constexpr TypeFlags flags() const
Definition qmetatype.h:2628
bool isValid() const
int id(int=0) const
Definition qmetatype.h:454
@ PointerToQObject
Definition qmetatype.h:385
constexpr const char * name() const
Definition qmetatype.h:2650
friend class QVariant
Definition qmetatype.h:775
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:90
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
bool isValid() const
Returns whether the context is valid.
QQmlEngine * engine() const
Return the context's QQmlEngine, or \nullptr if the context has no QQmlEngine or the QQmlEngine was d...
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
bool isNull() const
const char * className() 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)
void setVMEProperty(int index, const QV4::Value &v)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
T * data() const noexcept
Value * valueRef() const
\inmodule QtCore
Definition qvariant.h:64
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:531
Private d
Definition qvariant.h:665
QString str
[2]
double e
Combined button and popup list for selecting options.
quint64 ReturnedValue
#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:76
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:71
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#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:43
#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
int propertyCount() const
Returns the number of properties in this class, including the number of properties provided by each b...
QMetaProperty property(int index) const
Returns the meta-data for the property with the given index.
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)
const QQmlPrivate::AOTCompiledFunction * aotCompiledFunction
CallData * callData(const Scope &scope, const FunctionObject *f=nullptr) const
Definition qv4jscall_p.h:89
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:111
TriggerList * next
void wrapper()