aboutsummaryrefslogtreecommitdiffstats
path: root/src/quickcontrols
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2024-03-08 14:46:35 +0800
committerMitch Curtis <mitch.curtis@qt.io>2024-04-17 18:27:36 +0800
commitc7248004c942b7bcd9dad68148a7c3ab8c712c62 (patch)
treeb153c35d9859d9e49abcebb7a63b9bcec2c69656 /src/quickcontrols
parent967997d93390cbfb0365209e79fc97ee2afbb8c5 (diff)
Fix attached property propagation through ListView with Behavior
If the user had code like this: ApplicationWindow { // ... Material.theme: Material.Dark // ... ListView { // ... header: Text { Behavior on Material.elevation {} The meta type that QQuickAttachedPropertyPropagator saw when looking for the attached parent of the Text item was e.g. QQuickMaterialStyle_QML_125. However, QQmlMetaType::attachedPropertiesFunc only has attached property data for QQuickMaterialStyle (i.e. attached property types created from C++), and so it would never find the attached Material object on the parent window and would fall back to the engine's. Fix it by finding the first C++ meta object, which works even for attached types created in QML. Fixes: QTBUG-122783 Pick-to: 6.5 6.7 Change-Id: Ifd1b887b514ade4f320ace8a033d54cd16dbee1e Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/quickcontrols')
-rw-r--r--src/quickcontrols/qquickattachedpropertypropagator.cpp64
1 files changed, 53 insertions, 11 deletions
diff --git a/src/quickcontrols/qquickattachedpropertypropagator.cpp b/src/quickcontrols/qquickattachedpropertypropagator.cpp
index d7af27663a..6447bf84a4 100644
--- a/src/quickcontrols/qquickattachedpropertypropagator.cpp
+++ b/src/quickcontrols/qquickattachedpropertypropagator.cpp
@@ -73,6 +73,7 @@ static QQuickAttachedPropertyPropagator *attachedObject(const QMetaObject *type,
*/
static QQuickAttachedPropertyPropagator *findAttachedParent(const QMetaObject *ourAttachedType, QObject *objectWeAreAttachedTo)
{
+ qCDebug(lcAttached).noquote() << "findAttachedParent called with" << ourAttachedType->className() << objectWeAreAttachedTo;
/*
In the Material ComboBox.qml, we have code like this:
@@ -94,37 +95,55 @@ static QQuickAttachedPropertyPropagator *findAttachedParent(const QMetaObject *o
*/
auto popupItem = qobject_cast<QQuickPopupItem *>(objectWeAreAttachedTo);
if (popupItem) {
+ qCDebug(lcAttached).noquote() << "- attachee belongs to popup item" << popupItem << "- checking if it has an attached object";
auto popupItemPrivate = QQuickPopupItemPrivate::get(popupItem);
QQuickAttachedPropertyPropagator *popupAttached = attachedObject(ourAttachedType, popupItemPrivate->popup);
- if (popupAttached)
+ if (popupAttached) {
+ qCDebug(lcAttached).noquote() << "- popup item has attached object" << popupAttached << "- returning";
return popupAttached;
+ } else {
+ qCDebug(lcAttached).noquote() << "- popup item does not have attached object";
+ }
+ } else {
+ qCDebug(lcAttached).noquote() << "- attachee does not belong to a popup";
}
QQuickItem *item = qobject_cast<QQuickItem *>(objectWeAreAttachedTo);
if (item) {
+ qCDebug(lcAttached).noquote() << "- attachee is an item; checking its parent items and popups";
// lookup parent items and popups
QQuickItem *parent = item->parentItem();
while (parent) {
+ qCDebug(lcAttached).noquote() << " - checking parent item" << parent;
QQuickAttachedPropertyPropagator *attached = attachedObject(ourAttachedType, parent);
- if (attached)
+ if (attached) {
+ qCDebug(lcAttached).noquote() << " - parent item has attached object" << attached << "- returning";
return attached;
+ }
QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent->parent());
- if (popup)
+ if (popup) {
+ qCDebug(lcAttached).noquote() << " - parent popup has attached object" << attached << "- returning";
return attachedObject(ourAttachedType, popup);
+ }
parent = parent->parentItem();
}
// fallback to item's window
+ qCDebug(lcAttached).noquote() << "- checking parent window" << item->window();
QQuickAttachedPropertyPropagator *attached = attachedObject(ourAttachedType, item->window());
- if (attached)
+ if (attached) {
+ qCDebug(lcAttached).noquote() << "- parent window has attached object" << attached << "- returning";
return attached;
+ }
} else {
// lookup popup's window
QQuickPopup *popup = qobject_cast<QQuickPopup *>(objectWeAreAttachedTo);
- if (popup)
+ if (popup) {
+ qCDebug(lcAttached).noquote() << "- attachee is a popup; checking its window";
return attachedObject(ourAttachedType, popup->popupItem()->window());
+ }
}
// lookup parent window
@@ -132,16 +151,20 @@ static QQuickAttachedPropertyPropagator *findAttachedParent(const QMetaObject *o
if (window) {
// It doesn't seem like a parent window can be anything but transient in Qt Quick.
QQuickWindow *parentWindow = qobject_cast<QQuickWindow *>(window->transientParent());
+ qCDebug(lcAttached).noquote() << "- attachee is a window; checking its parent window" << parentWindow;
if (parentWindow) {
QQuickAttachedPropertyPropagator *attached = attachedObject(ourAttachedType, parentWindow);
- if (attached)
+ if (attached) {
+ qCDebug(lcAttached).noquote() << "- parent window has attached object" << attached << "- returning";
return attached;
+ }
}
}
// fallback to engine (global)
if (objectWeAreAttachedTo) {
QQmlEngine *engine = qmlEngine(objectWeAreAttachedTo);
+ qCDebug(lcAttached).noquote() << "- falling back to engine" << engine;
if (engine) {
QByteArray name = QByteArray("_q_") + ourAttachedType->className();
QQuickAttachedPropertyPropagator *attached = engine->property(name).value<QQuickAttachedPropertyPropagator *>();
@@ -294,14 +317,31 @@ void QQuickAttachedPropertyPropagatorPrivate::setAttachedParent(QQuickAttachedPr
q->attachedParentChange(parent, oldParent);
}
+/*
+ If there's e.g. code like this:
+
+ Behavior on Material.elevation {}
+
+ The meta type will be something like QQuickMaterialStyle_QML_125,
+ whereas QQmlMetaType::attachedPropertiesFunc only has attached
+ property data for QQuickMaterialStyle (i.e. attached property types
+ created from C++). We work around this by finding the first C++
+ meta object, which works even for attached types created in QML.
+*/
+const QMetaObject *firstCppMetaObject(QQuickAttachedPropertyPropagator *propagator)
+{
+ return QQmlData::ensurePropertyCache(propagator)->firstCppMetaObject();
+}
+
void QQuickAttachedPropertyPropagatorPrivate::itemWindowChanged(QQuickWindow *window)
{
Q_Q(QQuickAttachedPropertyPropagator);
QQuickAttachedPropertyPropagator *attachedParent = nullptr;
qCDebug(lcAttached).noquote() << "window of" << q << "changed to" << window;
- attachedParent = findAttachedParent(q->metaObject(), q->parent());
+
+ attachedParent = findAttachedParent(firstCppMetaObject(q), q->parent());
if (!attachedParent)
- attachedParent = attachedObject(q->metaObject(), window);
+ attachedParent = attachedObject(firstCppMetaObject(q), window);
setAttachedParent(attachedParent);
}
@@ -310,9 +350,9 @@ void QQuickAttachedPropertyPropagatorPrivate::transientParentWindowChanged(QWind
Q_Q(QQuickAttachedPropertyPropagator);
QQuickAttachedPropertyPropagator *attachedParent = nullptr;
qCDebug(lcAttached).noquote() << "transient parent window of" << q << "changed to" << newTransientParent;
- attachedParent = findAttachedParent(q->metaObject(), q->parent());
+ attachedParent = findAttachedParent(firstCppMetaObject(q), q->parent());
if (!attachedParent)
- attachedParent = attachedObject(q->metaObject(), newTransientParent);
+ attachedParent = attachedObject(firstCppMetaObject(q), newTransientParent);
setAttachedParent(attachedParent);
}
@@ -321,7 +361,7 @@ void QQuickAttachedPropertyPropagatorPrivate::itemParentChanged(QQuickItem *item
Q_Q(QQuickAttachedPropertyPropagator);
Q_UNUSED(item);
Q_UNUSED(parent);
- setAttachedParent(findAttachedParent(q->metaObject(), q->parent()));
+ setAttachedParent(findAttachedParent(firstCppMetaObject(q), q->parent()));
}
/*!
@@ -410,6 +450,8 @@ void QQuickAttachedPropertyPropagator::initialize()
qCDebug(lcAttached) << " -" << child->parent();
QQuickAttachedPropertyPropagatorPrivate::get(child)->setAttachedParent(this);
}
+
+ qCDebug(lcAttached) << "... finished initializing";
}
/*!