1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qproperty.h"
41#include "qproperty_p.h"
42
43#include <qscopedvaluerollback.h>
44#include <QScopeGuard>
45
46QT_BEGIN_NAMESPACE
47
48using namespace QtPrivate;
49
50void QPropertyBindingDataPointer::addObserver(QPropertyObserver *observer)
51{
52 if (auto *binding = bindingPtr()) {
53 observer->prev = &binding->firstObserver.ptr;
54 observer->next = binding->firstObserver.ptr;
55 if (observer->next)
56 observer->next->prev = &observer->next;
57 binding->firstObserver.ptr = observer;
58 } else {
59 auto firstObserver = reinterpret_cast<QPropertyObserver*>(ptr->d_ptr & ~QPropertyBindingData::FlagMask);
60 observer->prev = reinterpret_cast<QPropertyObserver**>(&ptr->d_ptr);
61 observer->next = firstObserver;
62 if (observer->next)
63 observer->next->prev = &observer->next;
64 }
65 setFirstObserver(observer);
66}
67
68QPropertyBindingPrivate::~QPropertyBindingPrivate()
69{
70 if (firstObserver)
71 firstObserver.unlink();
72}
73
74void QPropertyBindingPrivate::unlinkAndDeref()
75{
76 propertyDataPtr = nullptr;
77 if (!ref.deref())
78 delete this;
79}
80
81void QPropertyBindingPrivate::markDirtyAndNotifyObservers()
82{
83 if (dirty)
84 return;
85 dirty = true;
86 if (eagerlyUpdating) {
87 error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
88 return;
89 }
90
91 eagerlyUpdating = true;
92 QScopeGuard guard([&](){eagerlyUpdating = false;});
93 if (requiresEagerEvaluation()) {
94 // these are compat properties that we will need to evaluate eagerly
95 evaluateIfDirtyAndReturnTrueIfValueChanged(propertyDataPtr);
96 }
97 if (firstObserver)
98 firstObserver.notify(this, propertyDataPtr);
99 if (hasStaticObserver)
100 staticObserverCallback(propertyDataPtr);
101}
102
103bool QPropertyBindingPrivate::evaluateIfDirtyAndReturnTrueIfValueChanged(const QUntypedPropertyData *data)
104{
105 if (!dirty)
106 return false;
107
108 if (updating) {
109 error = QPropertyBindingError(QPropertyBindingError::BindingLoop);
110 return false;
111 }
112
113 /*
114 * Evaluating the binding might lead to the binding being broken. This can
115 * cause ref to reach zero at the end of the function. However, the
116 * updateGuard's destructor will then still trigger, trying to set the
117 * updating bool to its old value
118 * To prevent this, we create a QPropertyBindingPrivatePtr which ensures
119 * that the object is still alive when updateGuard's dtor runs.
120 */
121 QPropertyBindingPrivatePtr keepAlive {this};
122 QScopedValueRollback<bool> updateGuard(updating, true);
123
124 BindingEvaluationState evaluationFrame(this);
125
126 bool changed = false;
127
128 Q_ASSERT(propertyDataPtr == data);
129 QUntypedPropertyData *mutable_data = const_cast<QUntypedPropertyData *>(data);
130
131 if (hasBindingWrapper) {
132 changed = staticBindingWrapper(metaType, mutable_data, evaluationFunction);
133 } else {
134 changed = evaluationFunction(metaType, mutable_data);
135 }
136
137 dirty = false;
138 return changed;
139}
140
141QUntypedPropertyBinding::QUntypedPropertyBinding() = default;
142
143QUntypedPropertyBinding::QUntypedPropertyBinding(QMetaType metaType, QUntypedPropertyBinding::BindingEvaluationFunction function,
144 const QPropertyBindingSourceLocation &location)
145 : d(new QPropertyBindingPrivate(metaType, std::move(function), std::move(location)))
146{
147}
148
149QUntypedPropertyBinding::QUntypedPropertyBinding(QUntypedPropertyBinding &&other)
150 : d(std::move(other.d))
151{
152}
153
154QUntypedPropertyBinding::QUntypedPropertyBinding(const QUntypedPropertyBinding &other)
155 : d(other.d)
156{
157}
158
159QUntypedPropertyBinding &QUntypedPropertyBinding::operator=(const QUntypedPropertyBinding &other)
160{
161 d = other.d;
162 return *this;
163}
164
165QUntypedPropertyBinding &QUntypedPropertyBinding::operator=(QUntypedPropertyBinding &&other)
166{
167 d = std::move(other.d);
168 return *this;
169}
170
171QUntypedPropertyBinding::QUntypedPropertyBinding(QPropertyBindingPrivate *priv)
172 : d(priv)
173{
174}
175
176QUntypedPropertyBinding::~QUntypedPropertyBinding()
177{
178}
179
180bool QUntypedPropertyBinding::isNull() const
181{
182 return !d;
183}
184
185QPropertyBindingError QUntypedPropertyBinding::error() const
186{
187 if (!d)
188 return QPropertyBindingError();
189 return d->bindingError();
190}
191
192QMetaType QUntypedPropertyBinding::valueMetaType() const
193{
194 if (!d)
195 return QMetaType();
196 return d->valueMetaType();
197}
198
199QPropertyBindingData::~QPropertyBindingData()
200{
201 QPropertyBindingDataPointer d{this};
202 for (auto observer = d.firstObserver(); observer;) {
203 auto next = observer.nextObserver();
204 observer.unlink();
205 observer = next;
206 }
207 if (auto binding = d.bindingPtr())
208 binding->unlinkAndDeref();
209}
210
211QUntypedPropertyBinding QPropertyBindingData::setBinding(const QUntypedPropertyBinding &binding,
212 QUntypedPropertyData *propertyDataPtr,
213 QPropertyObserverCallback staticObserverCallback,
214 QtPrivate::QPropertyBindingWrapper guardCallback)
215{
216 QPropertyBindingPrivatePtr oldBinding;
217 QPropertyBindingPrivatePtr newBinding = binding.d;
218
219 QPropertyBindingDataPointer d{this};
220 QPropertyObserverPointer observer;
221
222 if (auto *existingBinding = d.bindingPtr()) {
223 if (existingBinding == newBinding.data())
224 return QUntypedPropertyBinding(oldBinding.data());
225 oldBinding = QPropertyBindingPrivatePtr(existingBinding);
226 observer = oldBinding->takeObservers();
227 oldBinding->unlinkAndDeref();
228 d_ptr &= FlagMask;
229 } else {
230 observer = d.firstObserver();
231 }
232
233 if (newBinding) {
234 newBinding.data()->ref.ref();
235 d_ptr = (d_ptr & FlagMask) | reinterpret_cast<quintptr>(newBinding.data());
236 d_ptr |= BindingBit;
237 newBinding->setDirty(true);
238 newBinding->setProperty(propertyDataPtr);
239 if (observer)
240 newBinding->prependObserver(observer);
241 newBinding->setStaticObserver(staticObserverCallback, guardCallback);
242 if (newBinding->requiresEagerEvaluation()) {
243 auto changed = newBinding->evaluateIfDirtyAndReturnTrueIfValueChanged(propertyDataPtr);
244 if (changed)
245 observer.notify(newBinding.data(), propertyDataPtr, /*alreadyKnownToHaveChanged=*/true);
246 }
247 } else if (observer) {
248 d.setObservers(observer.ptr);
249 } else {
250 d_ptr &= ~QPropertyBindingData::BindingBit;
251 }
252
253 if (oldBinding)
254 oldBinding->detachFromProperty();
255
256 return QUntypedPropertyBinding(oldBinding.data());
257}
258
259QPropertyBindingData::QPropertyBindingData(QPropertyBindingData &&other) : d_ptr(std::exchange(other.d_ptr, 0))
260{
261 QPropertyBindingDataPointer d{this};
262 d.fixupFirstObserverAfterMove();
263}
264
265QPropertyBindingPrivate *QPropertyBindingData::binding() const
266{
267 QPropertyBindingDataPointer d{this};
268 if (auto binding = d.bindingPtr())
269 return binding;
270 return nullptr;
271}
272
273static thread_local QBindingStatus bindingStatus;
274
275BindingEvaluationState::BindingEvaluationState(QPropertyBindingPrivate *binding)
276 : binding(binding)
277{
278 // store a pointer to the currentBindingEvaluationState to avoid a TLS lookup in
279 // the destructor (as these come with a non zero cost)
280 currentState = &bindingStatus.currentlyEvaluatingBinding;
281 previousState = *currentState;
282 *currentState = this;
283 binding->clearDependencyObservers();
284}
285
286CurrentCompatProperty::CurrentCompatProperty(QBindingStatus *status, QUntypedPropertyData *property)
287 : property(property)
288{
289 // store a pointer to the currentBindingEvaluationState to avoid a TLS lookup in
290 // the destructor (as these come with a non zero cost)
291 currentState = &status->currentCompatProperty;
292 previousState = *currentState;
293 *currentState = this;
294}
295
296QPropertyBindingPrivate *QPropertyBindingPrivate::currentlyEvaluatingBinding()
297{
298 auto currentState = bindingStatus.currentlyEvaluatingBinding ;
299 return currentState ? currentState->binding : nullptr;
300}
301
302void QPropertyBindingData::evaluateIfDirty(const QUntypedPropertyData *property) const
303{
304 QPropertyBindingDataPointer d{this};
305 QPropertyBindingPrivate *binding = d.bindingPtr();
306 if (!binding)
307 return;
308 binding->evaluateIfDirtyAndReturnTrueIfValueChanged(property);
309}
310
311void QPropertyBindingData::removeBinding()
312{
313 QPropertyBindingDataPointer d{this};
314
315 if (auto *existingBinding = d.bindingPtr()) {
316 auto observer = existingBinding->takeObservers();
317 d_ptr &= ExtraBit;
318 if (observer)
319 d.setObservers(observer.ptr);
320 existingBinding->unlinkAndDeref();
321 }
322}
323
324void QPropertyBindingData::registerWithCurrentlyEvaluatingBinding() const
325{
326 auto currentState = bindingStatus.currentlyEvaluatingBinding;
327 if (!currentState)
328 return;
329
330 QPropertyBindingDataPointer d{this};
331
332 QPropertyObserverPointer dependencyObserver = currentState->binding->allocateDependencyObserver();
333 dependencyObserver.setBindingToMarkDirty(currentState->binding);
334 dependencyObserver.observeProperty(d);
335}
336
337void QPropertyBindingData::notifyObservers(QUntypedPropertyData *propertyDataPtr) const
338{
339 QPropertyBindingDataPointer d{this};
340 if (QPropertyObserverPointer observer = d.firstObserver())
341 observer.notify(d.bindingPtr(), propertyDataPtr);
342}
343
344int QPropertyBindingDataPointer::observerCount() const
345{
346 int count = 0;
347 for (auto observer = firstObserver(); observer; observer = observer.nextObserver())
348 ++count;
349 return count;
350}
351
352QPropertyObserver::QPropertyObserver(ChangeHandler changeHandler)
353{
354 QPropertyObserverPointer d{this};
355 d.setChangeHandler(changeHandler);
356}
357
358QPropertyObserver::QPropertyObserver(QUntypedPropertyData *aliasedPropertyPtr)
359{
360 QPropertyObserverPointer d{this};
361 d.setAliasedProperty(aliasedPropertyPtr);
362}
363
364/*! \internal
365 */
366void QPropertyObserver::setSource(const QPropertyBindingData &property)
367{
368 QPropertyObserverPointer d{this};
369 QPropertyBindingDataPointer propPrivate{&property};
370 d.observeProperty(propPrivate);
371}
372
373QPropertyObserver::~QPropertyObserver()
374{
375 if (next.tag() == ActivelyExecuting) {
376 if (nodeState)
377 *nodeState = nullptr;
378 }
379 QPropertyObserverPointer d{this};
380 d.unlink();
381}
382
383QPropertyObserver::QPropertyObserver(QPropertyObserver &&other) noexcept
384{
385 bindingToMarkDirty = std::exchange(other.bindingToMarkDirty, {});
386 next = std::exchange(other.next, {});
387 prev = std::exchange(other.prev, {});
388 if (next)
389 next->prev = &next;
390 if (prev)
391 prev.setPointer(this);
392 if (next.tag() == ActivelyExecuting)
393 *nodeState = this;
394}
395
396QPropertyObserver &QPropertyObserver::operator=(QPropertyObserver &&other) noexcept
397{
398 if (this == &other)
399 return *this;
400
401 QPropertyObserverPointer d{this};
402 d.unlink();
403 bindingToMarkDirty = nullptr;
404
405 bindingToMarkDirty = std::exchange(other.bindingToMarkDirty, {});
406 next = std::exchange(other.next, {});
407 prev = std::exchange(other.prev, {});
408 if (next)
409 next->prev = &next;
410 if (prev)
411 prev.setPointer(this);
412 if (next.tag() == ActivelyExecuting)
413 *nodeState = this;
414
415 return *this;
416}
417
418void QPropertyObserverPointer::unlink()
419{
420 if (ptr->next.tag() == QPropertyObserver::ObserverNotifiesAlias)
421 ptr->aliasedPropertyData = nullptr;
422 if (ptr->next)
423 ptr->next->prev = ptr->prev;
424 if (ptr->prev)
425 ptr->prev.setPointer(ptr->next.data());
426 ptr->next = nullptr;
427 ptr->prev.clear();
428}
429
430void QPropertyObserverPointer::setChangeHandler(QPropertyObserver::ChangeHandler changeHandler)
431{
432 Q_ASSERT(ptr->next.tag() != QPropertyObserver::ActivelyExecuting);
433 ptr->changeHandler = changeHandler;
434 ptr->next.setTag(QPropertyObserver::ObserverNotifiesChangeHandler);
435}
436
437void QPropertyObserverPointer::setAliasedProperty(QUntypedPropertyData *property)
438{
439 Q_ASSERT(ptr->next.tag() != QPropertyObserver::ActivelyExecuting);
440 ptr->aliasedPropertyData = property;
441 ptr->next.setTag(QPropertyObserver::ObserverNotifiesAlias);
442}
443
444void QPropertyObserverPointer::setBindingToMarkDirty(QPropertyBindingPrivate *binding)
445{
446 Q_ASSERT(ptr->next.tag() != QPropertyObserver::ActivelyExecuting);
447 ptr->bindingToMarkDirty = binding;
448 ptr->next.setTag(QPropertyObserver::ObserverNotifiesBinding);
449}
450
451/*!
452 \internal
453 QPropertyObserverNodeProtector is a RAII wrapper which takes care of the internal switching logic
454 for QPropertyObserverPointer::notify (described ibidem)
455*/
456template <QPropertyObserver::ObserverTag tag>
457struct [[nodiscard]] QPropertyObserverNodeProtector {
458 QPropertyObserver m_placeHolder;
459 QPropertyObserver *&m_observer;
460 union {
461 QPropertyBindingPrivate *m_binding;
462 QPropertyObserver::ChangeHandler m_changeHandler;
463 };
464 QPropertyObserverNodeProtector(QPropertyObserver *&observer)
465 : m_observer(observer)
466 {
467 static_assert(tag == QPropertyObserver::ObserverNotifiesBinding ||
468 tag == QPropertyObserver::ObserverNotifiesChangeHandler);
469 if constexpr (tag == QPropertyObserver::ObserverNotifiesBinding)
470 m_binding = m_observer->bindingToMarkDirty;
471 else
472 m_changeHandler = m_observer->changeHandler;
473 switchNodes(m_placeHolder, m_observer);
474 m_observer->nodeState = &m_observer;
475 m_observer->next.setTag(QPropertyObserver::ActivelyExecuting);
476 m_placeHolder.next.setTag(QPropertyObserver::ActivelyExecuting);
477 }
478
479 ~QPropertyObserverNodeProtector() {
480 if (m_observer) {
481 if constexpr (tag == QPropertyObserver::ObserverNotifiesBinding)
482 m_observer->bindingToMarkDirty = m_binding;
483 else
484 m_observer->changeHandler = m_changeHandler;
485 switchNodes(*m_observer, &m_placeHolder);
486 m_observer->next.setTag(tag);
487 }
488 // set tag to a safer value where we don't execute anything in the dtor
489 m_placeHolder.next.setTag(QPropertyObserver::ObserverNotifiesChangeHandler);
490 }
491
492 /*!
493 \internal
494 replaces a node \a observer in the list with another node \a placeholder which must not be in the list
495 */
496 static void switchNodes(QPropertyObserver &placeHolder, QPropertyObserver *observer) {
497 placeHolder.next = std::exchange(observer->next, {});
498 placeHolder.prev = std::exchange(observer->prev, {});
499 if (placeHolder.next) {
500 placeHolder.next->prev = &placeHolder.next;
501 }
502 if (placeHolder.prev)
503 placeHolder.prev.setPointer(&placeHolder);
504 };
505};
506
507/*! \internal
508 \a propertyDataPtr is a pointer to the observed property's property data
509 In case that property has a binding, \a triggeringBinding points to the binding's QPropertyBindingPrivate
510 \a alreadyKnownToHaveChanged is an optional parameter, which is needed in the case
511 of eager evaluation:
512 There, we have already evaluated the binding, and thus the change detection for the
513 ObserverNotifiesChangeHandler case would not work. Thus we instead pass the knowledge of
514 whether the value has changed we obtained when evaluating the binding eagerly along
515 */
516void QPropertyObserverPointer::notify(QPropertyBindingPrivate *triggeringBinding, QUntypedPropertyData *propertyDataPtr,bool alreadyKnownToHaveChanged)
517{
518 bool knownIfPropertyChanged = alreadyKnownToHaveChanged;
519 bool propertyChanged = true;
520
521 auto observer = const_cast<QPropertyObserver*>(ptr);
522 /*
523 * The basic idea of the loop is as follows: We iterate over all observers in the linked list,
524 * and execute the functionality corresponding to their tag.
525 * However, complication arise due to the fact that the triggered operations might modify the list,
526 * which includes deletion and move of the current and next nodes.
527 * Therefore, we take a few safety precautions:
528 * 1. Before executing any action which might modify the list, we replace the actual node in the list with
529 * a placeholder node. As that one is stack allocated and owned by us, we can rest assured that it is
530 * still there after the action has executed, and placeHolder->next points to the actual next node in the list.
531 * Note that taking next at the beginning of the loop does not work, as the execuated action might either move
532 * or delete that node.
533 * 2. To properly handle deletion or moves of the real current node, we store a pointer to a pointer to itself in
534 * its nodeState. Whenever the node is reallocated and moved, we update that pointer to point to its new
535 * location. If the node is actually deleted, we set it to nullptr.
536 * 3. After the triggered action has finished, we can use that information to restore the list to contain the actual
537 * node again. We either switch the nodes with the real nodes current location, or, if the real node has been
538 * deleted, we simply unlink the temporary node.
539 */
540 while (observer) {
541 QPropertyObserver *next = nullptr;
542 char preventBug[1] = {'\0'}; // QTBUG-87245
543 Q_UNUSED(preventBug);
544 switch (observer->next.tag()) {
545 case QPropertyObserver::ObserverNotifiesChangeHandler:
546 if (auto handlerToCall = observer->changeHandler) {
547 // both evaluateIfDirtyAndReturnTrueIfValueChanged and handlerToCall might modify the list
548 QPropertyObserverNodeProtector<QPropertyObserver::ObserverNotifiesChangeHandler> protector(observer);
549 if (!knownIfPropertyChanged && triggeringBinding) {
550 knownIfPropertyChanged = true;
551 propertyChanged = triggeringBinding->evaluateIfDirtyAndReturnTrueIfValueChanged(propertyDataPtr);
552 }
553 if (!propertyChanged)
554 return;
555 handlerToCall(observer, propertyDataPtr);
556 next = protector.m_placeHolder.next.data();
557 } else {
558 next = observer->next.data();
559 }
560 break;
561 case QPropertyObserver::ObserverNotifiesBinding:
562 if (auto bindingToMarkDirty = observer->bindingToMarkDirty) {
563 QPropertyObserverNodeProtector<QPropertyObserver::ObserverNotifiesBinding> protector(observer);
564 bindingToMarkDirty->markDirtyAndNotifyObservers();
565 next = protector.m_placeHolder.next.data();
566 } else {
567 next = observer->next.data();
568 }
569 break;
570 case QPropertyObserver::ObserverNotifiesAlias:
571 next = observer->next.data();
572 break;
573 case QPropertyObserver::ActivelyExecuting:
574 // recursion is already properly handled somewhere else
575 return;
576 default:
577 Q_UNREACHABLE();
578 }
579 observer = next;
580 }
581}
582
583void QPropertyObserverPointer::observeProperty(QPropertyBindingDataPointer property)
584{
585 if (ptr->prev)
586 unlink();
587 property.addObserver(ptr);
588}
589
590QPropertyBindingError::QPropertyBindingError()
591{
592}
593
594QPropertyBindingError::QPropertyBindingError(Type type, const QString &description)
595{
596 if (type != NoError) {
597 d = new QPropertyBindingErrorPrivate;
598 d->type = type;
599 d->description = description;
600 }
601}
602
603QPropertyBindingError::QPropertyBindingError(const QPropertyBindingError &other)
604 : d(other.d)
605{
606}
607
608QPropertyBindingError &QPropertyBindingError::operator=(const QPropertyBindingError &other)
609{
610 d = other.d;
611 return *this;
612}
613
614QPropertyBindingError::QPropertyBindingError(QPropertyBindingError &&other)
615 : d(std::move(other.d))
616{
617}
618
619QPropertyBindingError &QPropertyBindingError::operator=(QPropertyBindingError &&other)
620{
621 d = std::move(other.d);
622 return *this;
623}
624
625QPropertyBindingError::~QPropertyBindingError()
626{
627}
628
629QPropertyBindingError::Type QPropertyBindingError::type() const
630{
631 if (!d)
632 return QPropertyBindingError::NoError;
633 return d->type;
634}
635
636QString QPropertyBindingError::description() const
637{
638 if (!d)
639 return QString();
640 return d->description;
641}
642
643/*!
644 \class QPropertyData
645 \inmodule QtCore
646 \brief The QPropertyData class is a helper class for properties with automatic property bindings.
647 \since 6.0
648
649 \ingroup tools
650
651 QPropertyData\<T\> is a common base class for classes that can hold properties with automatic
652 data bindings. It mainly wraps the stored data, and offers low level access to that data.
653
654 The low level access to the data provided by this class bypasses the binding mechanism, and should be
655 used with care, as updates to the values will not get propagated to any bindings that depend on this
656 property.
657
658 You should usually call value() and setValue() on QProperty<T> or QObjectBindableProperty<T>, not use
659 the low level mechanisms provided in this class.
660*/
661
662/*! \fn template <typename T> QPropertyData<T>::parameter_type QPropertyData<T>::valueBypassingBindings() const
663
664 Returns the data stored in this property.
665
666 \note As this will bypass any binding evaluation it might return an outdated value if a
667 binding is set on this property. Using this method will also not register the property
668 access with any currently executing binding.
669*/
670
671/*! \fn template <typename T> void QPropertyData<T>::setValueBypassingBindings(parameter_type v)
672
673 Sets the data value stored in this property to \a v.
674
675 \note Using this method will bypass any potential binding registered for this property.
676*/
677
678/*! \fn template <typename T> void QPropertyData<T>::setValueBypassingBindings(rvalue_ref v)
679 \overload
680
681 Sets the data value stored in this property to \a v.
682
683 \note Using this method will bypass any potential binding registered for this property.
684*/
685
686
687/*!
688 \class QProperty
689 \inmodule QtCore
690 \brief The QProperty class is a template class that enables automatic property bindings.
691 \since 6.0
692
693 \ingroup tools
694
695 QProperty\<T\> is a generic container that holds an instance of T. You can assign
696 a value to it and you can read it via the value() function or the T conversion
697 operator. You can also tie the property to an expression that computes the value
698 dynamically, the binding expression. It is represented as a C++ lambda and
699 can be used to express relationships between different properties in your
700 application.
701
702 The binding expression computes the value by reading other QProperty values.
703 Behind the scenes this dependency is tracked. Whenever a change in any property's
704 dependency is detected, the binding expression is re-evaluated and the new
705 result is applied to the property. This happens lazily, by marking the binding
706 as dirty and evaluating it only when the property's value is requested. For example:
707
708 \code
709 QProperty<QString> firstname("John");
710 QProperty<QString> lastname("Smith");
711 QProperty<int> age(41);
712
713 QProperty<QString> fullname;
714 fullname.setBinding([&]() { return firstname.value() + " " + lastname.value() + " age:" + QString::number(age.value()); });
715
716 qDebug() << fullname.value(); // Prints "John Smith age: 41"
717
718 firstname = "Emma"; // Marks binding expression as dirty
719
720 qDebug() << fullname.value(); // Re-evaluates the binding expression and prints "Emma Smith age: 41"
721
722 // Birthday is coming up
723 age.setValue(age.value() + 1);
724
725 qDebug() << fullname.value(); // Re-evaluates the binding expression and prints "Emma Smith age: 42"
726 \endcode
727
728 When a new value is assigned to the \c firstname property, the binding
729 expression for \c fullname is marked as dirty. So when the last \c qDebug() statement
730 tries to read the name value of the \c fullname property, the expression is
731 evaluated again, \c firstname() will be called again and return the new value.
732
733 Since bindings are C++ lambda expressions, they may do anything that's possible
734 in C++. This includes calling other functions. If those functions access values
735 held by QProperty, they automatically become dependencies to the binding.
736
737 Binding expressions may use properties of any type, so in the above example the age
738 is an integer and folded into the string value using conversion to integer, but
739 the dependency is fully tracked.
740
741 \section1 Tracking properties
742
743 Sometimes the relationships between properties cannot be expressed using
744 bindings. Instead you may need to run custom code whenever the value of a property
745 changes and instead of assigning the value to another property, pass it to
746 other parts of your application. For example writing data into a network socket
747 or printing debug output. QProperty provides two mechanisms for tracking.
748
749 You can register for a callback function to be called whenever the value of
750 a property changes, by using onValueChanged(). If you want the callback to also
751 be called for the current value of the property, register your callback using
752 subscribe() instead.
753*/
754
755/*!
756 \fn template <typename T> QProperty<T>::QProperty()
757
758 Constructs a property with a default constructed instance of T.
759*/
760
761/*!
762 \fn template <typename T> explicit QProperty<T>::QProperty(const T &initialValue)
763
764 Constructs a property with the provided \a initialValue.
765*/
766
767/*!
768 \fn template <typename T> explicit QProperty<T>::QProperty(T &&initialValue)
769
770 Move-Constructs a property with the provided \a initialValue.
771*/
772
773/*!
774 \fn template <typename T> QProperty<T>::QProperty(QProperty<T> &&other)
775
776 Move-constructs a QProperty instance, making it point at the same object that
777 \a other was pointing to.
778*/
779
780/*!
781 \fn template <typename T> QProperty<T>::QProperty(const QPropertyBinding<T> &binding)
782
783 Constructs a property that is tied to the provided \a binding expression. The
784 first time the property value is read, the binding is evaluated. Whenever a
785 dependency of the binding changes, the binding will be re-evaluated the next
786 time the value of this property is read.
787*/
788
789/*!
790 \fn template <typename T> template <typename Functor> QProperty<T>::QProperty(Functor &&f)
791
792 Constructs a property that is tied to the provided binding expression \a f. The
793 first time the property value is read, the binding is evaluated. Whenever a
794 dependency of the binding changes, the binding will be re-evaluated the next
795 time the value of this property is read.
796*/
797
798/*!
799 \fn template <typename T> QProperty<T>::~QProperty()
800
801 Destroys the property.
802*/
803
804/*!
805 \fn template <typename T> T QProperty<T>::value() const
806
807 Returns the value of the property. This may evaluate a binding expression that
808 is tied to this property, before returning the value.
809*/
810
811/*!
812 \fn template <typename T> void QProperty<T>::setValue(rvalue_ref newValue)
813 \fn template <typename T> void QProperty<T>::setValue(parameter_type newValue)
814
815 Assigns \a newValue to this property and removes the property's associated
816 binding, if present.
817*/
818
819/*!
820 \fn template <typename T> QProperty<T> &QProperty<T>::operator=(rvalue_ref newValue)
821 \fn template <typename T> QProperty<T> &QProperty<T>::operator=(parameter_type newValue)
822
823 Assigns \a newValue to this property and returns a reference to this QProperty.
824*/
825
826/*!
827 \fn template <typename T> QProperty<T> &QProperty<T>::operator=(const QPropertyBinding<T> &newBinding)
828
829 Associates the value of this property with the provided \a newBinding
830 expression and returns a reference to this property. The first time the
831 property value is read, the binding is evaluated. Whenever a dependency of the
832 binding changes, the binding will be re-evaluated the next time the value of
833 this property is read.
834*/
835
836/*!
837 \fn template <typename T> QPropertyBinding<T> QProperty<T>::setBinding(const QPropertyBinding<T> &newBinding)
838
839 Associates the value of this property with the provided \a newBinding
840 expression and returns the previously associated binding. The first time the
841 property value is read, the binding is evaluated. Whenever a dependency of the
842 binding changes, the binding will be re-evaluated the next time the value of
843 this property is read.
844*/
845
846/*!
847 \fn template <typename T> template <typename Functor> QPropertyBinding<T> QProperty<T>::setBinding(Functor f)
848 \overload
849
850 Associates the value of this property with the provided functor \a f and
851 returns the previously associated binding. The first time the property value
852 is read, the binding is evaluated by invoking the call operator () of \a f.
853 Whenever a dependency of the binding changes, the binding will be re-evaluated
854 the next time the value of this property is read.
855*/
856
857/*!
858 \fn template <typename T> QPropertyBinding<T> bool QProperty<T>::setBinding(const QUntypedPropertyBinding &newBinding)
859 \overload
860
861 Associates the value of this property with the provided \a newBinding
862 expression. The first time the property value is read, the binding is evaluated.
863 Whenever a dependency of the binding changes, the binding will be re-evaluated
864 the next time the value of this property is read.
865
866 Returns true if the type of this property is the same as the type the binding
867 function returns; false otherwise.
868*/
869
870/*!
871 \fn template <typename T> QPropertyBinding<T> QProperty<T>::binding() const
872
873 Returns the binding expression that is associated with this property. A
874 default constructed QPropertyBinding<T> will be returned if no such
875 association exists.
876*/
877
878/*!
879 \fn template <typename T> QPropertyBinding<T> QProperty<T>::takeBinding()
880
881 Disassociates the binding expression from this property and returns it. After
882 calling this function, the value of the property will only change if you
883 assign a new value to it, or when a new binding is set.
884*/
885
886/*!
887 \fn template <typename T> template <typename Functor> QPropertyChangeHandler<T, Functor> QProperty<T>::onValueChanged(Functor f)
888
889 Registers the given functor \a f as a callback that shall be called whenever
890 the value of the property changes.
891
892 The callback \a f is expected to be a type that has a plain call operator () without any
893 parameters. This means that you can provide a C++ lambda expression, an std::function
894 or even a custom struct with a call operator.
895
896 The returned property change handler object keeps track of the registration. When it
897 goes out of scope, the callback is de-registered.
898*/
899
900/*!
901 \fn template <typename T> template <typename Functor> QPropertyChangeHandler<T, Functor> QProperty<T>::subscribe(Functor f)
902
903 Subscribes the given functor \a f as a callback that is called immediately and whenever
904 the value of the property changes in the future.
905
906 The callback \a f is expected to be a type that has a plain call operator () without any
907 parameters. This means that you can provide a C++ lambda expression, an std::function
908 or even a custom struct with a call operator.
909
910 The returned property change handler object keeps track of the subscription. When it
911 goes out of scope, the callback is unsubscribed.
912*/
913
914/*!
915 \fn template <typename T> QtPrivate::QPropertyBindingData &QProperty<T>::bindingData() const
916 \internal
917*/
918
919/*!
920 \class QObjectBindableProperty
921 \inmodule QtCore
922 \brief The QObjectBindableProperty class is a template class that enables automatic property bindings
923 for property data stored in QObject derived classes.
924 \since 6.0
925
926 \ingroup tools
927
928 QObjectBindableProperty is a generic container that holds an
929 instance of T and behaves mostly like \l QProperty. The extra template
930 parameters are used to identify the surrounding class and a member function of
931 that class. The member function will be called whenever the value held by the
932 property changes.
933
934 You can use QObjectBindableProperty to add binding support to code that uses Q_PROPERTY.
935 The getter and setter methods are easy to adapt for accessing a \l QObjectBindableProperty
936 rather than the plain value. In order to invoke the change signal on property changes, use
937 QObjectBindableProperty and pass the change signal as a callback.
938
939 QObjectBindableProperty is usually not used directly, instead an instance of it is created by
940 using the Q_BINDABLE_PROPERTY_DATA macro.
941
942 Use the Q_BINDABLE_PROPERTY macro in the class declaration to declare the property as bindable.
943
944 \code
945 class MyClass : public QObject
946 {
947 \Q_OBJECT
948 Q_PROPERTY(int x READ x WRITE setX NOTIFY xChanged BINDABLE bindableX)
949 public:
950 int x() const { return xProp; }
951 void setX(int x) { xProp = x; }
952 Bindable<int> bindableX() { return QBindable<int>(&xProp); }
953
954 signals:
955 void xChanged();
956
957 private:
958 // Declare the instance of the bindable property data.
959 Q_OBJECT_BINDABLE_PROPERTY(MyClass, int, xProp, &MyClass::xChanged)
960 };
961 \endcode
962*/
963
964/*!
965 \fn template <typename Class, typename T, auto offset, auto Callback> QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty()
966
967 Constructs a property with a default constructed instance of T.
968*/
969
970/*!
971 \fn template <typename Class, typename T, auto offset, auto Callback> explicit QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(const T &initialValue)
972
973 Constructs a property with the provided \a initialValue.
974*/
975
976/*!
977 \fn template <typename Class, typename T, auto offset, auto Callback> explicit QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(T &&initialValue)
978
979 Move-Constructs a property with the provided \a initialValue.
980*/
981
982/*!
983 \fn template <typename Class, typename T, auto offset, auto Callback> QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(Class *owner, const QPropertyBinding<T> &binding)
984
985 Constructs a property that is tied to the provided \a binding expression. The
986 first time the property value is read, the binding is evaluated. Whenever a
987 dependency of the binding changes, the binding will be re-evaluated the next
988 time the value of this property is read. When the property value changes \a
989 owner is notified via the Callback function.
990*/
991
992/*!
993 \fn template <typename Class, typename T, auto offset, auto Callback> QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(Class *owner, QPropertyBinding<T> &&binding)
994
995 Constructs a property that is tied to the provided \a binding expression. The
996 first time the property value is read, the binding is evaluated. Whenever a
997 dependency of the binding changes, the binding will be re-evaluated the next
998 time the value of this property is read. When the property value changes \a
999 owner is notified via the Callback function.
1000*/
1001
1002
1003/*!
1004 \fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QObjectBindableProperty<Class, T, offset, Callback>::QObjectBindableProperty(Functor &&f)
1005
1006 Constructs a property that is tied to the provided binding expression \a f. The
1007 first time the property value is read, the binding is evaluated. Whenever a
1008 dependency of the binding changes, the binding will be re-evaluated the next
1009 time the value of this property is read.
1010*/
1011
1012/*!
1013 \fn template <typename Class, typename T, auto offset, auto Callback> QObjectBindableProperty<Class, T, offset, Callback>::~QObjectBindableProperty()
1014
1015 Destroys the property.
1016*/
1017
1018/*!
1019 \fn template <typename Class, typename T, auto offset, auto Callback> T QObjectBindableProperty<Class, T, offset, Callback>::value() const
1020
1021 Returns the value of the property. This may evaluate a binding expression that
1022 is tied to this property, before returning the value.
1023*/
1024
1025/*!
1026 \fn template <typename Class, typename T, auto offset, auto Callback> void QObjectBindableProperty<Class, T, offset, Callback>::setValue(parameter_type newValue)
1027 \fn template <typename Class, typename T, auto offset, auto Callback> void QObjectBindableProperty<Class, T, offset, Callback>::setValue(rvalue_ref newValue)
1028
1029 Assigns \a newValue to this property and removes the property's associated
1030 binding, if present. If the property value changes as a result, calls the
1031 Callback function on \a owner.
1032*/
1033
1034/*!
1035 \fn template <typename Class, typename T, auto offset, auto Callback> QPropertyBinding<T> QObjectBindableProperty<Class, T, offset, Callback>::setBinding(const QPropertyBinding<T> &newBinding)
1036
1037 Associates the value of this property with the provided \a newBinding
1038 expression and returns the previously associated binding. The first time the
1039 property value is read, the binding is evaluated. Whenever a dependency of the
1040 binding changes, the binding will be re-evaluated the next time the value of
1041 this property is read. When the property value changes \a owner is notified
1042 via the Callback function.
1043*/
1044
1045/*!
1046 \fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QPropertyBinding<T> QObjectBindableProperty<Class, T, offset, Callback>::setBinding(Functor f)
1047 \overload
1048
1049 Associates the value of this property with the provided functor \a f and
1050 returns the previously associated binding. The first time the property value
1051 is read, the binding is evaluated by invoking the call operator () of \a f.
1052 Whenever a dependency of the binding changes, the binding will be re-evaluated
1053 the next time the value of this property is read. When the property value
1054 changes \a owner is notified via the Callback function.
1055*/
1056
1057/*!
1058 \fn template <typename Class, typename T, auto offset, auto Callback> QPropertyBinding<T> bool QObjectBindableProperty<Class, T, offset, Callback>::setBinding(const QUntypedPropertyBinding &newBinding)
1059 \overload
1060
1061 Associates the value of this property with the provided \a newBinding
1062 expression. The first time the property value is read, the binding is evaluated.
1063 Whenever a dependency of the binding changes, the binding will be re-evaluated
1064 the next time the value of this property is read.
1065
1066 Returns \c true if the type of this property is the same as the type the binding
1067 function returns; \c false otherwise.
1068*/
1069
1070/*!
1071 \fn template <typename Class, typename T, auto offset, auto Callback> bool QObjectBindableProperty<Class, T, offset, Callback>::hasBinding() const
1072
1073 Returns true if the property is associated with a binding; false otherwise.
1074*/
1075
1076
1077/*!
1078 \fn template <typename Class, typename T, auto offset, auto Callback> QPropertyBinding<T> QObjectBindableProperty<Class, T, offset, Callback>::binding() const
1079
1080 Returns the binding expression that is associated with this property. A
1081 default constructed QPropertyBinding<T> will be returned if no such
1082 association exists.
1083*/
1084
1085/*!
1086 \fn template <typename Class, typename T, auto offset, auto Callback> QPropertyBinding<T> QObjectBindableProperty<Class, T, offset, Callback>::takeBinding()
1087
1088 Disassociates the binding expression from this property and returns it. After
1089 calling this function, the value of the property will only change if you
1090 assign a new value to it, or when a new binding is set.
1091*/
1092
1093/*!
1094 \fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QPropertyChangeHandler<T, Functor> QObjectBindableProperty<Class, T, offset, Callback>::onValueChanged(Functor f)
1095
1096 Registers the given functor \a f as a callback that shall be called whenever
1097 the value of the property changes.
1098
1099 The callback \a f is expected to be a type that has a plain call operator () without any
1100 parameters. This means that you can provide a C++ lambda expression, an std::function
1101 or even a custom struct with a call operator.
1102
1103 The returned property change handler object keeps track of the registration. When it
1104 goes out of scope, the callback is de-registered.
1105*/
1106
1107/*!
1108 \fn template <typename Class, typename T, auto offset, auto Callback> template <typename Functor> QPropertyChangeHandler<T, Functor> QObjectBindableProperty<Class, T, offset, Callback>::subscribe(Functor f)
1109
1110 Subscribes the given functor \a f as a callback that is called immediately and whenever
1111 the value of the property changes in the future.
1112
1113 The callback \a f is expected to be a type that has a plain call operator () without any
1114 parameters. This means that you can provide a C++ lambda expression, an std::function
1115 or even a custom struct with a call operator.
1116
1117 The returned property change handler object keeps track of the subscription. When it
1118 goes out of scope, the callback is unsubscribed.
1119*/
1120
1121/*!
1122 \fn template <typename T> QtPrivate::QPropertyBase &QObjectBindableProperty<Class, T, offset, Callback>::propertyBase() const
1123 \internal
1124*/
1125
1126/*!
1127 \class QPropertyChangeHandler
1128 \inmodule QtCore
1129 \brief The QPropertyChangeHandler class controls the lifecycle of change callback installed on a QProperty.
1130
1131 \ingroup tools
1132
1133 QPropertyChangeHandler\<PropertyType, Functor\> is created when registering a
1134 callback on a QProperty to listen to changes to the property's value, using QProperty::onValueChanged
1135 and QProperty::subscribe. As long as the change handler is alive, the callback remains installed.
1136
1137 A handler instance can be transferred between C++ scopes using move semantics.
1138*/
1139
1140/*!
1141 \class QPropertyAlias
1142 \inmodule QtCore
1143 \brief The QPropertyAlias class is a safe alias for a QProperty with same template parameter.
1144
1145 \ingroup tools
1146
1147 QPropertyAlias\<T\> wraps a pointer to a QProperty\<T\> and automatically
1148 invalidates itself when the QProperty\<T\> is destroyed. It forwards all
1149 method invocations to the wrapped property. For example:
1150
1151 \code
1152 QProperty<QString> *name = new QProperty<QString>("John");
1153 QProperty<int> age(41);
1154
1155 QPropertyAlias<QString> nameAlias(name);
1156 QPropertyAlias<int> ageAlias(&age);
1157
1158 QPropertyAlias<QString> fullname;
1159 fullname.setBinding([&]() { return nameAlias.value() + " age:" + QString::number(ageAlias.value()); });
1160
1161 qDebug() << fullname.value(); // Prints "Smith age: 41"
1162
1163 *name = "Emma"; // Marks binding expression as dirty
1164
1165 qDebug() << fullname.value(); // Re-evaluates the binding expression and prints "Emma age: 41"
1166
1167 // Birthday is coming up
1168 ageAlias.setValue(age.value() + 1); // Writes the age property through the alias
1169
1170 qDebug() << fullname.value(); // Re-evaluates the binding expression and prints "Emma age: 42"
1171
1172 delete name; // Leaves the alias in an invalid, but accessible state
1173 nameAlias.setValue("Eve"); // Ignored: nameAlias carries a default-constructed QString now
1174
1175 ageAlias.setValue(92);
1176 qDebug() << fullname.value(); // Re-evaluates the binding expression and prints " age: 92"
1177 \endcode
1178*/
1179
1180/*!
1181 \fn template <typename T> QPropertyAlias<T>::QPropertyAlias(QProperty<T> *property)
1182
1183 Constructs a property alias for the given \a property.
1184*/
1185
1186/*!
1187 \fn template <typename T> explicit QPropertyAlias<T>::QPropertyAlias(QPropertyAlias<T> *alias)
1188
1189 Constructs a property alias for the property aliased by \a alias.
1190*/
1191
1192/*!
1193 \fn template <typename T> T QPropertyAlias<T>::value() const
1194
1195 Returns the value of the aliased property. This may evaluate a binding
1196 expression that is tied to the property, before returning the value.
1197*/
1198
1199/*!
1200 \fn template <typename T> QPropertyAlias<T>::operator T() const
1201
1202 Returns the value of the aliased property. This may evaluate a binding
1203 expression that is tied to the property, before returning the value.
1204*/
1205
1206/*!
1207 \fn template <typename T> void QPropertyAlias<T>::setValue(const T &newValue)
1208
1209 Assigns \a newValue to the aliased property and removes the property's
1210 associated binding, if present.
1211*/
1212
1213/*!
1214 \fn template <typename T> QPropertyAlias<T> &QPropertyAlias<T>::operator=(const T &newValue)
1215
1216 Assigns \a newValue to the aliased property and returns a reference to this
1217 QPropertyAlias.
1218*/
1219
1220/*!
1221 \fn template <typename T> QPropertyAlias<T> &QPropertyAlias<T>::operator=(T &&newValue)
1222 \overload
1223
1224 Assigns \a newValue to the aliased property and returns a reference to this
1225 QPropertyAlias.
1226*/
1227
1228/*!
1229 \fn template <typename T> QPropertyAlias<T> &QPropertyAlias<T>::operator=(const QPropertyBinding<T> &newBinding)
1230 \overload
1231
1232 Associates the value of the aliased property with the provided \a newBinding
1233 expression and returns a reference to this alias. The first time the
1234 property value is read, either from the property itself or from any alias, the
1235 binding is evaluated. Whenever a dependency of the binding changes, the
1236 binding will be re-evaluated the next time the value of this property is read.
1237*/
1238
1239/*!
1240 \fn template <typename T> QPropertyBinding<T> QPropertyAlias<T>::setBinding(const QPropertyBinding<T> &newBinding)
1241
1242 Associates the value of the aliased property with the provided \a newBinding
1243 expression and returns any previous binding the associated with the aliased
1244 property. The first time the property value is read, either from the property
1245 itself or from any alias, the binding is evaluated. Whenever a dependency of
1246 the binding changes, the binding will be re-evaluated the next time the value
1247 of this property is read.
1248
1249 Returns any previous binding associated with the property, or a
1250 default-constructed QPropertyBinding<T>.
1251*/
1252
1253/*!
1254 \fn template <typename T> QPropertyBinding<T> bool QPropertyAlias<T>::setBinding(const QUntypedPropertyBinding &newBinding)
1255 \overload
1256
1257 Associates the value of the aliased property with the provided \a newBinding
1258 expression. The first time the property value is read, either from the
1259 property itself or from any alias, the binding is evaluated. Whenever a
1260 dependency of the binding changes, the binding will be re-evaluated the next
1261 time the value of this property is read.
1262
1263 Returns true if the type of this property is the same as the type the binding
1264 function returns; false otherwise.
1265*/
1266
1267/*!
1268 \fn template <typename T> template <typename Functor> QPropertyBinding<T> QPropertyAlias<T>::setBinding(Functor f)
1269 \overload
1270
1271 Associates the value of the aliased property with the provided functor \a f
1272 expression. The first time the property value is read, either from the
1273 property itself or from any alias, the binding is evaluated. Whenever a
1274 dependency of the binding changes, the binding will be re-evaluated the next
1275 time the value of this property is read.
1276
1277 Returns any previous binding associated with the property, or a
1278 default-constructed QPropertyBinding<T>.
1279*/
1280
1281/*!
1282 \fn template <typename T> bool QPropertyAlias<T>::hasBinding() const
1283
1284 Returns true if the aliased property is associated with a binding; false
1285 otherwise.
1286*/
1287
1288/*!
1289 \fn template <typename T> QPropertyBinding<T> QPropertyAlias<T>::binding() const
1290
1291 Returns the binding expression that is associated with the aliased property. A
1292 default constructed QPropertyBinding<T> will be returned if no such
1293 association exists.
1294*/
1295
1296/*!
1297 \fn template <typename T> QPropertyBinding<T> QPropertyAlias<T>::takeBinding()
1298
1299 Disassociates the binding expression from the aliased property and returns it.
1300 After calling this function, the value of the property will only change if
1301 you assign a new value to it, or when a new binding is set.
1302*/
1303
1304/*!
1305 \fn template <typename T> template <typename Functor> QPropertyChangeHandler<T, Functor> QPropertyAlias<T>::onValueChanged(Functor f)
1306
1307 Registers the given functor \a f as a callback that shall be called whenever
1308 the value of the aliased property changes.
1309
1310 The callback \a f is expected to be a type that has a plain call operator () without any
1311 parameters. This means that you can provide a C++ lambda expression, an std::function
1312 or even a custom struct with a call operator.
1313
1314 The returned property change handler object keeps track of the registration. When it
1315 goes out of scope, the callback is de-registered.
1316*/
1317
1318/*!
1319 \fn template <typename T> template <typename Functor> QPropertyChangeHandler<T, Functor> QPropertyAlias<T>::subscribe(Functor f)
1320
1321 Subscribes the given functor \a f as a callback that is called immediately and whenever
1322 the value of the aliased property changes in the future.
1323
1324 The callback \a f is expected to be a type that has a plain call operator () without any
1325 parameters. This means that you can provide a C++ lambda expression, an std::function
1326 or even a custom struct with a call operator.
1327
1328 The returned property change handler object keeps track of the subscription. When it
1329 goes out of scope, the callback is unsubscribed.
1330*/
1331
1332/*!
1333 \fn template <typename T> bool QPropertyAlias<T>::isValid() const
1334
1335 Returns true if the aliased property still exists; false otherwise.
1336
1337 If the aliased property doesn't exist, all other method calls are ignored.
1338*/
1339
1340struct QBindingStorageData
1341{
1342 size_t size = 0;
1343 size_t used = 0;
1344 // Pair[] pairs;
1345};
1346
1347struct QBindingStoragePrivate
1348{
1349 // This class basically implements a simple and fast hash map to store bindings for a QObject
1350 // The reason that we're not using QHash is that QPropertyBindingData can not be copied, only
1351 // moved. That doesn't work well together with an implicitly shared class.
1352 struct Pair
1353 {
1354 QUntypedPropertyData *data;
1355 QPropertyBindingData bindingData;
1356 };
1357 static_assert(alignof(Pair) == alignof(void *));
1358 static_assert(alignof(size_t) == alignof(void *));
1359
1360 QBindingStorageData *&d;
1361
1362 static inline Pair *pairs(QBindingStorageData *dd)
1363 {
1364 Q_ASSERT(dd);
1365 return reinterpret_cast<Pair *>(dd + 1);
1366 }
1367 void reallocate(size_t newSize)
1368 {
1369 Q_ASSERT(!d || newSize > d->size);
1370 size_t allocSize = sizeof(QBindingStorageData) + newSize*sizeof(Pair);
1371 void *nd = malloc(allocSize);
1372 memset(nd, 0, allocSize);
1373 QBindingStorageData *newData = new (nd) QBindingStorageData;
1374 newData->size = newSize;
1375 if (!d) {
1376 d = newData;
1377 return;
1378 }
1379 newData->used = d->used;
1380 Pair *p = pairs(d);
1381 for (size_t i = 0; i < d->size; ++i, ++p) {
1382 if (p->data) {
1383 Pair *pp = pairs(newData);
1384 Q_ASSERT(newData->size && (newData->size & (newData->size - 1)) == 0); // size is a power of two
1385 size_t index = qHash(p->data) & (newData->size - 1);
1386 while (pp[index].data) {
1387 ++index;
1388 if (index == newData->size)
1389 index = 0;
1390 }
1391 new (pp + index) Pair{p->data, QPropertyBindingData(std::move(p->bindingData))};
1392 }
1393 }
1394 // data has been moved, no need to call destructors on old Pairs
1395 free(d);
1396 d = newData;
1397 }
1398
1399 QBindingStoragePrivate(QBindingStorageData *&_d) : d(_d) {}
1400
1401 QPropertyBindingData *get(const QUntypedPropertyData *data)
1402 {
1403 if (!d)
1404 return nullptr;
1405 Q_ASSERT(d->size && (d->size & (d->size - 1)) == 0); // size is a power of two
1406 size_t index = qHash(data) & (d->size - 1);
1407 Pair *p = pairs(d);
1408 while (p[index].data) {
1409 if (p[index].data == data)
1410 return &p[index].bindingData;
1411 ++index;
1412 if (index == d->size)
1413 index = 0;
1414 }
1415 return nullptr;
1416 }
1417 QPropertyBindingData *getAndCreate(QUntypedPropertyData *data)
1418 {
1419 if (!d)
1420 reallocate(8);
1421 else if (d->used*2 >= d->size)
1422 reallocate(d->size*2);
1423 Q_ASSERT(d->size && (d->size & (d->size - 1)) == 0); // size is a power of two
1424 size_t index = qHash(data) & (d->size - 1);
1425 Pair *p = pairs(d);
1426 while (p[index].data) {
1427 if (p[index].data == data)
1428 return &p[index].bindingData;
1429 ++index;
1430 if (index == d->size)
1431 index = 0;
1432 }
1433 ++d->used;
1434 new (p + index) Pair{data, QPropertyBindingData()};
1435 return &p[index].bindingData;
1436 }
1437
1438 void destroy()
1439 {
1440 if (!d)
1441 return;
1442 Pair *p = pairs(d);
1443 for (size_t i = 0; i < d->size; ++i) {
1444 if (p->data)
1445 p->~Pair();
1446 ++p;
1447 }
1448 free(d);
1449 }
1450};
1451
1452/*!
1453 \class QBindingStorage
1454 \internal
1455
1456 QBindingStorage acts as a storage for property binding related data in QObject.
1457 Any property in a QObject can be made bindable, by using the Q_BINDABLE_PROPERTY_DATA
1458 macro to declare the data storage. Then implement a setter and getter for the property
1459 and declare it as a Q_PROPERTY as usual. Finally make it bindable, but using
1460 the Q_BINDABLE_PROPERTY macro after the declaration of the setter and getter.
1461*/
1462
1463QBindingStorage::QBindingStorage()
1464{
1465 bindingStatus = &QT_PREPEND_NAMESPACE(bindingStatus);
1466 Q_ASSERT(bindingStatus);
1467}
1468
1469QBindingStorage::~QBindingStorage()
1470{
1471 QBindingStoragePrivate(d).destroy();
1472}
1473
1474void QBindingStorage::maybeUpdateBindingAndRegister(const QUntypedPropertyData *data) const
1475{
1476 Q_ASSERT(bindingStatus);
1477 QUntypedPropertyData *dd = const_cast<QUntypedPropertyData *>(data);
1478 auto storage = bindingStatus->currentlyEvaluatingBinding ?
1479 QBindingStoragePrivate(d).getAndCreate(dd) :
1480 QBindingStoragePrivate(d).get(dd);
1481 if (!storage)
1482 return;
1483 if (auto *binding = storage->binding())
1484 binding->evaluateIfDirtyAndReturnTrueIfValueChanged(const_cast<QUntypedPropertyData *>(data));
1485 storage->registerWithCurrentlyEvaluatingBinding();
1486}
1487
1488QPropertyBindingData *QBindingStorage::bindingData(const QUntypedPropertyData *data) const
1489{
1490 return QBindingStoragePrivate(d).get(data);
1491}
1492
1493QPropertyBindingData *QBindingStorage::bindingData(QUntypedPropertyData *data, bool create)
1494{
1495 auto storage = create ?
1496 QBindingStoragePrivate(d).getAndCreate(data) :
1497 QBindingStoragePrivate(d).get(data);
1498 return storage;
1499}
1500
1501QT_END_NAMESPACE
1502