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
qqmlbind.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 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 "qqmlbind_p.h"
5
6#include <private/qqmlanybinding_p.h>
7#include <private/qqmlbinding_p.h>
8#include <private/qqmlcomponent_p.h>
9#include <private/qqmlmetatype_p.h>
10#include <private/qqmlnullablevalue_p.h>
11#include <private/qqmlproperty_p.h>
12#include <private/qqmlvmemetaobject_p.h>
13#include <private/qv4persistent_p.h>
14#include <private/qv4qmlcontext_p.h>
15#include <private/qv4resolvedtypereference_p.h>
16
17#include <QtQml/qqmlcontext.h>
18#include <QtQml/qqmlengine.h>
19#include <QtQml/qqmlinfo.h>
20#include <QtQml/qqmlproperty.h>
21#include <QtQml/qqmlpropertymap.h>
22
23#include <QtCore/private/qobject_p.h>
24
25#include <QtCore/qdebug.h>
26#include <QtCore/qfile.h>
27#include <QtCore/qloggingcategory.h>
28#include <QtCore/qpointer.h>
29#include <QtCore/qtimer.h>
30
32
33Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
34
36 V4Value,
37 Variant,
38 Binding,
39 None
40};
41
50 Q_DISABLE_COPY_MOVE(QQmlBindEntryContent)
51public:
54
55 [[nodiscard]] QQmlBindEntryKind set(
57 {
58 silentDestroy(oldKind);
59 switch (newKind) {
61 new (&v4Value) QV4::PersistentValue(std::move(other.v4Value));
62 break;
64 new (&variant) QVariant(std::move(other.variant));
65 break;
67 new (&binding) QQmlAnyBinding(std::move(other.binding));
68 break;
70 break;
71 }
72 return newKind;
73 }
74
75 [[nodiscard]] QQmlBindEntryKind set(
77 {
78 silentDestroy(oldKind);
79 switch (newKind) {
81 new (&v4Value) QV4::PersistentValue(other.v4Value);
82 break;
84 new (&variant) QVariant(other.variant);
85 break;
87 new (&binding) QQmlAnyBinding(other.binding);
88 break;
90 break;
91 }
92 return newKind;
93 }
94
96 {
97 switch (kind) {
100 break;
103 break;
106 break;
108 break;
109 }
111 }
112
114 {
115 silentDestroy(oldKind);
116 new (&variant) QVariant(std::move(v));
118 }
119
121 {
122 silentDestroy(oldKind);
123 new (&v4Value) QV4::PersistentValue(std::move(v));
125 }
126
128 {
129 silentDestroy(oldKind);
130 new (&binding) QQmlAnyBinding(std::move(v));
132 }
133
137
138private:
139 void silentDestroy(QQmlBindEntryKind oldKind)
140 {
141 const QQmlBindEntryKind dead = destroy(oldKind);
143 Q_UNUSED(dead);
144 }
145};
146
156{
157 QQmlBindEntry() = default;
158 QQmlBindEntry(QQmlBindEntry &&other) noexcept : prop(std::move(other.prop))
159 {
160 currentKind = current.set(std::move(other.current), other.currentKind, currentKind);
161 previousKind = previous.set(std::move(other.previous), other.previousKind, previousKind);
162 }
163
165 : prop(other.prop)
166 {
167 currentKind = current.set(other.current, other.currentKind, currentKind);
168 previousKind = previous.set(other.previous, other.previousKind, previousKind);
169 }
170
176
178 {
179 if (this == &other)
180 return *this;
181 prop = std::move(other.prop);
182 currentKind = current.set(std::move(other.current), other.currentKind, currentKind);
183 previousKind = previous.set(std::move(other.previous), other.previousKind, previousKind);
184 return *this;
185 }
186
188 {
189 if (this == &other)
190 return *this;
191 prop = other.prop;
192 currentKind = current.set(other.current, other.currentKind, currentKind);
193 previousKind = previous.set(other.previous, other.previousKind, previousKind);
194 return *this;
195 }
196
197
203
204 void validate(QQmlBind *q) const;
205 void clearPrev();
206 void setTarget(QQmlBind *q, const QQmlProperty &p);
207};
208
210{
211public:
213 : when(true)
214 , componentComplete(true)
215 , delayed(false)
217 , restoreBinding(true)
218 , restoreValue(true)
221 {
222 }
224
225 // There can be multiple entries when using the generalized grouped
226 // property syntax. One is used for target/property/value.
227 QVarLengthArray<QQmlBindEntry, 1> entries;
228
229 // The target object if using the \l target property
230 QPointer<QObject> obj;
231
232 // Any values we need to create a proxy for. This is necessary when
233 // using the \l delayed member on generalized grouped properties. See
234 // the note on \l delayed.
235 std::unique_ptr<QQmlPropertyMap> delayedValues;
236
237 // The property name if using the \l property property.
239
240 // Whether the binding is enabled.
241 bool when: 1;
242
243 // Whether we have already parsed any generalized grouped properties
244 // we might need.
246
247 // Whether we should run in "delayed" mode and proxy all values before
248 // applying them to the target.
249 bool delayed:1;
250
251 // In delayed mode, when using the target/property mode, the \l value
252 // is the proxy. Then pendingEval denotes that a timer is active to
253 // apply the value. We should not start another timer then.
255
256 // Whether we should restore bindings on !when.
257 // TODO: Deprecate this and always do.
259
260 // Whether we should restore values on !when.
261 // TODO: Deprecate this and always do.
263
264 // writingProperty tracks whether we are updating the target property
265 // when using target/property/value. We use this information to warn about
266 // binding removal if we detect the target property to be updated while we
267 // are not writing it. This doesn't remove the Binding after all.
268 // For generalized grouped properties, we don't have to do this as writing
269 // the target property does remove the binding, just like it removes any
270 // other binding.
272
273 // Whether the last entry is the the target property referred to by the
274 // \l target object and the \l property property. This will generally be
275 // the case when using \l target and \l property.
277
279 void validate(QQmlBind *binding) const;
280 void decodeBinding(
281 QQmlBind *q, const QString &propertyPrefix, QQmlData::DeferredData *deferredData,
282 const QV4::CompiledData::Binding *binding,
284 void createDelayedValues();
285 void onDelayedValueChanged(QString delayedName);
286 void evalDelayed();
288};
289
291{
292 if (!prop.isWritable()) {
293 qmlWarning(q) << "Property '" << prop.name() << "' on "
294 << QQmlMetaType::prettyTypeName(prop.object()) << " is read-only.";
295 }
296}
297
299{
300 if (!lastIsTarget) {
302 lastIsTarget = true;
303 }
304 return &entries.last();
305}
306
308{
309 if (!when)
310 return;
311
312 qsizetype iterationEnd = entries.size();
313 if (lastIsTarget) {
314 if (obj) {
316 const QQmlBindEntry &last = entries.last();
317 if (!last.prop.isValid()) {
318 qmlWarning(q) << "Property '" << propName << "' does not exist on "
320 --iterationEnd;
321 }
322 } else {
323 --iterationEnd;
324 }
325 }
326
327 for (qsizetype i = 0; i < iterationEnd; ++i)
329}
330
390 : QObject(*(new QQmlBindPrivate), parent)
391{
392}
393
412bool QQmlBind::when() const
413{
414 Q_D(const QQmlBind);
415 return d->when;
416}
417
419{
420 Q_D(QQmlBind);
421 if (d->when == v)
422 return;
423
424 d->when = v;
425 if (v && d->componentComplete)
426 d->validate(this);
427 eval();
428}
429
453{
454 Q_D(const QQmlBind);
455 return d->obj;
456}
457
459{
460 Q_D(QQmlBind);
461 if (d->obj && d->when) {
462 /* if we switch the object at runtime, we need to restore the
463 previous binding on the old object before continuing */
464 d->when = false;
465 eval();
466 d->when = true;
467 }
468 /* if "when" and "target" depend on the same property, we might
469 end up here before we could have updated "when". So reevaluate
470 when manually here.
471 */
472 const QQmlProperty whenProp(this, QLatin1StringView("when"));
473 const auto potentialWhenBinding = QQmlAnyBinding::ofProperty(whenProp);
474 if (auto abstractBinding = potentialWhenBinding.asAbstractBinding()) {
475 QQmlBinding *binding = static_cast<QQmlBinding *>(abstractBinding);
476 if (binding->hasValidContext()) {
477 const auto boolType = QMetaType::fromType<bool>();
478 bool when;
479 binding->evaluate(&when, boolType);
480 d->when = when;
481 }
482 }
483 d->obj = obj;
484 if (d->componentComplete) {
485 setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this)));
486 if (d->when)
487 d->validate(this);
488 }
489 eval();
490}
491
523{
524 Q_D(const QQmlBind);
525 return d->propName;
526}
527
529{
530 Q_D(QQmlBind);
531 if (!d->propName.isEmpty() && d->when) {
532 /* if we switch the property name at runtime, we need to restore the
533 previous binding on the old object before continuing */
534 d->when = false;
535 eval();
536 d->when = true;
537 }
538 d->propName = p;
539 if (d->componentComplete) {
540 setTarget(QQmlProperty(d->obj, d->propName, qmlContext(this)));
541 if (d->when)
542 d->validate(this);
543 }
544 eval();
545}
546
557{
558 Q_D(const QQmlBind);
559 if (!d->lastIsTarget)
560 return QVariant();
561 Q_ASSERT(d->entries.last().currentKind == QQmlBindEntryKind::Variant);
562 return d->entries.last().current.variant;
563}
564
566{
567 Q_D(QQmlBind);
568 QQmlBindEntry *targetEntry = d->targetEntry();
569 targetEntry->currentKind = targetEntry->current.set(v, targetEntry->currentKind);
570 prepareEval();
571}
572
600{
601 Q_D(const QQmlBind);
602 return d->delayed;
603}
604
605void QQmlBind::setDelayed(bool delayed)
606{
607 Q_D(QQmlBind);
608 if (d->delayed == delayed)
609 return;
610
611 d->delayed = delayed;
612 if (!d->componentComplete)
613 return;
614
615 d->delayedValues.reset();
616
617 QVarLengthArray<QQmlBindEntry, 1> oldEntries = std::move(d->entries);
618 d->entries.clear();
619 d->buildBindEntries(this, nullptr);
620
621 if (d->lastIsTarget) {
622 d->entries.append(std::move(oldEntries.last()));
623 oldEntries.pop_back();
624 }
625
626 for (qsizetype i = 0, end = oldEntries.size(); i < end; ++i) {
627 QQmlBindEntry &newEntry = d->entries[i];
628 QQmlBindEntry &oldEntry = oldEntries[i];
629 newEntry.previousKind = newEntry.previous.set(
630 std::move(oldEntry.previous), oldEntry.previousKind, newEntry.previousKind);
631 if (d->delayed && oldEntry.currentKind == QQmlBindEntryKind::Binding)
633 }
634
635 if (!d->delayed)
636 eval();
637}
638
661{
662 Q_D(const QQmlBind);
663 unsigned result = RestoreNone;
664 if (d->restoreValue)
666 if (d->restoreBinding)
668 return RestorationMode(result);
669}
670
672{
673 Q_D(QQmlBind);
674 if (newMode != restoreMode()) {
675 d->restoreValue = (newMode & RestoreValue);
676 d->restoreBinding = (newMode & RestoreBinding);
678 }
679}
680
682{
683 Q_D(QQmlBind);
684 d->targetEntry()->setTarget(this, p);
685}
686
688{
689 if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
690 if (QObject *oldObject = prop.object()) {
691 QMetaProperty metaProp = oldObject->metaObject()->property(prop.index());
692 if (metaProp.hasNotifySignal()) {
693 QByteArray signal('2' + metaProp.notifySignal().methodSignature());
694 QObject::disconnect(oldObject, signal.constData(),
695 q, SLOT(targetValueChanged()));
696 }
697 }
698 p.connectNotifySignal(q, SLOT(targetValueChanged()));
699 }
700
701 prop = p;
702}
703
705{
706 Q_D(QQmlBind);
707 d->componentComplete = false;
708}
709
711 const QQmlProperty &prop, const QV4::CompiledData::Binding *binding,
712 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
713 const QQmlRefPointer<QQmlContextData> &contextData,
714 QObject *scopeObject)
715{
716 switch (binding->type()) {
719 return QQmlAnyBinding::createTranslationBinding(prop, compilationUnit, binding, scopeObject);
721 const QQmlBinding::Identifier id = binding->value.compiledScriptIndex;
722 if (id == QQmlBinding::Invalid) {
724 prop, compilationUnit->bindingValueAsString(binding), scopeObject,
725 contextData, compilationUnit->finalUrlString(), binding->location.line());
726 }
727 QV4::Scope scope(contextData->engine()->handle());
730 scope.engine->rootContext(), contextData, scopeObject));
732 prop, compilationUnit->runtimeFunctions.at(id), scopeObject, contextData,
733 qmlCtxt);
734 }
735 default:
736 break;
737 }
738 return QQmlAnyBinding();
739}
740
741static void initCreator(
742 QQmlData::DeferredData *deferredData,
743 const QQmlRefPointer<QQmlContextData> &contextData,
745{
746 if (!immediateState->hasCreator()) {
747 immediateState->setCompletePending(true);
748 immediateState->initCreator(
749 deferredData->context->parent(), deferredData->compilationUnit,
750 contextData);
751 immediateState->creator()->beginPopulateDeferred(deferredData->context);
752 }
753}
754
756 QQmlBind *q, const QString &propertyPrefix,
757 QQmlData::DeferredData *deferredData,
758 const QV4::CompiledData::Binding *binding,
760{
761 const QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
762 = deferredData->compilationUnit;
763 const QString propertySuffix = compilationUnit->stringAt(binding->propertyNameIndex);
764 const QString propertyName = propertyPrefix + propertySuffix;
765
766 switch (binding->type()) {
768 if (propertyPrefix.isEmpty()) {
769 // Top-level attached properties cannot be generalized grouped properties.
770 // Treat them as regular properties.
771 // ... unless we're not supposed to handle regular properties. Then ignore them.
772 if (!immediateState)
773 return;
774
775 Q_ASSERT(compilationUnit->stringAt(compilationUnit->objectAt(binding->value.objectIndex)
776 ->inheritedTypeNameIndex).isEmpty());
777
778 const QV4::ResolvedTypeReference *typeReference
779 = compilationUnit->resolvedType(binding->propertyNameIndex);
780 Q_ASSERT(typeReference);
781 QQmlType attachedType = typeReference->type();
782 if (!attachedType.isValid()) {
783 if (QQmlTypeLoader *typeLoader = compilationUnit->engine->typeLoader()) {
785 = deferredData->context->imports()->query(propertySuffix, typeLoader);
786 if (!result.isValid()) {
787 qmlWarning(q).nospace()
788 << "Unknown name " << propertySuffix << ". The binding is ignored.";
789 return;
790 }
791 attachedType = result.type;
792 }
793 }
794
797 q, attachedType.attachedPropertiesFunction(
798 QQmlEnginePrivate::get(context->engine())));
799 if (!attachedObject) {
800 qmlWarning(q).nospace() <<"Could not create attached properties object '"
801 << attachedType.typeName() << "'";
802 return;
803 }
804
805 initCreator(deferredData, QQmlContextData::get(context), immediateState);
806 immediateState->creator()->populateDeferredInstance(
807 q, deferredData->deferredIdx, binding->value.objectIndex, attachedObject,
808 attachedObject, /*value type property*/ nullptr, binding);
809 return;
810 }
813 const QString pre = propertyName + u'.';
814 const QV4::CompiledData::Object *subObj
815 = compilationUnit->objectAt(binding->value.objectIndex);
816 const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
817 for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding)
818 decodeBinding(q, pre, deferredData, subBinding, immediateState);
819 return;
820 }
821 default:
822 break;
823 }
824
827 const QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
828 entry.prop = QQmlPropertyPrivate::create(nullptr, propertyName, contextData,
830 if (!entry.prop.isValid()) {
831 // Try again in the context of this object. If that works, it's a regular property.
832 // ... unless we're not supposed to handle regular properties. Then ignore it.
833 if (!immediateState)
834 return;
835
837 q, propertyName, contextData, QQmlPropertyPrivate::InitFlag::AllowSignal);
838 if (property.isValid()) {
839 initCreator(deferredData, contextData, immediateState);
840 immediateState->creator()->populateDeferredBinding(
841 property, deferredData->deferredIdx, binding);
842 } else {
843 qmlWarning(q).nospace() << "Unknown name " << propertyName
844 << ". The binding is ignored.";
845 }
846 return;
847 }
848
849 const auto setVariant = [&entry](QVariant var) {
850 entry.currentKind = entry.current.set(std::move(var), entry.currentKind);
851 };
852
853 const auto setBinding = [&entry](QQmlAnyBinding binding) {
854 entry.currentKind = entry.current.set(binding, entry.currentKind);
855 };
856
857 switch (binding->type()) {
860 Q_UNREACHABLE(); // Handled above
861 break;
865 if (delayed) {
866 if (!delayedValues)
868 const QString delayedName = QString::number(entries.size());
869 delayedValues->insert(delayedName, QVariant());
870 QQmlProperty bindingTarget = QQmlProperty(delayedValues.get(), delayedName);
871 Q_ASSERT(bindingTarget.isValid());
872 QQmlAnyBinding anyBinding = createBinding(
873 bindingTarget, binding, compilationUnit, contextData, q);
874 anyBinding.installOn(bindingTarget);
875 } else {
876 setBinding(createBinding(entry.prop, binding, compilationUnit, contextData, q));
877 }
878 break;
880 setVariant(compilationUnit->bindingValueAsString(binding));
881 break;
883 setVariant(compilationUnit->bindingValueAsNumber(binding));
884 break;
886 setVariant(binding->valueAsBoolean());
887 break;
889 setVariant(QVariant::fromValue(nullptr));
890 break;
893 break;
894 }
895
896 entries.append(std::move(entry));
897}
898
900{
901 delayedValues = std::make_unique<QQmlPropertyMap>();
904 delayedValues.get(), [this](QString delayedName, const QVariant &value) {
905 Q_UNUSED(value);
906 onDelayedValueChanged(std::move(delayedName));
907 }
908 );
909}
910
912{
915 const QString pendingName = QStringLiteral("pending");
916 QStringList pending = qvariant_cast<QStringList>((*delayedValues)[pendingName]);
917 if (componentComplete && pending.size() == 0)
918 QTimer::singleShot(0, delayedValues.get(), [this]() { evalDelayed(); });
919 else if (pending.contains(delayedName))
920 return;
921
922 pending.append(std::move(delayedName));
923 (*delayedValues)[pendingName].setValue(std::move(pending));
924}
925
927{
928 if (!when || !delayedValues)
929 return;
930
931 const QString pendingName = QStringLiteral("pending");
932 const QStringList pending = qvariant_cast<QStringList>((*delayedValues)[pendingName]);
933 for (const QString &delayedName : pending) {
934 bool ok;
935 const int delayedIndex = delayedName.toInt(&ok);
936 Q_ASSERT(ok);
937 Q_ASSERT(delayedIndex >= 0 && delayedIndex < entries.size());
938 entries[delayedIndex].prop.write((*delayedValues)[delayedName]);
939 }
940 (*delayedValues)[pendingName].setValue(QStringList());
941}
942
944{
946 if (data && !data->deferredData.isEmpty()) {
947 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
948 for (QQmlData::DeferredData *deferredData : data->deferredData) {
949 QMultiHash<int, const QV4::CompiledData::Binding *> *bindings = &deferredData->bindings;
950 if (deferredState) {
952 for (auto it = bindings->cbegin(); it != bindings->cend(); ++it)
953 decodeBinding(q, QString(), deferredData, *it, &constructionState);
954
955
956 if (constructionState.hasCreator()) {
958 constructionState.creator()->finalizePopulateDeferred();
959 constructionState.appendCreatorErrors();
960 deferredState->push_back(std::move(constructionState));
961 }
962 } else {
963 for (auto it = bindings->cbegin(); it != bindings->cend(); ++it)
964 decodeBinding(q, QString(), deferredData, *it, nullptr);
965 }
966 }
967
968 if (deferredState) {
969 data->releaseDeferredData();
970 if (!deferredState->empty())
972 }
973 }
974}
975
977{
978 Q_D(QQmlBind);
980 d->buildBindEntries(this, &deferredState);
981 d->componentComplete = true;
982 if (!d->propName.isEmpty() || d->obj) {
983 QQmlBindEntry *target = d->targetEntry();
984 if (!target->prop.isValid())
985 target->setTarget(this, QQmlProperty(d->obj, d->propName, qmlContext(this)));
986 }
987 d->validate(this);
988 d->evalDelayed();
989 eval();
990}
991
992void QQmlBind::prepareEval()
993{
994 Q_D(QQmlBind);
995 if (d->delayed) {
996 if (!d->pendingEval)
997 QTimer::singleShot(0, this, &QQmlBind::eval);
998 d->pendingEval = true;
999 } else {
1000 eval();
1001 }
1002}
1003
1008
1009void QQmlBind::eval()
1010{
1011 Q_D(QQmlBind);
1012 d->pendingEval = false;
1013 if (!d->componentComplete)
1014 return;
1015
1016 for (QQmlBindEntry &entry : d->entries) {
1017 if (!entry.prop.isValid() || (entry.currentKind == QQmlBindEntryKind::None))
1018 continue;
1019
1020 if (!d->when) {
1021 //restore any previous binding
1022 switch (entry.previousKind) {
1024 if (d->restoreBinding) {
1025 QQmlAnyBinding p = std::move(entry.previous.binding);
1026 entry.clearPrev(); // Do that before setBinding(), as setBinding() may recurse.
1027 p.installOn(entry.prop);
1028 }
1029 break;
1031 if (d->restoreValue) {
1032 QQmlAnyBinding::takeFrom(entry.prop); // we don't want to have a binding active
1033 auto propPriv = QQmlPropertyPrivate::get(entry.prop);
1034 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
1035 Q_ASSERT(vmemo);
1036 vmemo->setVMEProperty(propPriv->core.coreIndex(),
1037 *entry.previous.v4Value.valueRef());
1038 entry.clearPrev();
1039 }
1040 break;
1042 if (d->restoreValue) {
1043 QQmlAnyBinding::takeFrom(entry.prop); // we don't want to have a binding active
1044 entry.prop.write(entry.previous.variant);
1045 entry.clearPrev();
1046 }
1047 break;
1049 break;
1050 }
1051 continue;
1052 }
1053
1054 //save any set binding for restoration
1055 if (entry.previousKind == QQmlBindEntryKind::None) {
1056 // try binding first; we need to use takeFrom to properly unlink the binding
1058 if (prevBind) {
1059 entry.previousKind = entry.previous.set(std::move(prevBind), entry.previousKind);
1060 } else {
1061 // nope, try a V4 value next
1062 auto propPriv = QQmlPropertyPrivate::get(entry.prop);
1063 auto propData = propPriv->core;
1064 if (!propPriv->valueTypeData.isValid() && propData.isVarProperty()) {
1065 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
1066 Q_ASSERT(vmemo);
1067 auto retVal = vmemo->vmeProperty(propData.coreIndex());
1068 entry.previousKind = entry.previous.set(
1069 QV4::PersistentValue(vmemo->engine, retVal), entry.previousKind);
1070 } else {
1071 // nope, use the meta object to get a QVariant
1072 entry.previousKind = entry.previous.set(entry.prop.read(), entry.previousKind);
1073 }
1074 }
1075 }
1076
1077 // NOTE: removeBinding has no effect on QProperty classes, but
1078 // we already used takeBinding to remove it
1080 }
1081
1082 if (!d->when)
1083 return;
1084
1085 d->writingProperty = true;
1086 for (qsizetype i = 0, end = d->entries.size(); i != end; ++i) {
1087 QQmlBindEntry &entry = d->entries[i];
1088 if (!entry.prop.isValid())
1089 continue;
1090 switch (entry.currentKind) {
1092 entry.prop.write(entry.current.variant);
1093 break;
1095 Q_ASSERT(!d->delayed);
1096 entry.current.binding.installOn(entry.prop);
1097 break;
1099 auto propPriv = QQmlPropertyPrivate::get(entry.prop);
1100 QQmlVMEMetaObject::get(propPriv->object)->setVMEProperty(
1101 propPriv->core.coreIndex(), *entry.current.v4Value.valueRef());
1102 break;
1103 }
1105 break;
1106 }
1107 }
1108 d->writingProperty = false;
1109}
1110
1111void QQmlBind::targetValueChanged()
1112{
1113 Q_D(QQmlBind);
1114 if (d->writingProperty)
1115 return;
1116
1117 if (!d->when)
1118 return;
1119
1120 QUrl url;
1121 quint16 line = 0;
1122
1123 const QQmlData *ddata = QQmlData::get(this, false);
1124 if (ddata && ddata->outerContext) {
1125 url = ddata->outerContext->url();
1126 line = ddata->lineNumber;
1127 }
1128
1129 qCInfo(lcBindingRemoval,
1130 "The target property of the Binding element created at %s:%d was changed from "
1131 "elsewhere. This does not overwrite the binding. The target property will still be "
1132 "updated when the value of the Binding element changes.",
1134}
1135
1137
1138#include "moc_qqmlbind_p.cpp"
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
QQmlAnyBinding is an abstraction over the various bindings in QML.
static QQmlAnyBinding createFromCodeString(const QQmlProperty &prop, const QString &code, QObject *obj, const QQmlRefPointer< QQmlContextData > &ctxt, const QString &url, quint16 lineNumber)
static void removeBindingFrom(QQmlProperty &prop)
static QQmlAnyBinding createTranslationBinding(const QQmlProperty &prop, const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit, const QV4::CompiledData::Binding *translationBinding, QObject *scopeObject=nullptr, QQmlRefPointer< QQmlContextData > context={})
static QQmlAnyBinding takeFrom(const QQmlProperty &prop)
Removes the binding from the property prop, and returns it as a QQmlAnyBinding if there was any.
~QQmlAnyBinding() noexcept
static QQmlAnyBinding ofProperty(const QQmlProperty &prop)
static QQmlAnyBinding createFromFunction(const QQmlProperty &prop, QV4::Function *function, QObject *obj, const QQmlRefPointer< QQmlContextData > &ctxt, QV4::ExecutionContext *scope)
void validate(QQmlBind *binding) const
Definition qqmlbind.cpp:307
std::unique_ptr< QQmlPropertyMap > delayedValues
Definition qqmlbind.cpp:235
QVarLengthArray< QQmlBindEntry, 1 > entries
Definition qqmlbind.cpp:227
QQmlBindEntry * targetEntry()
Definition qqmlbind.cpp:298
void onDelayedValueChanged(QString delayedName)
Definition qqmlbind.cpp:911
void decodeBinding(QQmlBind *q, const QString &propertyPrefix, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding, QQmlComponentPrivate::ConstructionState *immediateState)
Definition qqmlbind.cpp:755
void buildBindEntries(QQmlBind *q, QQmlComponentPrivate::DeferredState *deferredState)
Definition qqmlbind.cpp:943
QPointer< QObject > obj
Definition qqmlbind.cpp:230
void createDelayedValues()
Definition qqmlbind.cpp:899
QString property
Definition qqmlbind_p.h:42
bool when
Definition qqmlbind_p.h:44
void setRestoreMode(RestorationMode)
Definition qqmlbind.cpp:671
void setDelayed(bool)
Definition qqmlbind.cpp:605
void setWhen(bool)
Definition qqmlbind.cpp:418
void classBegin() override
Invoked after class creation, but before any properties have been set.
Definition qqmlbind.cpp:704
RestorationMode restoreMode
Definition qqmlbind_p.h:47
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
Definition qqmlbind.cpp:976
void setTarget(const QQmlProperty &) override
Set the target property for the value source.
Definition qqmlbind.cpp:681
QQmlBind(QObject *parent=nullptr)
Definition qqmlbind.cpp:389
QObject * object()
\qmlproperty QtObject QtQml::Binding::target
Definition qqmlbind.cpp:452
void setValue(const QVariant &)
Definition qqmlbind.cpp:565
QVariant value
Definition qqmlbind_p.h:43
@ RestoreNone
Definition qqmlbind_p.h:30
@ RestoreValue
Definition qqmlbind_p.h:32
@ RestoreBinding
Definition qqmlbind_p.h:31
void setObject(QObject *)
Definition qqmlbind.cpp:458
bool delayed
Definition qqmlbind_p.h:45
void setProperty(const QString &)
Definition qqmlbind.cpp:528
void restoreModeChanged()
QVariant evaluate()
std::vector< ConstructionState > DeferredState
static void completeDeferred(QQmlEnginePrivate *enginePriv, DeferredState *deferredState)
QQmlRefPointer< QQmlTypeNameCache > imports() const
static QQmlRefPointer< QQmlContextData > get(QQmlContext *context)
QQmlRefPointer< QQmlContextData > parent() const
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
static QQmlEnginePrivate * get(QQmlEngine *e)
static QString prettyTypeName(const QObject *object)
Returns the pretty QML type name (e.g.
void valueChanged(const QString &key, const QVariant &value)
This signal is emitted whenever one of the values in the map is changed.
static QQmlProperty create(QObject *target, const QString &propertyName, const QQmlRefPointer< QQmlContextData > &context, QQmlPropertyPrivate::InitFlags flags)
static void removeBinding(const QQmlProperty &that)
static QQmlPropertyPrivate * get(const QQmlProperty &p)
The QQmlProperty class abstracts accessing properties on objects created from QML.
bool isValid() const
Returns true if the QQmlProperty refers to a valid property, otherwise false.
int index() const
Return the Qt metaobject index of the property.
QML_ANONYMOUSQObject * object
bool isWritable() const
Returns true if the property is writable, otherwise false.
The QQmlTypeLoader class abstracts loading files and their dependencies over the network.
Result query(const QHashedStringRef &key, QQmlTypeLoader *typeLoader) const
QQmlAttachedPropertiesFunc attachedPropertiesFunction(QQmlEnginePrivate *engine) const
Definition qqmltype.cpp:709
QByteArray typeName() const
Definition qqmltype.cpp:451
bool isValid() const
Definition qqmltype_p.h:54
static QQmlVMEMetaObject * get(QObject *o)
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
bool singleShot
whether the timer is a single-shot timer
Definition qtimer.h:22
\inmodule QtCore
Definition qurl.h:94
QString url(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2817
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2831
constexpr size_type size() const noexcept
bool isEmpty() const
void append(const T &t)
\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
~QVariant()
Destroys the QVariant and the contained object.
Definition qvariant.cpp:529
QSet< QString >::iterator it
auto signal
Combined button and popup list for selecting options.
static void * context
#define Q_FALLTHROUGH()
#define Q_UNLIKELY(x)
QList< QString > QStringList
Constructs a string list that contains the given string, str.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall * pending
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qCInfo(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
#define SLOT(a)
Definition qobjectdefs.h:52
GLsizei const GLfloat * v
[13]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum target
GLhandleARB obj
[2]
GLuint entry
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
QObject * qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
Definition qqml.cpp:114
static void initCreator(QQmlData::DeferredData *deferredData, const QQmlRefPointer< QQmlContextData > &contextData, QQmlComponentPrivate::ConstructionState *immediateState)
Definition qqmlbind.cpp:741
QQmlBindEntryKind
Definition qqmlbind.cpp:35
static QQmlAnyBinding createBinding(const QQmlProperty &prop, const QV4::CompiledData::Binding *binding, const QQmlRefPointer< QV4::ExecutableCompilationUnit > &compilationUnit, const QQmlRefPointer< QQmlContextData > &contextData, QObject *scopeObject)
Definition qqmlbind.cpp:710
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
static QQuickAttachedPropertyPropagator * attachedObject(const QMetaObject *type, QObject *object, bool create=false)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1531
#define QStringLiteral(str)
#define emit
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
unsigned short quint16
Definition qtypes.h:48
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned char quint8
Definition qtypes.h:46
const char property[13]
Definition qwizard.cpp:101
QUrl url("example.com")
[constructor-url-reference]
QSharedPointer< T > other(t)
[5]
QQmlBindEntryKind previousKind
Definition qqmlbind.cpp:202
QQmlBindEntry(const QQmlBindEntry &other)
Definition qqmlbind.cpp:164
QQmlBindEntry & operator=(QQmlBindEntry &&other) noexcept
Definition qqmlbind.cpp:177
QQmlProperty prop
Definition qqmlbind.cpp:200
void setTarget(QQmlBind *q, const QQmlProperty &p)
Definition qqmlbind.cpp:687
QQmlBindEntryKind currentKind
Definition qqmlbind.cpp:201
QQmlBindEntry & operator=(const QQmlBindEntry &other)
Definition qqmlbind.cpp:187
QQmlBindEntryContent current
Definition qqmlbind.cpp:198
QQmlBindEntryContent previous
Definition qqmlbind.cpp:199
void validate(QQmlBind *q) const
Definition qqmlbind.cpp:290
QQmlBindEntry(QQmlBindEntry &&other) noexcept
Definition qqmlbind.cpp:158
QQmlBindEntry()=default
QQmlRefPointer< QQmlContextData > context
Definition qqmldata_p.h:183
unsigned int deferredIdx
Definition qqmldata_p.h:176
QQmlRefPointer< QV4::ExecutableCompilationUnit > compilationUnit
Definition qqmldata_p.h:180
union QV4::CompiledData::Binding::@540 value
ExecutionContext * rootContext() const
static Heap::QmlContext * create(QV4::ExecutionContext *parent, QQmlRefPointer< QQmlContextData > context, QObject *scopeObject)
ExecutionEngine * engine
QQmlAnyBinding binding
Definition qqmlbind.cpp:136
QQmlBindEntryKind set(const QQmlBindEntryContent &other, QQmlBindEntryKind newKind, QQmlBindEntryKind oldKind)
Definition qqmlbind.cpp:75
QQmlBindEntryKind set(QQmlAnyBinding v, QQmlBindEntryKind oldKind)
Definition qqmlbind.cpp:127
QV4::PersistentValue v4Value
Definition qqmlbind.cpp:134
QQmlBindEntryKind set(QV4::PersistentValue v, QQmlBindEntryKind oldKind)
Definition qqmlbind.cpp:120
QQmlBindEntryKind set(QVariant v, QQmlBindEntryKind oldKind)
Definition qqmlbind.cpp:113
QQmlBindEntryKind set(QQmlBindEntryContent &&other, QQmlBindEntryKind newKind, QQmlBindEntryKind oldKind)
Definition qqmlbind.cpp:55
QQmlBindEntryKind destroy(QQmlBindEntryKind kind)
Definition qqmlbind.cpp:95