diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2022-12-15 16:47:27 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2022-12-22 11:00:49 +0100 |
commit | 75ec5421c07b5f56f21504a15f0f069bd375728c (patch) | |
tree | 28b27e46c1335d6bfbda3e96b91722be47806e13 | |
parent | 5ccfea3bf01a598a4ec3f859cafeeffab46f780d (diff) |
QML: Consider deep aliases when finding binding targets
If we have a deep alias we need to bind to the inner object rather than
the outer one.
Fixes: QTBUG-109417
Change-Id: Iefe8641026cfbbf9199b2bb8d9fa2f5fba591f17
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit e9b7eaaf6e627c84cf77dc0ea76c9cb40d705711)
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
-rw-r--r-- | src/qml/qml/qqmlbinding.cpp | 56 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/MyRectangle.qml | 10 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/data/alias.19.qml | 11 | ||||
-rw-r--r-- | tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 10 |
4 files changed, 71 insertions, 16 deletions
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 9bebc4c67e..cb0dd2fe25 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -691,14 +691,34 @@ bool QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const valueType ? valueType->coreIndex() : -1); } -bool QQmlBinding::setTarget(QObject *object, int coreIndex, bool coreIsAlias, int valueTypeIndex) +static const QQmlPropertyData *getObjectPropertyData(QObject *object, int coreIndex) { - m_target = object; + QQmlData *data = QQmlData::get(object, true); + if (!data) + return nullptr; + if (!data->propertyCache) { + data->propertyCache = QQmlMetaType::propertyCache(object->metaObject()); + if (!data->propertyCache) + return nullptr; + data->propertyCache->addref(); + } + const QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); + Q_ASSERT(propertyData); + return propertyData; +} - if (!object) { +bool QQmlBinding::setTarget(QObject *object, int coreIndex, bool coreIsAlias, int valueTypeIndex) +{ + auto invalidate = [this]() { + m_target = nullptr; m_targetIndex = QQmlPropertyIndex(); return false; - } + }; + + if (!object) + return invalidate(); + + m_target = object; for (bool isAlias = coreIsAlias; isAlias;) { QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); @@ -706,21 +726,25 @@ bool QQmlBinding::setTarget(QObject *object, int coreIndex, bool coreIsAlias, in int aValueTypeIndex; if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) { // can't resolve id (yet) - m_target = nullptr; - m_targetIndex = QQmlPropertyIndex(); - return false; + return invalidate(); } - if (valueTypeIndex == -1) - valueTypeIndex = aValueTypeIndex; - QQmlData *data = QQmlData::get(object, false); - if (!data || !data->propertyCache) { - m_target = nullptr; - m_targetIndex = QQmlPropertyIndex(); - return false; + const QQmlPropertyData *propertyData = getObjectPropertyData(object, coreIndex); + if (!propertyData) + return invalidate(); + if (aValueTypeIndex != -1) { + if (propertyData->propType().flags().testFlag(QMetaType::PointerToQObject)) { + // deep alias + propertyData->readProperty(object, &object); + coreIndex = aValueTypeIndex; + valueTypeIndex = -1; + propertyData = getObjectPropertyData(object, coreIndex); + if (!propertyData) + return invalidate(); + } else { + valueTypeIndex = aValueTypeIndex; + } } - QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); - Q_ASSERT(propertyData); m_target = object; isAlias = propertyData->isAlias(); diff --git a/tests/auto/qml/qqmllanguage/data/MyRectangle.qml b/tests/auto/qml/qqmllanguage/data/MyRectangle.qml new file mode 100644 index 0000000000..4d5e7c6c8d --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/MyRectangle.qml @@ -0,0 +1,10 @@ +import QtQuick + +Item { + property alias rectangle1AnchorsleftMargin: rectangle1.anchors.leftMargin + + Rectangle { + id: rectangle1 + anchors.leftMargin: 250 + } +} diff --git a/tests/auto/qml/qqmllanguage/data/alias.19.qml b/tests/auto/qml/qqmllanguage/data/alias.19.qml new file mode 100644 index 0000000000..a96c0c694d --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.19.qml @@ -0,0 +1,11 @@ +import QtQuick + +Item { + id: myThing + width: 1920 + + MyRectangle { + rectangle1AnchorsleftMargin: myThing.width / 2 + Component.onCompleted: myThing.height = rectangle1AnchorsleftMargin + } +} diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 06b2738c9e..047df2f6d0 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -2257,6 +2257,16 @@ void tst_qqmllanguage::aliasProperties() QQmlComponent component(&engine, testFileUrl("alias.18.qml")); VERIFY_ERRORS("alias.18.errors.txt"); } + + // Binding on deep alias + { + QQmlComponent component(&engine, testFileUrl("alias.19.qml")); + VERIFY_ERRORS(0); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + QCOMPARE(object->property("height").toInt(), 960); + } } // QTBUG-13374 Test that alias properties and signals can coexist |