Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickattachedpropertypropagator.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
7
8#include <QtQuick/qquickwindow.h>
9#include <QtQuick/private/qquickitem_p.h>
10
11QT_BEGIN_NAMESPACE
12
13Q_LOGGING_CATEGORY(lcAttachedPropertyPropagator, "qt.quick.private.attachedpropertypropagator")
14
15namespace QtPrivate {
16
17/*!
18 \internal
19
20 This is a copy of the type from Controls. We need it here
21 so that QQuickContextMenuAttached can derive from it.
22
23 ### Qt 7: remove the type in Controls and make this public: QTBUG-138546
24*/
25
30
41
52
53/*!
54 \internal
55
56 This function sets the attached parent of this attached object.
57
58 Currently it is called when:
59 \list
60 \li The target item's parent changes.
61 \li The target item's window changes.
62 \li The attached object is constructed, to set the attached parent
63 and the attached parent of the attached object children.
64 \li The attached object is destructed.
65 \endlist
66*/
86
99
115
117{
121 qCDebug(lcAttachedPropertyPropagator).noquote().nospace() << "parent item of attachee " << item
122 << " changed to " << parent << "; calling findAttachedParent()...";
125 << "... finished handling item parent change of" << item;
126}
127
128/*
129 If there's e.g. code like this:
130
131 Behavior on Material.elevation {}
132
133 The meta type will be something like QQuickMaterialStyle_QML_125,
134 whereas QQmlMetaType::attachedPropertiesFunc only has attached
135 property data for QQuickMaterialStyle (i.e. attached property types
136 created from C++). We work around this by finding the first C++
137 meta object, which works even for attached types created in QML.
138*/
144
145/*!
146 \internal
147
148 Tries to find a QQuickAttachedPropertyPropagator whose type is \a ourAttachedType
149 and is attached to an ancestor of \a attachee.
150
151 QQuickAttachedPropertyPropagator needs to know who its parent attached object is in
152 order to inherit attached property values from it. This is called when an
153 instance of QQuickAttachedPropertyPropagator is created, and whenever
154 \c {attachee}'s parent changes, for example.
155*/
158{
159 qCDebug(lcAttachedPropertyPropagator).noquote() << "findAttachedParent called with"
161
163
164 // A QQmlEngine is the fallback; it can't have an attached parent.
166 return {};
167
169 while (object) {
171 << "- checking for attached parent on object" << object;
172
175 << "- object is a QQuickAttachedPropertyPropagatorTarget; delegating to attachedParent()";
176 // If attachedParent returns nullptr, we assume we should continue the search.
179 << "- target has attached object " << objectAttached << "; returning";
180 return objectAttached;
181 }
182
183 // QQuickPopup::attachedParent already checks the popup's window, so the next step is
184 // to check the engine fallback.
185 object = nullptr;
186 } else if (auto *window = qobject_cast<QQuickWindow *>(object)) {
187 // It doesn't seem like a parent window can be anything but transient in Qt Quick.
190 << "- object is a window; checking its parent window:" << parentWindow;
191 if (parentWindow) {
194 if (attached) {
196 << "- parent window has attached object " << attached << "; returning";
197 return attached;
198 }
199
200 // Try the parent window's parent (TODO: will this actually ever get hit?)
202 } else {
203 qCDebug(lcAttachedPropertyPropagator).noquote() << "- reached root window; ending search";
204 object = nullptr;
205 }
206 } else if (auto *item = qobject_cast<QQuickItem *>(object)) {
208 << "- object is an item; calling attachedPropertyPropagator_parent() on it";
209 // If this returns nullptr, we assume we should continue the search.
211 return objectAttached;
212
214
215 // If we ran out of parent items, try our window. Note that we can't just set object to
216 // item->window() here and let the next loop iteration do the check, because the window
217 // check in the loop checks the window's transient parent, so it would skip the window
218 // itself.
219 if (!object) {
222 if (attached) {
224 << "- parent window has attached object" << attached << "- returning";
225 return attached;
226 }
227
228 // Now try the window's transientParent(), via the next loop iteration.
229 object = item->window();
230 }
231 } else {
232 // We don't know what to do with this.
233 object = nullptr;
234 }
235 } while (object);
236
237 // We found no attached parent: use the engine as a fallback.
240 return fallbackAttached;
241 }
242
243 return {};
244}
245
248{
249 qCDebug(lcAttachedPropertyPropagator).noquote() << "findAttachedChildren called with"
251
253
255 if (!item) {
257 if (window)
259 }
260
261 if (!item) {
262 qCDebug(lcAttachedPropertyPropagator).noquote() << "- object is not an item; returning early";
263 return children;
264 }
265
266 // At this point, "item" could either be an item that the attached object is
267 // attached to directly, or the contentItem of a window that the attached object
268 // is attached to.
269
270 // Look for attached properties on items.
271 const auto childItems = item->childItems();
272 for (QQuickItem *child : childItems) {
275 qCDebug(lcAttachedPropertyPropagator).noquote() << " - checking child" << child;
276 if (attached) {
278 << " has attached object " << attached << "; adding it to the list of children";
280 } else {
282 << "has no attached object; calling findAttachedChildren...";
286 qCDebug(lcAttachedPropertyPropagator).noquote() << " - ... found and added"
287 << attachedChildren.size() << "children of" << child;
288 }
289 }
290
291 // Look for attached properties on windows. Windows declared in QML
292 // as children of a Window are QObject-parented to the contentItem (see
293 // QQuickWindowPrivate::data_append()). Windows declared as children
294 // of items are QObject-parented to those items.
295 const auto &windowChildren = item->children();
296 for (QObject *child : windowChildren) {
298 if (childWindow) {
301 if (attached)
303 }
304 }
305
306 return children;
307}
308
320
326
332
339
345
351
360
361/*!
362 \internal
363
364 Returns the fallback attached object for the given \a attachedType and \a attachee.
365
366 The \l QQmlEngine associated with \a attachee is used as the fallback
367 object. The fallback object is used to ensure that \a attachee has an
368 attached parent if none can be found during \l initialize().
369*/
386
414
421
422#ifndef QT_NO_DEBUG_STREAM
423QDebug operator<<(QDebug debug, const QQuickAttachedPropertyPropagator *propagator)
424{
425 QDebugStateSaver saver(debug);
426 debug.nospace().noquote();
427 if (!propagator) {
428 debug << "QQuickAttachedPropertyPropagator(nullptr)";
429 return debug;
430 }
431
432 // Cast to QObject to avoid recursion.
433 debug << static_cast<const QObject *>(propagator) << " (which is attached to " << propagator->parent() << ')';
434 return debug;
435}
436#endif
437
438} // namespace QtPrivate
439
440QT_END_NAMESPACE
441
442#include "moc_qquickattachedpropertypropagator_p.cpp"
QDebug operator<<(QDebug debug, const QQuickAttachedPropertyPropagator *propagator)