mirror of https://github.com/qt/qtbase.git
QProperty add markdirty
This adds functionality for marking properties (QProperty and related classes) manually as dirty. This facilliates the integration of bindable properties with non-binable properties and makes it possible for bindable properties to change due to external events. Fixes: QTBUG-89167 Change-Id: I256cf154d914149dacb6cadaba92b13c88c9d027 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
abd2cbc12a
commit
10bf3ae90c
|
@ -381,6 +381,13 @@ void QPropertyBindingData::notifyObservers(QUntypedPropertyData *propertyDataPtr
|
|||
observer.notify(d.bindingPtr(), propertyDataPtr);
|
||||
}
|
||||
|
||||
void QPropertyBindingData::markDirty()
|
||||
{
|
||||
QPropertyBindingDataPointer d{this};
|
||||
if (auto *binding = d.bindingPtr())
|
||||
binding->setDirty(true);
|
||||
}
|
||||
|
||||
int QPropertyBindingDataPointer::observerCount() const
|
||||
{
|
||||
int count = 0;
|
||||
|
@ -836,6 +843,31 @@ QString QPropertyBindingError::description() const
|
|||
this property is read.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> void QProperty<T>::markDirty()
|
||||
|
||||
Programatically sets the property dirty. Any binding which depends on it will
|
||||
be notified.
|
||||
This can be useful for properties which do not only depend on bindable properties,
|
||||
but also on non-bindable properties or some other state.
|
||||
|
||||
For example, assume we have a \c Circle class, with a non-bindable \c radius property
|
||||
and a corresponding \c radiusChanged signal. We now want to create a property for a
|
||||
cylinders volume, based on a height \c QProperty and an instance of Circle. To ensure
|
||||
that the volume changes, we can call setDirty in a slot connected to radiusChanged.
|
||||
\code
|
||||
Circle circle;
|
||||
QProperty<double> height;
|
||||
|
||||
QProperty<double> volume;
|
||||
volume.setBinding([&]() {return height * std::pi_v<double> * circle.radius() * circle.radius()};
|
||||
QOBject::connect(&circle, &Circle::radiusChanged, [&](){volume.markDirty();});
|
||||
\endcode
|
||||
|
||||
\note Binding to a QObjectBindableProperty's signal does not make sense in general. Bindings
|
||||
across bindable properties get marked dirty automatically.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename T> QPropertyBinding<T> QProperty<T>::setBinding(const QPropertyBinding<T> &newBinding)
|
||||
|
||||
|
@ -1035,6 +1067,17 @@ QString QPropertyBindingError::description() const
|
|||
Callback function on \a owner.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename Class, typename T, auto offset, auto Callback> void QObjectBindableProperty<Class, T, offset, Callback>::markDirty()
|
||||
|
||||
Programatically sets the property dirty. Any binding which depend on it will
|
||||
be notified.
|
||||
This can be useful for properties which do not only depend on bindable properties,
|
||||
but also on non-bindable properties or some other state.
|
||||
|
||||
\sa QProperty<T>::markDirty
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename Class, typename T, auto offset, auto Callback> QPropertyBinding<T> QObjectBindableProperty<Class, T, offset, Callback>::setBinding(const QPropertyBinding<T> &newBinding)
|
||||
|
||||
|
|
|
@ -406,6 +406,11 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
void markDirty() {
|
||||
d.markDirty();
|
||||
notify();
|
||||
}
|
||||
|
||||
#ifndef Q_CLANG_QDOC
|
||||
template <typename Functor>
|
||||
QPropertyBinding<T> setBinding(Functor &&f,
|
||||
|
@ -972,6 +977,15 @@ public:
|
|||
return bd && bd->binding() != nullptr;
|
||||
}
|
||||
|
||||
void markDirty() {
|
||||
QBindingStorage *storage = qGetBindingStorage(owner());
|
||||
auto bd = storage->bindingData(this, /*create=*/false);
|
||||
if (bd) { // if we have no BindingData, nobody can listen anyway
|
||||
bd->markDirty();
|
||||
notify(bd);
|
||||
}
|
||||
}
|
||||
|
||||
QPropertyBinding<T> binding() const
|
||||
{
|
||||
auto *bd = qGetBindingStorage(owner())->bindingData(this);
|
||||
|
@ -1121,6 +1135,14 @@ public:
|
|||
return *storage->bindingData(const_cast<QObjectComputedProperty *>(this), true);
|
||||
}
|
||||
|
||||
void markDirty() {
|
||||
// computed property can't store a binding, so there's nothing to mark
|
||||
auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
|
||||
auto bd = storage->bindingData(const_cast<QObjectComputedProperty *>(this), false);
|
||||
if (bd)
|
||||
bindingData().notifyObservers(this);
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
|
|
@ -498,6 +498,15 @@ public:
|
|||
return bd && bd->binding() != nullptr;
|
||||
}
|
||||
|
||||
void markDirty() {
|
||||
QBindingStorage *storage = qGetBindingStorage(owner());
|
||||
auto *bd = storage->bindingData(this, false);
|
||||
if (bd) {
|
||||
bd->markDirty();
|
||||
notify(bd);
|
||||
}
|
||||
}
|
||||
|
||||
QPropertyBinding<T> binding() const
|
||||
{
|
||||
auto *bd = qGetBindingStorage(owner())->bindingData(this);
|
||||
|
|
|
@ -248,6 +248,8 @@ public:
|
|||
}
|
||||
|
||||
void evaluateIfDirty(const QUntypedPropertyData *property) const;
|
||||
void markDirty();
|
||||
|
||||
void removeBinding()
|
||||
{
|
||||
if (hasBinding())
|
||||
|
|
|
@ -91,6 +91,7 @@ private slots:
|
|||
void noFakeDependencies();
|
||||
|
||||
void bindablePropertyWithInitialization();
|
||||
void markDirty();
|
||||
};
|
||||
|
||||
void tst_QProperty::functorBinding()
|
||||
|
@ -1480,6 +1481,82 @@ void tst_QProperty::bindablePropertyWithInitialization()
|
|||
QCOMPARE(tester.prop3().anotherValue, 20);
|
||||
}
|
||||
|
||||
class MarkDirtyTester : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_PROPERTY(int value1 READ value1 WRITE setValue1 BINDABLE bindableValue1)
|
||||
Q_PROPERTY(int value2 READ value2 WRITE setValue1 BINDABLE bindableValue2)
|
||||
Q_PROPERTY(int computed READ computed BINDABLE bindableComputed)
|
||||
|
||||
inline static int staticValue = 0;
|
||||
|
||||
int value1() const {return m_value1;}
|
||||
void setValue1(int val) {m_value1 = val;}
|
||||
QBindable<int> bindableValue1() {return { &m_value1 };}
|
||||
|
||||
int value2() const {return m_value2;}
|
||||
void setValue2(int val) {m_value2 = val;}
|
||||
QBindable<int> bindableValue2() {return { &m_value2 };}
|
||||
|
||||
int computed() const { return staticValue + m_value1; }
|
||||
QBindable<int> bindableComputed() {return {&m_computed};}
|
||||
|
||||
void incrementStaticValue() {
|
||||
++staticValue;
|
||||
m_computed.markDirty();
|
||||
}
|
||||
|
||||
void markValue1Dirty() {
|
||||
m_value1.markDirty();
|
||||
}
|
||||
|
||||
void markValue2Dirty() {
|
||||
m_value2.markDirty();
|
||||
}
|
||||
private:
|
||||
Q_OBJECT_BINDABLE_PROPERTY(MarkDirtyTester, int, m_value1, nullptr)
|
||||
Q_OBJECT_COMPAT_PROPERTY(MarkDirtyTester, int, m_value2, &MarkDirtyTester::setValue2)
|
||||
Q_OBJECT_COMPUTED_PROPERTY(MarkDirtyTester, int, m_computed, &MarkDirtyTester::computed)
|
||||
};
|
||||
|
||||
void tst_QProperty::markDirty()
|
||||
{
|
||||
{
|
||||
QProperty<int> testProperty;
|
||||
int changeCounter = 0;
|
||||
auto handler = testProperty.onValueChanged([&](){++changeCounter;});
|
||||
testProperty.markDirty();
|
||||
QCOMPARE(changeCounter, 1);
|
||||
}
|
||||
{
|
||||
MarkDirtyTester dirtyTester;
|
||||
int computedChangeCounter = 0;
|
||||
int value1ChangeCounter = 0;
|
||||
auto handler = dirtyTester.bindableComputed().onValueChanged([&](){
|
||||
computedChangeCounter++;
|
||||
});
|
||||
auto handler2 = dirtyTester.bindableValue1().onValueChanged([&](){
|
||||
value1ChangeCounter++;
|
||||
});
|
||||
dirtyTester.incrementStaticValue();
|
||||
QCOMPARE(computedChangeCounter, 1);
|
||||
QCOMPARE(dirtyTester.computed(), 1);
|
||||
dirtyTester.markValue1Dirty();
|
||||
QCOMPARE(value1ChangeCounter, 1);
|
||||
QCOMPARE(computedChangeCounter, 1);
|
||||
}
|
||||
{
|
||||
MarkDirtyTester dirtyTester;
|
||||
int changeCounter = 0;
|
||||
auto handler = dirtyTester.bindableValue2().onValueChanged([&](){
|
||||
changeCounter++;
|
||||
});
|
||||
dirtyTester.markValue2Dirty();
|
||||
QCOMPARE(changeCounter, 1);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QProperty);
|
||||
|
||||
#include "tst_qproperty.moc"
|
||||
|
|
Loading…
Reference in New Issue