Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickattachedpropertypropagator.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 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
5
6#include <QtCore/qpointer.h>
7#include <QtQuick/qquickwindow.h>
8#include <QtQuick/private/qquickitem_p.h>
9#include <QtQuick/private/qquickitemchangelistener_p.h>
10#include <QtQuickTemplates2/private/qquickpopup_p.h>
11#include <QtQuickTemplates2/private/qquickpopupitem_p_p.h>
12
14
15Q_LOGGING_CATEGORY(lcAttached, "qt.quick.controls.attachedpropertypropagator")
16
17
59{
60 if (!object)
61 return nullptr;
63 return qobject_cast<QQuickAttachedPropertyPropagator *>(qmlAttachedPropertiesObject(object, func, create));
64}
65
77static QQuickAttachedPropertyPropagator *findAttachedParent(const QMetaObject *ourAttachedType, QObject *objectWeAreAttachedTo)
78{
79 qCDebug(lcAttached).noquote() << "findAttachedParent called with" << ourAttachedType->className() << objectWeAreAttachedTo;
80 /*
81 In the Material ComboBox.qml, we have code like this:
82
83 popup: T.Popup {
84 // ...
85 Material.theme: control.Material.theme
86 // ...
87
88 background: Rectangle {
89 //...
90 color: parent.Material.dialogColor
91
92 The Material attached object has to be accessed this way due to
93 deferred execution limitations (see 3e87695fb4b1a5d503c744046e6d9f43a2ae18a6).
94 However, since parent here refers to QQuickPopupItem and not the popup,
95 the color will actually come from the window. If a dark theme was set on
96 the ComboBox, it will not be respected in the background if we don't have
97 the check below.
98 */
99 auto popupItem = qobject_cast<QQuickPopupItem *>(objectWeAreAttachedTo);
100 if (popupItem) {
101 qCDebug(lcAttached).noquote() << "- attachee belongs to popup item" << popupItem << "- checking if it has an attached object";
102 auto popupItemPrivate = QQuickPopupItemPrivate::get(popupItem);
103 QQuickAttachedPropertyPropagator *popupAttached = attachedObject(ourAttachedType, popupItemPrivate->popup);
104 if (popupAttached) {
105 qCDebug(lcAttached).noquote() << "- popup item has attached object" << popupAttached << "- returning";
106 return popupAttached;
107 } else {
108 qCDebug(lcAttached).noquote() << "- popup item does not have attached object";
109 }
110 } else {
111 qCDebug(lcAttached).noquote() << "- attachee does not belong to a popup";
112 }
113
114 QQuickItem *item = qobject_cast<QQuickItem *>(objectWeAreAttachedTo);
115 if (item) {
116 qCDebug(lcAttached).noquote() << "- attachee is an item; checking its parent items and popups";
117 // lookup parent items and popups
118 QQuickItem *parent = item->parentItem();
119 while (parent) {
120 qCDebug(lcAttached).noquote() << " - checking parent item" << parent;
121 QQuickAttachedPropertyPropagator *attached = attachedObject(ourAttachedType, parent);
122 if (attached) {
123 qCDebug(lcAttached).noquote() << " - parent item has attached object" << attached << "- returning";
124 return attached;
125 }
126
127 QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent->parent());
128 if (popup) {
129 qCDebug(lcAttached).noquote() << " - parent popup has attached object" << attached << "- returning";
130 return attachedObject(ourAttachedType, popup);
131 }
132
133 parent = parent->parentItem();
134 }
135
136 // fallback to item's window
137 qCDebug(lcAttached).noquote() << "- checking parent window" << item->window();
138 QQuickAttachedPropertyPropagator *attached = attachedObject(ourAttachedType, item->window());
139 if (attached) {
140 qCDebug(lcAttached).noquote() << "- parent window has attached object" << attached << "- returning";
141 return attached;
142 }
143 } else {
144 // lookup popup's window
145 QQuickPopup *popup = qobject_cast<QQuickPopup *>(objectWeAreAttachedTo);
146 if (popup) {
147 qCDebug(lcAttached).noquote() << "- attachee is a popup; checking its window";
148 return attachedObject(ourAttachedType, popup->popupItem()->window());
149 }
150 }
151
152 // lookup parent window
153 QQuickWindow *window = qobject_cast<QQuickWindow *>(objectWeAreAttachedTo);
154 if (window) {
155 // It doesn't seem like a parent window can be anything but transient in Qt Quick.
156 QQuickWindow *parentWindow = qobject_cast<QQuickWindow *>(window->transientParent());
157 qCDebug(lcAttached).noquote() << "- attachee is a window; checking its parent window" << parentWindow;
158 if (parentWindow) {
159 QQuickAttachedPropertyPropagator *attached = attachedObject(ourAttachedType, parentWindow);
160 if (attached) {
161 qCDebug(lcAttached).noquote() << "- parent window has attached object" << attached << "- returning";
162 return attached;
163 }
164 }
165 }
166
167 // fallback to engine (global)
168 if (objectWeAreAttachedTo) {
169 QQmlEngine *engine = qmlEngine(objectWeAreAttachedTo);
170 qCDebug(lcAttached).noquote() << "- falling back to engine" << engine;
171 if (engine) {
172 QByteArray name = QByteArray("_q_") + ourAttachedType->className();
174 if (!attached) {
175 attached = attachedObject(ourAttachedType, engine, true);
177 }
178 return attached;
179 }
180 }
181
182 return nullptr;
183}
184
185static QList<QQuickAttachedPropertyPropagator *> findAttachedChildren(const QMetaObject *type, QObject *object)
186{
187 QList<QQuickAttachedPropertyPropagator *> children;
188
190 if (!item) {
191 QQuickWindow *window = qobject_cast<QQuickWindow *>(object);
192 if (window)
193 item = window->contentItem();
194 }
195
196 if (!item)
197 return children;
198
199 // At this point, "item" could either be an item that the attached object is
200 // attached to directly, or the contentItem of a window that the attached object
201 // is attached to.
202
203 // Look for attached properties on items.
204 const auto childItems = item->childItems();
205 for (QQuickItem *child : childItems) {
207 if (attached)
208 children += attached;
209 else
210 children += findAttachedChildren(type, child);
211 }
212
213 // Look for attached properties on windows. Windows declared in QML
214 // as children of a Window are QObject-parented to the contentItem (see
215 // QQuickWindowPrivate::data_append()). Windows declared as children
216 // of items are QObject-parented to those items.
217 const auto &windowChildren = item->children();
218 for (QObject *child : windowChildren) {
219 QQuickWindow *childWindow = qobject_cast<QQuickWindow *>(child);
220 if (childWindow) {
221 QQuickAttachedPropertyPropagator *attached = attachedObject(type, childWindow);
222 if (attached)
223 children += attached;
224 }
225 }
226
227 return children;
228}
229
231{
233 if (!item) {
234 QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent);
235 if (popup)
236 item = popup->popupItem();
237 }
238 return item;
239}
240
242{
243public:
244 Q_DECLARE_PUBLIC(QQuickAttachedPropertyPropagator)
245
250
251 void attachTo(QObject *object);
252 void detachFrom(QObject *object);
254
256 void transientParentWindowChanged(QWindow *newTransientParent);
258
259 QList<QQuickAttachedPropertyPropagator *> attachedChildren;
260 QPointer<QQuickAttachedPropertyPropagator> attachedParent;
261};
262
264{
265 if (QQuickItem *item = findAttachedItem(object)) {
267 QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Parent);
268 } else if (auto *window = qobject_cast<QQuickWindow *>(object)) {
269 QObjectPrivate::connect(window, &QWindow::transientParentChanged, this,
271 }
272}
273
275{
276 if (QQuickItem *item = findAttachedItem(object)) {
278 QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Parent);
279 } else if (auto *window = qobject_cast<QQuickWindow *>(object)) {
280 QObjectPrivate::disconnect(window, &QWindow::transientParentChanged,
282 }
283}
284
304{
306 if (attachedParent == parent)
307 return;
308
310 qCDebug(lcAttached).noquote() << "setAttachedParent called on" << q << "with parent" << parent;
311 if (attachedParent) {
312 qCDebug(lcAttached).noquote() << "- removing ourselves as an attached child of" << attachedParent;
314 }
316 if (parent) {
317 qCDebug(lcAttached).noquote() << "- adding ourselves as an attached child of" << parent;
318 QQuickAttachedPropertyPropagatorPrivate::get(parent)->attachedChildren.append(q);
319 }
320 q->attachedParentChange(parent, oldParent);
321}
322
323/*
324 If there's e.g. code like this:
325
326 Behavior on Material.elevation {}
327
328 The meta type will be something like QQuickMaterialStyle_QML_125,
329 whereas QQmlMetaType::attachedPropertiesFunc only has attached
330 property data for QQuickMaterialStyle (i.e. attached property types
331 created from C++). We work around this by finding the first C++
332 meta object, which works even for attached types created in QML.
333*/
335{
336 return QQmlData::ensurePropertyCache(propagator)->firstCppMetaObject();
337}
338
350
352{
355 qCDebug(lcAttached).noquote() << "transient parent window of" << q << "changed to" << newTransientParent;
357 if (!attachedParent)
358 attachedParent = attachedObject(firstCppMetaObject(q), newTransientParent);
360}
361
369
384
389{
391 d->detachFrom(parent());
392 d->setAttachedParent(nullptr);
393}
394
405QList<QQuickAttachedPropertyPropagator *> QQuickAttachedPropertyPropagator::attachedChildren() const
406{
408 return d->attachedChildren;
409}
410
425
443{
445 qCDebug(lcAttached) << "initialize called for" << parent() << "- looking for attached parent...";
447 if (attachedParent)
448 d->setAttachedParent(attachedParent);
449
450 const QList<QQuickAttachedPropertyPropagator *> attachedChildren = findAttachedChildren(metaObject(), parent());
451 qCDebug(lcAttached) << "- found" << attachedChildren.size() << "attached children:";
453 qCDebug(lcAttached) << " -" << child->parent();
454 QQuickAttachedPropertyPropagatorPrivate::get(child)->setAttachedParent(this);
455 }
456
457 qCDebug(lcAttached) << "... finished initializing";
458}
459
477
478#ifndef QT_NO_DEBUG_STREAM
480{
481 QDebugStateSaver saver(debug);
482 debug.nospace().noquote();
483 if (!propagator) {
484 debug << "QQuickAttachedPropertyPropagator(nullptr)";
485 return debug;
486 }
487
488 // Cast to QObject to avoid recursion.
489 debug << static_cast<const QObject *>(propagator) << " (which is attached to " << propagator->parent() << ')';
490 return debug;
491}
492#endif
493
495
496#include "moc_qquickattachedpropertypropagator.cpp"
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
\inmodule QtCore
QList< QGraphicsItem * > childItems() const
QGraphicsWidget * window() const
QGraphicsItem * parentItem() const
Returns a pointer to this item's parent item.
qsizetype size() const noexcept
Definition qlist.h:397
QObject * parent
Definition qobject.h:73
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:299
static bool disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot)
Definition qobject_p.h:328
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object's name property to value.
static QQmlPropertyCache::ConstPtr ensurePropertyCache(QObject *object)
Definition qqmldata_p.h:252
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
QList< QQuickAttachedPropertyPropagator * > attachedChildren
QPointer< QQuickAttachedPropertyPropagator > attachedParent
void transientParentWindowChanged(QWindow *newTransientParent)
static QQuickAttachedPropertyPropagatorPrivate * get(QQuickAttachedPropertyPropagator *attachedObject)
void itemParentChanged(QQuickItem *item, QQuickItem *parent) override
void setAttachedParent(QQuickAttachedPropertyPropagator *parent)
The QQuickAttachedPropertyPropagator class provides a way to propagate attached properties.
QQuickAttachedPropertyPropagator * attachedParent() const
This function returns the attached parent of this attached object.
~QQuickAttachedPropertyPropagator()
Destroys the QQuickAttachedPropertyPropagator.
QQuickAttachedPropertyPropagator(QObject *parent=nullptr)
Constructs a QQuickAttachedPropertyPropagator with the given parent.
QList< QQuickAttachedPropertyPropagator * > attachedChildren() const
This function returns the attached children of this attached object.
void initialize()
Finds and sets the attached parent for this attached object, and then does the same for its children.
virtual void attachedParentChange(QQuickAttachedPropertyPropagator *newParent, QQuickAttachedPropertyPropagator *oldParent)
This function is called whenever the attached parent of this QQuickAttachedPropertyPropagator changes...
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
QQuickWindow * window() const
Returns the window in which this item is rendered.
QQuickItem * parentItem() const
QQuickItem * parent
\qmlproperty Item QtQuick::Item::parent This property holds the visual parent of the item.
Definition qquickitem.h:67
static QQuickPopupItemPrivate * get(QQuickPopupItem *popupItem)
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
T value() const &
Definition qvariant.h:516
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
\inmodule QtGui
Definition qwindow.h:63
Combined button and popup list for selecting options.
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLenum type
GLuint name
GLenum func
Definition qopenglext.h:663
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
QQmlAttachedPropertiesFunc qmlAttachedPropertiesFunction(QObject *object, const QMetaObject *attachedMetaObject)
Definition qqml.cpp:106
QQmlEngine * qmlEngine(const QObject *obj)
Definition qqml.cpp:80
QObject * qmlAttachedPropertiesObject(QObject *object, QQmlAttachedPropertiesFunc func, bool create)
Definition qqml.cpp:114
static QList< QQuickAttachedPropertyPropagator * > findAttachedChildren(const QMetaObject *type, QObject *object)
static QQuickAttachedPropertyPropagator * attachedObject(const QMetaObject *type, QObject *object, bool create=false)
static QQuickItem * findAttachedItem(QObject *parent)
static QQuickAttachedPropertyPropagator * findAttachedParent(const QMetaObject *ourAttachedType, QObject *objectWeAreAttachedTo)
QDebug operator<<(QDebug debug, const QQuickAttachedPropertyPropagator *propagator)
const QMetaObject * firstCppMetaObject(QQuickAttachedPropertyPropagator *propagator)
QQuickItem * qobject_cast< QQuickItem * >(QObject *o)
Definition qquickitem.h:492
#define Q_UNUSED(x)
obj metaObject() -> className()
myObject disconnect()
[26]
QGraphicsItem * item
QLayoutItem * child
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
view create()
QJSEngine engine
[0]
\inmodule QtCore