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 targetProperty: if (mouse.pressed) mouse.mouseX
428 \endqml
429
430 The Binding type can prevent this warning.
431
432 \qml
433 Binding on targetProperty {
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 However, the binding to \c{Binding}'s \l{value} property is still evaluated
443 unconditionally, even when \c{when} is \c{false}.
444
445 This might cause warnings when the Binding is for example used to guard
446 against a value being \c{null}:
447
448 \qml
449 Binding on targetProperty {
450 when: root.object !== null
451 // produces warning: "TypeError: Cannot read property 'someProperty' of null"
452 value: root.object.someProperty
453 }
454 \endqml
455
456 There are to ways to avoid this issue:
457 \list
458 \li If the target has an \c id, you can use the syntax described in
459 \l{Multiple targets in one Binding}, which also causes the
460 binding expression to only run when the \c{Binding} is enabled:
461 \qml
462 Binding {
463 when: root.object !== null
464 root.targetProperty: root.object.someProperty
465 }
466 \endqml
467
468 \li You can repeat the check in the binding and return early:
469 \qml
470 Binding on targetProperty {
471 when: root.object !== null
472 value: {
473 if (root.object === null)
474 return
475 return root.object.someProperty
476 }
477 }
478 \endqml
479 \endlist
480 \section1 Multiple targets in one Binding
481
482 You can specify multiple bindings to the same object in one Binding element:
483
484 \qml
485 Text {
486 id: t1
487 }
488
489 Binding {
490 t1 {
491 color: "#00FF00"
492 text: "green text"
493 }
494 }
495 \endqml
496
497 You can also specify several bindings with different target objects in a
498 single Binding element:
499
500 \qml
501 Text {
502 id: t1
503 }
504
505 Text {
506 id: t2
507 }
508
509 Binding {
510 t1.text: "Foo"
511 t2.text: "Bar"
512 }
513 \endqml
514
515 \sa {Qt Qml}
516*/
517QQmlBind::QQmlBind(QObject *parent)
518 : QObject(*(new QQmlBindPrivate), parent)
519{
520}
521
522QQmlBind::~QQmlBind()
523{
524 Q_D(QQmlBind);
525 // restore state when dynamic Binding is destroyed
526 if (!(d->when && d->componentComplete && restoreMode() != RestoreNone))
527 return;
528 // isDeletingChildren is supposed to happen later; we couldn't use declarativeData
529 // if isDeletingChildren were set
530 Q_ASSERT(!d->isDeletingChildren);
531 // We can't use qmlEngine (or QQmlData::get), as that checks for scheduled deletion
532 if (auto ddata = static_cast<QQmlData *>(d->declarativeData);
533 ddata && ddata->context && QQmlData::wasDeleted(ddata->context->engine()))
534 return; // whole engine is going away; don't bother resetting
535 d->when = false; // internal only change, no signal emission
536 eval();
537}
538
539/*!
540 \qmlproperty bool QtQml::Binding::when
541
542 This property holds when the binding is active.
543 This should be set to an expression that evaluates to true when you want the binding to be active.
544
545 \qml
546 Binding {
547 contactName.text: name
548 when: list.ListView.isCurrentItem
549 }
550 \endqml
551
552 By default, any binding or value that was set perviously is restored when the binding becomes
553 inactive. You can customize the restoration behavior using the \l restoreMode property.
554
555 \sa restoreMode
556*/
557bool QQmlBind::when() const
558{
559 Q_D(const QQmlBind);
560 return d->when;
561}
562
563void QQmlBind::setWhen(bool v)
564{
565 Q_D(QQmlBind);
566 if (d->when == v)
567 return;
568
569 d->when = v;
570 if (v && d->componentComplete)
571 d->validate(this);
572 eval();
573 emit whenChanged();
574}
575
576/*!
577 \qmlproperty QtObject QtQml::Binding::target
578
579 The object to be updated. You need to use this property if the binding target
580 does not have an \c id attribute (for example, when the target is a singleton).
581 Otherwise, the following two pieces of code are equivalent:
582
583 \qml
584 Binding { contactName.text: name }
585 \endqml
586
587 \qml
588 Binding {
589 target: contactName
590 property: "text"
591 value: name
592 }
593 \endqml
594
595 The former one is much more compact, but you cannot replace the target
596 object or property at run time. With the latter one you can.
597*/
598QObject *QQmlBind::object() const
599{
600 Q_D(const QQmlBind);
601 switch (d->mode) {
602 case QQmlBindPrivate::GeneralizedGroup:
603 case QQmlBindPrivate::Unknown:
604 return nullptr;
605 case QQmlBindPrivate::ObjectPropertyValue:
606 return d->objectPropertyValueData.obj;
607 }
608
609 Q_UNREACHABLE_RETURN(nullptr);
610}
611
612void QQmlBind::setObject(QObject *obj)
613{
614 Q_D(QQmlBind);
615 switch (d->mode) {
616 case QQmlBindPrivate::GeneralizedGroup:
617 if (obj != nullptr)
618 warnIgnoredProperties(this);
619 return;
620 case QQmlBindPrivate::ObjectPropertyValue:
621 if (d->objectPropertyValueData.obj == obj)
622 return;
623 break;
624 case QQmlBindPrivate::Unknown:
625 if (obj == nullptr)
626 return;
627 new (&d->objectPropertyValueData) ObjectPropertyValueData;
628 d->mode = QQmlBindPrivate::ObjectPropertyValue;
629 break;
630 }
631
632 if (d->when) {
633 /* if we switch the object at runtime, we need to restore the
634 previous binding on the old object before continuing */
635 d->when = false;
636 eval();
637 d->when = true;
638 }
639 /* if "when" and "target" depend on the same property, we might
640 end up here before we could have updated "when". So reevaluate
641 when manually here.
642 */
643 const QQmlProperty whenProp(this, QLatin1StringView("when"));
644 const auto potentialWhenBinding = QQmlAnyBinding::ofProperty(whenProp);
645 if (auto abstractBinding = potentialWhenBinding.asAbstractBinding()) {
646 QQmlBinding *binding = static_cast<QQmlBinding *>(abstractBinding);
647 if (binding->hasValidContext()) {
648 const auto boolType = QMetaType::fromType<bool>();
649 bool when;
650 binding->evaluate(&when, boolType);
651 if (when != d->when) {
652 d->when = when;
653 emit whenChanged();
654 }
655 }
656 }
657
658 switch (d->mode) {
659 case QQmlBindPrivate::GeneralizedGroup:
660 case QQmlBindPrivate::Unknown:
661 Q_UNREACHABLE();
662 return;
663 case QQmlBindPrivate::ObjectPropertyValue:
664 d->objectPropertyValueData.obj = obj;
665 if (d->componentComplete) {
666 setTarget(QQmlProperty(
667 d->objectPropertyValueData.obj, d->objectPropertyValueData.propName,
668 qmlContext(this)));
669 }
670 break;
671 }
672
673 if (d->componentComplete && d->when)
674 d->validate(this);
675
676 eval();
677 emit objectChanged();
678}
679
680/*!
681 \qmlproperty string QtQml::Binding::property
682
683 The property to be updated.
684
685 This can be a group property if the expression results in accessing a
686 property of a \l {QML Value Types}{value type}. For example:
687
688 \qml
689 Item {
690 id: item
691
692 property rect rectangle: Qt.rect(0, 0, 200, 200)
693 }
694
695 Binding {
696 target: item
697 property: "rectangle.x"
698 value: 100
699 }
700 \endqml
701
702 You only need to use this property if you can't supply the binding target
703 declaratively. The following snippet of code is equivalent to the above
704 binding, but more compact:
705
706 \qml
707 Binding { item.rectangle.x: 100 }
708 \endqml
709*/
710QString QQmlBind::property() const
711{
712 Q_D(const QQmlBind);
713 switch (d->mode) {
714 case QQmlBindPrivate::GeneralizedGroup:
715 case QQmlBindPrivate::Unknown:
716 return QString();
717 case QQmlBindPrivate::ObjectPropertyValue:
718 return d->objectPropertyValueData.propName;
719 }
720
721 Q_UNREACHABLE_RETURN(QString());
722}
723
724void QQmlBind::setProperty(const QString &p)
725{
726 Q_D(QQmlBind);
727 switch (d->mode) {
728 case QQmlBindPrivate::GeneralizedGroup:
729 if (!p.isEmpty())
730 warnIgnoredProperties(this);
731 return;
732 case QQmlBindPrivate::ObjectPropertyValue:
733 if (d->objectPropertyValueData.propName == p)
734 return;
735 break;
736 case QQmlBindPrivate::Unknown:
737 if (p.isEmpty())
738 return;
739 new (&d->objectPropertyValueData) ObjectPropertyValueData;
740 d->mode = QQmlBindPrivate::ObjectPropertyValue;
741 break;
742 }
743
744 if (!d->objectPropertyValueData.propName.isEmpty() && d->when) {
745 /* if we switch the property name at runtime, we need to restore the
746 previous binding on the old object before continuing */
747 d->when = false;
748 eval();
749 d->when = true;
750 }
751 d->objectPropertyValueData.propName = p;
752 if (d->componentComplete) {
753 setTarget(QQmlProperty(
754 d->objectPropertyValueData.obj, d->objectPropertyValueData.propName,
755 qmlContext(this)));
756 if (d->when)
757 d->validate(this);
758 }
759 eval();
760 emit propertyChanged();
761}
762
763/*!
764 \qmlproperty var QtQml::Binding::value
765
766 The value to be set on the target object and property. This can be a
767 constant (which isn't very useful), or a bound expression.
768
769 You only need to use this property if you can't supply the binding target
770 declaratively. Otherwise you can directly bind to the target.
771*/
772QVariant QQmlBind::value() const
773{
774 Q_D(const QQmlBind);
775 if (d->mode == QQmlBindPrivate::ObjectPropertyValue) {
776 Q_ASSERT(d->objectPropertyValueData.entry.currentKind == QQmlBindEntryKind::Variant);
777 QV4::ExecutionEngine *engine = d->objectPropertyValueData.entry.current.v4Value.engine();
778 return engine->toVariant(
779 *d->objectPropertyValueData.entry.current.v4Value.valueRef(), QMetaType());
780
781 }
782 return QVariant();
783}
784
785void QQmlBind::setValue(const QVariant &v)
786{
787 Q_D(QQmlBind);
788 switch (d->mode) {
789 case QQmlBindPrivate::GeneralizedGroup:
790 if (v.isValid())
791 warnIgnoredProperties(this);
792 return;
793 case QQmlBindPrivate::Unknown:
794 if (!v.isValid())
795 return;
796 new (&d->objectPropertyValueData) ObjectPropertyValueData;
797 d->mode = QQmlBindPrivate::ObjectPropertyValue;
798 Q_FALLTHROUGH();
799 case QQmlBindPrivate::ObjectPropertyValue: {
800 QQmlBindEntry *targetEntry = &d->objectPropertyValueData.entry;
801 QQmlEngine *engine = qmlEngine(this);
802 if (!engine) {
803 qWarning() << "QQmlBind must be created in a QML context";
804 return;
805 }
806 targetEntry->currentKind
807 = targetEntry->current.set(engine->handle(), v, targetEntry->currentKind);
808 prepareEval();
809 break;
810 }
811 }
812 emit valueChanged();
813}
814
815/*!
816 \qmlproperty bool QtQml::Binding::delayed
817 \since 5.8
818
819 This property holds whether the binding should be delayed.
820
821 A delayed binding will not immediately update the target, but rather wait
822 until the event queue has been cleared. This can be used as an optimization,
823 or to prevent intermediary values from being assigned.
824
825 \code
826 Binding {
827 contactName.text.value: givenName + " " + familyName
828 when: list.ListView.isCurrentItem
829 delayed: true
830 }
831 \endcode
832
833 \note Using the \l delayed property incurs a run time cost as the Binding
834 element has to create a proxy for the value, so that it can delay its
835 application to the actual target. When using the \l target and
836 \l property properties, this cost is lower because the \l value
837 property can be re-used as proxy. When using the form shown above,
838 Binding will allocate a separate object with a dynamic meta-object to
839 hold the proxy values.
840*/
841bool QQmlBind::delayed() const
842{
843 Q_D(const QQmlBind);
844 return d->delayed;
845}
846
847void QQmlBind::setDelayed(bool delayed)
848{
849 Q_D(QQmlBind);
850 if (d->delayed == delayed)
851 return;
852
853 d->delayed = delayed;
854 if (!d->componentComplete)
855 return;
856
857 if (d->mode == QQmlBindPrivate::GeneralizedGroup) {
858 d->generalizedGroupData.delayedValues.reset();
859
860 QVarLengthArray<QQmlBindEntry, 1> oldEntries = std::move(d->generalizedGroupData.entries);
861 d->generalizedGroupData.entries.clear();
862 d->buildBindEntries(this, nullptr);
863
864 for (qsizetype i = 0, end = oldEntries.size(); i < end; ++i) {
865 QQmlBindEntry &newEntry = d->generalizedGroupData.entries[i];
866 QQmlBindEntry &oldEntry = oldEntries[i];
867 newEntry.previousKind = newEntry.previous.set(
868 std::move(oldEntry.previous), oldEntry.previousKind, newEntry.previousKind);
869 if (d->delayed && oldEntry.currentKind == QQmlBindEntryKind::Binding)
870 QQmlAnyBinding::removeBindingFrom(oldEntry.prop);
871 }
872 }
873
874 if (!d->delayed)
875 eval();
876
877 emit delayedChanged();
878}
879
880/*!
881 \qmlproperty enumeration QtQml::Binding::restoreMode
882 \since 5.14
883
884 This property can be used to describe if and how the original value should
885 be restored when the binding is disabled.
886
887 The possible values are:
888
889 \value Binding.RestoreNone The original value is not restored at all
890 \value Binding.RestoreBinding The original value is restored if it was another binding.
891 In that case the old binding is in effect again.
892 \value Binding.RestoreValue The original value is restored if it was a plain
893 value rather than a binding.
894 \value Binding.RestoreBindingOrValue The original value is always restored.
895
896 The default value is \c Binding.RestoreBindingOrValue.
897
898 \note This property exists for backwards compatibility with earlier versions
899 of Qt. Don't use it in new code.
900*/
901QQmlBind::RestorationMode QQmlBind::restoreMode() const
902{
903 Q_D(const QQmlBind);
904 unsigned result = RestoreNone;
905 if (d->restoreValue)
906 result |= RestoreValue;
907 if (d->restoreBinding)
908 result |= RestoreBinding;
909 return RestorationMode(result);
910}
911
912void QQmlBind::setRestoreMode(RestorationMode newMode)
913{
914 Q_D(QQmlBind);
915 if (newMode != restoreMode()) {
916 d->restoreValue = (newMode & RestoreValue);
917 d->restoreBinding = (newMode & RestoreBinding);
918 emit restoreModeChanged();
919 }
920}
921
922void QQmlBind::setTarget(const QQmlProperty &p)
923{
924 Q_D(QQmlBind);
925 if (QQmlBindEntry *target = d->targetEntry()) {
926 target->setTarget(this, p);
927 return;
928 }
929 qmlWarning(this).nospace()
930 << "You should not use the 'on' syntax for Binding elements with generalized group "
931 "properties. It is ignored.";
932
933}
934
935void QQmlBindEntry::setTarget(QQmlBind *q, const QQmlProperty &p)
936{
937 if (Q_UNLIKELY(lcQtQmlBindingRemoval().isInfoEnabled())) {
938 if (QObject *oldObject = prop.object()) {
939 QMetaProperty metaProp = oldObject->metaObject()->property(prop.index());
940 if (metaProp.hasNotifySignal()) {
941 QByteArray signal('2' + metaProp.notifySignal().methodSignature());
942 QObject::disconnect(oldObject, signal.constData(),
943 q, SLOT(targetValueChanged()));
944 }
945 }
946 p.connectNotifySignal(q, SLOT(targetValueChanged()));
947 }
948
949 prop = p;
950}
951
952void QQmlBind::classBegin()
953{
954 Q_D(QQmlBind);
955 d->componentComplete = false;
956}
957
959 const QQmlProperty &prop, const QV4::CompiledData::Binding *binding,
960 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
961 const QQmlRefPointer<QQmlContextData> &contextData,
962 QObject *scopeObject)
963{
964 switch (binding->type()) {
965 case QV4::CompiledData::Binding::Type_Translation:
966 case QV4::CompiledData::Binding::Type_TranslationById:
967 return QQmlAnyBinding::createTranslationBinding(prop, compilationUnit, binding, scopeObject);
968 case QV4::CompiledData::Binding::Type_Script: {
969 const QQmlBinding::Identifier id = binding->value.compiledScriptIndex;
970 if (id == QQmlBinding::Invalid) {
971 return QQmlAnyBinding::createFromCodeString(
972 prop, compilationUnit->bindingValueAsString(binding), scopeObject,
973 contextData, compilationUnit->finalUrlString(), binding->location.line());
974 }
975 QV4::Scope scope(contextData->engine()->handle());
976 QV4::Scoped<QV4::QmlContext> qmlCtxt(
977 scope, QV4::QmlContext::create(
978 scope.engine->rootContext(), contextData, scopeObject));
979 return QQmlAnyBinding::createFromFunction(
980 prop, compilationUnit->runtimeFunctions.at(id), scopeObject, contextData,
981 qmlCtxt);
982 }
983 default:
984 break;
985 }
986 return QQmlAnyBinding();
987}
988
989static void initCreator(
990 QQmlData::DeferredData *deferredData,
991 const QQmlRefPointer<QQmlContextData> &contextData,
992 QQmlComponentPrivate::ConstructionState *immediateState)
993{
994 if (!immediateState->hasCreator()) {
995 immediateState->setCompletePending(true);
996 immediateState->initCreator(
997 deferredData->context->parent(), deferredData->compilationUnit,
998 contextData, deferredData->inlineComponentName);
999 immediateState->creator()->beginPopulateDeferred(deferredData->context);
1000 }
1001}
1002
1003void QQmlBindPrivate::decodeBinding(
1004 QQmlBind *q, const QString &propertyPrefix,
1005 QQmlData::DeferredData *deferredData,
1006 const QV4::CompiledData::Binding *binding,
1007 QQmlComponentPrivate::ConstructionState *immediateState)
1008{
1009 const QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit
1010 = deferredData->compilationUnit;
1011 const QString propertySuffix = compilationUnit->stringAt(binding->propertyNameIndex);
1012 const QString propertyName = propertyPrefix + propertySuffix;
1013
1014 switch (binding->type()) {
1015 case QV4::CompiledData::Binding::Type_AttachedProperty:
1016 if (propertyPrefix.isEmpty()) {
1017 // Top-level attached properties cannot be generalized grouped properties.
1018 // Treat them as regular properties.
1019 // ... unless we're not supposed to handle regular properties. Then ignore them.
1020 if (!immediateState)
1021 return;
1022
1023 Q_ASSERT(compilationUnit->stringAt(compilationUnit->objectAt(binding->value.objectIndex)
1024 ->inheritedTypeNameIndex).isEmpty());
1025
1026 const QV4::ResolvedTypeReference *typeReference
1027 = compilationUnit->resolvedType(binding->propertyNameIndex);
1028 Q_ASSERT(typeReference);
1029 QQmlType attachedType = typeReference->type();
1030 if (!attachedType.isValid()) {
1031 if (QQmlTypeLoader *typeLoader = compilationUnit->engine->typeLoader()) {
1032 const QQmlTypeNameCache::Result result
1033 = deferredData->context->imports()->query(propertySuffix, typeLoader);
1034 if (!result.isValid()) {
1035 qmlWarning(q).nospace()
1036 << "Unknown name " << propertySuffix << ". The binding is ignored.";
1037 return;
1038 }
1039 attachedType = result.type;
1040 }
1041 }
1042
1043 QQmlContext *context = qmlContext(q);
1044 QObject *attachedObject = qmlAttachedPropertiesObject(
1045 q, attachedType.attachedPropertiesFunction(QQmlTypeLoader::get(context->engine())));
1046 if (!attachedObject) {
1047 qmlWarning(q).nospace() <<"Could not create attached properties object '"
1048 << attachedType.typeName() << "'";
1049 return;
1050 }
1051
1052 initCreator(deferredData, QQmlContextData::get(context), immediateState);
1053 immediateState->creator()->populateDeferredInstance(
1054 q, deferredData->deferredIdx, binding->value.objectIndex, attachedObject,
1055 attachedObject, /*value type property*/ nullptr, binding);
1056 return;
1057 }
1058 Q_FALLTHROUGH();
1059 case QV4::CompiledData::Binding::Type_GroupProperty: {
1060 const QString pre = propertyName + u'.';
1061 const QV4::CompiledData::Object *subObj
1062 = compilationUnit->objectAt(binding->value.objectIndex);
1063 const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
1064 for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding)
1065 decodeBinding(q, pre, deferredData, subBinding, immediateState);
1066 return;
1067 }
1068 default:
1069 break;
1070 }
1071
1072 QQmlBindEntry entry;
1073 QQmlContext *context = qmlContext(q);
1074 const QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(context);
1075 entry.prop = QQmlPropertyPrivate::create(nullptr, propertyName, contextData,
1076 QQmlPropertyPrivate::InitFlag::AllowId);
1077 if (!entry.prop.isValid()) {
1078 // Try again in the context of this object. If that works, it's a regular property.
1079 // ... unless we're not supposed to handle regular properties. Then ignore it.
1080 if (!immediateState)
1081 return;
1082
1083 QQmlProperty property = QQmlPropertyPrivate::create(
1084 q, propertyName, contextData, QQmlPropertyPrivate::InitFlag::AllowSignal);
1085 if (property.isValid()) {
1086 initCreator(deferredData, contextData, immediateState);
1087 immediateState->creator()->populateDeferredBinding(
1088 property, deferredData->deferredIdx, binding);
1089 } else {
1090 qmlWarning(q).nospace() << "Unknown name " << propertyName
1091 << ". The binding is ignored.";
1092 }
1093 return;
1094 }
1095
1096 switch (mode) {
1097 case GeneralizedGroup:
1098 break;
1099 case ObjectPropertyValue:
1100 warnIgnoredProperties(q);
1101 objectPropertyValueData.~ObjectPropertyValueData();
1102 Q_FALLTHROUGH();
1103 case Unknown:
1104 new (&generalizedGroupData) GeneralizedGroupData;
1105 mode = GeneralizedGroup;
1106 break;
1107 }
1108
1109 const auto setVariant = [&entry](QV4::PersistentValue value) {
1110 entry.currentKind = entry.current.setVariant(value, entry.currentKind);
1111 };
1112
1113 const auto setBinding = [&entry](QQmlAnyBinding binding) {
1114 entry.currentKind = entry.current.set(binding, entry.currentKind);
1115 };
1116
1117 switch (binding->type()) {
1118 case QV4::CompiledData::Binding::Type_AttachedProperty:
1119 case QV4::CompiledData::Binding::Type_GroupProperty:
1120 Q_UNREACHABLE(); // Handled above
1121 break;
1122 case QV4::CompiledData::Binding::Type_Translation:
1123 case QV4::CompiledData::Binding::Type_TranslationById:
1124 case QV4::CompiledData::Binding::Type_Script:
1125 if (delayed) {
1126 if (!generalizedGroupData.delayedValues)
1127 createDelayedValues();
1128 const QString delayedName = QString::number(generalizedGroupData.entries.size());
1129 generalizedGroupData.delayedValues->insert(delayedName, QVariant());
1130 QQmlProperty bindingTarget
1131 = QQmlProperty(generalizedGroupData.delayedValues.get(), delayedName);
1132 Q_ASSERT(bindingTarget.isValid());
1133 QQmlAnyBinding anyBinding = createBinding(
1134 bindingTarget, binding, compilationUnit, contextData, q);
1135 anyBinding.installOn(bindingTarget);
1136 } else {
1137 setBinding(createBinding(entry.prop, binding, compilationUnit, contextData, q));
1138 }
1139 break;
1140 case QV4::CompiledData::Binding::Type_String:
1141 setVariant(QV4::PersistentValue(
1142 compilationUnit->engine,
1143 compilationUnit->runtimeStrings[binding->stringIndex]->asReturnedValue()));
1144 break;
1145 case QV4::CompiledData::Binding::Type_Number:
1146 setVariant(QV4::PersistentValue(
1147 compilationUnit->engine,
1148 compilationUnit->constants[binding->value.constantValueIndex].asReturnedValue()));
1149 break;
1150 case QV4::CompiledData::Binding::Type_Boolean:
1151 setVariant(QV4::PersistentValue(compilationUnit->engine, QV4::Encode(binding->value.b)));
1152 break;
1153 case QV4::CompiledData::Binding::Type_Null:
1154 setVariant(QV4::PersistentValue(compilationUnit->engine, QV4::Encode::null()));
1155 break;
1156 case QV4::CompiledData::Binding::Type_Object:
1157 case QV4::CompiledData::Binding::Type_Invalid:
1158 break;
1159 }
1160
1161 generalizedGroupData.entries.append(std::move(entry));
1162}
1163
1165{
1166 generalizedGroupData.delayedValues.reset(QQmlPropertyMap::create());
1167 QQmlPropertyMap *delayedValues = generalizedGroupData.delayedValues.get();
1168 QObject::connect(
1169 delayedValues, &QQmlPropertyMap::valueChanged,
1170 delayedValues, [this](QString delayedName, const QVariant &value) {
1171 Q_UNUSED(value);
1172 onDelayedValueChanged(std::move(delayedName));
1173 }
1174 );
1175}
1176
1177void QQmlBindPrivate::onDelayedValueChanged(QString delayedName)
1178{
1179 Q_ASSERT(delayed);
1180 Q_ASSERT(mode == GeneralizedGroup);
1181 QQmlPropertyMap *delayedValues = generalizedGroupData.delayedValues.get();
1182 Q_ASSERT(delayedValues);
1183 const QString pendingName = QStringLiteral("pending");
1184 QStringList pending = qvariant_cast<QStringList>((*delayedValues)[pendingName]);
1185 if (componentComplete && pending.size() == 0)
1186 QTimer::singleShot(0, delayedValues, [this]() { evalDelayed(); });
1187 else if (pending.contains(delayedName))
1188 return;
1189
1190 pending.append(std::move(delayedName));
1191 (*delayedValues)[pendingName].setValue(std::move(pending));
1192}
1193
1195{
1196 Q_ASSERT(mode == GeneralizedGroup);
1197 QQmlPropertyMap *delayedValues = generalizedGroupData.delayedValues.get();
1198 if (!when || !delayedValues)
1199 return;
1200
1201 const QString pendingName = QStringLiteral("pending");
1202 const QStringList pending = qvariant_cast<QStringList>((*delayedValues)[pendingName]);
1203 for (const QString &delayedName : pending) {
1204 bool ok;
1205 const int delayedIndex = delayedName.toInt(&ok);
1206 Q_ASSERT(ok);
1207 Q_ASSERT(delayedIndex >= 0 && delayedIndex < generalizedGroupData.entries.size());
1208 generalizedGroupData.entries[delayedIndex].prop.write((*delayedValues)[delayedName]);
1209 }
1210 (*delayedValues)[pendingName].setValue(QStringList());
1211}
1212
1213void QQmlBindPrivate::buildBindEntries(QQmlBind *q, QQmlComponentPrivate::DeferredState *deferredState)
1214{
1215 QQmlData *data = QQmlData::get(q);
1216 if (data && !data->deferredData.isEmpty()) {
1217 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
1218 for (QQmlData::DeferredData *deferredData : data->deferredData) {
1219 QMultiHash<int, const QV4::CompiledData::Binding *> *bindings = &deferredData->bindings;
1220 if (deferredState) {
1221 QQmlComponentPrivate::ConstructionState constructionState;
1222 for (auto it = bindings->cbegin(); it != bindings->cend(); ++it)
1223 decodeBinding(q, QString(), deferredData, *it, &constructionState);
1224
1225
1226 if (constructionState.hasCreator()) {
1227 ++ep->inProgressCreations;
1228 constructionState.creator()->finalizePopulateDeferred();
1229 constructionState.appendCreatorErrors();
1230 deferredState->push_back(std::move(constructionState));
1231 }
1232 } else {
1233 for (auto it = bindings->cbegin(); it != bindings->cend(); ++it)
1234 decodeBinding(q, QString(), deferredData, *it, nullptr);
1235 }
1236 }
1237
1238 if (deferredState) {
1239 data->releaseDeferredData();
1240 if (!deferredState->empty())
1241 QQmlComponentPrivate::completeDeferred(ep, deferredState);
1242 }
1243 }
1244}
1245
1246void QQmlBind::componentComplete()
1247{
1248 Q_D(QQmlBind);
1249 QQmlComponentPrivate::DeferredState deferredState;
1250 d->buildBindEntries(this, &deferredState);
1251 d->componentComplete = true;
1252 if (d->mode == QQmlBindPrivate::ObjectPropertyValue) {
1253 QQmlBindEntry *target = d->targetEntry();
1254 if (!target->prop.isValid()) {
1255 target->setTarget(this, QQmlProperty(
1256 d->objectPropertyValueData.obj,
1257 d->objectPropertyValueData.propName, qmlContext(this)));
1258 }
1259 }
1260 d->validate(this);
1261 if (d->mode == QQmlBindPrivate::GeneralizedGroup)
1262 d->evalDelayed();
1263 eval();
1264}
1265
1266void QQmlBind::prepareEval()
1267{
1268 Q_D(QQmlBind);
1269 if (d->delayed) {
1270 if (!d->pendingEval)
1271 QTimer::singleShot(0, this, &QQmlBind::eval);
1272 d->pendingEval = true;
1273 } else {
1274 eval();
1275 }
1276}
1277
1279{
1280 previousKind = previous.destroy(previousKind);
1281}
1282
1284{
1285 switch (entry->currentKind) {
1286 case QQmlBindEntryKind::V4Value: {
1287 auto propPriv = QQmlPropertyPrivate::get(entry->prop);
1288 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
1289 Q_ASSERT(vmemo);
1290 return QV4::RuntimeHelpers::strictEqual(
1291 // fromReturnedValue is OK here because strictEqual will not allocate
1292 QV4::Value::fromReturnedValue(vmemo->vmeProperty(propPriv->core.coreIndex())),
1293 *entry->current.v4Value.valueRef());
1294 }
1295 case QQmlBindEntryKind::Variant: {
1296 const QV4::PersistentValue &v4Value = entry->current.v4Value;
1297 QMetaType propMetaType = entry->prop.propertyMetaType();
1298 /*
1299 * We currently really want to use toVariant here, and not metaTypeFromJS.
1300 * metaTypeFromJS can't do all conversions, and would leave us with an
1301 * empty QVariant if it fails; whereas toVariant tries very hard to give
1302 * us a QVariant representation, even though its type might not match the
1303 * property's meta-type. In case of an actual mismatch, we use
1304 * convertToWriteTargetType to mirror the conversions that writing to a
1305 * property would have done; with the exception of list properties, where
1306 * we directly go through a specialized code path using
1307 * QQmlPropertyPrivate::convertToQQmlListProperty
1308 */
1309 QVariant valueAsVariant = v4Value.engine()->toVariant(*v4Value.valueRef(),
1310 propMetaType);
1311 if (propMetaType.flags() & QMetaType::IsQmlList) {
1312 // our expected value is not necessarily of the correct type, so we copy the steps done by
1313 // QQmlPropertyPrivate::write to bring them into the correct format
1314 QList<QObject *> expectedObjectList;
1315 QQmlListProperty<QObject> expectedAsListProp(nullptr, &expectedObjectList);
1316 QQmlPropertyPrivate::convertToQQmlListProperty(&expectedAsListProp, propMetaType, valueAsVariant);
1317
1318 QVariant actualValue = entry->prop.read();
1319 // reading a QQmlListProperty property yields a QQmlListReference
1320 QQmlListReference* listReference = get_if<QQmlListReference>(&actualValue);
1321 Q_ASSERT(listReference);
1322 auto actualObjectList = QQmlListReferencePrivate::get(listReference)->property.toList<QList<QObject *>>();
1323 return std::equal(expectedObjectList.constBegin(), expectedObjectList.constEnd(),
1324 actualObjectList.constBegin(), actualObjectList.constEnd());
1325
1326 } else if (QMetaType varMetaType = valueAsVariant.metaType(); varMetaType != propMetaType) {
1327 QVariant converted = QQmlPropertyPrivate::convertToWriteTargetType(
1328 valueAsVariant, propMetaType);
1329 if (converted.isValid())
1330 valueAsVariant = std::move(converted);
1331 }
1332 return valueAsVariant
1333 == entry->prop.read();
1334 }
1335 case QQmlBindEntryKind::Binding:
1336 return entry->current.binding == QQmlAnyBinding::ofProperty(entry->prop);
1337 case QQmlBindEntryKind::None:
1338 break;
1339 }
1340
1341 return false;
1342}
1343
1345{
1346 if (!entry->prop.isValid() || (entry->currentKind == QQmlBindEntryKind::None))
1347 return;
1348 if (!entry->prop.object())
1349 return; // if the target is already gone, we can't do anything
1350
1351 if (!when) {
1352 if (!isCurrent(entry)) {
1353 entry->clearPrev();
1354 return;
1355 }
1356
1357 //restore any previous binding
1358 switch (entry->previousKind) {
1359 case QQmlBindEntryKind::Binding:
1360 if (restoreBinding) {
1361 QQmlAnyBinding p = std::move(entry->previous.binding);
1362 entry->clearPrev(); // Do that before setBinding(), as setBinding() may recurse.
1363 p.installOn(entry->prop);
1364 }
1365 break;
1366 case QQmlBindEntryKind::V4Value:
1367 if (restoreValue) {
1368 QQmlAnyBinding::takeFrom(entry->prop); // we don't want to have a binding active
1369 auto propPriv = QQmlPropertyPrivate::get(entry->prop);
1370 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
1371 Q_ASSERT(vmemo);
1372 vmemo->setVMEProperty(propPriv->core.coreIndex(),
1373 *entry->previous.v4Value.valueRef());
1374 entry->clearPrev();
1375 }
1376 break;
1377 case QQmlBindEntryKind::Variant:
1378 if (restoreValue) {
1379 QQmlAnyBinding::takeFrom(entry->prop); // we don't want to have a binding active
1380 const QV4::PersistentValue &v4Value = entry->previous.v4Value;
1381 entry->prop.write(v4Value.engine()->toVariant(
1382 *v4Value.valueRef(), entry->prop.propertyMetaType()));
1383 entry->clearPrev();
1384 }
1385 break;
1386 case QQmlBindEntryKind::None:
1387 break;
1388 }
1389 return;
1390 }
1391
1392 //save any set binding for restoration
1393 if (entry->previousKind == QQmlBindEntryKind::None) {
1394 // try binding first; we need to use takeFrom to properly unlink the binding
1395 QQmlAnyBinding prevBind = QQmlAnyBinding::takeFrom(entry->prop);
1396 if (prevBind) {
1397 entry->previousKind = entry->previous.set(std::move(prevBind), entry->previousKind);
1398 } else {
1399 // nope, try a V4 value next
1400 auto propPriv = QQmlPropertyPrivate::get(entry->prop);
1401 auto propData = propPriv->core;
1402 if (!propPriv->valueTypeData.isValid() && propData.isVarProperty()) {
1403 QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object);
1404 Q_ASSERT(vmemo);
1405 auto retVal = vmemo->vmeProperty(propData.coreIndex());
1406 entry->previousKind = entry->previous.set(
1407 QV4::PersistentValue(vmemo->engine(), retVal), entry->previousKind);
1408 } else if (entry->prop.propertyMetaType().flags() & QMetaType::IsQmlList) {
1409 using namespace QV4;
1410 ExecutionEngine *v4 = qmlEngine(q_func())->handle();
1411 entry->previousKind = entry->previous.setVariant(
1412 QV4::PersistentValue(v4, QV4::QmlListWrapper::createOwned(v4, entry->prop)),
1413 entry->previousKind);
1414
1415 } else {
1416 // nope, use the meta object to get a QVariant
1417 entry->previousKind = entry->previous.set(
1418 propPriv->engine->handle(), entry->prop.read(), entry->previousKind);
1419 }
1420 }
1421 }
1422
1423 // NOTE: removeBinding has no effect on QProperty classes, but
1424 // we already used takeBinding to remove it
1425 QQmlPropertyPrivate::removeBinding(entry->prop, QQmlPropertyPrivate::OverrideSticky);
1426}
1427
1429{
1430 if (!entry->prop.isValid())
1431 return;
1432 switch (entry->currentKind) {
1433 case QQmlBindEntryKind::Variant: {
1434 const QV4::PersistentValue &v4Value = entry->current.v4Value;
1435 entry->prop.write(
1436 v4Value.engine()->toVariant(*v4Value.valueRef(), entry->prop.propertyMetaType()));
1437 break;
1438 }
1439 case QQmlBindEntryKind::Binding:
1440 Q_ASSERT(!delayed);
1441 entry->current.binding.installOn(entry->prop);
1442 break;
1443 case QQmlBindEntryKind::V4Value: {
1444 auto propPriv = QQmlPropertyPrivate::get(entry->prop);
1445 QQmlVMEMetaObject::get(propPriv->object)->setVMEProperty(
1446 propPriv->core.coreIndex(), *entry->current.v4Value.valueRef());
1447 break;
1448 }
1449 case QQmlBindEntryKind::None:
1450 break;
1451 }
1452}
1453
1454void QQmlBind::eval()
1455{
1456 Q_D(QQmlBind);
1457 d->pendingEval = false;
1458 if (!d->componentComplete)
1459 return;
1460
1461 switch (d->mode) {
1462 case QQmlBindPrivate::GeneralizedGroup:
1463 for (QQmlBindEntry &entry : d->generalizedGroupData.entries)
1464 d->preEvalEntry(&entry);
1465 break;
1466 case QQmlBindPrivate::ObjectPropertyValue:
1467 d->preEvalEntry(&d->objectPropertyValueData.entry);
1468 break;
1469 case QQmlBindPrivate::Unknown:
1470 break;
1471 }
1472
1473 if (!d->when)
1474 return;
1475
1476 d->writingProperty = true;
1477 switch (d->mode) {
1478 case QQmlBindPrivate::GeneralizedGroup:
1479 for (QQmlBindEntry &entry : d->generalizedGroupData.entries)
1480 d->postEvalEntry(&entry);
1481 break;
1482 case QQmlBindPrivate::ObjectPropertyValue:
1483 d->postEvalEntry(&d->objectPropertyValueData.entry);
1484 break;
1485 case QQmlBindPrivate::Unknown:
1486 break;
1487 }
1488 d->writingProperty = false;
1489}
1490
1491void QQmlBind::targetValueChanged()
1492{
1493 Q_D(QQmlBind);
1494 if (d->writingProperty)
1495 return;
1496
1497 if (!d->when)
1498 return;
1499
1500 QUrl url;
1501 quint16 line = 0;
1502
1503 const QQmlData *ddata = QQmlData::get(this, false);
1504 if (ddata && ddata->outerContext) {
1505 url = ddata->outerContext->url();
1506 line = ddata->lineNumber;
1507 }
1508
1509 qCInfo(lcQtQmlBindingRemoval,
1510 "The target property of the Binding element created at %s:%d was changed from "
1511 "elsewhere. This does not overwrite the binding. The target property will still be "
1512 "updated when the value of the Binding element changes.",
1513 qPrintable(url.toString()), line);
1514}
1515
1516QT_END_NAMESPACE
1517
1518#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)
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:989
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:958
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:935
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