diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2020-05-25 12:51:39 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-05-27 11:54:30 +0200 |
commit | 524d78160726b25ed424a2c7a6d5e423b7ea4b93 (patch) | |
tree | c5ca373ef8231454dab4a73ffe2d479a73f103aa /src/corelib | |
parent | 36bd34dbdcaa0fcfd47d1edb3494a4babb709ca3 (diff) |
QProperty: Support multiple observers
Previously, only the first observer would get notified. Also, make sure
that the notifiers are always retained when switching between bindings
and values.
Change-Id: I9c25c0f2e288dac3a335b68e618f7ddeb44be25a
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/kernel/qproperty.cpp | 37 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty.h | 4 | ||||
-rw-r--r-- | src/corelib/kernel/qproperty_p.h | 1 | ||||
-rw-r--r-- | src/corelib/kernel/qpropertybinding_p.h | 7 |
4 files changed, 32 insertions, 17 deletions
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp index 7554e91aba..4ed4af4c8e 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -83,8 +83,11 @@ void QPropertyBase::moveAssign(QPropertyBase &&other, void *propertyDataPtr) QPropertyBase::~QPropertyBase() { QPropertyBasePointer d{this}; - if (auto observer = d.firstObserver()) + for (auto observer = d.firstObserver(); observer;) { + auto next = observer.nextObserver(); observer.unlink(); + observer = next; + } if (auto binding = d.bindingPtr()) binding->unlinkAndDeref(); } @@ -95,18 +98,19 @@ QUntypedPropertyBinding QPropertyBase::setBinding(const QUntypedPropertyBinding QPropertyBindingPrivatePtr newBinding = binding.d; QPropertyBasePointer d{this}; - - auto observer = d.firstObserver(); - if (observer) - observer.unlink(); + QPropertyObserverPointer observer; if (auto *existingBinding = d.bindingPtr()) { if (existingBinding == newBinding.data()) return QUntypedPropertyBinding(oldBinding.data()); oldBinding = QPropertyBindingPrivatePtr(existingBinding); + observer = oldBinding->takeObservers(); oldBinding->unlinkAndDeref(); d_ptr &= FlagMask; + } else { + observer = d.firstObserver(); } + if (newBinding) { newBinding.data()->ref.ref(); d_ptr = (d_ptr & FlagMask) | reinterpret_cast<quintptr>(newBinding.data()); @@ -115,8 +119,10 @@ QUntypedPropertyBinding QPropertyBase::setBinding(const QUntypedPropertyBinding newBinding->setProperty(propertyDataPtr); if (observer) newBinding->prependObserver(observer); + } else if (observer) { + d.setObservers(observer.ptr); } else { - d_ptr &= ~BindingBit; + d_ptr &= ~QPropertyBase::BindingBit; } return QUntypedPropertyBinding(oldBinding.data()); @@ -137,6 +143,12 @@ QPropertyBindingPrivate *QPropertyBasePointer::bindingPtr() const return nullptr; } +void QPropertyBasePointer::setObservers(QPropertyObserver *observer) +{ + observer->prev = reinterpret_cast<QPropertyObserver**>(&(ptr->d_ptr)); + ptr->d_ptr = (reinterpret_cast<quintptr>(observer) & ~QPropertyBase::FlagMask); +} + void QPropertyBasePointer::addObserver(QPropertyObserver *observer) { if (auto *binding = bindingPtr()) { @@ -199,18 +211,13 @@ void QPropertyBase::removeBinding() { QPropertyBasePointer d{this}; - auto observer = d.firstObserver(); - if (observer) - observer.unlink(); - if (auto *existingBinding = d.bindingPtr()) { + auto observer = existingBinding->takeObservers(); existingBinding->unlinkAndDeref(); - d_ptr &= FlagMask; + d_ptr &= ExtraBit; + if (observer) + d.setObservers(observer.ptr); } - d_ptr &= ~BindingBit; - - if (observer) - observer.observeProperty(d); } void QPropertyBase::registerWithCurrentlyEvaluatingBinding() const diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h index 22313bc92e..938de61fd5 100644 --- a/src/corelib/kernel/qproperty.h +++ b/src/corelib/kernel/qproperty.h @@ -254,16 +254,16 @@ public: void setValue(T &&newValue) { + d.priv.removeBinding(); if (d.setValueAndReturnTrueIfChanged(std::move(newValue))) notify(); - d.priv.removeBinding(); } void setValue(const T &newValue) { + d.priv.removeBinding(); if (d.setValueAndReturnTrueIfChanged(newValue)) notify(); - d.priv.removeBinding(); } QProperty<T> &operator=(T &&newValue) diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h index 13cdb311c1..6638785ccf 100644 --- a/src/corelib/kernel/qproperty_p.h +++ b/src/corelib/kernel/qproperty_p.h @@ -65,6 +65,7 @@ struct Q_AUTOTEST_EXPORT QPropertyBasePointer QPropertyBindingPrivate *bindingPtr() const; + void setObservers(QPropertyObserver *observer); void addObserver(QPropertyObserver *observer); void setFirstObserver(QPropertyObserver *observer); QPropertyObserverPointer firstObserver() const; diff --git a/src/corelib/kernel/qpropertybinding_p.h b/src/corelib/kernel/qpropertybinding_p.h index 66e969547c..7c4166592b 100644 --- a/src/corelib/kernel/qpropertybinding_p.h +++ b/src/corelib/kernel/qpropertybinding_p.h @@ -101,6 +101,13 @@ public: firstObserver = observer; } + QPropertyObserverPointer takeObservers() + { + auto observers = firstObserver; + firstObserver.ptr = nullptr; + return observers; + } + void clearDependencyObservers() { for (size_t i = 0; i < inlineDependencyObservers.size(); ++i) { QPropertyObserver empty; |