QPropertyBinding: Add sticky mode

A sticky QPropertyBinding is a binding that does not get removed when a
write occurs. This is used in the QML engine to implement support for
the QQmlPropertyData::DontRemoveBinding flag.

Task-number: QTBUG-91689
Change-Id: Ib575b49abe634215318ccc7ba46212cc21eb4dad
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Fabian Kosmale 2021-03-07 20:26:56 +01:00
parent a794c5e287
commit e835bccb1e
3 changed files with 36 additions and 0 deletions

View File

@ -508,6 +508,9 @@ void QPropertyBindingData::removeBinding_helper()
auto *existingBinding = d.binding();
Q_ASSERT(existingBinding);
if (existingBinding->isSticky()) {
return;
}
auto observer = existingBinding->takeObservers();
d_ref() = 0;

View File

@ -184,6 +184,11 @@ private:
bool hasBindingWrapper:1;
// used to detect binding loops for eagerly evaluated properties
bool isQQmlPropertyBinding:1;
/* a sticky binding does not get removed in removeBinding
this is used to support QQmlPropertyData::DontRemoveBinding
in qtdeclarative
*/
bool m_sticky:1;
const QtPrivate::BindingFunctionVTable *vtable;
@ -234,11 +239,14 @@ public:
size_t dependencyObserverCount = 0;
bool isUpdating() {return updating;}
void setSticky(bool keep = true) {m_sticky = keep;}
bool isSticky() {return m_sticky;}
QPropertyBindingPrivate(QMetaType metaType, const QtPrivate::BindingFunctionVTable *vtable,
const QPropertyBindingSourceLocation &location, bool isQQmlPropertyBinding=false)
: hasBindingWrapper(false)
, isQQmlPropertyBinding(isQQmlPropertyBinding)
, m_sticky(false)
, vtable(vtable)
, location(location)
, metaType(metaType)

View File

@ -56,6 +56,7 @@ private slots:
void avoidDependencyAllocationAfterFirstEval();
void boolProperty();
void takeBinding();
void stickyBinding();
void replaceBinding();
void changeHandler();
void propertyChangeHandlerApi();
@ -307,6 +308,30 @@ void tst_QProperty::takeBinding()
QVERIFY(!existingBinding.isNull());
}
void tst_QProperty::stickyBinding()
{
QProperty<int> prop;
QProperty<int> prop2 {2};
prop.setBinding([&](){ return prop2.value(); });
QCOMPARE(prop.value(), 2);
auto privBinding = QPropertyBindingPrivate::get(prop.binding());
// If we make a binding sticky,
privBinding->setSticky();
// then writing to the property does not remove it
prop = 1;
QVERIFY(prop.hasBinding());
// but the value still changes.
QCOMPARE(prop.value(), 1);
// The binding continues to work normally.
prop2 = 3;
QCOMPARE(prop.value(), 3);
// If we remove the stickiness
privBinding->setSticky(false);
// the binding goes away on the next write
prop = 42;
QVERIFY(!prop.hasBinding());
}
void tst_QProperty::replaceBinding()
{
QProperty<int> first(100);