summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-05-25 12:51:39 +0200
committerUlf Hermann <ulf.hermann@qt.io>2020-05-27 11:54:30 +0200
commit524d78160726b25ed424a2c7a6d5e423b7ea4b93 (patch)
treec5ca373ef8231454dab4a73ffe2d479a73f103aa /src/corelib
parent36bd34dbdcaa0fcfd47d1edb3494a4babb709ca3 (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.cpp37
-rw-r--r--src/corelib/kernel/qproperty.h4
-rw-r--r--src/corelib/kernel/qproperty_p.h1
-rw-r--r--src/corelib/kernel/qpropertybinding_p.h7
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;