Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
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// Qt-Security score:significant
4
5#include "qqmlbind_p.h"
6
7#include <private/qqmlanybinding_p.h>
8#include <private/qqmlbinding_p.h>
9#include <private/qqmlcomponent_p.h>
10#include <private/qqmlmetatype_p.h>
11#include <private/qqmlnullablevalue_p.h>
12#include <private/qqmlproperty_p.h>
13#include <private/qqmlvmemetaobject_p.h>
14#include <private/qv4persistent_p.h>
15#include <private/qv4qmlcontext_p.h>
16#include <private/qv4resolvedtypereference_p.h>
17#include <private/qv4runtime_p.h>
18#include <private/qv4qobjectwrapper_p.h>
19
20#include <QtQml/qqmlcontext.h>
21#include <QtQml/qqmlengine.h>
22#include <QtQml/qqmlinfo.h>
23#include <QtQml/qqmlproperty.h>
24#include <QtQml/qqmlpropertymap.h>
25#include <QtQml/private/qqmllist_p.h>
26#include <QtQml/private/qqmllistwrapper_p.h>
27
28#include <QtCore/private/qobject_p.h>
29
30#include <QtCore/qdebug.h>
31#include <QtCore/qfile.h>
32#include <QtCore/qloggingcategory.h>
33#include <QtCore/qpointer.h>
34#include <QtCore/qtimer.h>
35
37
38Q_STATIC_LOGGING_CATEGORY(lcQtQmlBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
39
40enum class QQmlBindEntryKind: quint8 {
41 V4Value,
42 Variant,
43 Binding,
44 None
45};
46
47/*!
48 * \internal
49 * QQmlBindEntryContent can store one of QV4::Value, QVariant, QQmlAnyBinding, or nothing,
50 * as denoted by QQmlBindEntryKind. It expects the calling code to know what is stored at
51 * any time. On each method invocation, the current kind has to be passed as last parameter
52 * and the new kind is returned.
53 */
56public:
59
77
95
97 {
98 switch (kind) {
102 break;
105 break;
107 break;
108 }
109 return QQmlBindEntryKind::None;
110 }
111
119
126
133
140
143 int none = 0;
144
145private:
146 void silentDestroy(QQmlBindEntryKind oldKind)
147 {
148 const QQmlBindEntryKind dead = destroy(oldKind);
149 Q_ASSERT(dead == QQmlBindEntryKind::None);
150 Q_UNUSED(dead);
151 }
152};
153
154/*!
155 * \internal
156 * QQmlBindEntry holds two QQmlBindEntryContent members, along with their kinds.
157 * The \l current content is the value or binding the Binding element installs on
158 * the target if enabled (that is, if \l{when}). The \l previous content is what
159 * the target holds before the Binding element installs its binding or value. It
160 * is restored if !\l{when}. The \l prop member holds the target property.
161 */
163{
164 QQmlBindEntry() = default;
166 {
167 currentKind = current.set(std::move(other.current), other.currentKind, currentKind);
168 previousKind = previous.set(std::move(other.previous), other.previousKind, previousKind);
169 }
170
172 : prop(other.prop)
173 {
174 currentKind = current.set(other.current, other.currentKind, currentKind);
175 previousKind = previous.set(other.previous, other.previousKind, previousKind);
176 }
177
179 {
180 currentKind = current.destroy(currentKind);
181 previousKind = previous.destroy(previousKind);
182 }
183
185 {
186 if (this == &other)
187 return *this;
188 prop = std::move(other.prop);
189 currentKind = current.set(std::move(other.current), other.currentKind, currentKind);
190 previousKind = previous.set(std::move(other.previous), other.previousKind, previousKind);
191 return *this;
192 }
193
195 {
196 if (this == &other)
197 return *this;
198 prop = other.prop;
199 currentKind = current.set(other.current, other.currentKind, currentKind);
200 previousKind = previous.set(other.previous, other.previousKind, previousKind);
201 return *this;
202 }
203
204
210
211 void validate(QQmlBind *q) const;
212 void clearPrev();
213 void setTarget(QQmlBind *q, const QQmlProperty &p);
214};
215
217{
218 // Only one entry is used for target/property/value
220
221 // The \l target object
223
224 // The \l property name
226};
227
229{
230 // There can be multiple entries when using the generalized grouped
231 // property mode.
233
234 // Any values we need to create a proxy for. This is necessary when
235 // using the \l delayed member on generalized grouped properties. See
236 // the note on \l delayed.
238};
239
241{
242public:
248
250 : when(true)
251 , componentComplete(true)
252 , delayed(false)
253 , pendingEval(false)
254 , restoreBinding(true)
255 , restoreValue(true)
256 , writingProperty(false)
257 {
258 }
259
261 {
262 switch (mode) {
263 case GeneralizedGroup:
264 generalizedGroupData.~GeneralizedGroupData();
265 return;
266 case ObjectPropertyValue:
267 objectPropertyValueData.~ObjectPropertyValueData();
268 return;
269 case Unknown:
270 return;
271 }
272 }
273
274 union {
275 int noData = 0;
278 };
279
281
282 // Whether the binding is enabled.
283 bool when: 1;
284
285 // Whether we have already parsed any generalized grouped properties
286 // we might need.
288
289 // Whether we should run in "delayed" mode and proxy all values before
290 // applying them to the target.
291 bool delayed:1;
292
293 // In delayed mode, when using the target/property mode, the \l value
294 // is the proxy. Then pendingEval denotes that a timer is active to
295 // apply the value. We should not start another timer then.
297
298 // Whether we should restore bindings on !when.
299 // TODO: Deprecate this and always do.
301
302 // Whether we should restore values on !when.
303 // TODO: Deprecate this and always do.
305
306 // writingProperty tracks whether we are updating the target property
307 // when using target/property/value. We use this information to warn about
308 // binding removal if we detect the target property to be updated while we
309 // are not writing it. This doesn't remove the Binding after all.
310 // For generalized grouped properties, we don't have to do this as writing
311 // the target property does remove the binding, just like it removes any
312 // other binding.
314
316 void validate(QQmlBind *binding) const;
318 QQmlBind *q, const QString &propertyPrefix, QQmlData::DeferredData *deferredData,
319 const QV4::CompiledData::Binding *binding,
320 QQmlComponentPrivate::ConstructionState *immediateState);
322 void onDelayedValueChanged(QString delayedName);
324 void buildBindEntries(QQmlBind *q, QQmlComponentPrivate::DeferredState *deferredState);
327 bool isCurrent(QQmlBindEntry *entry) const;
328};
329
330static void warnIgnoredProperties(QQmlBind *q)
331{
332 qmlWarning(q)
333 << "You should not set the 'object', 'property', or 'value' properties when using "
334 "generalized group properties. They are ignored.";
335}
336
337void QQmlBindEntry::validate(QQmlBind *q) const
338{
339 if (!prop.isWritable()) {
340 qmlWarning(q) << "Property '" << prop.name() << "' on "
341 << QQmlMetaType::prettyTypeName(prop.object()) << " is read-only.";
342 }
343}
344
346{
347 switch (mode) {
348 case GeneralizedGroup:
349 Q_UNREACHABLE_RETURN(nullptr);
350 case Unknown:
351 new (&objectPropertyValueData) ObjectPropertyValueData;
353 Q_FALLTHROUGH();
354 case ObjectPropertyValue:
355 return &objectPropertyValueData.entry;
356 }
357
358 return nullptr;
359}
360
361void QQmlBindPrivate::validate(QQmlBind *q) const
362{
363 if (!when)
364 return;
365
366 switch (mode) {
367 case ObjectPropertyValue:
368 if (!objectPropertyValueData.obj)
369 break;
370 if (objectPropertyValueData.entry.prop.isValid()) {
371 objectPropertyValueData.entry.validate(q);
372 } else {
373 qmlWarning(q) << "Property '" << objectPropertyValueData.propName
374 << "' does not exist on "
375 << QQmlMetaType::prettyTypeName(objectPropertyValueData.obj) << ".";
376 }
377 break;
378 case GeneralizedGroup:
379 for (const QQmlBindEntry &entry : generalizedGroupData.entries)
380 entry.validate(q);
381 break;
382 case Unknown:
383 break;
384 }
385}
386
387/*!
388 \qmltype Binding
389 \inqmlmodule QtQml
390 \ingroup qtquick-interceptors
391 \brief Enables the arbitrary creation of property bindings.
392
393 In QML, property bindings result in a dependency between the properties of
394 different objects.
395
396 \section1 Binding to an Inaccessible Property
397
398 Sometimes it is necessary to bind an object's property to
399 that of another object that isn't directly instantiated by QML, such as a
400 property of a class exported to QML by C++. You can use the Binding type
401 to establish this dependency; binding any value to any object's property.
402
403 For example, in a C++ application that maps an "app.enteredText" property
404 into QML, you can use Binding to update the enteredText property.
405
406 \qml
407 TextEdit { id: myTextField; text: "Please type here..." }
408 Binding { app.enteredText: myTextField.text }
409 \endqml
410
411 When \c{text} changes, the C++ property \c{enteredText} will update
412 automatically.
413
414 \section1 Conditional Bindings
415
416 In some cases you may want to modify the value of a property when a certain
417 condition is met but leave it unmodified otherwise. Often, it's not possible
418 to do this with direct bindings, as you have to supply values for all
419 possible branches.
420
421 For example, the code snippet below results in a warning whenever you
422 release the mouse. This is because the value of the binding is undefined
423 when the mouse isn't pressed.
424
425 \qml
426 // produces warning: "Unable to assign [undefined] to double value"
427 value: if (mouse.pressed) mouse.mouseX
428 \endqml
429
430 The Binding type can prevent this warning.
431
432 \qml
433 Binding on value {
434 when: mouse.pressed
435 value: mouse.mouseX
436 }
437 \endqml
438
439 The Binding type restores any previously set direct bindings on the
440 property.
441
442 \section1 Multiple targets in one Binding
443
444 You can specify multiple bindings to the same object in one Binding element:
445
446 \qml
447 Text {
448 id: t1
449 }
450
451 Binding {
452 t1 {
453 color: "#00FF00"
454 text: "green text"
455 }
456 }
457 \endqml
458
459 You can also specify several bindings with different target objects in a
460 single Binding element:
461
462 \qml
463 Text {
464 id: t1
465 }
466
467 Text {
468 id: t2
469 }
470
471 Binding {
472 t1.text: "Foo"
473 t2.text: "Bar"
474 }
475 \endqml
476
477 \sa {Qt Qml}
478*/
479QQmlBind::QQmlBind(QObject *parent)
480 : QObject(*(new QQmlBindPrivate), parent)
481{
482}
483
484QQmlBind::~QQmlBind()
485{
486 Q_D(QQmlBind);
487 // restore state when dynamic Binding is destroyed
488 if (!(d->when && d->componentComplete && restoreMode() != RestoreNone))
489 return;
490 // isDeletingChildren is supposed to happen later; we couldn't use declarativeData
491 // if isDeletingChildren were set
492 Q_ASSERT(!d->isDeletingChildren);
493 // We can't use qmlEngine (or QQmlData::get), as that checks for scheduled deletion
494 if (auto ddata = static_cast<QQmlData *>(d->declarativeData);
495 ddata && ddata->context && QQmlData::wasDeleted(ddata->context->engine()))
496 return; // whole engine is going away; don't bother resetting
497 d->when = false; // internal only change, no signal emission
498 eval();
499}
500
501/*!
502 \qmlproperty bool QtQml::Binding::when
503
504 This property holds when the binding is active.
505 This should be set to an expression that evaluates to true when you want the binding to be active.
506
507 \qml
508 Binding {
509 contactName.text: name
510 when: list.ListView.isCurrentItem
511 }
512 \endqml
513
514 By default, any binding or value that was set perviously is restored when the binding becomes
515 inactive. You can customize the restoration behavior using the \l restoreMode property.
516
517 \sa restoreMode
518*/
519bool QQmlBind::when() const
520{
521 Q_D(const QQmlBind);
522 return d->when;
523}
524
525void QQmlBind::setWhen(bool v)
526{
527 Q_D(QQmlBind);
528 if (d->when == v)
529 return;
530
531 d->when = v;
532 if (v && d->componentComplete)
533 d->validate(this);
534 eval();
535 emit whenChanged();
536}
537
538/*!
539 \qmlproperty QtObject QtQml::Binding::target
540
541 The object to be updated. You need to use this property if the binding target
542 does not have an \c id attribute (for example, when the target is a singleton).
543 Otherwise, the following two pieces of code are equivalent:
544
545 \qml
546 Binding { contactName.text: name }
547 \endqml
548
549 \qml
550 Binding {
551 target: contactName
552 property: "text"
553 value: name
554 }
555 \endqml
556
557 The former one is much more compact, but you cannot replace the target
558 object or property at run time. With the latter one you can.
559*/
560QObject *QQmlBind::object() const
561{
562 Q_D(const QQmlBind);
563 switch (d->mode) {
564 case QQmlBindPrivate::GeneralizedGroup:
565 case QQmlBindPrivate::Unknown:
566 return nullptr;
567 case QQmlBindPrivate::ObjectPropertyValue:
568 return d->objectPropertyValueData.obj;
569 }
570
571 Q_UNREACHABLE_RETURN(nullptr);
572}
573
574void QQmlBind::setObject(QObject *obj)
575{
576 Q_D(QQmlBind);
577 switch (d->mode) {
578 case QQmlBindPrivate::GeneralizedGroup:
579 if (obj != nullptr)
580 warnIgnoredProperties(this);
581 return;
582 case QQmlBindPrivate::ObjectPropertyValue:
583 if (d->objectPropertyValueData.obj == obj)
584 return;
585 break;
586 case QQmlBindPrivate::Unknown:
587 if (obj == nullptr)
588 return;
589 new (&d->objectPropertyValueData) ObjectPropertyValueData;
590 d->mode = QQmlBindPrivate::ObjectPropertyValue;
591 break;
592 }
593
594 if (d->when) {
595 /* if we switch the object at runtime, we need to restore the
596 previous binding on the old object before continuing */
597 d->when = false;
598 eval();
599 d->when = true;
600 }
601 /* if "when" and "target" depend on the same property, we might
602 end up here before we could have updated "when". So reevaluate
603 when manually here.
604 */
605 const QQmlProperty whenProp(this, QLatin1StringView("when"));
606 const auto potentialWhenBinding = QQmlAnyBinding::ofProperty(whenProp);
607 if (auto abstractBinding = potentialWhenBinding.asAbstractBinding()) {
608 QQmlBinding *binding = static_cast<QQmlBinding *>(abstractBinding);
609 if (binding->hasValidContext()) {
610 const auto boolType = QMetaType::fromType<bool>();
611 bool when;
612 binding->evaluate(&when, boolType);
613 if (when != d->when) {
614 d->when = when;
615 emit whenChanged();
616 }
617 }
618 }
619
620 switch (d->mode) {
621 case QQmlBindPrivate::GeneralizedGroup:
622 case QQmlBindPrivate::Unknown:
623 Q_UNREACHABLE();
624 return;
625 case QQmlBindPrivate::ObjectPropertyValue:
626 d->objectPropertyValueData.obj = obj;
627 if (d->componentComplete) {
628 setTarget(QQmlProperty(
629 d->objectPropertyValueData.obj, d->objectPropertyValueData.propName,
630 qmlContext(this)));
631 }
632 break;
633 }
634
635 if (d->componentComplete && d->when)
636 d->validate(this);
637
638 eval();
639 emit objectChanged();
640}
641
642/*!
643 \qmlproperty string QtQml::Binding::property
644
645 The property to be updated.
646
647 This can be a group property if the expression results in accessing a
648 property of a \l {QML Value Types}{value type}. For example:
649
650 \qml
651 Item {
652 id: item
653
654 property rect rectangle: Qt.rect(0, 0, 200, 200)
655 }
656
657 Binding {
658 target: item
659 property: "rectangle.x"
660 value: 100
661 }
662 \endqml
663
664 You only need to use this property if you can't supply the binding target
665 declaratively. The following snippet of code is equivalent to the above
666 binding, but more compact:
667
668 \qml
669 Binding { item.rectangle.x: 100 }
670 \endqml
671*/
672QString QQmlBind::property() const
673{
674 Q_D(const QQmlBind);
675 switch (d->mode) {
676 case QQmlBindPrivate::GeneralizedGroup:
677 case QQmlBindPrivate::Unknown:
678 return QString();
679 case QQmlBindPrivate::ObjectPropertyValue:
680 return d->objectPropertyValueData.propName;
681 }
682
683 Q_UNREACHABLE_RETURN(QString());
684}
685
686void QQmlBind::setProperty(const QString &p)
687{
688 Q_D(QQmlBind);
689 switch (d->mode) {
690 case QQmlBindPrivate::GeneralizedGroup:
691 if (!p.isEmpty())
692 warnIgnoredProperties(this);
693 return;
694 case QQmlBindPrivate::ObjectPropertyValue:
695 if (d->objectPropertyValueData.propName == p)
696 return;
697 break;
698 case QQmlBindPrivate::Unknown:
699 if (p.isEmpty())
700 return;
701 new (&d->objectPropertyValueData) ObjectPropertyValueData;
702 d->mode = QQmlBindPrivate::ObjectPropertyValue;
703 break;
704 }
705
706 if (!d->objectPropertyValueData.propName.isEmpty() && d->when) {
707 /* if we switch the property name at runtime, we need to restore the
708 previous binding on the old object before continuing */
709 d->when = false;
710 eval();
711 d->when = true;
712 }
713 d->objectPropertyValueData.propName = p;
714 if (d->componentComplete) {
715 setTarget(QQmlProperty(
716 d->objectPropertyValueData.obj, d->objectPropertyValueData.propName,
717 qmlContext(this)));
718 if (d->when)
719 d->validate(this);
720 }
721 eval();
722 emit propertyChanged();
723}
724
725/*!
726 \qmlproperty var QtQml::Binding::value
727
728 The value to be set on the target object and property. This can be a
729 constant (which isn't very useful), or a bound expression.
730
731 You only need to use this property if you can't supply the binding target
732 declaratively. Otherwise you can directly bind to the target.
733*/
734QVariant QQmlBind::value() const
735{
736 Q_D(const QQmlBind);
737 if (d->mode == QQmlBindPrivate::ObjectPropertyValue) {
738 Q_ASSERT(d->objectPropertyValueData.entry.currentKind == QQmlBindEntryKind::Variant);
739 QV4::ExecutionEngine *engine = d->objectPropertyValueData.entry.current.v4Value.engine();
740 return engine->toVariant(
741 *d->objectPropertyValueData.entry.current.v4Value.valueRef(), QMetaType());
742
743 }
744 return QVariant();
745}
746
747void QQmlBind::setValue(const QVariant &v)
748{
749 Q_D(QQmlBind);
750 switch (d->mode) {
751 case QQmlBindPrivate::GeneralizedGroup:
752 if (v.isValid())
753 warnIgnoredProperties(this);
754 return;
755 case QQmlBindPrivate::Unknown:
756 if (!v.isValid())
757 return;
758 new (&d->objectPropertyValueData) ObjectPropertyValueData;
759 d->mode = QQmlBindPrivate::ObjectPropertyValue;
760 Q_FALLTHROUGH();
761 case QQmlBindPrivate::ObjectPropertyValue: {
762 QQmlBindEntry *targetEntry = &d->objectPropertyValueData.entry;
763 QQmlEngine *engine = qmlEngine(this);
764 if (!engine) {
765 qWarning() << "QQmlBind must be created in a QML context";
766 return;
767 }
768 targetEntry->currentKind
769 = targetEntry->current.set(engine->handle(), v, targetEntry->currentKind);
770 prepareEval();
771 break;
772 }
773 }
774 emit valueChanged();
775}
776
777/*!
778 \qmlproperty bool QtQml::Binding::delayed
779 \since 5.8
780
781 This property holds whether the binding should be delayed.
782
783 A delayed binding will not immediately update the target, but rather wait
784 until the event queue has been cleared. This can be used as an optimization,
785 or to prevent intermediary values from being assigned.
786
787 \code
788 Binding {
789 contactName.text.value: givenName + " " + familyName
790 when: list.ListView.isCurrentItem
791 delayed: true
792 }
793 \endcode
794
795 \note Using the \l delayed property incurs a run time cost as the Binding
796 element has to create a proxy for the value, so that it can delay its
797 application to the actual target. When using the \l target and
798 \l property properties, this cost is lower because the \l value
799 property can be re-used as proxy. When using the form shown above,
800 Binding will allocate a separate object with a dynamic meta-object to
801 hold the proxy values.
802*/
803bool QQmlBind::delayed() const
804{
805 Q_D(const QQmlBind);
806 return d->delayed;
807}
808
809void QQmlBind::setDelayed(bool delayed)
810{
811 Q_D(QQmlBind);
812 if (d->delayed == delayed)
813 return;
814
815 d->delayed = delayed;
816 if (!d->componentComplete)
817 return;
818
819 if (d->mode == QQmlBindPrivate::GeneralizedGroup) {
820 d->generalizedGroupData.delayedValues.reset();
821
822 QVarLengthArray<QQmlBindEntry, 1> oldEntries = std::move(d->generalizedGroupData.entries);
823 d->generalizedGroupData.entries.clear();
824 d->buildBindEntries(this, nullptr);
825
826 for (qsizetype i = 0, end = oldEntries.size(); i < end; ++i) {
827 QQmlBindEntry &newEntry = d->generalizedGroupData.entries[i];
828 QQmlBindEntry &oldEntry = oldEntries[i];
829 newEntry.previousKind = newEntry.previous.set(
830 std::move(oldEntry.previous), oldEntry.previousKind, newEntry.previousKind);
831 if (d->delayed && oldEntry.currentKind == QQmlBindEntryKind::Binding)
832 QQmlAnyBinding::removeBindingFrom(oldEntry.prop);
833 }
834 }
835
836 if (!d->delayed)
837 eval();
838
839 emit delayedChanged();
840}
841
842/*!
843 \qmlproperty enumeration QtQml::Binding::restoreMode
844 \since 5.14
845
846 This property can be used to describe if and how the original value should
847 be restored when the binding is disabled.
848
849 The possible values are:
850
851 \value Binding.RestoreNone The original value is not restored at all
852 \value Binding.RestoreBinding The original value is restored if it was another binding.
853 In that case the old binding is in effect again.
854 \value Binding.RestoreValue The original value is restored if it was a plain
855 value rather than a binding.
856 \value Binding.RestoreBindingOrValue The original value is always restored.
857
858 The default value is \c Binding.RestoreBindingOrValue.
859
860 \note This property exists for backwards compatibility with earlier versions
861 of Qt. Don't use it in new code.
862*/
863QQmlBind::RestorationMode QQmlBind::restoreMode() const
864{
865 Q_D(const QQmlBind);
866 unsigned result = RestoreNone;
867 if (d->restoreValue)
868 result |= RestoreValue;
869 if (d->restoreBinding)
870 result |= RestoreBinding;
871 return RestorationMode(result);
872}
873
874void QQmlBind::setRestoreMode(RestorationMode newMode)
875{
876 Q_D(QQmlBind);
877 if (newMode != restoreMode()) {
878 d->restoreValue = (newMode & RestoreValue);
879 d->restoreBinding = (newMode & RestoreBinding);
880 emit restoreModeChanged();
881 }
882}
883
884void QQmlBind::setTarget(const QQmlProperty &p)
885{
886 Q_D(QQmlBind);
887 if (QQmlBindEntry *target = d->targetEntry()) {
888 target->setTarget(this, p);
889 return;
890 }
891 qmlWarning(this).nospace()
892 << "You should not use the 'on' syntax for Binding elements with generalized group "
893 "properties. It is ignored.";
894
895}
896
897void QQmlBindEntry::setTarget(QQmlBind *q, const QQmlProperty &p)
898{
899 if (Q_UNLIKELY(lcQtQmlBindingRemoval().isInfoEnabled())) {
900 if (QObject *oldObject = prop.object()) {
901 QMetaProperty metaProp = oldObject->metaObject()->property(prop.index());
902 if (metaProp.hasNotifySignal()) {
903 QByteArray signal('2' + metaProp.notifySignal().methodSignature());
904 QObject::disconnect(oldObject, signal.constData(),
905 q, SLOT(targetValueChanged()));
906 }
907 }
908 p.connectNotifySignal(q, SLOT(targetValueChanged()));
909 }
910
911 prop = p;
912}
913
914void QQmlBind::classBegin()
915{
916 Q_D(QQmlBind);
917 d->componentComplete = false;
918}
919
921 const QQmlProperty &prop, const QV4::CompiledData::Binding *binding,
922 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
923 const QQmlRefPointer<QQmlContextData> &contextData,
924 QObject *scopeObject)
925{
926 switch (binding->type()) {
927 case QV4::CompiledData::Binding::Type_Translation:
928 case QV4::CompiledData::Binding::Type_TranslationById:
929 return QQmlAnyBinding::createTranslationBinding(prop, compilationUnit, binding, scopeObject);
930 case QV4::CompiledData::Binding::Type_Script: {
931 const QQmlBinding::Identifier id = binding->value.compiledScriptIndex;
932 if (id == QQmlBinding::Invalid) {
933 return QQmlAnyBinding::createFromCodeString(
934 prop, compilationUnit->bindingValueAsString(binding), scopeObject,
935 contextData, compilationUnit->finalUrlString(), binding->location.line());
936 }
937 QV4::Scope scope(contextData->engine()->handle());
938 QV4::Scoped<QV4::QmlContext> qmlCtxt(
939 scope, QV4::QmlContext::create(
940 scope.engine->rootContext(), contextData, scopeObject));
941 return QQmlAnyBinding::createFromFunction(
942 prop, compilationUnit->runtimeFunctions.at(id), scopeObject, contextData,
943 qmlCtxt);
944 }
945 default:
946 break;
947 }
948 return QQmlAnyBinding();
949}
950
951static void initCreator(
952 QQmlData::DeferredData *deferredData,
953 const QQmlRefPointer<QQmlContextData> &contextData,
954 QQmlComponentPrivate::ConstructionState *immediateState)
955{
956 if (!immediateState->hasCreator()) {
957 immediateState->setCompletePending(true);
958 immediateState->initCreator(
959 deferredData->context->parent(), deferredData->compilationUnit,
960 contextData, deferredData->inlineComponentName);
961 immediateState->creator()->beginPopulateDeferred(deferredData->context);
962 }
963}
964
965void QQmlBindPrivate::decodeBinding(
966 QQmlBind *q, const QString &propertyPrefix,
967 QQmlData::DeferredData *deferredData,
968 const QV4::CompiledData::Binding *binding,
969 QQmlComponentPrivate::ConstructionState *immediateState)
970{
971 const QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
972 = deferredData->compilationUnit;
973 const QString propertySuffix = compilationUnit->stringAt(binding->propertyNameIndex);
974 const QString propertyName = propertyPrefix + propertySuffix;
975
976 switch (binding->type()) {
977 case QV4::CompiledData::Binding::Type_AttachedProperty:
978 if (propertyPrefix.isEmpty()) {
979 // Top-level attached properties cannot be generalized grouped properties.
980 // Treat them as regular properties.
981 // ... unless we're not supposed to handle regular properties. Then ignore them.
982 if (!immediateState)
983 return;
984
985 Q_ASSERT(compilationUnit->stringAt(compilationUnit->objectAt(binding->value.objectIndex)
986 ->inheritedTypeNameIndex).isEmpty());
987
988 const QV4::ResolvedTypeReference *typeReference
989 = compilationUnit->resolvedType(binding->propertyNameIndex);
990 Q_ASSERT(typeReference);
991 QQmlType attachedType = typeReference->type();
992 if (!attachedType.isValid()) {
993 if (QQmlTypeLoader *typeLoader = compilationUnit->engine->typeLoader()) {
994 const QQmlTypeNameCache::Result result
995 = deferredData->context->imports()->query(propertySuffix, typeLoader);
996 if (!result.isValid()) {
997 qmlWarning(q).nospace()
998 << "Unknown name " << propertySuffix << ". The binding is ignored.";
999 return;
1000 }
1001 attachedType = result.type;
1002 }
1003 }
1004
1005 QQmlContext *context = qmlContext(q);
1006 QObject *attachedObject = qmlAttachedPropertiesObject(
1007 q, attachedType.attachedPropertiesFunction(QQmlTypeLoader::get(context->engine())));
1008 if (!attachedObject) {
1009 qmlWarning(q).nospace() <<"Could not create attached properties object '"
1010 << attachedType.typeName() << "'";
1011 return;
1012 }
1013
1014 initCreator(deferredData, QQmlContextData::get(context), immediateState);
1015 immediateState->creator()->populateDeferredInstance(
1016 q, deferredData->deferredIdx, binding->value.objectIndex, attachedObject,
1017 attachedObject, /*value type property*/ nullptr, binding);
1018 return;
1019 }
1020 Q_FALLTHROUGH();
1021 case QV4::CompiledData::Binding::Type_GroupProperty: {
1022 const QString pre = propertyName + u'.';
1023 const QV4::CompiledData::Object *subObj
1024 = compilationUnit->objectAt(binding->value.objectIndex);
1025 const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
1026 for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding)
1027 decodeBinding(q, pre, deferredData, subBinding, immediateState);
1028 return;
1029 }
1030 default:
1031 break;
1032 }
1033
1034 QQmlBindEntry entry;
1035 QQmlContext *context = qmlContext(q);
1036 const QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
1037 entry.prop = QQmlPropertyPrivate::create(nullptr, propertyName, contextData,
1038 QQmlPropertyPrivate::InitFlag::AllowId);
1039 if (!entry.prop.isValid()) {
1040 // Try again in the context of this object. If that works, it's a regular property.
1041 // ... unless we're not supposed to handle regular properties. Then ignore it.
1042 if (!immediateState)
1043 return;
1044
1045 QQmlProperty property = QQmlPropertyPrivate::create(
1046 q, propertyName, contextData, QQmlPropertyPrivate::InitFlag::AllowSignal);
1047 if (property.isValid()) {
1048 initCreator(deferredData, contextData, immediateState);
1049 immediateState->creator()->populateDeferredBinding(
1050 property, deferredData->deferredIdx, binding);
1051 } else {
1052 qmlWarning(q).nospace() << "Unknown name " << propertyName
1053 << ". The binding is ignored.";
1054 }
1055 return;
1056 }
1057
1058 switch (mode) {
1059 case GeneralizedGroup:
1060 break;
1061 case ObjectPropertyValue:
1062 warnIgnoredProperties(q);
1063 objectPropertyValueData.~ObjectPropertyValueData();
1064 Q_FALLTHROUGH();
1065 case Unknown:
1066 new (&generalizedGroupData) GeneralizedGroupData;
1067 mode = GeneralizedGroup;
1068 break;
1069 }
1070
1071 const auto setVariant = [&entry](QV4::PersistentValue value) {
1072 entry.currentKind = entry.current.setVariant(value, entry.currentKind);
1073 };
1074
1075 const auto setBinding = [&entry](QQmlAnyBinding binding) {
1076 entry.currentKind = entry.current.set(binding, entry.currentKind);
1077 };
1078
1079 switch (binding->type()) {
1080 case QV4::CompiledData::Binding::Type_AttachedProperty:
1081 case QV4::CompiledData::Binding::Type_GroupProperty:
1082 Q_UNREACHABLE(); // Handled above
1083 break;
1084 case QV4::CompiledData::Binding::Type_Translation:
1085 case QV4::CompiledData::Binding::Type_TranslationById:
1086 case QV4::CompiledData::Binding::Type_Script:
1087 if (delayed) {
1088 if (!generalizedGroupData.delayedValues)
1089 createDelayedValues();
1090 const QString delayedName = QString::number(generalizedGroupData.entries.size());
1091 generalizedGroupData.delayedValues->insert(delayedName, QVariant());
1092 QQmlProperty bindingTarget
1093 = QQmlProperty(generalizedGroupData.delayedValues.get(), delayedName);
1094 Q_ASSERT(bindingTarget.isValid());
1095 QQmlAnyBinding anyBinding = createBinding(
1096 bindingTarget, binding, compilationUnit, contextData, q);
1097 anyBinding.installOn(bindingTarget);
1098 } else {
1099 setBinding(createBinding(entry.prop, binding, compilationUnit, contextData, q));
1100 }
1101 break;
1102 case QV4::CompiledData::Binding::Type_String:
1103 setVariant(QV4::PersistentValue(
1104 compilationUnit->engine,
1105 compilationUnit->runtimeStrings[binding->stringIndex]->asReturnedValue()));
1106 break;
1107 case QV4::CompiledData::Binding::Type_Number:
1108 setVariant(QV4::PersistentValue(
1109 compilationUnit->engine,
1110 compilationUnit->constants[binding->value.constantValueIndex].asReturnedValue()));
1111 break;
1112 case QV4::CompiledData::Binding::Type_Boolean:
1113 setVariant(QV4::PersistentValue(compilationUnit->engine, QV4::Encode(binding->value.b)));
1114 break;
1115 case QV4::CompiledData::Binding::Type_Null:
1116 setVariant(QV4::PersistentValue(compilationUnit->engine, QV4::Encode::null()));
1117 break;
1118 case QV4::CompiledData::Binding::Type_Object:
1119 case QV4::CompiledData::Binding::Type_Invalid:
1120 break;
1121 }
1122
1123 generalizedGroupData.entries.append(std::move(entry));
1124}
1125
1127{
1128 generalizedGroupData.delayedValues.reset(QQmlPropertyMap::create());
1129 QQmlPropertyMap *delayedValues = generalizedGroupData.delayedValues.get();
1130 QObject::connect(
1131 delayedValues, &QQmlPropertyMap::valueChanged,
1132 delayedValues, [this](QString delayedName, const QVariant &value) {
1133 Q_UNUSED(value);
1134 onDelayedValueChanged(std::move(delayedName));
1135 }
1136 );
1137}
1138
1139void QQmlBindPrivate::onDelayedValueChanged(QString delayedName)
1140{
1141 Q_ASSERT(delayed);
1142 Q_ASSERT(mode == GeneralizedGroup);
1143 QQmlPropertyMap *delayedValues = generalizedGroupData.delayedValues.get();
1144 Q_ASSERT(delayedValues);
1145 const QString pendingName = QStringLiteral("pending");
1146 QStringList pending = qvariant_cast<QStringList>((*delayedValues)[pendingName]);
1147 if (componentComplete && pending.size() == 0)
1148 QTimer::singleShot(0, delayedValues, [this]() { evalDelayed(); });
1149 else if (pending.contains(delayedName))
1150 return;
1151
1152 pending.append(std::move(delayedName));
1153 (*delayedValues)[pendingName].setValue(std::move(pending));
1154}
1155
1157{
1158 Q_ASSERT(mode == GeneralizedGroup);
1159 QQmlPropertyMap *delayedValues = generalizedGroupData.delayedValues.get();
1160 if (!when || !delayedValues)
1161 return;
1162
1163 const QString pendingName = QStringLiteral("pending");
1164 const QStringList pending = qvariant_cast<QStringList>((*delayedValues)[pendingName]);
1165 for (const QString &delayedName : pending) {
1166 bool ok;
1167 const int delayedIndex = delayedName.toInt(&ok);
1168 Q_ASSERT(ok);
1169 Q_ASSERT(delayedIndex >= 0 && delayedIndex < generalizedGroupData.entries.size());
1170 generalizedGroupData.entries[delayedIndex].prop.write((*delayedValues)[delayedName]);
1171 }
1172 (*delayedValues)[pendingName].setValue(QStringList());
1173}
1174
1175void QQmlBindPrivate::buildBindEntries(QQmlBind *q, QQmlComponentPrivate::DeferredState *deferredState)
1176{
1177 QQmlData *data = QQmlData::get(q);
1178 if (data && !data->deferredData.isEmpty()) {
1179 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
1180 for (QQmlData::DeferredData *deferredData : data->deferredData) {
1181 QMultiHash<int, const QV4::CompiledData::Binding *> *bindings = &deferredData->bindings;
1182 if (deferredState) {
1183 QQmlComponentPrivate::ConstructionState constructionState;
1184 for (auto it = bindings->cbegin(); it != bindings->cend(); ++it)
1185 decodeBinding(q, QString(), deferredData, *it, &constructionState);
1186
1187
1188 if (constructionState.hasCreator()) {
1189 ++ep->inProgressCreations;
1190 constructionState.creator()->finalizePopulateDeferred();
1191 constructionState.appendCreatorErrors();
1192 deferredState->push_back(std::move(constructionState));
1193 }
1194 } else {
1195 for (auto it = bindings->cbegin(); it != bindings->cend(); ++it)
1196 decodeBinding(q, QString(), deferredData, *it, nullptr);
1197 }
1198 }
1199
1200 if (deferredState) {
1201 data->releaseDeferredData();
1202 if (!deferredState->empty())
1203 QQmlComponentPrivate::completeDeferred(ep, deferredState);
1204 }
1205 }
1206}
1207
1208void QQmlBind::componentComplete()
1209{
1210 Q_D(QQmlBind);
1211 QQmlComponentPrivate::DeferredState deferredState;
1212 d->buildBindEntries(this, &deferredState);
1213 d->componentComplete = true;
1214 if (d->mode == QQmlBindPrivate::ObjectPropertyValue) {
1215 QQmlBindEntry *target = d->targetEntry();
1216 if (!target->prop.isValid()) {
1217 target->setTarget(this, QQmlProperty(
1218 d->objectPropertyValueData.obj,
1219 d->objectPropertyValueData.propName, qmlContext(this)));
1220 }
1221 }
1222 d->validate(this);
1223 if (d->mode == QQmlBindPrivate::GeneralizedGroup)
1224 d->evalDelayed();
1225 eval();
1226}
1227
1228void QQmlBind::prepareEval()
1229{
1230 Q_D(QQmlBind);
1231 if (d->delayed) {
1232 if (!d->pendingEval)
1233 QTimer::singleShot(0, this, &QQmlBind::eval);
1234 d->pendingEval = true;
1235 } else {
1236 eval();
1237 }
1238}
1239
1241{
1242 previousKind = previous.destroy(previousKind);
1243}
1244
1246{
1247 switch (entry->currentKind) {
1248 case QQmlBindEntryKind::V4Value: {
1249 auto propPriv = QQmlPropertyPrivate::get(entry->prop);
1250 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
1251 Q_ASSERT(vmemo);
1252 return QV4::RuntimeHelpers::strictEqual(
1253 // fromReturnedValue is OK here because strictEqual will not allocate
1254 QV4::Value::fromReturnedValue(vmemo->vmeProperty(propPriv->core.coreIndex())),
1255 *entry->current.v4Value.valueRef());
1256 }
1257 case QQmlBindEntryKind::Variant: {
1258 const QV4::PersistentValue &v4Value = entry->current.v4Value;
1259 QMetaType propMetaType = entry->prop.propertyMetaType();
1260 /*
1261 * We currently really want to use toVariant here, and not metaTypeFromJS.
1262 * metaTypeFromJS can't do all conversions, and would leave us with an
1263 * empty QVariant if it fails; whereas toVariant tries very hard to give
1264 * us a QVariant representation, even though its type might not match the
1265 * property's meta-type. In case of an actual mismatch, we use
1266 * convertToWriteTargetType to mirror the conversions that writing to a
1267 * property would have done; with the exception of list properties, where
1268 * we directly go through a specialized code path using
1269 * QQmlPropertyPrivate::convertToQQmlListProperty
1270 */
1271 QVariant valueAsVariant = v4Value.engine()->toVariant(*v4Value.valueRef(),
1272 propMetaType);
1273 if (propMetaType.flags() & QMetaType::IsQmlList) {
1274 // our expected value is not necessarily of the correct type, so we copy the steps done by
1275 // QQmlPropertyPrivate::write to bring them into the correct format
1276 QList<QObject *> expectedObjectList;
1277 QQmlListProperty<QObject> expectedAsListProp(nullptr, &expectedObjectList);
1278 QQmlPropertyPrivate::convertToQQmlListProperty(&expectedAsListProp, propMetaType, valueAsVariant);
1279
1280 QVariant actualValue = entry->prop.read();
1281 // reading a QQmlListProperty property yields a QQmlListReference
1282 QQmlListReference* listReference = get_if<QQmlListReference>(&actualValue);
1283 Q_ASSERT(listReference);
1284 auto actualObjectList = QQmlListReferencePrivate::get(listReference)->property.toList<QList<QObject *>>();
1285 return std::equal(expectedObjectList.constBegin(), expectedObjectList.constEnd(),
1286 actualObjectList.constBegin(), actualObjectList.constEnd());
1287
1288 } else if (QMetaType varMetaType = valueAsVariant.metaType(); varMetaType != propMetaType) {
1289 QVariant converted = QQmlPropertyPrivate::convertToWriteTargetType(
1290 valueAsVariant, propMetaType);
1291 if (converted.isValid())
1292 valueAsVariant = std::move(converted);
1293 }
1294 return valueAsVariant
1295 == entry->prop.read();
1296 }
1297 case QQmlBindEntryKind::Binding:
1298 return entry->current.binding == QQmlAnyBinding::ofProperty(entry->prop);
1299 case QQmlBindEntryKind::None:
1300 break;
1301 }
1302
1303 return false;
1304}
1305
1307{
1308 if (!entry->prop.isValid() || (entry->currentKind == QQmlBindEntryKind::None))
1309 return;
1310 if (!entry->prop.object())
1311 return; // if the target is already gone, we can't do anything
1312
1313 if (!when) {
1314 if (!isCurrent(entry)) {
1315 entry->clearPrev();
1316 return;
1317 }
1318
1319 //restore any previous binding
1320 switch (entry->previousKind) {
1321 case QQmlBindEntryKind::Binding:
1322 if (restoreBinding) {
1323 QQmlAnyBinding p = std::move(entry->previous.binding);
1324 entry->clearPrev(); // Do that before setBinding(), as setBinding() may recurse.
1325 p.installOn(entry->prop);
1326 }
1327 break;
1328 case QQmlBindEntryKind::V4Value:
1329 if (restoreValue) {
1330 QQmlAnyBinding::takeFrom(entry->prop); // we don't want to have a binding active
1331 auto propPriv = QQmlPropertyPrivate::get(entry->prop);
1332 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
1333 Q_ASSERT(vmemo);
1334 vmemo->setVMEProperty(propPriv->core.coreIndex(),
1335 *entry->previous.v4Value.valueRef());
1336 entry->clearPrev();
1337 }
1338 break;
1339 case QQmlBindEntryKind::Variant:
1340 if (restoreValue) {
1341 QQmlAnyBinding::takeFrom(entry->prop); // we don't want to have a binding active
1342 const QV4::PersistentValue &v4Value = entry->previous.v4Value;
1343 entry->prop.write(v4Value.engine()->toVariant(
1344 *v4Value.valueRef(), entry->prop.propertyMetaType()));
1345 entry->clearPrev();
1346 }
1347 break;
1348 case QQmlBindEntryKind::None:
1349 break;
1350 }
1351 return;
1352 }
1353
1354 //save any set binding for restoration
1355 if (entry->previousKind == QQmlBindEntryKind::None) {
1356 // try binding first; we need to use takeFrom to properly unlink the binding
1357 QQmlAnyBinding prevBind = QQmlAnyBinding::takeFrom(entry->prop);
1358 if (prevBind) {
1359 entry->previousKind = entry->previous.set(std::move(prevBind), entry->previousKind);
1360 } else {
1361 // nope, try a V4 value next
1362 auto propPriv = QQmlPropertyPrivate::get(entry->prop);
1363 auto propData = propPriv->core;
1364 if (!propPriv->valueTypeData.isValid() && propData.isVarProperty()) {
1365 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
1366 Q_ASSERT(vmemo);
1367 auto retVal = vmemo->vmeProperty(propData.coreIndex());
1368 entry->previousKind = entry->previous.set(
1369 QV4::PersistentValue(vmemo->engine, retVal), entry->previousKind);
1370 } else if (entry->prop.propertyMetaType().flags() & QMetaType::IsQmlList) {
1371 using namespace QV4;
1372 ExecutionEngine *v4 = qmlEngine(q_func())->handle();
1373 entry->previousKind = entry->previous.setVariant(
1374 QV4::PersistentValue(v4, QV4::QmlListWrapper::createOwned(v4, entry->prop)),
1375 entry->previousKind);
1376
1377 } else {
1378 // nope, use the meta object to get a QVariant
1379 entry->previousKind = entry->previous.set(
1380 propPriv->engine->handle(), entry->prop.read(), entry->previousKind);
1381 }
1382 }
1383 }
1384
1385 // NOTE: removeBinding has no effect on QProperty classes, but
1386 // we already used takeBinding to remove it
1387 QQmlPropertyPrivate::removeBinding(entry->prop, QQmlPropertyPrivate::OverrideSticky);
1388}
1389
1391{
1392 if (!entry->prop.isValid())
1393 return;
1394 switch (entry->currentKind) {
1395 case QQmlBindEntryKind::Variant: {
1396 const QV4::PersistentValue &v4Value = entry->current.v4Value;
1397 entry->prop.write(
1398 v4Value.engine()->toVariant(*v4Value.valueRef(), entry->prop.propertyMetaType()));
1399 break;
1400 }
1401 case QQmlBindEntryKind::Binding:
1402 Q_ASSERT(!delayed);
1403 entry->current.binding.installOn(entry->prop);
1404 break;
1405 case QQmlBindEntryKind::V4Value: {
1406 auto propPriv = QQmlPropertyPrivate::get(entry->prop);
1407 QQmlVMEMetaObject::get(propPriv->object)->setVMEProperty(
1408 propPriv->core.coreIndex(), *entry->current.v4Value.valueRef());
1409 break;
1410 }
1411 case QQmlBindEntryKind::None:
1412 break;
1413 }
1414}
1415
1416void QQmlBind::eval()
1417{
1418 Q_D(QQmlBind);
1419 d->pendingEval = false;
1420 if (!d->componentComplete)
1421 return;
1422
1423 switch (d->mode) {
1424 case QQmlBindPrivate::GeneralizedGroup:
1425 for (QQmlBindEntry &entry : d->generalizedGroupData.entries)
1426 d->preEvalEntry(&entry);
1427 break;
1428 case QQmlBindPrivate::ObjectPropertyValue:
1429 d->preEvalEntry(&d->objectPropertyValueData.entry);
1430 break;
1431 case QQmlBindPrivate::Unknown:
1432 break;
1433 }
1434
1435 if (!d->when)
1436 return;
1437
1438 d->writingProperty = true;
1439 switch (d->mode) {
1440 case QQmlBindPrivate::GeneralizedGroup:
1441 for (QQmlBindEntry &entry : d->generalizedGroupData.entries)
1442 d->postEvalEntry(&entry);
1443 break;
1444 case QQmlBindPrivate::ObjectPropertyValue:
1445 d->postEvalEntry(&d->objectPropertyValueData.entry);
1446 break;
1447 case QQmlBindPrivate::Unknown:
1448 break;
1449 }
1450 d->writingProperty = false;
1451}
1452
1453void QQmlBind::targetValueChanged()
1454{
1455 Q_D(QQmlBind);
1456 if (d->writingProperty)
1457 return;
1458
1459 if (!d->when)
1460 return;
1461
1462 QUrl url;
1463 quint16 line = 0;
1464
1465 const QQmlData *ddata = QQmlData::get(this, false);
1466 if (ddata && ddata->outerContext) {
1467 url = ddata->outerContext->url();
1468 line = ddata->lineNumber;
1469 }
1470
1471 qCInfo(lcQtQmlBindingRemoval,
1472 "The target property of the Binding element created at %s:%d was changed from "
1473 "elsewhere. This does not overwrite the binding. The target property will still be "
1474 "updated when the value of the Binding element changes.",
1475 qPrintable(url.toString()), line);
1476}
1477
1478QT_END_NAMESPACE
1479
1480#include "moc_qqmlbind_p.cpp"
void validate(QQmlBind *binding) const
Definition qqmlbind.cpp:361
GeneralizedGroupData generalizedGroupData
Definition qqmlbind.cpp:276
void postEvalEntry(QQmlBindEntry *entry)
QQmlBindEntry * targetEntry()
Definition qqmlbind.cpp:345
void onDelayedValueChanged(QString delayedName)
void decodeBinding(QQmlBind *q, const QString &propertyPrefix, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding, QQmlComponentPrivate::ConstructionState *immediateState)
Definition qqmlbind.cpp:965
bool isCurrent(QQmlBindEntry *entry) const
void preEvalEntry(QQmlBindEntry *entry)
void buildBindEntries(QQmlBind *q, QQmlComponentPrivate::DeferredState *deferredState)
void createDelayedValues()
ObjectPropertyValueData objectPropertyValueData
Definition qqmlbind.cpp:277
Combined button and popup list for selecting options.
static void warnIgnoredProperties(QQmlBind *q)
Definition qqmlbind.cpp:330
static void initCreator(QQmlData::DeferredData *deferredData, const QQmlRefPointer< QQmlContextData > &contextData, QQmlComponentPrivate::ConstructionState *immediateState)
Definition qqmlbind.cpp:951
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:920
std::unique_ptr< QQmlPropertyMap > delayedValues
Definition qqmlbind.cpp:237
QVarLengthArray< QQmlBindEntry, 1 > entries
Definition qqmlbind.cpp:232
QPointer< QObject > obj
Definition qqmlbind.cpp:222
QQmlBindEntryKind previousKind
Definition qqmlbind.cpp:209
QQmlBindEntry(const QQmlBindEntry &other)
Definition qqmlbind.cpp:171
QQmlBindEntry & operator=(QQmlBindEntry &&other) noexcept
Definition qqmlbind.cpp:184
QQmlProperty prop
Definition qqmlbind.cpp:207
void setTarget(QQmlBind *q, const QQmlProperty &p)
Definition qqmlbind.cpp:897
QQmlBindEntryKind currentKind
Definition qqmlbind.cpp:208
QQmlBindEntry & operator=(const QQmlBindEntry &other)
Definition qqmlbind.cpp:194
QQmlBindEntryContent current
Definition qqmlbind.cpp:205
QQmlBindEntryContent previous
Definition qqmlbind.cpp:206
void validate(QQmlBind *q) const
Definition qqmlbind.cpp:337
QQmlBindEntry(QQmlBindEntry &&other) noexcept
Definition qqmlbind.cpp:165
QQmlBindEntry()=default
QQmlAnyBinding binding
Definition qqmlbind.cpp:142