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
qproperty.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qproperty.h"
5#include "qproperty_p.h"
6
7#include <qscopedvaluerollback.h>
8#include <QScopeGuard>
9#include <QtCore/qloggingcategory.h>
10#include <QThread>
11#include <QtCore/qmetaobject.h>
12
13#include "qobject_p.h"
14
16
17Q_STATIC_LOGGING_CATEGORY(lcQPropertyBinding, "qt.qproperty.binding");
18
19using namespace QtPrivate;
20
21void QPropertyBindingPrivatePtr::destroyAndFreeMemory()
22{
23 QPropertyBindingPrivate::destroyAndFreeMemory(static_cast<QPropertyBindingPrivate *>(d));
24}
25
26void QPropertyBindingPrivatePtr::reset(QtPrivate::RefCounted *ptr) noexcept
27{
28 if (ptr != d) {
29 if (ptr)
30 ptr->addRef();
31 auto *old = std::exchange(d, ptr);
32 if (old && !old->deref())
33 QPropertyBindingPrivate::destroyAndFreeMemory(static_cast<QPropertyBindingPrivate *>(d));
34 }
35}
36
37
38void QPropertyBindingDataPointer::addObserver(QPropertyObserver *observer)
39{
40 if (auto *b = binding()) {
41 observer->prev = &b->firstObserver.ptr;
42 observer->next = b->firstObserver.ptr;
43 if (observer->next)
44 observer->next->prev = &observer->next;
45 b->firstObserver.ptr = observer;
46 } else {
47 auto &d = ptr->d_ref();
48 Q_ASSERT(!(d & QPropertyBindingData::BindingBit));
49 auto firstObserver = reinterpret_cast<QPropertyObserver*>(d);
50 observer->prev = reinterpret_cast<QPropertyObserver**>(&d);
51 observer->next = firstObserver;
52 if (observer->next)
53 observer->next->prev = &observer->next;
54 d = reinterpret_cast<quintptr>(observer);
55 }
56}
57
58/*!
59 \internal
60
61 QPropertyDelayedNotifications is used to manage delayed notifications in grouped property updates.
62 It acts as a pool allocator for QPropertyProxyBindingData, and has methods to manage delayed
63 notifications.
64
65 \sa beginPropertyUpdateGroup, endPropertyUpdateGroup
66*/
68{
69 // we can't access the dynamic page size as we need a constant value
70 // use 4096 as a sensible default
71 static constexpr inline auto PageSize = 4096;
72 int ref = 0;
73 QPropertyDelayedNotifications *next = nullptr; // in case we have more than size dirty properties...
75 // Size chosen to avoid allocating more than one page of memory, while still ensuring
76 // that we can store many delayed properties without doing further allocations
77 static constexpr qsizetype size = (PageSize - 3*sizeof(void *))/sizeof(QPropertyProxyBindingData);
79
80 /*!
81 \internal
82 This method is called when a property attempts to notify its observers while inside of a
83 property update group. Instead of actually notifying, it replaces \a bindingData's d_ptr
84 with a QPropertyProxyBindingData.
85 \a bindingData and \a propertyData are the binding data and property data of the property
86 whose notify call gets delayed.
87 \sa QPropertyBindingData::notifyObservers
88 */
89 void addProperty(const QPropertyBindingData *bindingData, QUntypedPropertyData *propertyData) {
90 if (bindingData->isNotificationDelayed())
91 return;
92 auto *data = this;
93 while (data->used == size) {
94 if (!data->next)
95 // add a new page
97 data = data->next;
98 }
99 auto *delayed = data->delayedProperties + data->used;
100 *delayed = QPropertyProxyBindingData { bindingData->d_ptr, bindingData, propertyData };
101 ++data->used;
102 // preserve the binding bit for faster access
103 quintptr bindingBit = bindingData->d_ptr & QPropertyBindingData::BindingBit;
104 bindingData->d_ptr = reinterpret_cast<quintptr>(delayed) | QPropertyBindingData::DelayedNotificationBit | bindingBit;
105 Q_ASSERT(bindingData->d_ptr > 3);
106 if (!bindingBit) {
107 if (auto observer = reinterpret_cast<QPropertyObserver *>(delayed->d_ptr))
108 observer->prev = reinterpret_cast<QPropertyObserver **>(&delayed->d_ptr);
109 }
110 }
111
112 /*!
113 \internal
114 Called in Qt::endPropertyUpdateGroup. For the QPropertyProxyBindingData at position
115 \a index, it
116 \list
117 \li restores the original binding data that was modified in addProperty and
118 \li evaluates any bindings which depend on properties that were changed inside
119 the group.
120 \endlist
121 Change notifications are sent later with notify (following the logic of separating
122 binding updates and notifications used in non-deferred updates).
123 */
124 void evaluateBindings(PendingBindingObserverList &bindingObservers, qsizetype index, QBindingStatus *status) {
125 auto *delayed = delayedProperties + index;
126 auto *bindingData = delayed->originalBindingData;
127 if (!bindingData)
128 return;
129
130 bindingData->d_ptr = delayed->d_ptr;
131 Q_ASSERT(!(bindingData->d_ptr & QPropertyBindingData::DelayedNotificationBit));
132 if (!bindingData->hasBinding()) {
133 if (auto observer = reinterpret_cast<QPropertyObserver *>(bindingData->d_ptr))
134 observer->prev = reinterpret_cast<QPropertyObserver **>(&bindingData->d_ptr);
135 }
136
137 QPropertyBindingDataPointer bindingDataPointer{bindingData};
138 QPropertyObserverPointer observer = bindingDataPointer.firstObserver();
139 if (observer)
140 observer.evaluateBindings(bindingObservers, status);
141 }
142
143 /*!
144 \internal
145 Called in Qt::endPropertyUpdateGroup. For the QPropertyProxyBindingData at position
146 \a i, it
147 \list
148 \li resets the proxy binding data and
149 \li sends any pending notifications.
150 \endlist
151 */
152 void notify(qsizetype index) {
153 auto *delayed = delayedProperties + index;
154 if (delayed->d_ptr & QPropertyBindingData::BindingBit)
155 return; // already handled
156 if (!delayed->originalBindingData)
157 return;
158 delayed->originalBindingData = nullptr;
159
160 QPropertyObserverPointer observer { reinterpret_cast<QPropertyObserver *>(delayed->d_ptr & ~QPropertyBindingData::DelayedNotificationBit) };
161 delayed->d_ptr = 0;
162
163 if (observer)
164 observer.notify(delayed->propertyData);
165 }
166};
167
168Q_CONSTINIT static thread_local QBindingStatus bindingStatus;
169
170/*!
171 \since 6.2
172
173 \relates QProperty
174
175 Marks the beginning of a property update group. Inside this group,
176 changing a property does neither immediately update any dependent properties
177 nor does it trigger change notifications.
178 Those are instead deferred until the group is ended by a call to endPropertyUpdateGroup.
179
180 Groups can be nested. In that case, the deferral ends only after the outermost group has been
181 ended.
182
183 \note Change notifications are only send after all property values affected by the group have
184 been updated to their new values. This allows re-establishing a class invariant if multiple
185 properties need to be updated, preventing any external observer from noticing an inconsistent
186 state.
187
188 \sa Qt::endPropertyUpdateGroup, QScopedPropertyUpdateGroup
189*/
191{
192 QPropertyDelayedNotifications *& groupUpdateData = bindingStatus.groupUpdateData;
193 if (!groupUpdateData)
194 groupUpdateData = new QPropertyDelayedNotifications;
195 ++groupUpdateData->ref;
196}
197
198/*!
199 \since 6.2
200 \relates QProperty
201
202 Ends a property update group. If the outermost group has been ended, and deferred
203 binding evaluations and notifications happen now.
204
205 \warning Calling endPropertyUpdateGroup without a preceding call to beginPropertyUpdateGroup
206 results in undefined behavior.
207
208 \sa Qt::beginPropertyUpdateGroup, QScopedPropertyUpdateGroup
209*/
211{
212 auto status = &bindingStatus;
213 QPropertyDelayedNotifications *& groupUpdateData = status->groupUpdateData;
214 auto *data = groupUpdateData;
215 Q_ASSERT(data->ref);
216 if (--data->ref)
217 return;
218 groupUpdateData = nullptr;
219 // ensures that bindings are kept alive until endPropertyUpdateGroup concludes
220 PendingBindingObserverList bindingObservers;
221 // update all delayed properties
222 auto start = data;
223 while (data) {
224 for (qsizetype i = 0; i < data->used; ++i)
225 data->evaluateBindings(bindingObservers, i, status);
226 data = data->next;
227 }
228 // notify all delayed notifications from binding evaluation
229 for (const auto &bindingPtr: bindingObservers) {
230 auto *binding = static_cast<QPropertyBindingPrivate *>(bindingPtr.get());
231 binding->notifyNonRecursive();
232 }
233 // do the same for properties which only have observers
234 data = start;
235 while (data) {
236 for (qsizetype i = 0; i < data->used; ++i)
237 data->notify(i);
238 delete std::exchange(data, data->next);
239 }
240}
241
242/*!
243 \since 6.6
244 \class QScopedPropertyUpdateGroup
245 \inmodule QtCore
246 \ingroup tools
247 \brief RAII class around Qt::beginPropertyUpdateGroup()/Qt::endPropertyUpdateGroup().
248
249 This class calls Qt::beginPropertyUpdateGroup() in its constructor and
250 Qt::endPropertyUpdateGroup() in its destructor, making sure the latter
251 function is reliably called even in the presence of early returns or thrown
252 exceptions.
253
254 \note Qt::endPropertyUpdateGroup() may re-throw exceptions thrown by
255 binding evaluations. This means your application may crash
256 (\c{std::terminate()} called) if another exception is causing
257 QScopedPropertyUpdateGroup's destructor to be called during stack
258 unwinding. If you expect exceptions from binding evaluations, use manual
259 Qt::endPropertyUpdateGroup() calls and \c{try}/\c{catch} blocks.
260
261 \sa QProperty
262*/
263
264/*!
265 \fn QScopedPropertyUpdateGroup::QScopedPropertyUpdateGroup()
266
267 Calls Qt::beginPropertyUpdateGroup().
268*/
269
270/*!
271 \fn QScopedPropertyUpdateGroup::~QScopedPropertyUpdateGroup()
272
273 Calls Qt::endPropertyUpdateGroup().
274*/
275
276
277// check everything stored in QPropertyBindingPrivate's union is trivially destructible
278// (though the compiler would also complain if that weren't the case)
279static_assert(std::is_trivially_destructible_v<QPropertyBindingSourceLocation>);
280static_assert(std::is_trivially_destructible_v<std::byte[sizeof(QPropertyBindingSourceLocation)]>);
281
282QPropertyBindingPrivate::~QPropertyBindingPrivate()
283{
284 if (firstObserver)
285 firstObserver.unlink();
286 if (vtable->size)
287 vtable->destroy(reinterpret_cast<std::byte *>(this)
288 + QPropertyBindingPrivate::getSizeEnsuringAlignment());
289}
290
291void QPropertyBindingPrivate::clearDependencyObservers() {
292 for (size_t i = 0; i < qMin(dependencyObserverCount, inlineDependencyObservers.size()); ++i) {
293 QPropertyObserverPointer p{&inlineDependencyObservers[i]};
294 p.unlink_fast();
295 }
296 if (heapObservers)
297 heapObservers->clear();
298 dependencyObserverCount = 0;
299}
300
301QPropertyObserverPointer QPropertyBindingPrivate::allocateDependencyObserver_slow()
302{
303 ++dependencyObserverCount;
304 if (!heapObservers)
305 heapObservers.reset(new std::vector<QPropertyObserver>());
306 return {&heapObservers->emplace_back()};
307}
308
309void QPropertyBindingPrivate::unlinkAndDeref()
310{
311 clearDependencyObservers();
312 propertyDataPtr = nullptr;
313 if (!deref())
314 destroyAndFreeMemory(this);
315}
316
317bool QPropertyBindingPrivate::evaluateRecursive(PendingBindingObserverList &bindingObservers, QBindingStatus *status)
318{
319 if (!status)
320 status = &bindingStatus;
321 return evaluateRecursive_inline(bindingObservers, status);
322}
323
324void QPropertyBindingPrivate::notifyNonRecursive(const PendingBindingObserverList &bindingObservers)
325{
326 notifyNonRecursive();
327 for (auto &&bindingPtr: bindingObservers) {
328 auto *binding = static_cast<QPropertyBindingPrivate *>(bindingPtr.get());
329 binding->notifyNonRecursive();
330 }
331}
332
333QPropertyBindingPrivate::NotificationState QPropertyBindingPrivate::notifyNonRecursive()
334{
335 if (!pendingNotify)
336 return Delayed;
337 pendingNotify = false;
338 Q_ASSERT(!updating);
339 updating = true;
340 if (firstObserver) {
341 firstObserver.noSelfDependencies(this);
342 firstObserver.notify(propertyDataPtr);
343 }
344 if (hasStaticObserver)
345 staticObserverCallback(propertyDataPtr);
346 updating = false;
347 return Sent;
348}
349
350/*!
351 Constructs a null QUntypedPropertyBinding.
352
353 \sa isNull()
354*/
355QUntypedPropertyBinding::QUntypedPropertyBinding() = default;
356
357/*!
358 \fn template<typename Functor>
359 QUntypedPropertyBinding(QMetaType metaType, Functor &&f, const QPropertyBindingSourceLocation &location)
360
361 \internal
362*/
363
364/*!
365 \internal
366
367 Constructs QUntypedPropertyBinding. Assumes that \a metaType, \a function and \a vtable match.
368 Unless a specialization of \c BindingFunctionVTable is used, this function should never be called
369 directly.
370*/
371QUntypedPropertyBinding::QUntypedPropertyBinding(QMetaType metaType, const BindingFunctionVTable *vtable, void *function,
372 const QPropertyBindingSourceLocation &location)
373{
374 std::byte *mem = new std::byte[QPropertyBindingPrivate::getSizeEnsuringAlignment() + vtable->size]();
375 d = new(mem) QPropertyBindingPrivate(metaType, vtable, std::move(location));
376 vtable->moveConstruct(mem + QPropertyBindingPrivate::getSizeEnsuringAlignment(), function);
377}
378
379/*!
380 Move-constructs a QUntypedPropertyBinding from \a other.
381
382 \a other is left in a null state.
383 \sa isNull()
384*/
385QUntypedPropertyBinding::QUntypedPropertyBinding(QUntypedPropertyBinding &&other)
386 : d(std::move(other.d))
387{
388}
389
390/*!
391 Copy-constructs a QUntypedPropertyBinding from \a other.
392*/
393QUntypedPropertyBinding::QUntypedPropertyBinding(const QUntypedPropertyBinding &other)
394 : d(other.d)
395{
396}
397
398/*!
399 Copy-assigns \a other to this QUntypedPropertyBinding.
400*/
401QUntypedPropertyBinding &QUntypedPropertyBinding::operator=(const QUntypedPropertyBinding &other)
402{
403 d = other.d;
404 return *this;
405}
406
407/*!
408 Move-assigns \a other to this QUntypedPropertyBinding.
409
410 \a other is left in a null state.
411 \sa isNull
412*/
413QUntypedPropertyBinding &QUntypedPropertyBinding::operator=(QUntypedPropertyBinding &&other)
414{
415 d = std::move(other.d);
416 return *this;
417}
418
419/*!
420 \internal
421*/
422QUntypedPropertyBinding::QUntypedPropertyBinding(QPropertyBindingPrivate *priv)
423 : d(priv)
424{
425}
426
427/*!
428 Destroys the QUntypedPropertyBinding.
429*/
430QUntypedPropertyBinding::~QUntypedPropertyBinding()
431{
432}
433
434/*!
435 Returns \c true if the \c QUntypedPropertyBinding is null.
436 This is only true for default-constructed and moved-from instances.
437
438 \sa isNull()
439*/
440bool QUntypedPropertyBinding::isNull() const
441{
442 return !d;
443}
444
445/*!
446 Returns the error state of the binding.
447
448 \sa QPropertyBindingError
449*/
450QPropertyBindingError QUntypedPropertyBinding::error() const
451{
452 if (!d)
453 return QPropertyBindingError();
454 return static_cast<QPropertyBindingPrivate *>(d.get())->bindingError();
455}
456
457/*!
458 Returns the meta-type of the binding.
459 If the QUntypedPropertyBinding is null, an invalid QMetaType is returned.
460*/
461QMetaType QUntypedPropertyBinding::valueMetaType() const
462{
463 if (!d)
464 return QMetaType();
465 return static_cast<QPropertyBindingPrivate *>(d.get())->valueMetaType();
466}
467
468QPropertyBindingData::~QPropertyBindingData()
469{
470 QPropertyBindingDataPointer d{this};
471 if (isNotificationDelayed())
472 proxyData()->originalBindingData = nullptr;
473 for (auto observer = d.firstObserver(); observer;) {
474 auto next = observer.nextObserver();
475 observer.unlink();
476 observer = next;
477 }
478 if (auto binding = d.binding())
479 binding->unlinkAndDeref();
480}
481
482QUntypedPropertyBinding QPropertyBindingData::setBinding(const QUntypedPropertyBinding &binding,
483 QUntypedPropertyData *propertyDataPtr,
484 QPropertyObserverCallback staticObserverCallback,
485 QtPrivate::QPropertyBindingWrapper guardCallback)
486{
487 QPropertyBindingPrivatePtr oldBinding;
488 QPropertyBindingPrivatePtr newBinding = binding.d;
489
490 QPropertyBindingDataPointer d{this};
491 QPropertyObserverPointer observer;
492
493 auto &data = d_ref();
494 if (auto *existingBinding = d.binding()) {
495 if (existingBinding == newBinding.data())
496 return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(oldBinding.data()));
497 if (existingBinding->isUpdating()) {
498 existingBinding->setError({QPropertyBindingError::BindingLoop, QStringLiteral("Binding set during binding evaluation!")});
499 return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(oldBinding.data()));
500 }
501 oldBinding = QPropertyBindingPrivatePtr(existingBinding);
502 observer = static_cast<QPropertyBindingPrivate *>(oldBinding.data())->takeObservers();
503 static_cast<QPropertyBindingPrivate *>(oldBinding.data())->unlinkAndDeref();
504 data = 0;
505 } else {
506 observer = d.firstObserver();
507 }
508
509 if (newBinding) {
510 newBinding.data()->addRef();
511 data = reinterpret_cast<quintptr>(newBinding.data());
512 data |= BindingBit;
513 auto newBindingRaw = static_cast<QPropertyBindingPrivate *>(newBinding.data());
514 newBindingRaw->setProperty(propertyDataPtr);
515 if (observer)
516 newBindingRaw->prependObserver(observer);
517 newBindingRaw->setStaticObserver(staticObserverCallback, guardCallback);
518
519 PendingBindingObserverList bindingObservers;
520 newBindingRaw->evaluateRecursive(bindingObservers);
521 newBindingRaw->notifyNonRecursive(bindingObservers);
522 } else if (observer) {
523 d.setObservers(observer.ptr);
524 } else {
525 data = 0;
526 }
527
528 if (oldBinding)
529 static_cast<QPropertyBindingPrivate *>(oldBinding.data())->detachFromProperty();
530
531 return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(oldBinding.data()));
532}
533
534QPropertyBindingData::QPropertyBindingData(QPropertyBindingData &&other) : d_ptr(std::exchange(other.d_ptr, 0))
535{
536 QPropertyBindingDataPointer::fixupAfterMove(this);
537}
538
539BindingEvaluationState::BindingEvaluationState(QPropertyBindingPrivate *binding, QBindingStatus *status)
541{
542 Q_ASSERT(status);
543 QBindingStatus *s = status;
544 // store a pointer to the currentBindingEvaluationState to avoid a TLS lookup in
545 // the destructor (as these come with a non zero cost)
546 currentState = &s->currentlyEvaluatingBinding;
548 *currentState = this;
549 binding->clearDependencyObservers();
550}
551
552CompatPropertySafePoint::CompatPropertySafePoint(QBindingStatus *status, QUntypedPropertyData *property)
553 : property(property)
554{
555 // store a pointer to the currentBindingEvaluationState to avoid a TLS lookup in
556 // the destructor (as these come with a non zero cost)
557 currentState = &status->currentCompatProperty;
559 *currentState = this;
560
561 currentlyEvaluatingBindingList = &bindingStatus.currentlyEvaluatingBinding;
564}
565
566QPropertyBindingPrivate *QPropertyBindingPrivate::currentlyEvaluatingBinding()
567{
568 auto currentState = bindingStatus.currentlyEvaluatingBinding ;
569 return currentState ? currentState->binding : nullptr;
570}
571
572// ### Unused, kept for BC with 6.0
573void QPropertyBindingData::evaluateIfDirty(const QUntypedPropertyData *) const
574{
575}
576
577void QPropertyBindingData::removeBinding_helper()
578{
579 QPropertyBindingDataPointer d{this};
580
581 auto *existingBinding = d.binding();
582 Q_ASSERT(existingBinding);
583 if (existingBinding->isSticky()) {
584 return;
585 }
586
587 auto observer = existingBinding->takeObservers();
588 d_ref() = 0;
589 if (observer)
590 d.setObservers(observer.ptr);
591 existingBinding->unlinkAndDeref();
592}
593
594void QPropertyBindingData::registerWithCurrentlyEvaluatingBinding() const
595{
596 auto currentState = bindingStatus.currentlyEvaluatingBinding;
597 if (!currentState)
598 return;
599 registerWithCurrentlyEvaluatingBinding_helper(currentState);
600}
601
602
603void QPropertyBindingData::registerWithCurrentlyEvaluatingBinding_helper(BindingEvaluationState *currentState) const
604{
605 QPropertyBindingDataPointer d{this};
606
607 if (currentState->alreadyCaptureProperties.contains(this))
608 return;
609 else
610 currentState->alreadyCaptureProperties.push_back(this);
611
612 QPropertyObserverPointer dependencyObserver = currentState->binding->allocateDependencyObserver();
613 Q_ASSERT(QPropertyObserver::ObserverNotifiesBinding == 0);
614 dependencyObserver.setBindingToNotify_unsafe(currentState->binding);
615 d.addObserver(dependencyObserver.ptr);
616}
617
618void QPropertyBindingData::notifyObservers(QUntypedPropertyData *propertyDataPtr) const
619{
620 notifyObservers(propertyDataPtr, nullptr);
621}
622
623void QPropertyBindingData::notifyObservers(QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage) const
624{
625 if (isNotificationDelayed())
626 return;
627 QPropertyBindingDataPointer d{this};
628
629 PendingBindingObserverList bindingObservers;
630 if (QPropertyObserverPointer observer = d.firstObserver()) {
631 if (notifyObserver_helper(propertyDataPtr, storage, observer, bindingObservers) == Evaluated) {
632 /* evaluateBindings() can trash the observers. We need to re-fetch here.
633 "this" might also no longer be valid in case we have a QObjectBindableProperty
634 and consequently d isn't either (this happens when binding evaluation has
635 caused the binding storage to resize.
636 If storage is nullptr, then there is no dynamically resizable storage,
637 and we cannot run into the issue.
638 */
639 if (storage)
640 d = QPropertyBindingDataPointer {storage->bindingData(propertyDataPtr)};
641 if (QPropertyObserverPointer observer = d.firstObserver())
642 observer.notify(propertyDataPtr);
643 for (auto &&bindingPtr: bindingObservers) {
644 auto *binding = static_cast<QPropertyBindingPrivate *>(bindingPtr.get());
645 binding->notifyNonRecursive();
646 }
647 }
648 }
649}
650
651QPropertyBindingData::NotificationResult QPropertyBindingData::notifyObserver_helper
652(
653 QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage,
654 QPropertyObserverPointer observer,
655 PendingBindingObserverList &bindingObservers) const
656{
657#ifdef QT_HAS_FAST_CURRENT_THREAD_ID
658 QBindingStatus *status = storage ? storage->bindingStatus : nullptr;
659 if (!status || status->threadId != QThread::currentThreadId())
660 status = &bindingStatus;
661#else
662 Q_UNUSED(storage);
663 QBindingStatus *status = &bindingStatus;
664#endif
665 if (QPropertyDelayedNotifications *delay = status->groupUpdateData) {
666 delay->addProperty(this, propertyDataPtr);
667 return Delayed;
668 }
669
670 observer.evaluateBindings(bindingObservers, status);
671 return Evaluated;
672}
673
674
675QPropertyObserver::QPropertyObserver(ChangeHandler changeHandler)
676{
677 QPropertyObserverPointer d{this};
678 d.setChangeHandler(changeHandler);
679}
680
681#if QT_DEPRECATED_SINCE(6, 6)
682QPropertyObserver::QPropertyObserver(QUntypedPropertyData *data)
683{
684 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
685 aliasData = data;
686 next.setTag(ObserverIsAlias);
687 QT_WARNING_POP
688}
689#endif
691/*! \internal
692*/
693void QPropertyObserver::setSource(const QPropertyBindingData &property)
694{
695 QPropertyObserverPointer d{this};
696 QPropertyBindingDataPointer propPrivate{&property};
697 d.observeProperty(propPrivate);
698}
699
700QPropertyObserver::~QPropertyObserver()
701{
702 QPropertyObserverPointer d{this};
703 d.unlink();
704}
705
706QPropertyObserver::QPropertyObserver(QPropertyObserver &&other) noexcept
707{
708 binding = std::exchange(other.binding, {});
709 next = std::exchange(other.next, {});
710 prev = std::exchange(other.prev, {});
711 if (next)
712 next->prev = &next;
713 if (prev)
714 prev.setPointer(this);
715}
716
717QPropertyObserver &QPropertyObserver::operator=(QPropertyObserver &&other) noexcept
718{
719 if (this == &other)
720 return *this;
721
722 QPropertyObserverPointer d{this};
723 d.unlink();
724 binding = nullptr;
725
726 binding = std::exchange(other.binding, {});
727 next = std::exchange(other.next, {});
728 prev = std::exchange(other.prev, {});
729 if (next)
730 next->prev = &next;
731 if (prev)
732 prev.setPointer(this);
733
734 return *this;
735}
736
737/*!
738 \fn QPropertyObserverPointer::unlink()
739 \internal
740 Unlinks
741 */
742
743
744/*!
745 \fn QPropertyObserverPointer::unlink_fast()
746 \internal
747 Like unlink, but does not handle ObserverIsAlias.
748 Must only be called in places where we know that we are not dealing
749 with such an observer.
750 */
751
752void QPropertyObserverPointer::setChangeHandler(QPropertyObserver::ChangeHandler changeHandler)
753{
754 Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsPlaceholder);
755 ptr->changeHandler = changeHandler;
756 ptr->next.setTag(QPropertyObserver::ObserverNotifiesChangeHandler);
757}
758
759/*!
760 \internal
761 The same as setBindingToNotify, but assumes that the tag is already correct.
762 */
763void QPropertyObserverPointer::setBindingToNotify_unsafe(QPropertyBindingPrivate *binding)
764{
765 Q_ASSERT(ptr->next.tag() == QPropertyObserver::ObserverNotifiesBinding);
766 ptr->binding = binding;
767}
768
769/*!
770 \class QPropertyObserverNodeProtector
771 \internal
772 QPropertyObserverNodeProtector is a RAII wrapper which takes care of the internal switching logic
773 for QPropertyObserverPointer::notify (described ibidem)
774*/
775
776/*!
777 \fn QPropertyObserverNodeProtector::notify(QUntypedPropertyData *propertyDataPtr)
778 \internal
779 \a propertyDataPtr is a pointer to the observed property's property data
780*/
781
782#ifndef QT_NO_DEBUG
783void QPropertyObserverPointer::noSelfDependencies(QPropertyBindingPrivate *binding)
784{
785 auto observer = const_cast<QPropertyObserver*>(ptr);
786 // See also comment in notify()
787 while (observer) {
788 if (QPropertyObserver::ObserverTag(observer->next.tag()) == QPropertyObserver::ObserverNotifiesBinding)
789 if (observer->binding == binding) {
790 qCritical("Property depends on itself!");
791 break;
792 }
793
794 observer = observer->next.data();
795 }
796
797}
798#endif
799
800void QPropertyObserverPointer::evaluateBindings(PendingBindingObserverList &bindingObservers, QBindingStatus *status)
801{
802 Q_ASSERT(status);
803 auto observer = const_cast<QPropertyObserver*>(ptr);
804 // See also comment in notify()
805 while (observer) {
806 QPropertyObserver *next = observer->next.data();
807
808 if (QPropertyObserver::ObserverTag(observer->next.tag()) == QPropertyObserver::ObserverNotifiesBinding) {
809 auto bindingToEvaluate = observer->binding;
810 QPropertyObserverNodeProtector protector(observer);
811 // binding must not be gone after evaluateRecursive_inline
812 QPropertyBindingPrivatePtr currentBinding(observer->binding);
813 const bool evalStatus = bindingToEvaluate->evaluateRecursive_inline(bindingObservers, status);
814 if (evalStatus)
815 bindingObservers.push_back(std::move(currentBinding));
816 next = protector.next();
817 }
818
819 observer = next;
820 }
821}
822
824{
825 if (ptr->prev)
826 unlink();
827 property.addObserver(ptr);
828}
829
830/*!
831 \class QPropertyBindingError
832 \inmodule QtCore
833 \ingroup tools
834 \since 6.0
835
836 QPropertyBindingError is used by \l{The Property System}{the property
837 system} to report errors that occurred when a binding was evaluated. Use \l
838 type() to query which error occurred, and \l
839 description() to extract an error message which might contain
840 more details.
841 If there is no error, QPropertyBindingError has type
842 \c QPropertyBindingError::NoError and \c hasError() returns false.
843
844 \code
845 extern QProperty<int> prop;
846
847 QPropertyBindingError error = prop.binding().error();
848 if (error.hasError())
849 qDebug() << error.description();
850 \endcode
851*/
852
853/*!
854 \enum QPropertyBindingError::Type
855
856 This enum specifies which error occurred.
857
858 \value NoError
859 No error occurred while evaluating the binding.
860 \value BindingLoop
861 Binding evaluation was stopped because a property depended on its own
862 value.
863 \value EvaluationError
864 Binding evaluation was stopped for any other reason than a binding loop.
865 For example, this value is used in the QML engine when an exception occurs
866 while a binding is evaluated.
867 \value UnknownError
868 A generic error type used when neither of the other values is suitable.
869 Calling \l description() might provide details.
870*/
871
872/*!
873 Default constructs QPropertyBindingError.
874 hasError() will return false, type will return \c NoError and
875 \l description() will return an empty string.
876*/
877QPropertyBindingError::QPropertyBindingError()
878{
879}
880
881/*!
882 Constructs a QPropertyBindingError of type \a type with \a description as its
883 description.
884*/
885QPropertyBindingError::QPropertyBindingError(Type type, const QString &description)
886{
887 if (type != NoError) {
888 d = new QPropertyBindingErrorPrivate;
889 d->type = type;
890 d->description = description;
891 }
892}
893
894/*!
895 Copy-constructs QPropertyBindingError from \a other.
896*/
897QPropertyBindingError::QPropertyBindingError(const QPropertyBindingError &other)
898 : d(other.d)
899{
900}
901
902/*!
903 Copies \a other to this QPropertyBindingError.
904*/
905QPropertyBindingError &QPropertyBindingError::operator=(const QPropertyBindingError &other)
906{
907 d = other.d;
908 return *this;
909}
910
911/*!
912 Move-constructs QPropertyBindingError from \a other.
913 \a other will be left in its default state.
914*/
915QPropertyBindingError::QPropertyBindingError(QPropertyBindingError &&other)
916 : d(std::move(other.d))
917{
918}
919
920/*!
921 Move-assigns \a other to this QPropertyBindingError.
922 \a other will be left in its default state.
923*/
924QPropertyBindingError &QPropertyBindingError::operator=(QPropertyBindingError &&other)
925{
926 d = std::move(other.d);
927 return *this;
928}
929
930/*!
931 Destroys the QPropertyBindingError.
932*/
933QPropertyBindingError::~QPropertyBindingError()
934{
935}
936
937/*!
938 Returns the type of the QPropertyBindingError.
939
940 \sa QPropertyBindingError::Type
941*/
942QPropertyBindingError::Type QPropertyBindingError::type() const
943{
944 if (!d)
945 return QPropertyBindingError::NoError;
946 return d->type;
947}
948
949/*!
950 Returns a descriptive error message for the QPropertyBindingError if
951 it has been set.
952*/
953QString QPropertyBindingError::description() const
954{
955 if (!d)
956 return QString();
957 return d->description;
958}
959
960/*!
961 \class QPropertyData
962 \inmodule QtCore
963 \brief The QPropertyData class is a helper class for properties with automatic property bindings.
964 \since 6.0
965
966 \ingroup tools
967
968 QPropertyData<T> is a common base class for classes that can hold properties with automatic
969 data bindings. It mainly wraps the stored data, and offers low level access to that data.
970
971 The low level access to the data provided by this class bypasses the binding mechanism, and should be
972 used with care, as updates to the values will not get propagated to any bindings that depend on this
973 property.
974
975 You should usually call value() and setValue() on QProperty<T> or QObjectBindableProperty<T>, not use
976 the low level mechanisms provided in this class.
977*/
978
979/*! \fn template <typename T> QPropertyData<T>::parameter_type QPropertyData<T>::valueBypassingBindings() const
980
981 Returns the data stored in this property.
982
983 \note As this will bypass any binding evaluation it might return an outdated value if a
984 binding is set on this property. Using this method will also not register the property
985 access with any currently executing binding.
986*/
987
988/*! \fn template <typename T> void QPropertyData<T>::setValueBypassingBindings(parameter_type v)
989
990 Sets the data value stored in this property to \a v.
991
992 \note Using this method will bypass any potential binding registered for this property.
993*/
994
995/*! \fn template <typename T> void QPropertyData<T>::setValueBypassingBindings(rvalue_ref v)
996 \overload
997
998 Sets the data value stored in this property to \a v.
999
1000 \note Using this method will bypass any potential binding registered for this property.
1001*/
1002
1003/*!
1004 \class QUntypedBindable
1005 \inmodule QtCore
1006 \brief QUntypedBindable is a uniform interface over bindable properties like \c QProperty<T>
1007 and \c QObjectBindableProperty of any type \c T.
1008 \since 6.0
1009
1010 \ingroup tools
1011
1012 QUntypedBindable is a fully type-erased generic interface to wrap bindable properties.
1013 You can use it to interact with properties without knowing their type nor caring what
1014 kind of bindable property they are (e.g. QProperty or QObjectBindableProperty).
1015 For most use cases, using QBindable<T> (which is generic over the property implementation
1016 but has a fixed type) should be preferred.
1017*/
1018
1019/*!
1020 \fn QUntypedBindable::QUntypedBindable()
1021
1022 Default-constructs a QUntypedBindable. It is in an invalid state.
1023 \sa isValid()
1024*/
1025
1026/*!
1027 \fn template<typename Property> QUntypedBindable::QUntypedBindable(Property *property)
1028
1029 Constructs a QUntypedBindable from the property \a property. If Property is const,
1030 the QUntypedBindable will be read only. If \a property is null, the QUntypedBindable
1031 will be invalid.
1032
1033 \sa isValid(), isReadOnly()
1034*/
1035
1036/*!
1037 \fn bool QUntypedBindable::isValid() const
1038
1039 Returns true if the QUntypedBindable is valid. Methods called on an invalid
1040 QUntypedBindable generally have no effect, unless otherwise noted.
1041*/
1042
1043/*!
1044 \fn bool QUntypedBindable::isReadOnly() const
1045 \since 6.1
1046
1047 Returns true if the QUntypedBindable is read-only.
1048*/
1049
1050/*!
1051 \fn bool QUntypedBindable::isBindable() const
1052 \internal
1053
1054 Returns true if the underlying property's binding can be queried
1055 with binding() and, if not read-only, changed with setBinding.
1056 Only QObjectComputedProperty currently leads to this method returning
1057 false.
1058
1059 \sa isReadOnly()
1060*/
1061
1062/*!
1063 \fn QUntypedPropertyBinding QUntypedBindable::makeBinding(const QPropertyBindingSourceLocation &location) const
1064
1065 Creates a binding returning the underlying properties' value, using a specified source \a location.
1066*/
1067
1068/*!
1069 \fn void QUntypedBindable::observe(QPropertyObserver *observer)
1070 \internal
1071
1072 Installs the observer on the underlying property.
1073*/
1074
1075/*!
1076 \fn template<typename Functor> QPropertyChangeHandler<Functor> QUntypedBindable::onValueChanged(Functor f) const
1077
1078 Installs \a f as a change handler. Whenever the underlying property changes, \a f will be called, as
1079 long as the returned \c QPropertyChangeHandler and the property are kept alive.
1080 On each value change, the handler is either called immediately, or deferred, depending on the context.
1081
1082 \sa onValueChanged(), subscribe()
1083*/
1084
1085/*!
1086 \fn template<typename Functor> QPropertyChangeHandler<Functor> QUntypedBindable::subscribe(Functor f) const
1087
1088 Behaves like a call to \a f followed by \c onValueChanged(f),
1089
1090 \sa onValueChanged()
1091*/
1092
1093/*!
1094 \fn template<typename Functor> QPropertyNotifier QUntypedBindable::addNotifier(Functor f)
1095
1096 Installs \a f as a change handler. Whenever the underlying property changes, \a f will be called, as
1097 long as the returned \c QPropertyNotifier and the property are kept alive.
1098
1099 This method is in some cases easier to use than onValueChanged(), as the returned object is not a template.
1100 It can therefore more easily be stored, e.g. as a member in a class.
1101
1102 \sa onValueChanged(), subscribe()
1103*/
1104
1105/*!
1106 \fn QUntypedPropertyBinding QUntypedBindable::binding() const
1107
1108 Returns the underlying property's binding if there is any, or a default
1109 constructed QUntypedPropertyBinding otherwise.
1110
1111 \sa hasBinding()
1112*/
1113
1114/*!
1115 \fn QUntypedPropertyBinding QUntypedBindable::takeBinding()
1116
1117 Removes the currently set binding from the property and returns it.
1118 Returns a default-constructed QUntypedPropertyBinding if no binding is set.
1119
1120 \since 6.1
1121*/
1122
1123/*!
1124 \fn bool QUntypedBindable::setBinding(const QUntypedPropertyBinding &binding)
1125
1126 Sets the underlying property's binding to \a binding. This does not have any effect
1127 if the QUntypedBindable is read-only, null or if \a binding's type does match the
1128 underlying property's type.
1129
1130 \return \c true when the binding was successfully set.
1131
1132 //! \sa QUntypedPropertyBinding::valueMetaType()
1133*/
1134
1135/*!
1136 \fn bool QUntypedBindable::hasBinding() const
1137
1138 Returns \c true if the underlying property has a binding.
1139*/
1140
1141/*!
1142 \fn QMetaType QUntypedBindable::metaType() const
1143 \since 6.2
1144
1145 Returns the metatype of the property from which the QUntypedBindable was created.
1146 If the bindable is invalid, an invalid metatype will be returned.
1147
1148 \sa isValid()
1149 //! \sa QUntypedPropertyBinding::valueMetaType()
1150*/
1151
1152/*!
1153 \class QBindable
1154 \inmodule QtCore
1155 \brief QBindable is a wrapper class around binding-enabled properties. It allows type-safe
1156 operations while abstracting the differences between the various property classes away.
1157 \inherits QUntypedBindable
1158
1159 \ingroup tools
1160
1161 QBindable<T> helps to integrate Qt's traditional Q_PROPERTY with
1162 \l {Qt Bindable Properties}{binding-enabled} properties.
1163 If a property is backed by a QProperty, QObjectBindableProperty or QObjectComputedProperty,
1164 you can add \c BINDABLE bindablePropertyName to the Q_PROPERTY
1165 declaration, where bindablePropertyName is a function returning an instance of QBindable
1166 constructed from the QProperty. The returned QBindable allows users of the property to set
1167 and query bindings of the property, without having to know the exact kind of binding-enabled
1168 property used.
1169
1170 \snippet code/src_corelib_kernel_qproperty.cpp 0
1171 \snippet code/src_corelib_kernel_qproperty.cpp 3
1172
1173 \sa QMetaProperty::isBindable, QProperty, QObjectBindableProperty,
1174 QObjectComputedProperty, {Qt Bindable Properties}
1175*/
1176
1177/*!
1178 \fn template<typename T> QBindable<T>::QBindable(QObject *obj, const char *property)
1179 \since 6.5
1180
1181 Constructs a QBindable for the \l Q_PROPERTY \a property on \a obj. The property must
1182 have a notify signal but does not need to have \c BINDABLE in its \c Q_PROPERTY
1183 definition, so even binding unaware \c {Q_PROPERTY}s can be bound or used in binding
1184 expressions. You must use \c QBindable::value() in binding expressions instead of the
1185 normal property \c READ function (or \c MEMBER) to enable dependency tracking if the
1186 property is not \c BINDABLE. When binding using a lambda, you may prefer to capture the
1187 QBindable by value to avoid the cost of calling this constructor in the binding
1188 expression.
1189 This constructor should not be used to implement \c BINDABLE for a Q_PROPERTY, as the
1190 resulting Q_PROPERTY will not support dependency tracking. To make a property that is
1191 usable directly without reading through a QBindable use \l QProperty or
1192 \l QObjectBindableProperty.
1193
1194 \code
1195 QProperty<QString> displayText;
1196 QDateTimeEdit *dateTimeEdit = findDateTimeEdit();
1197 QBindable<QDateTime> dateTimeBindable(dateTimeEdit, "dateTime");
1198 displayText.setBinding([dateTimeBindable](){ return dateTimeBindable.value().toString(); });
1199 \endcode
1200
1201 \sa QProperty, QObjectBindableProperty, {Qt Bindable Properties}
1202*/
1203
1204/*!
1205 \fn template<typename T> QBindable<T>::QBindable(QObject *obj, const QMetaProperty &property)
1206 \since 6.5
1207
1208 See \l QBindable::QBindable(QObject *obj, const char *property)
1209*/
1210
1211/*!
1212 \fn template<typename T> QPropertyBinding<T> QBindable<T>::makeBinding(const QPropertyBindingSourceLocation &location) const
1213
1214 Constructs a binding evaluating to the underlying property's value, using a specified source
1215 \a location.
1216*/
1217
1218/*!
1219 \fn template <typename T> QPropertyBinding<T> QBindable<T>::binding() const
1220
1221 Returns the currently set binding of the underlying property. If the property does not
1222 have a binding, the returned \c QPropertyBinding<T> will be invalid.
1223
1224 \sa setBinding, hasBinding
1225 //! \sa QPropertyBinding::isValid()
1226*/
1227
1228/*!
1229 \fn template <typename T> QPropertyBinding<T> QBindable<T>::takeBinding()
1230
1231 Removes the currently set binding of the underlying property and returns it.
1232 If the property does not have a binding, the returned \c QPropertyBinding<T> will be invalid.
1233
1234 \sa binding, setBinding, hasBinding
1235 //! \sa QPropertyBinding::isValid()
1236*/
1237
1238
1239/*!
1240 \fn template <typename T> void QBindable<T>::setBinding(const QPropertyBinding<T> &binding)
1241
1242 Sets the underlying property's binding to \a binding. Does nothing if the QBindable is
1243 read-only or invalid.
1244
1245 \sa binding, isReadOnly(), isValid()
1246 //! \sa QPropertyBinding::isValid()
1247*/
1248
1249/*!
1250 \fn template <typename T> template <typename Functor> QPropertyBinding<T> QBindable<T>::setBinding(Functor f);
1251 \overload
1252
1253 Creates a \c QPropertyBinding<T> from \a f, and sets it as the underlying property's binding.
1254*/
1255
1256/*!
1257 \fn template <typename T> T QBindable<T>::value() const
1258
1259 Returns the underlying property's current value. If the QBindable is invalid,
1260 a default constructed \c T is returned.
1261
1262 \sa isValid()
1263*/
1264
1265/*!
1266 \fn template <typename T> void QBindable<T>::setValue(const T &value)
1267
1268 Sets the underlying property's value to \a value. This removes any currenltly set
1269 binding from it. This function has no effect if the QBindable is read-only or invalid.
1270
1271 \sa isValid(), isReadOnly(), setBinding()
1272*/
1273
1274/*!
1275 \class QProperty
1276 \inmodule QtCore
1277 \brief The QProperty class is a template class that enables automatic property bindings.
1278 \since 6.0
1279
1280 \ingroup tools
1281
1282 QProperty<T> is one of the classes implementing \l {Qt Bindable Properties}.
1283 It is a container that holds an instance of T. You can assign
1284 a value to it and you can read it via the value() function or the T conversion
1285 operator. You can also tie the property to an expression that computes the value
1286 dynamically, the binding expression. It is represented as a C++ lambda and
1287 can be used to express relationships between different properties in your
1288 application.
1289
1290 \note For QML, it's important to expose the \l QProperty in \l Q_PROPERTY
1291 with the BINDABLE keyword. As a result, the QML engine uses
1292 it as the bindable interface to set up the property binding. In turn, the
1293 binding can then be interacted with C++ via the normal API:
1294 QProperty<T>::onValueChanged, QProperty::takeBinding and QBindable::hasBinding
1295 If the property is BINDABLE, the engine will use the change-tracking
1296 inherent to the C++ property system for getting notified about changes, and it
1297 won't rely on signals being emitted.
1298*/
1299
1300/*!
1301 \fn template <typename T> QProperty<T>::QProperty()
1302
1303 Constructs a property with a default constructed instance of T.
1304*/
1305
1306/*!
1307 \fn template <typename T> explicit QProperty<T>::QProperty(const T &initialValue)
1308
1309 Constructs a property with the provided \a initialValue.
1310*/
1311
1312/*!
1313 \fn template <typename T> explicit QProperty<T>::QProperty(T &&initialValue)
1314
1315 Move-Constructs a property with the provided \a initialValue.
1316*/
1317
1318/*!
1319 \fn template <typename T> QProperty<T>::QProperty(QProperty<T> &&other)
1320
1321 Move-constructs a QProperty instance, making it point at the same object that
1322 \a other was pointing to.
1323*/
1324
1325/*!
1326 \fn template <typename T> QProperty<T>::QProperty(const QPropertyBinding<T> &binding)
1327
1328 Constructs a property that is tied to the provided \a binding expression.
1329 The property's value is set to the result of evaluating the new binding.
1330 Whenever a dependency of the binding changes, the binding will be re-evaluated,
1331 and the property's value gets updated accordingly.
1332*/
1333
1334/*!
1335 \fn template <typename T> template <typename Functor> QProperty<T>::QProperty(Functor &&f)
1336
1337 Constructs a property that is tied to the provided binding expression \a f.
1338 The property's value is set to the result of evaluating the new binding.
1339 Whenever a dependency of the binding changes, the binding will be re-evaluated,
1340 and the property's value gets updated accordingly.
1341 */
1342
1343/*!
1344 \fn template <typename T> QProperty<T>::~QProperty()
1345
1346 Destroys the property.
1347*/
1348
1349/*!
1350 \fn template <typename T> T QProperty<T>::value() const
1351
1352 Returns the value of the property. This may evaluate a binding expression that
1353 is tied to this property, before returning the value.
1354*/
1355
1356/*!
1357 \fn template <typename T> void QProperty<T>::setValue(rvalue_ref newValue)
1358 \fn template <typename T> void QProperty<T>::setValue(parameter_type newValue)
1359
1360 Assigns \a newValue to this property and removes the property's associated
1361 binding, if present.
1362*/
1363
1364/*!
1365 \fn template <typename T> QProperty<T> &QProperty<T>::operator=(rvalue_ref newValue)
1366 \fn template <typename T> QProperty<T> &QProperty<T>::operator=(parameter_type newValue)
1367
1368 Assigns \a newValue to this property and returns a reference to this QProperty.
1369*/
1370
1371/*!
1372 \fn template <typename T> QPropertyBinding<T> QProperty<T>::setBinding(const QPropertyBinding<T> &newBinding)
1373
1374 Associates the value of this property with the provided \a newBinding
1375 expression and returns the previously associated binding. The property's value
1376 is set to the result of evaluating the new binding. Whenever a dependency of
1377 the binding changes, the binding will be re-evaluated, and the property's
1378 value gets updated accordingly.
1379*/
1380
1381/*!
1382 \fn template <typename T> template <typename Functor> QPropertyBinding<T> QProperty<T>::setBinding(Functor f)
1383 \overload
1384
1385 Associates the value of this property with the provided functor \a f and
1386 returns the previously associated binding. The property's value is set to the
1387 result of evaluating the new binding. Whenever a dependency of the binding
1388 changes, the binding will be re-evaluated, and the property's value gets
1389 updated accordingly.
1390
1391 \sa {Formulating a Property Binding}
1392*/
1393
1394/*!
1395 \fn template <typename T> QPropertyBinding<T> bool QProperty<T>::setBinding(const QUntypedPropertyBinding &newBinding)
1396 \overload
1397
1398 Associates the value of this property with the provided \a newBinding
1399 expression. The property's value is set to the result of evaluating the new
1400 binding. Whenever a dependency of the binding changes, the binding will be
1401 re-evaluated, and the property's value gets updated accordingly.
1402
1403
1404 Returns true if the type of this property is the same as the type the binding
1405 function returns; false otherwise.
1406*/
1407
1408/*!
1409 \fn template <typename T> QPropertyBinding<T> QProperty<T>::binding() const
1410
1411 Returns the binding expression that is associated with this property. A
1412 default constructed QPropertyBinding<T> will be returned if no such
1413 association exists.
1414*/
1415
1416/*!
1417 \fn template <typename T> QPropertyBinding<T> QProperty<T>::takeBinding()
1418
1419 Disassociates the binding expression from this property and returns it. After
1420 calling this function, the value of the property will only change if you
1421 assign a new value to it, or when a new binding is set.
1422*/
1423
1424/*!
1425 \fn template <typename T> template <typename Functor> QPropertyChangeHandler<T, Functor> QProperty<T>::onValueChanged(Functor f)
1426
1427 Registers the given functor \a f as a callback that shall be called whenever
1428 the value of the property changes. On each value change, the handler
1429 is either called immediately, or deferred, depending on the context.
1430
1431 The callback \a f is expected to be a type that has a plain call operator
1432 \c{()} without any parameters. This means that you can provide a C++ lambda
1433 expression, a std::function or even a custom struct with a call operator.
1434
1435 The returned property change handler object keeps track of the registration.
1436 When it goes out of scope, the callback is de-registered.
1437*/
1438
1439/*!
1440 \fn template <typename T> template <typename Functor> QPropertyChangeHandler<T, Functor> QProperty<T>::subscribe(Functor f)
1441
1442 Subscribes the given functor \a f as a callback that is called immediately and
1443 whenever the value of the property changes in the future. On each value
1444 change, the handler is either called immediately, or deferred, depending on
1445 the context.
1446
1447 The callback \a f is expected to be a type that can be copied and has a plain
1448 call operator() without any parameters. This means that you can provide a C++
1449 lambda expression, a std::function or even a custom struct with a call
1450 operator.
1451
1452 The returned property change handler object keeps track of the subscription.
1453 When it goes out of scope, the callback is unsubscribed.
1454*/
1455
1456/*!
1457 \fn template <typename T> template <typename Functor> QPropertyNotifier QProperty<T>::addNotifier(Functor f)
1458
1459 Subscribes the given functor \a f as a callback that is called whenever
1460 the value of the property changes.
1461
1462 The callback \a f is expected to be a type that has a plain call operator
1463 \c{()} without any parameters. This means that you can provide a C++ lambda
1464 expression, a std::function or even a custom struct with a call operator.
1465
1466 The returned property change handler object keeps track of the subscription.
1467 When it goes out of scope, the callback is unsubscribed.
1468
1469 This method is in some cases easier to use than onValueChanged(), as the
1470 returned object is not a template. It can therefore more easily be stored,
1471 e.g. as a member in a class.
1472
1473 \sa onValueChanged(), subscribe()
1474*/
1475
1476/*!
1477 \fn template <typename T> QtPrivate::QPropertyBindingData &QProperty<T>::bindingData() const
1478 \internal
1479*/
1480
1481/*!
1482 \class QObjectBindableProperty
1483 \inmodule QtCore
1484 \brief The QObjectBindableProperty class is a template class that enables
1485 automatic property bindings for property data stored in QObject derived
1486 classes.
1487 \since 6.0
1488
1489 \ingroup tools
1490
1491 QObjectBindableProperty is a generic container that holds an
1492 instance of T and behaves mostly like \l QProperty.
1493 It is one of the classes implementing \l {Qt Bindable Properties}.
1494 Unlike QProperty, it stores its management data structure in
1495 the surrounding QObject.
1496 The extra template parameters are used to identify the surrounding
1497 class and a member function of that class acting as a change handler.
1498
1499 You can use QObjectBindableProperty to add binding support to code that uses
1500 Q_PROPERTY. The getter and setter methods must be adapted carefully according
1501 to the rules described in \l {Bindable Property Getters and Setters}.
1502
1503 In order to invoke the change signal on property changes, use
1504 QObjectBindableProperty and pass the change signal as a callback.
1505
1506 A simple example is given in the following.
1507
1508 \snippet code/src_corelib_kernel_qproperty.cpp 4
1509
1510 QObjectBindableProperty is usually not used directly, instead an instance of
1511 it is created by using the Q_OBJECT_BINDABLE_PROPERTY macro.
1512
1513 Use the Q_OBJECT_BINDABLE_PROPERTY macro in the class declaration to declare
1514 the property as bindable.
1515
1516 \snippet code/src_corelib_kernel_qproperty.cpp 0
1517
1518 If you need to directly initialize the property with some non-default value,
1519 you can use the Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS macro. It accepts a
1520 value for the initialization as one of its parameters.
1521
1522 \snippet code/src_corelib_kernel_qproperty.cpp 1
1523
1524 Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS does not support multiple arguments
1525 directly. If your property requires multiple arguments for initialization,
1526 please explicitly call the specific constructor.
1527
1528 \snippet code/src_corelib_kernel_qproperty.cpp 2
1529
1530 The change handler can optionally accept one argument, of the same type as the
1531 property, in which case it is passed the new value of the property. Otherwise,
1532 it should take no arguments.
1533
1534 If the property does not need a changed notification, you can leave out the
1535 "NOTIFY xChanged" in the Q_PROPERTY macro as well as the last argument
1536 of the Q_OBJECT_BINDABLE_PROPERTY and Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS
1537 macros.
1538
1539 \sa Q_OBJECT_BINDABLE_PROPERTY, Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS,
1540 QProperty, QObjectComputedProperty, {Qt's Property System}, {Qt Bindable
1541 Properties}
1542*/
1543
1544/*!
1545 \macro Q_OBJECT_BINDABLE_PROPERTY(containingClass, type, name, signal)
1546 \since 6.0
1547 \relates QObjectBindableProperty
1548 \brief Declares a \l QObjectBindableProperty inside \a containingClass of type
1549 \a type with name \a name. If the optional argument \a signal is given, this
1550 signal will be emitted when the property is marked dirty.
1551
1552 \sa {Qt's Property System}, {Qt Bindable Properties}
1553*/
1554
1555/*!
1556 \macro Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(containingClass, type, name, initialvalue, signal)
1557 \since 6.0
1558 \relates QObjectBindableProperty
1559 \brief Declares a \l QObjectBindableProperty inside \a containingClass
1560 of type \a type with name \a name which is initialized to \a initialvalue.
1561 If the optional argument \a signal is given, this signal will be emitted when
1562 the property is marked dirty.
1563
1564 \sa {Qt's Property System}, {Qt Bindable Properties}
1565*/
1566
1567/*!
1568 \class QObjectCompatProperty
1569 \inmodule QtCore
1570 \brief The QObjectCompatProperty class is a template class to help port old
1571 properties to the bindable property system.
1572 \since 6.0
1573 \ingroup tools
1574 \internal
1575
1576 QObjectCompatProperty is a generic container that holds an
1577 instance of \c T and behaves mostly like QProperty, just like
1578 QObjectBindableProperty. It's one of the Qt internal classes implementing
1579 \l {Qt Bindable Properties}. Like QObjectBindableProperty,
1580 QObjectCompatProperty stores its management data structure in the surrounding
1581 QObject. The last template parameter specifies a method (of the owning
1582 class) to be called when the property is changed through the binding.
1583 This is usually a setter.
1584
1585 As explained in \l {Qt Bindable Properties}, getters and setters for bindable
1586 properties have to be almost trivial to be correct. However, in legacy code,
1587 there is often complex logic in the setter. QObjectCompatProperty is a helper
1588 to port these properties to the bindable property system.
1589
1590 With QObjectCompatProperty, the same rules as described in
1591 \l {Bindable Property Getters and Setters} hold for the getter.
1592 For the setter, the rules are different. It remains that every possible code
1593 path in the setter must write to the underlying QObjectCompatProperty,
1594 otherwise calling the setter might not remove a pre-existing binding, as
1595 it should. However, as QObjectCompatProperty will call the setter on every
1596 change, the setter is allowed to contain code like updating class internals
1597 or emitting signals. Every write to the QObjectCompatProperty has to
1598 be analyzed carefully to comply with the rules given in
1599 \l {Writing to a Bindable Property}.
1600
1601 \section2 Properties with Virtual Setters
1602
1603 Some of the pre-existing Qt classes (for example, \l QAbstractProxyModel)
1604 have properties with virtual setters. Special care must be taken when
1605 making such properties bindable.
1606
1607 For the binding to work properly, the property must be correctly handled in
1608 all reimplemented methods of each derived class.
1609
1610 Unless the derived class has access to the underlying property object, the
1611 base implementation \e must be called for the binding to work correctly.
1612
1613 If the derived class can directly access the property instance, there is no
1614 need to explicitly call the base implementation, but the property's value
1615 \e must be correctly updated.
1616
1617 Refer to \l {Bindable Properties with Virtual Setters and Getters} for more
1618 details.
1619
1620 In both cases the expected behavior \e must be documented in the property's
1621 documentation, so that users can correctly override the setter.
1622
1623 Properties for which these conditions cannot be met should not be made
1624 bindable.
1625
1626 \sa Q_OBJECT_COMPAT_PROPERTY, QObjectBindableProperty, {Qt's Property System}, {Qt Bindable
1627 Properties}
1628*/
1629
1630/*!
1631 \macro Q_OBJECT_COMPAT_PROPERTY(containingClass, type, name, callback)
1632 \since 6.0
1633 \relates QObjectCompatProperty
1634 \internal
1635 \brief Declares a \l QObjectCompatProperty inside \a containingClass
1636 of type \a type with name \a name. The argument \a callback specifies
1637 a setter function to be called when the property is changed through the binding.
1638
1639 \sa QObjectBindableProperty, {Qt's Property System}, {Qt Bindable Properties}
1640*/
1641
1642/*!
1643 \macro Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(containingClass, type, name, callback, value)
1644 \since 6.0
1645 \relates QObjectCompatProperty
1646 \internal
1647 \brief Declares a \l QObjectCompatProperty inside of \a containingClass
1648 of type \a type with name \a name. The argument \a callback specifies
1649 a setter function to be called when the property is changed through the binding.
1650 \a value specifies an initialization value.
1651*/
1652
1653/*!
1654 \class QObjectComputedProperty
1655 \inmodule QtCore
1656 \brief The QObjectComputedProperty class is a template class to help port old
1657 properties to the bindable property system.
1658 \since 6.0
1659 \ingroup tools
1660
1661 QObjectComputedProperty is a read-only property which is recomputed on each read.
1662 It does not store the computed value.
1663 It is one of the Qt internal classes implementing \l {Qt Bindable Properties}.
1664 QObjectComputedProperty is usually not used directly, instead an instance of it is created by
1665 using the Q_OBJECT_COMPUTED_PROPERTY macro.
1666
1667 See the following example.
1668
1669 \snippet code/src_corelib_kernel_qproperty.cpp 5
1670
1671 The rules for getters in \l {Bindable Property Getters and Setters}
1672 also apply for QObjectComputedProperty. Especially, the getter
1673 should be trivial and only return the value of the QObjectComputedProperty object.
1674 The callback given to the QObjectComputedProperty should usually be a private
1675 method which is only called by the QObjectComputedProperty.
1676
1677 No setter is required or allowed, as QObjectComputedProperty is read-only.
1678
1679 To correctly participate in dependency handling, QObjectComputedProperty
1680 has to know when its value, the result of the callback given to it, might
1681 have changed. Whenever a bindable property used in the callback changes,
1682 this happens automatically. If the result of the callback might change
1683 because of a change in a value which is not a bindable property,
1684 it is the developer's responsibility to call \c notify
1685 on the QObjectComputedProperty object.
1686 This will inform dependent properties about the potential change.
1687
1688 Note that calling \c notify might trigger change handlers in dependent
1689 properties, which might in turn use the object the QObjectComputedProperty
1690 is a member of. So \c notify must not be called when in a transitional
1691 or invalid state.
1692
1693 QObjectComputedProperty is not suitable for use with a computation that depends
1694 on any input that might change without notice, such as the contents of a file.
1695
1696 \sa Q_OBJECT_COMPUTED_PROPERTY, QProperty, QObjectBindableProperty,
1697 {Qt's Property System}, {Qt Bindable Properties}
1698*/
1699
1700/*!
1701 \macro Q_OBJECT_COMPUTED_PROPERTY(containingClass, type, name, callback)
1702 \since 6.0
1703 \relates QObjectComputedProperty
1704 \brief Declares a \l QObjectComputedProperty inside \a containingClass
1705 of type \a type with name \a name. The argument \a callback specifies
1706 a GETTER function to be called when the property is evaluated.
1707
1708 \sa QObjectBindableProperty, {Qt's Property System}, {Qt Bindable Properties}
1709*/
1710
1711/*!
1712 \fn template <typename Class, typename T, auto offset, auto Callback> QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty()
1713
1714 Constructs a property with a default constructed instance of T.
1715*/
1716
1717/*!
1718 \fn template <typename Class, typename T, auto offset, auto Callback> explicit QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(const T &initialValue)
1719
1720 Constructs a property with the provided \a initialValue.
1721*/
1722
1723/*!
1724 \fn template <typename Class, typename T, auto offset, auto Callback> explicit QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(T &&initialValue)
1725
1726 Move-Constructs a property with the provided \a initialValue.
1727*/
1728
1729/*!
1730 \fn template <typename Class, typename T, auto offset, auto Callback> QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(Class *owner, const QPropertyBinding<T> &binding)
1731
1732 Constructs a property that is tied to the provided \a binding expression.
1733 The property's value is set to the result of evaluating the new binding.
1734 Whenever a dependency of the binding changes, the binding will be
1735 re-evaluated, and the property's value gets updated accordingly.
1736
1737 When the property value changes, \a owner is notified via the Callback
1738 function.
1739*/
1740
1741/*!
1742 \fn template <typename Class, typename T, auto offset, auto Callback> QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(Class *owner, QPropertyBinding<T> &&binding)
1743
1744 Constructs a property that is tied to the provided \a binding expression.
1745 The property's value is set to the result of evaluating the new binding.
1746 Whenever a dependency of the binding changes, the binding will be
1747 re-evaluated, and the property's value gets updated accordingly.
1748
1749 When the property value changes, \a
1750 owner is notified via the Callback function.
1751*/
1752
1753/*!
1754 \fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(Functor &&f)
1755
1756 Constructs a property that is tied to the provided binding expression \a f.
1757 The property's value is set to the result of evaluating the new binding.
1758 Whenever a dependency of the binding changes, the binding will be
1759 re-evaluated, and the property's value gets updated accordingly.
1760
1761*/
1762
1763/*!
1764 \fn template <typename Class, typename T, auto offset, auto Callback> QObjectBindableProperty<Class, T, offset, Callback>::~QObjectBindableProperty()
1765
1766 Destroys the property.
1767*/
1768
1769/*!
1770 \fn template <typename Class, typename T, auto offset, auto Callback> T QObjectBindableProperty<Class, T, offset, Callback>::value() const
1771
1772 Returns the value of the property. This may evaluate a binding expression that
1773 is tied to this property, before returning the value.
1774*/
1775
1776/*!
1777 \fn template <typename Class, typename T, auto offset, auto Callback> void QObjectBindableProperty<Class, T, offset, Callback>::setValue(parameter_type newValue)
1778 \fn template <typename Class, typename T, auto offset, auto Callback> void QObjectBindableProperty<Class, T, offset, Callback>::setValue(rvalue_ref newValue)
1779
1780 Assigns \a newValue to this property and removes the property's associated
1781 binding, if present. If the property value changes as a result, calls the
1782 Callback function on \a owner.
1783*/
1784
1785/*!
1786 \fn template <typename Class, typename T, auto offset, auto Callback> void QObjectBindableProperty<Class, T, offset, Callback>::notify()
1787
1788 Programmatically signals a change of the property. Any binding which depend on
1789 it will be notified, and if the property has a signal, it will be emitted.
1790
1791 This can be useful in combination with setValueBypassingBindings to defer
1792 signalling the change until a class invariant has been restored.
1793
1794 \note If this property has a binding (i.e. hasBinding() returns true), that
1795 binding is not reevaluated when notify() is called. Any binding depending on
1796 this property is still reevaluated as usual.
1797
1798 \sa Qt::beginPropertyUpdateGroup(), setValueBypassingBindings()
1799*/
1800
1801/*!
1802 \fn template <typename Class, typename T, auto offset, auto Callback> QPropertyBinding<T> QObjectBindableProperty<Class, T, offset, Callback>::setBinding(const QPropertyBinding<T> &newBinding)
1803
1804 Associates the value of this property with the provided \a newBinding
1805 expression and returns the previously associated binding.
1806 The property's value is set to the result of evaluating the new binding. Whenever a dependency of
1807 the binding changes, the binding will be re-evaluated,
1808 and the property's value gets updated accordingly.
1809 When the property value changes, the owner
1810 is notified via the Callback function.
1811*/
1812
1813/*!
1814 \fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QPropertyBinding<T> QObjectBindableProperty<Class, T, offset, Callback>::setBinding(Functor f)
1815 \overload
1816
1817 Associates the value of this property with the provided functor \a f and
1818 returns the previously associated binding. The property's value is set to the
1819 result of evaluating the new binding by invoking the call operator \c{()} of \a
1820 f. Whenever a dependency of the binding changes, the binding will be
1821 re-evaluated, and the property's value gets updated accordingly.
1822
1823 When the property value changes, the owner is notified via the Callback
1824 function.
1825
1826 \sa {Formulating a Property Binding}
1827*/
1828
1829/*!
1830 \fn template <typename Class, typename T, auto offset, auto Callback> QPropertyBinding<T> bool QObjectBindableProperty<Class, T, offset, Callback>::setBinding(const QUntypedPropertyBinding &newBinding)
1831 \overload
1832
1833 Associates the value of this property with the provided \a newBinding
1834 expression. The property's value is set to the result of evaluating the new
1835 binding. Whenever a dependency of the binding changes, the binding will be
1836 re-evaluated, and the property's value gets updated accordingly.
1837
1838
1839 Returns \c true if the type of this property is the same as the type the
1840 binding function returns; \c false otherwise.
1841*/
1842
1843/*!
1844 \fn template <typename Class, typename T, auto offset, auto Callback> bool QObjectBindableProperty<Class, T, offset, Callback>::hasBinding() const
1845
1846 Returns true if the property is associated with a binding; false otherwise.
1847*/
1848
1849
1850/*!
1851 \fn template <typename Class, typename T, auto offset, auto Callback> QPropertyBinding<T> QObjectBindableProperty<Class, T, offset, Callback>::binding() const
1852
1853 Returns the binding expression that is associated with this property. A
1854 default constructed QPropertyBinding<T> will be returned if no such
1855 association exists.
1856*/
1857
1858/*!
1859 \fn template <typename Class, typename T, auto offset, auto Callback> QPropertyBinding<T> QObjectBindableProperty<Class, T, offset, Callback>::takeBinding()
1860
1861 Disassociates the binding expression from this property and returns it. After
1862 calling this function, the value of the property will only change if you
1863 assign a new value to it, or when a new binding is set.
1864*/
1865
1866/*!
1867 \fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QPropertyChangeHandler<T, Functor> QObjectBindableProperty<Class, T, offset, Callback>::onValueChanged(Functor f)
1868
1869 Registers the given functor \a f as a callback that shall be called whenever
1870 the value of the property changes. On each value change, the handler is either
1871 called immediately, or deferred, depending on the context.
1872
1873 The callback \a f is expected to be a type that has a plain call operator
1874 \c{()} without any parameters. This means that you can provide a C++ lambda
1875 expression, a std::function or even a custom struct with a call operator.
1876
1877 The returned property change handler object keeps track of the registration.
1878 When it goes out of scope, the callback is de-registered.
1879*/
1880
1881/*!
1882 \fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QPropertyChangeHandler<T, Functor> QObjectBindableProperty<Class, T, offset, Callback>::subscribe(Functor f)
1883
1884 Subscribes the given functor \a f as a callback that is called immediately and
1885 whenever the value of the property changes in the future. On each value
1886 change, the handler is either called immediately, or deferred, depending on
1887 the context.
1888
1889 The callback \a f is expected to be a type that has a plain call operator
1890 \c{()} without any parameters. This means that you can provide a C++ lambda
1891 expression, a std::function or even a custom struct with a call operator.
1892
1893 The returned property change handler object keeps track of the subscription.
1894 When it goes out of scope, the callback is unsubscribed.
1895*/
1896
1897/*!
1898 \fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QPropertyNotifier QObjectBindableProperty<Class, T, offset, Callback>::addNotifier(Functor f)
1899
1900 Subscribes the given functor \a f as a callback that is called whenever the
1901 value of the property changes.
1902
1903 The callback \a f is expected to be a type that has a plain call operator
1904 \c{()} without any parameters. This means that you can provide a C++ lambda
1905 expression, a std::function or even a custom struct with a call operator.
1906
1907 The returned property change handler object keeps track of the subscription.
1908 When it goes out of scope, the callback is unsubscribed.
1909
1910 This method is in some cases easier to use than onValueChanged(), as the
1911 returned object is not a template. It can therefore more easily be stored,
1912 e.g. as a member in a class.
1913
1914 \sa onValueChanged(), subscribe()
1915*/
1916
1917/*!
1918 \fn template <typename T> QtPrivate::QPropertyBase &QObjectBindableProperty<Class, T, offset, Callback>::propertyBase() const
1919 \internal
1920*/
1921
1922/*!
1923 \class QPropertyChangeHandler
1924 \inmodule QtCore
1925 \brief The QPropertyChangeHandler class controls the lifecycle of change
1926 callback installed on a QProperty.
1927
1928 \ingroup tools
1929
1930 QPropertyChangeHandler<Functor> is created when registering a callback on a
1931 QProperty to listen to changes to the property's value, using
1932 QProperty::onValueChanged and QProperty::subscribe. As long as the change
1933 handler is alive, the callback remains installed.
1934
1935 A handler instance can be transferred between C++ scopes using move semantics.
1936*/
1937
1938/*!
1939 \class QPropertyNotifier
1940 \inmodule QtCore
1941 \brief The QPropertyNotifier class controls the lifecycle of change callback installed on a QProperty.
1942
1943 \ingroup tools
1944
1945 QPropertyNotifier is created when registering a callback on a QProperty to
1946 listen to changes to the property's value, using QProperty::addNotifier. As
1947 long as the change handler is alive, the callback remains installed.
1948
1949 A handler instance can be transferred between C++ scopes using move semantics.
1950*/
1951
1952/*!
1953 \class QPropertyAlias
1954 \inmodule QtCore
1955 \internal
1956
1957 \brief The QPropertyAlias class is a safe alias for a QProperty with same
1958 template parameter.
1959
1960 \ingroup tools
1961
1962 QPropertyAlias<T> wraps a pointer to a QProperty<T> and automatically
1963 invalidates itself when the QProperty<T> is destroyed. It forwards all
1964 method invocations to the wrapped property. For example:
1965
1966 \code
1967 QProperty<QString> *name = new QProperty<QString>("John");
1968 QProperty<int> age(41);
1969
1970 QPropertyAlias<QString> nameAlias(name);
1971 QPropertyAlias<int> ageAlias(&age);
1972
1973 QProperty<QString> fullname;
1974 fullname.setBinding([&]() { return nameAlias.value() + " age: " + QString::number(ageAlias.value()); });
1975
1976 qDebug() << fullname.value(); // Prints "John age: 41"
1977
1978 *name = "Emma"; // Marks binding expression as dirty
1979
1980 qDebug() << fullname.value(); // Re-evaluates the binding expression and prints "Emma age: 41"
1981
1982 // Birthday is coming up
1983 ageAlias.setValue(age.value() + 1); // Writes the age property through the alias
1984
1985 qDebug() << fullname.value(); // Re-evaluates the binding expression and prints "Emma age: 42"
1986
1987 delete name; // Leaves the alias in an invalid, but accessible state
1988 nameAlias.setValue("Eve"); // Ignored: nameAlias carries a default-constructed QString now
1989
1990 ageAlias.setValue(92);
1991 qDebug() << fullname.value(); // Re-evaluates the binding expression and prints " age: 92"
1992 \endcode
1993*/
1994
1995/*!
1996 \fn template <typename T> QPropertyAlias<T>::QPropertyAlias(QProperty<T> *property)
1997
1998 Constructs a property alias for the given \a property.
1999*/
2000
2001/*!
2002 \fn template <typename T> explicit QPropertyAlias<T>::QPropertyAlias(QPropertyAlias<T> *alias)
2003
2004 Constructs a property alias for the property aliased by \a alias.
2005*/
2006
2007/*!
2008 \fn template <typename T> T QPropertyAlias<T>::value() const
2009
2010 Returns the value of the aliased property. This may evaluate a binding
2011 expression that is tied to the property, before returning the value.
2012*/
2013
2014/*!
2015 \fn template <typename T> QPropertyAlias<T>::operator T() const
2016
2017 Returns the value of the aliased property. This may evaluate a binding
2018 expression that is tied to the property, before returning the value.
2019*/
2020
2021/*!
2022 \fn template <typename T> void QPropertyAlias<T>::setValue(const T &newValue)
2023
2024 Assigns \a newValue to the aliased property and removes the property's
2025 associated binding, if present.
2026*/
2027
2028/*!
2029 \fn template <typename T> QPropertyAlias<T> &QPropertyAlias<T>::operator=(const T &newValue)
2030
2031 Assigns \a newValue to the aliased property and returns a reference to this
2032 QPropertyAlias.
2033*/
2034
2035/*!
2036 \fn template <typename T> QPropertyBinding<T> QPropertyAlias<T>::setBinding(const QPropertyBinding<T> &newBinding)
2037
2038 Associates the value of the aliased property with the provided \a newBinding
2039 expression and returns any previous binding the associated with the aliased
2040 property.The property's value is set to the result of evaluating the new
2041 binding. Whenever a dependency of the binding changes, the binding will be
2042 re-evaluated, and the property's value gets updated accordingly.
2043
2044
2045 Returns any previous binding associated with the property, or a
2046 default-constructed QPropertyBinding<T>.
2047*/
2048
2049/*!
2050 \fn template <typename T> QPropertyBinding<T> bool QPropertyAlias<T>::setBinding(const QUntypedPropertyBinding &newBinding)
2051 \overload
2052
2053 Associates the value of the aliased property with the provided \a newBinding
2054 expression. The property's value is set to the result of evaluating the new
2055 binding. Whenever a dependency of the binding changes, the binding will be
2056 re-evaluated, and the property's value gets updated accordingly.
2057
2058
2059 Returns true if the type of this property is the same as the type the binding
2060 function returns; false otherwise.
2061*/
2062
2063/*!
2064 \fn template <typename T> template <typename Functor> QPropertyBinding<T> QPropertyAlias<T>::setBinding(Functor f)
2065 \overload
2066
2067 Associates the value of the aliased property with the provided functor \a f
2068 expression. The property's value is set to the result of evaluating the new
2069 binding. Whenever a dependency of the binding changes, the binding will be
2070 re-evaluated, and the property's value gets updated accordingly.
2071
2072
2073 Returns any previous binding associated with the property, or a
2074 default-constructed QPropertyBinding<T>.
2075
2076 \sa {Formulating a Property Binding}
2077*/
2078
2079/*!
2080 \fn template <typename T> bool QPropertyAlias<T>::hasBinding() const
2081
2082 Returns true if the aliased property is associated with a binding; false
2083 otherwise.
2084*/
2085
2086/*!
2087 \fn template <typename T> QPropertyBinding<T> QPropertyAlias<T>::binding() const
2088
2089 Returns the binding expression that is associated with the aliased property. A
2090 default constructed QPropertyBinding<T> will be returned if no such
2091 association exists.
2092*/
2093
2094/*!
2095 \fn template <typename T> QPropertyBinding<T> QPropertyAlias<T>::takeBinding()
2096
2097 Disassociates the binding expression from the aliased property and returns it.
2098 After calling this function, the value of the property will only change if
2099 you assign a new value to it, or when a new binding is set.
2100*/
2101
2102/*!
2103 \fn template <typename T> template <typename Functor> QPropertyChangeHandler<T, Functor> QPropertyAlias<T>::onValueChanged(Functor f)
2104
2105 Registers the given functor \a f as a callback that shall be called whenever
2106 the value of the aliased property changes. On each value change, the handler
2107 is either called immediately, or deferred, depending on the context.
2108
2109 The callback \a f is expected to be a type that has a plain call operator
2110 \c{()} without any parameters. This means that you can provide a C++ lambda
2111 expression, a std::function or even a custom struct with a call operator.
2112
2113 The returned property change handler object keeps track of the registration. When it
2114 goes out of scope, the callback is de-registered.
2115*/
2116
2117/*!
2118 \fn template <typename T> template <typename Functor> QPropertyChangeHandler<T, Functor> QPropertyAlias<T>::subscribe(Functor f)
2119
2120 Subscribes the given functor \a f as a callback that is called immediately and
2121 whenever the value of the aliased property changes in the future. On each
2122 value change, the handler is either called immediately, or deferred, depending
2123 on the context.
2124
2125 The callback \a f is expected to be a type that has a plain call operator
2126 \c{()} without any parameters. This means that you can provide a C++ lambda
2127 expression, a std::function or even a custom struct with a call operator.
2128
2129 The returned property change handler object keeps track of the subscription.
2130 When it goes out of scope, the callback is unsubscribed.
2131*/
2132
2133/*!
2134 \fn template <typename T> template <typename Functor> QPropertyNotifier QPropertyAlias<T>::addNotifier(Functor f)
2135
2136 Subscribes the given functor \a f as a callback that is called whenever
2137 the value of the aliased property changes.
2138
2139 The callback \a f is expected to be a type that has a plain call operator
2140 \c{()} without any parameters. This means that you can provide a C++ lambda
2141 expression, a std::function or even a custom struct with a call operator.
2142
2143 The returned property change handler object keeps track of the subscription.
2144 When it goes out of scope, the callback is unsubscribed.
2145
2146 This method is in some cases easier to use than onValueChanged(), as the
2147 returned object is not a template. It can therefore more easily be stored,
2148 e.g. as a member in a class.
2149
2150 \sa onValueChanged(), subscribe()
2151*/
2152
2153/*!
2154 \fn template <typename T> bool QPropertyAlias<T>::isValid() const
2155
2156 Returns true if the aliased property still exists; false otherwise.
2157
2158 If the aliased property doesn't exist, all other method calls are ignored.
2159*/
2160
2162{
2165 // Pair[] pairs;
2166};
2167
2169{
2170 // This class basically implements a simple and fast hash map to store bindings for a QObject
2171 // The reason that we're not using QHash is that QPropertyBindingData can not be copied, only
2172 // moved. That doesn't work well together with an implicitly shared class.
2178 static_assert(alignof(Pair) == alignof(void *));
2179 static_assert(alignof(size_t) == alignof(void *));
2180
2182
2183 static inline Pair *pairs(QBindingStorageData *dd)
2184 {
2185 Q_ASSERT(dd);
2186 return reinterpret_cast<Pair *>(dd + 1);
2187 }
2188 void reallocate(size_t newSize)
2189 {
2190 Q_ASSERT(!d || newSize > d->size);
2191 size_t allocSize = sizeof(QBindingStorageData) + newSize*sizeof(Pair);
2192 void *nd = malloc(allocSize);
2193 memset(nd, 0, allocSize);
2194 QBindingStorageData *newData = new (nd) QBindingStorageData;
2195 newData->size = newSize;
2196 if (!d) {
2197 d = newData;
2198 return;
2199 }
2200 newData->used = d->used;
2201 Pair *p = pairs(d);
2202 for (size_t i = 0; i < d->size; ++i, ++p) {
2203 if (p->data) {
2204 Pair *pp = pairs(newData);
2205 Q_ASSERT(newData->size && (newData->size & (newData->size - 1)) == 0); // size is a power of two
2206 size_t index = qHash(p->data) & (newData->size - 1);
2207 while (pp[index].data) {
2208 ++index;
2209 if (index == newData->size)
2210 index = 0;
2211 }
2212 new (pp + index) Pair{p->data, QPropertyBindingData(std::move(p->bindingData))};
2213 }
2214 }
2215 // data has been moved, no need to call destructors on old Pairs
2216 free(d);
2217 d = newData;
2218 }
2219
2221
2222 QPropertyBindingData *get(const QUntypedPropertyData *data)
2223 {
2224 Q_ASSERT(d);
2225 Q_ASSERT(d->size && (d->size & (d->size - 1)) == 0); // size is a power of two
2226 size_t index = qHash(data) & (d->size - 1);
2227 Pair *p = pairs(d);
2228 while (p[index].data) {
2229 if (p[index].data == data)
2230 return &p[index].bindingData;
2231 ++index;
2232 if (index == d->size)
2233 index = 0;
2234 }
2235 return nullptr;
2236 }
2237 QPropertyBindingData *get(QUntypedPropertyData *data, bool create)
2238 {
2239 if (!d) {
2240 if (!create)
2241 return nullptr;
2242 reallocate(8);
2243 }
2244 else if (d->used*2 >= d->size)
2245 reallocate(d->size*2);
2246 Q_ASSERT(d->size && (d->size & (d->size - 1)) == 0); // size is a power of two
2247 size_t index = qHash(data) & (d->size - 1);
2248 Pair *p = pairs(d);
2249 while (p[index].data) {
2250 if (p[index].data == data)
2251 return &p[index].bindingData;
2252 ++index;
2253 if (index == d->size)
2254 index = 0;
2255 }
2256 if (!create)
2257 return nullptr;
2258 ++d->used;
2259 new (p + index) Pair{data, QPropertyBindingData()};
2260 return &p[index].bindingData;
2261 }
2262
2263 void destroy()
2264 {
2265 if (!d)
2266 return;
2267 Pair *p = pairs(d);
2268 for (size_t i = 0; i < d->size; ++i) {
2269 if (p->data)
2270 p->~Pair();
2271 ++p;
2272 }
2273 free(d);
2274 }
2275};
2276
2277/*!
2278 \class QBindingStorage
2279 \internal
2280
2281 QBindingStorage acts as a storage for property binding related data in QObject.
2282 Any property in a QObject can be made bindable by using the Q_OBJECT_BINDABLE_PROPERTY
2283 macro to declare it. A setter and a getter for the property and a declaration using
2284 Q_PROPERTY have to be made as usual.
2285 Binding related data will automatically be stored within the QBindingStorage
2286 inside the QObject.
2287*/
2288
2289QBindingStorage::QBindingStorage()
2290{
2291 bindingStatus = &QT_PREPEND_NAMESPACE(bindingStatus);
2292 Q_ASSERT(bindingStatus);
2293}
2294
2295QBindingStorage::~QBindingStorage()
2296{
2297 QBindingStoragePrivate(d).destroy();
2298}
2299
2300void QBindingStorage::reinitAfterThreadMove()
2301{
2302 bindingStatus = &QT_PREPEND_NAMESPACE(bindingStatus);
2303 Q_ASSERT(bindingStatus);
2304}
2305
2306void QBindingStorage::clear()
2307{
2308 QBindingStoragePrivate(d).destroy();
2309 d = nullptr;
2310 bindingStatus = nullptr;
2311}
2312
2313void QBindingStorage::registerDependency_helper(const QUntypedPropertyData *data) const
2314{
2315 Q_ASSERT(bindingStatus);
2316 // Use ::bindingStatus to get the binding from TLS. This is required, so that reads from
2317 // another thread do not register as dependencies
2318 QtPrivate::BindingEvaluationState *currentBinding;
2319#ifdef QT_HAS_FAST_CURRENT_THREAD_ID
2320 const bool threadMatches = (QThread::currentThreadId() == bindingStatus->threadId);
2321 if (Q_LIKELY(threadMatches))
2322 currentBinding = bindingStatus->currentlyEvaluatingBinding;
2323 else
2324 currentBinding = QT_PREPEND_NAMESPACE(bindingStatus).currentlyEvaluatingBinding;
2325#else
2326 currentBinding = QT_PREPEND_NAMESPACE(bindingStatus).currentlyEvaluatingBinding;
2327#endif
2328 QUntypedPropertyData *dd = const_cast<QUntypedPropertyData *>(data);
2329 if (!currentBinding)
2330 return;
2331 auto storage = QBindingStoragePrivate(d).get(dd, true);
2332 if (!storage)
2333 return;
2334 storage->registerWithCurrentlyEvaluatingBinding(currentBinding);
2335}
2336
2337
2338QPropertyBindingData *QBindingStorage::bindingData_helper(const QUntypedPropertyData *data) const
2339{
2340 return QBindingStoragePrivate(d).get(data);
2341}
2342
2343const QBindingStatus *QBindingStorage::status(QtPrivate::QBindingStatusAccessToken) const
2344{
2345 return bindingStatus;
2346}
2347
2348QPropertyBindingData *QBindingStorage::bindingData_helper(QUntypedPropertyData *data, bool create)
2349{
2350 return QBindingStoragePrivate(d).get(data, create);
2351}
2352
2353
2354namespace QtPrivate {
2355
2356
2357void initBindingStatusThreadId()
2358{
2359 bindingStatus.threadId = QThread::currentThreadId();
2360}
2361
2362BindingEvaluationState *suspendCurrentBindingStatus()
2363{
2364 auto ret = bindingStatus.currentlyEvaluatingBinding;
2365 bindingStatus.currentlyEvaluatingBinding = nullptr;
2366 return ret;
2367}
2368
2373
2374/*!
2375 \internal
2376 This function can be used to detect whether we are currently
2377 evaluating a binding. This can e.g. be used to defer the allocation
2378 of extra data for a QPropertyBindingStorage in a getter.
2379 Note that this function accesses TLS storage, and is therefore soemwhat
2380 costly to call.
2381*/
2383{
2384 return bindingStatus.currentlyEvaluatingBinding != nullptr;
2385}
2386
2387bool isPropertyInBindingWrapper(const QUntypedPropertyData *property)
2388{
2389 // Accessing bindingStatus is expensive because it's thread-local. Do it only once.
2390 if (const auto current = bindingStatus.currentCompatProperty)
2391 return current->property == property;
2392 return false;
2393}
2394
2396
2397void printUnsuitableBindableWarning(QAnyStringView prefix, BindableWarnings::Reason reason)
2398{
2399 switch (reason) {
2400 case QtPrivate::BindableWarnings::NonBindableInterface:
2401 qCWarning(lcQPropertyBinding).noquote() << prefix.toString()
2402 << "The QBindable does not allow interaction with the binding.";
2403 break;
2404 case QtPrivate::BindableWarnings::ReadOnlyInterface:
2405 qCWarning(lcQPropertyBinding).noquote() << prefix.toString()
2406 << "The QBindable is read-only.";
2407 break;
2408 default:
2409 case QtPrivate::BindableWarnings::InvalidInterface:
2410 qCWarning(lcQPropertyBinding).noquote() << prefix.toString()
2411 << "The QBindable is invalid.";
2412 break;
2413 }
2414}
2415
2416void printMetaTypeMismatch(QMetaType actual, QMetaType expected)
2417{
2418 qCWarning(lcQPropertyBinding) << "setBinding: Could not set binding as the property expects it to be of type"
2419 << actual.name()
2420 << "but got" << expected.name() << "instead.";
2421}
2422
2423} // namespace BindableWarnings end
2424
2425/*!
2426 \internal
2427 Returns the binding statusof the current thread.
2428 */
2429QBindingStatus* getBindingStatus(QtPrivate::QBindingStatusAccessToken) { return &QT_PREPEND_NAMESPACE(bindingStatus); }
2430
2432void getter(const QUntypedPropertyData *d, void *value)
2433{
2434 auto adaptor = static_cast<const QtPrivate::QPropertyAdaptorSlotObject *>(d);
2435 adaptor->bindingData().registerWithCurrentlyEvaluatingBinding();
2436 auto mt = adaptor->metaProperty().metaType();
2437 mt.destruct(value);
2438 mt.construct(value, adaptor->metaProperty().read(adaptor->object()).data());
2439}
2440
2441void setter(QUntypedPropertyData *d, const void *value)
2442{
2443 auto adaptor = static_cast<QtPrivate::QPropertyAdaptorSlotObject *>(d);
2444 adaptor->bindingData().removeBinding();
2445 adaptor->metaProperty().write(adaptor->object(),
2446 QVariant(adaptor->metaProperty().metaType(), value));
2447}
2448
2449QUntypedPropertyBinding getBinding(const QUntypedPropertyData *d)
2450{
2451 auto adaptor = static_cast<const QtPrivate::QPropertyAdaptorSlotObject *>(d);
2452 return QUntypedPropertyBinding(adaptor->bindingData().binding());
2453}
2454
2455bool bindingWrapper(QMetaType type, QUntypedPropertyData *d,
2456 QtPrivate::QPropertyBindingFunction binding, QUntypedPropertyData *temp,
2457 void *value)
2458{
2459 auto adaptor = static_cast<const QtPrivate::QPropertyAdaptorSlotObject *>(d);
2460 type.destruct(value);
2461 type.construct(value, adaptor->metaProperty().read(adaptor->object()).data());
2462 if (binding.vtable->call(type, temp, binding.functor)) {
2463 adaptor->metaProperty().write(adaptor->object(), QVariant(type, value));
2464 return true;
2465 }
2466 return false;
2467}
2468
2469QUntypedPropertyBinding setBinding(QUntypedPropertyData *d, const QUntypedPropertyBinding &binding,
2470 QPropertyBindingWrapper wrapper)
2471{
2472 auto adaptor = static_cast<QPropertyAdaptorSlotObject *>(d);
2473 return adaptor->bindingData().setBinding(binding, d, nullptr, wrapper);
2474}
2475
2476void setObserver(const QUntypedPropertyData *d, QPropertyObserver *observer)
2477{
2478 observer->setSource(static_cast<const QPropertyAdaptorSlotObject *>(d)->bindingData());
2479}
2480}
2481
2482QPropertyAdaptorSlotObject::QPropertyAdaptorSlotObject(QObject *o, const QMetaProperty &p)
2483 : QSlotObjectBase(&impl), obj(o), metaProperty_(p)
2484{
2485}
2486
2487#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
2489 bool *ret)
2490#else
2491void QPropertyAdaptorSlotObject::impl(QSlotObjectBase *this_, QObject *r, void **a, int which,
2492 bool *ret)
2493#endif
2494{
2495 auto self = static_cast<QPropertyAdaptorSlotObject *>(this_);
2496 switch (which) {
2497 case Destroy:
2498 delete self;
2499 break;
2500 case Call:
2501 if (!self->bindingData_.hasBinding())
2502 self->bindingData_.notifyObservers(self);
2503 break;
2504 case Compare:
2505 case NumOperations:
2506 Q_UNUSED(r);
2507 Q_UNUSED(a);
2508 Q_UNUSED(ret);
2509 break;
2510 }
2511}
2512
2513} // namespace QtPrivate end
2514
2515QUntypedBindable::QUntypedBindable(QObject *obj, const QMetaProperty &metaProperty,
2516 const QtPrivate::QBindableInterface *i)
2517 : iface(i)
2518{
2519 if (!obj)
2520 return;
2521
2522 if (!metaProperty.isValid()) {
2523 qCWarning(lcQPropertyBinding) << "QUntypedBindable: Property is not valid";
2524 return;
2525 }
2526
2527 if (metaProperty.isBindable()) {
2528 *this = metaProperty.bindable(obj);
2529 return;
2530 }
2531
2532 if (!metaProperty.hasNotifySignal()) {
2533 qCWarning(lcQPropertyBinding)
2534 << "QUntypedBindable: Property" << metaProperty.name() << "has no notify signal";
2535 return;
2536 }
2537
2538 auto metatype = iface->metaType();
2539 if (metaProperty.metaType() != metatype) {
2540 qCWarning(lcQPropertyBinding) << "QUntypedBindable: Property" << metaProperty.name()
2541 << "of type" << metaProperty.metaType().name()
2542 << "does not match requested type" << metatype.name();
2543 return;
2544 }
2545
2546 // Test for name pointer equality proves it's exactly the same property
2547 if (obj->metaObject()->property(metaProperty.propertyIndex()).name() != metaProperty.name()) {
2548 qCWarning(lcQPropertyBinding) << "QUntypedBindable: Property" << metaProperty.name()
2549 << "does not belong to this object";
2550 return;
2551 }
2552
2553 // Get existing binding data if it exists
2554 auto adaptor = QObjectPrivate::get(obj)->getPropertyAdaptorSlotObject(metaProperty);
2555
2556 if (!adaptor) {
2557 adaptor = new QPropertyAdaptorSlotObject(obj, metaProperty);
2558
2559 auto c = QObjectPrivate::connect(obj, metaProperty.notifySignalIndex(), obj, adaptor,
2560 Qt::DirectConnection);
2561 Q_ASSERT(c);
2562 }
2563
2564 data = adaptor;
2565}
2566
2567QUntypedBindable::QUntypedBindable(QObject *obj, const char *property,
2568 const QtPrivate::QBindableInterface *i)
2569 : QUntypedBindable(
2570 obj,
2571 [=]() -> QMetaProperty {
2572 if (!obj)
2573 return {};
2574 auto propertyIndex = obj->metaObject()->indexOfProperty(property);
2575 if (propertyIndex < 0) {
2576 qCWarning(lcQPropertyBinding)
2577 << "QUntypedBindable: No property named" << property;
2578 return {};
2579 }
2580 return obj->metaObject()->property(propertyIndex);
2581 }(),
2582 i)
2583{
2584}
2585
2586QT_END_NAMESPACE
\inmodule QtCore
Definition qproperty.h:680
const QtPrivate::QBindableInterface * iface
Definition qproperty.h:684
Combined button and popup list for selecting options.
void printMetaTypeMismatch(QMetaType actual, QMetaType expected)
void printUnsuitableBindableWarning(QAnyStringView prefix, BindableWarnings::Reason reason)
void setter(QUntypedPropertyData *d, const void *value)
void getter(const QUntypedPropertyData *d, void *value)
bool bindingWrapper(QMetaType type, QUntypedPropertyData *d, QtPrivate::QPropertyBindingFunction binding, QUntypedPropertyData *temp, void *value)
QUntypedPropertyBinding getBinding(const QUntypedPropertyData *d)
QUntypedPropertyBinding setBinding(QUntypedPropertyData *d, const QUntypedPropertyBinding &binding, QPropertyBindingWrapper wrapper)
void setObserver(const QUntypedPropertyData *d, QPropertyObserver *observer)
\macro QT_NO_KEYWORDS >
Definition qcompare.h:24
Q_CORE_EXPORT bool isAnyBindingEvaluating()
Q_CORE_EXPORT void restoreBindingStatus(BindingEvaluationState *status)
QBindingStatus * getBindingStatus(QtPrivate::QBindingStatusAccessToken)
Q_CORE_EXPORT bool isPropertyInBindingWrapper(const QUntypedPropertyData *property)
Definition qcompare.h:72
Q_CORE_EXPORT void beginPropertyUpdateGroup()
Q_CORE_EXPORT void endPropertyUpdateGroup()
QPropertyBindingData bindingData
QUntypedPropertyData * data
static Pair * pairs(QBindingStorageData *dd)
QBindingStoragePrivate(QBindingStorageData *&_d)
void reallocate(size_t newSize)
QPropertyBindingData * get(QUntypedPropertyData *data, bool create)
QPropertyBindingData * get(const QUntypedPropertyData *data)
QBindingStorageData *& d
QPropertyObserverPointer firstObserver() const
QPropertyProxyBindingData delayedProperties[size]
Definition qproperty.cpp:78
void notify(qsizetype index)
static constexpr auto PageSize
Definition qproperty.cpp:71
void addProperty(const QPropertyBindingData *bindingData, QUntypedPropertyData *propertyData)
Definition qproperty.cpp:89
static constexpr qsizetype size
Definition qproperty.cpp:77
void evaluateBindings(PendingBindingObserverList &bindingObservers, qsizetype index, QBindingStatus *status)
QPropertyDelayedNotifications * next
Definition qproperty.cpp:73
void observeProperty(QPropertyBindingDataPointer property)
QPropertyObserver * ptr
void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler)
BindingEvaluationState(QPropertyBindingPrivate *binding, QBindingStatus *status)
BindingEvaluationState * previousState
BindingEvaluationState ** currentState
QtPrivate::BindingEvaluationState ** currentlyEvaluatingBindingList
CompatPropertySafePoint * previousState
CompatPropertySafePoint ** currentState
QtPrivate::BindingEvaluationState * bindingState