Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
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
4
#
include
"qquickattachedpropertypropagator_p.h"
5
#
include
"qquickattachedpropertypropagator_p_p.h"
6
#
include
"qquickattachedpropertypropagatortarget_p.h"
7
8
#
include
<
QtQuick
/
qquickwindow
.
h
>
9
#
include
<
QtQuick
/
private
/
qquickitem_p
.
h
>
10
11
QT_BEGIN_NAMESPACE
12
13
Q_LOGGING_CATEGORY(lcAttachedPropertyPropagator,
"qt.quick.private.attachedpropertypropagator"
)
14
15
namespace
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
26
void
QQuickAttachedPropertyPropagatorPrivate
::
init
()
27
{
28
attachTo
(
parent
);
29
}
30
31
void
QQuickAttachedPropertyPropagatorPrivate
::
attachTo
(
QObject
*
object
)
32
{
33
if
(
QQuickItem
*
item
=
findAttachedItem
(
object
)) {
34
connect
(
item
, &
QQuickItem
::
windowChanged
,
this
, &
QQuickAttachedPropertyPropagatorPrivate
::
itemWindowChanged
);
35
QQuickItemPrivate
::
get
(
item
)->
addItemChangeListener
(
this
,
QQuickItemPrivate
::
Parent
);
36
}
else
if
(
auto
*
window
=
qobject_cast
<
QQuickWindow
*>(
object
)) {
37
QObjectPrivate
::
connect
(
window
, &
QWindow
::
transientParentChanged
,
this
,
38
&
QQuickAttachedPropertyPropagatorPrivate
::
transientParentWindowChanged
);
39
}
40
}
41
42
void
QQuickAttachedPropertyPropagatorPrivate
::
detachFrom
(
QObject
*
object
)
43
{
44
if
(
QQuickItem
*
item
=
findAttachedItem
(
object
)) {
45
disconnect
(
item
, &
QQuickItem
::
windowChanged
,
this
, &
QQuickAttachedPropertyPropagatorPrivate
::
itemWindowChanged
);
46
QQuickItemPrivate
::
get
(
item
)->
removeItemChangeListener
(
this
,
QQuickItemPrivate
::
Parent
);
47
}
else
if
(
auto
*
window
=
qobject_cast
<
QQuickWindow
*>(
object
)) {
48
QObjectPrivate
::
disconnect
(
window
, &
QWindow
::
transientParentChanged
,
49
this
, &
QQuickAttachedPropertyPropagatorPrivate
::
transientParentWindowChanged
);
50
}
51
}
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
*/
67
void
QQuickAttachedPropertyPropagatorPrivate
::
setAttachedParent
(
QQuickAttachedPropertyPropagator
*
parent
)
68
{
69
Q_Q
(
QQuickAttachedPropertyPropagator
);
70
if
(
attachedParent
==
parent
)
71
return
;
72
73
QQuickAttachedPropertyPropagator
*
oldParent
=
attachedParent
;
74
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
() <<
"setAttachedParent called on"
<<
q
<<
"with parent"
<<
parent
;
75
if
(
attachedParent
) {
76
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
() <<
"- removing ourselves as an attached child of"
<<
attachedParent
;
77
QQuickAttachedPropertyPropagatorPrivate
::
get
(
attachedParent
)->
attachedChildren
.
removeOne
(
q
);
78
}
79
attachedParent
=
parent
;
80
if
(
parent
) {
81
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
() <<
"- adding ourselves as an attached child of"
<<
parent
;
82
QQuickAttachedPropertyPropagatorPrivate
::
get
(
parent
)->
attachedChildren
.
append
(
q
);
83
}
84
q
->
attachedParentChange
(
parent
,
oldParent
);
85
}
86
87
void
QQuickAttachedPropertyPropagatorPrivate
::
itemWindowChanged
(
QQuickWindow
*
window
)
88
{
89
Q_Q
(
QQuickAttachedPropertyPropagator
);
90
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
().
nospace
() <<
"window of "
<<
q
<<
" changed to "
91
<<
window
<<
"..."
;
92
QQuickAttachedPropertyPropagator
*
attachedParent
=
findAttachedParent
(
attacherMetaObject
,
q
->
parent
());
93
if
(!
attachedParent
)
94
attachedParent
=
QQuickAttachedPropertyPropagator
::
attachedObject
(
attacherMetaObject
,
window
);
95
setAttachedParent
(
attachedParent
);
96
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
()
97
<<
"... finished handling parent window change of"
<<
q
;
98
}
99
100
void
QQuickAttachedPropertyPropagatorPrivate
::
transientParentWindowChanged
(
QWindow
*
newTransientParent
)
101
{
102
Q_Q
(
QQuickAttachedPropertyPropagator
);
103
QQuickAttachedPropertyPropagator
*
attachedParent
=
nullptr
;
104
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
().
nospace
() <<
"transient parent window of "
105
<<
q
<<
" changed to "
<<
newTransientParent
<<
"..."
;
106
attachedParent
=
findAttachedParent
(
attacherMetaObject
,
q
->
parent
());
107
if
(!
attachedParent
) {
108
attachedParent
=
QQuickAttachedPropertyPropagator
::
attachedObject
(
109
attacherMetaObject
,
newTransientParent
);
110
}
111
setAttachedParent
(
attachedParent
);
112
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
()
113
<<
"... finished handling transient parent window change of"
<<
q
;
114
}
115
116
void
QQuickAttachedPropertyPropagatorPrivate
::
itemParentChanged
(
QQuickItem
*
item
,
QQuickItem
*
parent
)
117
{
118
Q_Q
(
QQuickAttachedPropertyPropagator
);
119
Q_UNUSED
(
item
)
120
Q_UNUSED
(
parent
)
121
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
().
nospace
() <<
"parent item of attachee "
<<
item
122
<<
" changed to "
<<
parent
<<
"; calling findAttachedParent()..."
;
123
setAttachedParent
(
findAttachedParent
(
attacherMetaObject
,
q
->
parent
()));
124
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
()
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
*/
139
const
QMetaObject
*
QQuickAttachedPropertyPropagatorPrivate
::
firstCppMetaObject
(
140
QQuickAttachedPropertyPropagator
*
propagator
)
141
{
142
return
QQmlData
::
ensurePropertyCache
(
propagator
)->
firstCppMetaObject
();
143
}
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
*/
156
QQuickAttachedPropertyPropagator
*
QQuickAttachedPropertyPropagatorPrivate
::
findAttachedParent
(
157
const
QMetaObject
*
attachedType
,
QObject
*
attachee
)
158
{
159
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
() <<
"findAttachedParent called with"
160
<<
attachedType
->
className
() <<
attachee
;
161
162
Q_ASSERT
(
attachee
);
163
164
// A QQmlEngine is the fallback; it can't have an attached parent.
165
if
(
qobject_cast
<
QQmlEngine
*>(
attachee
))
166
return
{};
167
168
QObject
*
object
=
attachee
;
169
while
(
object
) {
170
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
()
171
<<
"- checking for attached parent on object"
<<
object
;
172
173
if
(
auto
*
attachedTarget
=
qobject_cast
<
QQuickAttachedPropertyPropagatorTarget
*>(
object
)) {
174
qCDebug
(
lcAttachedPropertyPropagator
)
175
<<
"- object is a QQuickAttachedPropertyPropagatorTarget; delegating to attachedParent()"
;
176
// If attachedParent returns nullptr, we assume we should continue the search.
177
if
(
auto
*
objectAttached
=
attachedTarget
->
attachedParent
(
attachedType
)) {
178
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
().
nospace
()
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.
188
QQuickWindow
*
parentWindow
=
qobject_cast
<
QQuickWindow
*>(
window
->
transientParent
());
189
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
()
190
<<
"- object is a window; checking its parent window:"
<<
parentWindow
;
191
if
(
parentWindow
) {
192
QQuickAttachedPropertyPropagator
*
attached
193
=
QQuickAttachedPropertyPropagator
::
attachedObject
(
attachedType
,
parentWindow
);
194
if
(
attached
) {
195
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
().
nospace
()
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?)
201
object
=
parentWindow
->
transientParent
();
202
}
else
{
203
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
() <<
"- reached root window; ending search"
;
204
object
=
nullptr
;
205
}
206
}
else
if
(
auto
*
item
=
qobject_cast
<
QQuickItem
*>(
object
)) {
207
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
()
208
<<
"- object is an item; calling attachedPropertyPropagator_parent() on it"
;
209
// If this returns nullptr, we assume we should continue the search.
210
if
(
auto
*
objectAttached
=
QQuickItemPrivate
::
get
(
item
)->
attachedPropertyPropagator_parent
(
attachedType
))
211
return
objectAttached
;
212
213
object
=
item
->
parentItem
();
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
) {
220
QQuickAttachedPropertyPropagator
*
attached
221
=
QQuickAttachedPropertyPropagator
::
attachedObject
(
attachedType
,
item
->
window
());
222
if
(
attached
) {
223
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
()
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.
238
if
(
auto
*
fallbackAttached
=
QQuickAttachedPropertyPropagator
::
fallbackAttachedObject
(
239
attachedType
,
attachee
)) {
240
return
fallbackAttached
;
241
}
242
243
return
{};
244
}
245
246
QList
<
QQuickAttachedPropertyPropagator
*>
QQuickAttachedPropertyPropagatorPrivate
::
findAttachedChildren
(
247
const
QMetaObject
*
attachedType
,
QObject
*
object
)
248
{
249
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
() <<
"findAttachedChildren called with"
250
<<
attachedType
->
className
() <<
object
;
251
252
QList
<
QQuickAttachedPropertyPropagator
*>
children
;
253
254
QQuickItem
*
item
=
qobject_cast
<
QQuickItem
*>(
object
);
255
if
(!
item
) {
256
QQuickWindow
*
window
=
qobject_cast
<
QQuickWindow
*>(
object
);
257
if
(
window
)
258
item
=
window
->
contentItem
();
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
) {
273
QQuickAttachedPropertyPropagator
*
attached
274
=
QQuickAttachedPropertyPropagator
::
attachedObject
(
attachedType
,
child
);
275
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
() <<
" - checking child"
<<
child
;
276
if
(
attached
) {
277
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
().
nospace
() <<
" - child "
<<
child
278
<<
" has attached object "
<<
attached
<<
"; adding it to the list of children"
;
279
children
+=
attached
;
280
}
else
{
281
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
() <<
" - child"
<<
child
282
<<
"has no attached object; calling findAttachedChildren..."
;
283
const
QList
<
QQuickAttachedPropertyPropagator
*>
attachedChildren
284
=
findAttachedChildren
(
attachedType
,
child
);
285
children
+=
attachedChildren
;
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
) {
297
QQuickWindow
*
childWindow
=
qobject_cast
<
QQuickWindow
*>(
child
);
298
if
(
childWindow
) {
299
QQuickAttachedPropertyPropagator
*
attached
300
=
QQuickAttachedPropertyPropagator
::
attachedObject
(
attachedType
,
childWindow
);
301
if
(
attached
)
302
children
+=
attached
;
303
}
304
}
305
306
return
children
;
307
}
308
309
QQuickItem
*
QQuickAttachedPropertyPropagatorPrivate
::
findAttachedItem
(
QObject
*
object
)
310
{
311
QQuickItem
*
item
=
qobject_cast
<
QQuickItem
*>(
object
);
312
if
(
item
)
313
return
item
;
314
315
if
(
auto
*
attachedTarget
=
qobject_cast
<
QQuickAttachedPropertyPropagatorTarget
*>(
object
))
316
return
attachedTarget
->
attacheeItem
();
317
318
return
{};
319
}
320
321
QQuickAttachedPropertyPropagator
::
QQuickAttachedPropertyPropagator
(
QObject
*
parent
)
322
:
QObject
(*(
new
QQuickAttachedPropertyPropagatorPrivate
),
parent
)
323
{
324
d_func
()->
init
();
325
}
326
327
QQuickAttachedPropertyPropagator
::
QQuickAttachedPropertyPropagator
(
QQuickAttachedPropertyPropagatorPrivate
&
dd
,
QObject
*
parent
)
328
:
QObject
(
dd
,
parent
)
329
{
330
d_func
()->
init
();
331
}
332
333
QQuickAttachedPropertyPropagator
::~
QQuickAttachedPropertyPropagator
()
334
{
335
Q_D
(
QQuickAttachedPropertyPropagator
);
336
d
->
detachFrom
(
parent
());
337
d
->
setAttachedParent
(
nullptr
);
338
}
339
340
QList
<
QQuickAttachedPropertyPropagator
*>
QQuickAttachedPropertyPropagator
::
attachedChildren
()
const
341
{
342
Q_D
(
const
QQuickAttachedPropertyPropagator
);
343
return
d
->
attachedChildren
;
344
}
345
346
QQuickAttachedPropertyPropagator
*
QQuickAttachedPropertyPropagator
::
attachedParent
()
const
347
{
348
Q_D
(
const
QQuickAttachedPropertyPropagator
);
349
return
d
->
attachedParent
;
350
}
351
352
QQuickAttachedPropertyPropagator
*
QQuickAttachedPropertyPropagator
::
attachedObject
(
353
const
QMetaObject
*
attachedType
,
QObject
*
attachee
,
bool
create
)
354
{
355
if
(!
attachee
)
356
return
nullptr
;
357
auto
func
=
qmlAttachedPropertiesFunction
(
attachee
,
attachedType
);
358
return
qobject_cast
<
QQuickAttachedPropertyPropagator
*>(
qmlAttachedPropertiesObject
(
attachee
,
func
,
create
));
359
}
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
*/
370
QQuickAttachedPropertyPropagator
*
QQuickAttachedPropertyPropagator
::
fallbackAttachedObject
(
371
const
QMetaObject
*
attachedType
,
QObject
*
attachee
)
372
{
373
QQmlEngine
*
engine
=
qmlEngine
(
attachee
);
374
qCDebug
(
lcAttachedPropertyPropagator
).
noquote
() <<
"- falling back to engine"
<<
engine
;
375
if
(
engine
) {
376
QByteArray
name
=
QByteArray
(
"_q_"
) +
attachedType
->
className
();
377
auto
*
attached
=
engine
->
property
(
name
).
value
<
QQuickAttachedPropertyPropagator
*>();
378
if
(!
attached
) {
379
attached
=
QQuickAttachedPropertyPropagator
::
attachedObject
(
attachedType
,
engine
,
true
);
380
engine
->
setProperty
(
name
,
QVariant
::
fromValue
(
attached
));
381
}
382
return
attached
;
383
}
384
return
nullptr
;
385
}
386
387
void
QQuickAttachedPropertyPropagator
::
initialize
()
388
{
389
Q_D
(
QQuickAttachedPropertyPropagator
);
390
using
Private
=
QQuickAttachedPropertyPropagatorPrivate
;
391
auto
ownMetaObject
=
Private
::
firstCppMetaObject
(
this
);
392
if
(
auto
type
=
QQmlMetaType
::
firstQmlTypeForAttachmentMetaObject
(
ownMetaObject
);
type
.
isValid
()) {
393
d
->
attacherMetaObject
=
type
.
metaObject
();
394
}
395
396
qCDebug
(
lcAttachedPropertyPropagator
) <<
"initialize called for"
<<
parent
()
397
<<
"- looking for attached parent..."
;
398
QQuickAttachedPropertyPropagator
*
attachedParent
=
Private
::
findAttachedParent
(
d
->
attacherMetaObject
,
parent
());
399
if
(
attachedParent
)
400
d
->
setAttachedParent
(
attachedParent
);
401
402
qCDebug
(
lcAttachedPropertyPropagator
) <<
"- looking for attached children"
;
403
const
QList
<
QQuickAttachedPropertyPropagator
*>
attachedChildren
404
=
Private
::
findAttachedChildren
(
d
->
attacherMetaObject
,
parent
());
405
qCDebug
(
lcAttachedPropertyPropagator
) <<
"- found"
<<
attachedChildren
.
size
()
406
<<
"attached children of"
<<
parent
();
407
for
(
QQuickAttachedPropertyPropagator
*
child
:
attachedChildren
) {
408
qCDebug
(
lcAttachedPropertyPropagator
) <<
" -"
<<
child
->
parent
();
409
QQuickAttachedPropertyPropagatorPrivate
::
get
(
child
)->
setAttachedParent
(
this
);
410
}
411
412
qCDebug
(
lcAttachedPropertyPropagator
) <<
"... finished initializing"
;
413
}
414
415
void
QQuickAttachedPropertyPropagator
::
attachedParentChange
(
416
QQuickAttachedPropertyPropagator
*
newParent
,
QQuickAttachedPropertyPropagator
*
oldParent
)
417
{
418
Q_UNUSED
(
newParent
);
419
Q_UNUSED
(
oldParent
);
420
}
421
422
#
ifndef
QT_NO_DEBUG_STREAM
423
QDebug
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
440
QT_END_NAMESPACE
441
442
#
include
"moc_qquickattachedpropertypropagator_p.cpp"
QtPrivate
Definition
qalloc.h:29
QtPrivate::operator<<
QDebug operator<<(QDebug debug, const QQuickAttachedPropertyPropagator *propagator)
Definition
qquickattachedpropertypropagator.cpp:423
qtdeclarative
src
quick
util
qquickattachedpropertypropagator.cpp
Generated on
for Qt by
1.18.0