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
qquickpopupitem.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 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// Qt-Security score:significant reason:default
4
11
12#include <QtQuick/private/qquickattachedpropertypropagator_p.h>
13
14#if QT_CONFIG(accessibility)
15#include <QtQuick/private/qquickaccessibleattached_p.h>
16#endif
17
19
20Q_STATIC_LOGGING_CATEGORY(lcPopupItem, "qt.quick.controls.popupitem")
21
22QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup)
23 : popup(popup)
24{
25 isTabFence = true;
26}
27
28QQuickPopupItemPrivate *QQuickPopupItemPrivate::get(QQuickPopupItem *popupItem)
29{
30 return popupItem->d_func();
31}
32
33void QQuickPopupItemPrivate::implicitWidthChanged()
34{
35 qCDebug(lcPopupItem).nospace() << "implicitWidthChanged called on " << q_func() << "; new implicitWidth is " << implicitWidth;
36 QQuickPagePrivate::implicitWidthChanged();
37 emit popup->implicitWidthChanged();
38}
39
40void QQuickPopupItemPrivate::implicitHeightChanged()
41{
42 qCDebug(lcPopupItem).nospace() << "implicitHeightChanged called on " << q_func() << "; new implicitHeight is " << implicitHeight;
43 QQuickPagePrivate::implicitHeightChanged();
44 emit popup->implicitHeightChanged();
45}
46
47void QQuickPopupItemPrivate::resolveFont()
48{
49 if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(popup->window()))
50 inheritFont(window->font());
51 else
52 inheritFont(QQuickTheme::font(QQuickTheme::System));
53}
54
55QQuickItem *QQuickPopupItemPrivate::getContentItem()
56{
57 Q_Q(QQuickPopupItem);
58 if (QQuickItem *item = QQuickPagePrivate::getContentItem())
59 return item;
60
61 return new QQuickContentItem(popup, q);
62}
63
64static inline QString contentItemName() { return QStringLiteral("contentItem"); }
65
66void QQuickPopupItemPrivate::cancelContentItem()
67{
68 quickCancelDeferred(popup, contentItemName());
69}
70
71void QQuickPopupItemPrivate::executeContentItem(bool complete)
72{
73 if (contentItem.wasExecuted())
74 return;
75
76 if (!contentItem || complete)
77 quickBeginDeferred(popup, contentItemName(), contentItem);
78 if (complete)
79 quickCompleteDeferred(popup, contentItemName(), contentItem);
80}
81
82void QQuickPopupItemPrivate::cancelBackground()
83{
84 quickCancelDeferred(popup, backgroundName());
85}
86
87void QQuickPopupItemPrivate::executeBackground(bool complete)
88{
89 if (background.wasExecuted())
90 return;
91
92 if (!background || complete)
93 quickBeginDeferred(popup, backgroundName(), background);
94 if (complete)
95 quickCompleteDeferred(popup, backgroundName(), background);
96}
97
98QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup)
99 : QQuickPage(*(new QQuickPopupItemPrivate(popup)), nullptr)
100{
101 setParent(popup);
102 setFlag(ItemIsFocusScope);
103 setAcceptedMouseButtons(Qt::AllButtons);
104#if QT_CONFIG(quicktemplates2_multitouch)
105 setAcceptTouchEvents(true);
106#endif
107#if QT_CONFIG(cursor)
108 setCursor(Qt::ArrowCursor);
109#endif
110
111 connect(popup, &QQuickPopup::paletteChanged, this, &QQuickItem::paletteChanged);
112 connect(popup, &QQuickPopup::paletteCreated, this, &QQuickItem::paletteCreated);
113
114#if QT_CONFIG(quicktemplates2_hover)
115 // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8
116 setHoverEnabled(true);
117 // setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects());
118 // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, this, &QQuickItem::setAcceptHoverEvents);
119#endif
120}
121
122QQuickPalette *QQuickPopupItemPrivate::palette() const
123{
124 return QQuickPopupPrivate::get(popup)->palette();
125}
126
127void QQuickPopupItemPrivate::setPalette(QQuickPalette *p)
128{
129 QQuickPopupPrivate::get(popup)->setPalette(p);
130}
131
132void QQuickPopupItemPrivate::resetPalette()
133{
134 QQuickPopupPrivate::get(popup)->resetPalette();
135}
136
137QPalette QQuickPopupItemPrivate::defaultPalette() const
138{
139 return QQuickPopupPrivate::get(popup)->defaultPalette();
140}
141
142bool QQuickPopupItemPrivate::providesPalette() const
143{
144 return QQuickPopupPrivate::get(popup)->providesPalette();
145}
146
147QPalette QQuickPopupItemPrivate::parentPalette(const QPalette &fallbackPalette) const
148{
149 return QQuickPopupPrivate::get(popup)->parentPalette(fallbackPalette);
150}
151
152/*!
153 \internal
154
155 This function is called as part of
156 QQuickAttachedPropertyPropagatorPrivate::findAttachedParent's parent item
157 lookup loop. E.g. if a Label in a Popup has an attached object, the lookup
158 will check the parent item of Label, which is a QQuickPopupItem. If the
159 Popup itself has an attached object, findAttachedParent will call
160 QQuickPopup::attachedParent since it's a
161 QQuickAttachedPropertyPropagatorTarget.
162
163 The reason we need this override:
164
165 In the Material ComboBox.qml, we have code like this:
166
167 \code
168 popup: T.Popup {
169 // ...
170 Material.theme: control.Material.theme
171 // ...
172
173 background: Rectangle {
174 //...
175 color: parent.Material.dialogColor
176 \endcode
177
178 The Material attached object has to be accessed this way due to
179 deferred execution limitations (see 3e87695fb4b1a5d503c744046e6d9f43a2ae18a6).
180 However, since parent here refers to QQuickPopupItem and not the popup,
181 the color will actually come from the window. If a dark theme was set on
182 the ComboBox, it will not be respected in the background if we don't
183 override this function.
184*/
185QtPrivate::QQuickAttachedPropertyPropagator *QQuickPopupItemPrivate::attachedPropertyPropagator_parent(
186 const QMetaObject *attachedType)
187{
188 qCDebug(lcAttachedPropertyPropagator).noquote() << "- attachee is a popup item" << q_func()
189 << "- checking if it has an attached object";
190 QtPrivate::QQuickAttachedPropertyPropagator *popupAttached
191 = QtPrivate::QQuickAttachedPropertyPropagator::attachedObject(attachedType, popup);
192 if (popupAttached) {
193 qCDebug(lcAttachedPropertyPropagator).noquote() << "- popup item has attached object"
194 << popupAttached << "- returning";
195 return popupAttached;
196 }
197
198 qCDebug(lcAttachedPropertyPropagator).noquote() << "- popup item does not have attached object";
199 // From here, findAttachedParent will check our parent item, which is the overlay,
200 // and then the overlay's window.
201 return nullptr;
202}
203
204void QQuickPopupItem::updatePolish()
205{
206 Q_D(QQuickPopupItem);
207 return QQuickPopupPrivate::get(d->popup)->reposition();
208}
209
210bool QQuickPopupItem::childMouseEventFilter(QQuickItem *child, QEvent *event)
211{
212 Q_D(QQuickPopupItem);
213 return d->popup->childMouseEventFilter(child, event);
214}
215
216void QQuickPopupItem::focusInEvent(QFocusEvent *event)
217{
218 Q_D(QQuickPopupItem);
219 d->popup->focusInEvent(event);
220}
221
222void QQuickPopupItem::focusOutEvent(QFocusEvent *event)
223{
224 Q_D(QQuickPopupItem);
225 d->popup->focusOutEvent(event);
226}
227
228void QQuickPopupItem::keyPressEvent(QKeyEvent *event)
229{
230 Q_D(QQuickPopupItem);
231 d->popup->keyPressEvent(event);
232}
233
234void QQuickPopupItem::keyReleaseEvent(QKeyEvent *event)
235{
236 Q_D(QQuickPopupItem);
237 d->popup->keyReleaseEvent(event);
238}
239
240void QQuickPopupItem::mousePressEvent(QMouseEvent *event)
241{
242 Q_D(QQuickPopupItem);
243 d->popup->mousePressEvent(event);
244}
245
246void QQuickPopupItem::mouseMoveEvent(QMouseEvent *event)
247{
248 Q_D(QQuickPopupItem);
249 d->popup->mouseMoveEvent(event);
250}
251
252void QQuickPopupItem::mouseReleaseEvent(QMouseEvent *event)
253{
254 Q_D(QQuickPopupItem);
255 d->popup->mouseReleaseEvent(event);
256}
257
258void QQuickPopupItem::mouseDoubleClickEvent(QMouseEvent *event)
259{
260 Q_D(QQuickPopupItem);
261 d->popup->mouseDoubleClickEvent(event);
262}
263
264void QQuickPopupItem::mouseUngrabEvent()
265{
266 Q_D(QQuickPopupItem);
267 d->popup->mouseUngrabEvent();
268}
269
270#if QT_CONFIG(quicktemplates2_multitouch)
271void QQuickPopupItem::touchEvent(QTouchEvent *event)
272{
273 Q_D(QQuickPopupItem);
274 d->popup->touchEvent(event);
275}
276
277void QQuickPopupItem::touchUngrabEvent()
278{
279 Q_D(QQuickPopupItem);
280 d->popup->touchUngrabEvent();
281}
282#endif
283
284#if QT_CONFIG(wheelevent)
285void QQuickPopupItem::wheelEvent(QWheelEvent *event)
286{
287 Q_D(QQuickPopupItem);
288 d->popup->wheelEvent(event);
289}
290#endif
291
292void QQuickPopupItem::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
293{
294 Q_D(QQuickPopupItem);
295 QQuickPage::contentItemChange(newItem, oldItem);
296 d->popup->contentItemChange(newItem, oldItem);
297}
298
299void QQuickPopupItem::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
300{
301 Q_D(QQuickPopupItem);
302 qCDebug(lcPopupItem) << "contentSizeChange called on" << this << "newSize" << newSize << "oldSize" << oldSize;
303 QQuickPage::contentSizeChange(newSize, oldSize);
304 d->popup->contentSizeChange(newSize, oldSize);
305}
306
307void QQuickPopupItem::fontChange(const QFont &newFont, const QFont &oldFont)
308{
309 Q_D(QQuickPopupItem);
310 QQuickPage::fontChange(newFont, oldFont);
311 d->popup->fontChange(newFont, oldFont);
312}
313
314void QQuickPopupItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
315{
316 Q_D(QQuickPopupItem);
317 qCDebug(lcPopupItem) << "geometryChange called on" << this << "newGeometry" << newGeometry << "oldGeometry" << oldGeometry;
318 QQuickPage::geometryChange(newGeometry, oldGeometry);
319 d->popup->geometryChange(newGeometry, oldGeometry);
320}
321
322void QQuickPopupItem::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
323{
324 Q_D(QQuickPopupItem);
325 QQuickPage::localeChange(newLocale, oldLocale);
326 d->popup->localeChange(newLocale, oldLocale);
327}
328
329void QQuickPopupItem::mirrorChange()
330{
331 Q_D(QQuickPopupItem);
332 emit d->popup->mirroredChanged();
333}
334
335void QQuickPopupItem::itemChange(ItemChange change, const ItemChangeData &data)
336{
337 Q_D(QQuickPopupItem);
338 QQuickPage::itemChange(change, data);
339 d->popup->itemChange(change, data);
340}
341
342void QQuickPopupItem::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
343{
344 Q_D(QQuickPopupItem);
345 QQuickPage::paddingChange(newPadding, oldPadding);
346 d->popup->paddingChange(newPadding, oldPadding);
347}
348
349void QQuickPopupItem::enabledChange()
350{
351 Q_D(QQuickPopupItem);
352 // Just having QQuickPopup connect our QQuickItem::enabledChanged() signal
353 // to its enabledChanged() signal is enough for the enabled property to work,
354 // but we must also ensure that its paletteChanged() signal is emitted
355 // so that bindings to palette are re-evaluated, because QQuickControl::palette()
356 // returns a different palette depending on whether or not the control is enabled.
357 // To save a connection, we also emit enabledChanged here.
358 emit d->popup->enabledChanged();
359}
360
361QFont QQuickPopupItem::defaultFont() const
362{
363 Q_D(const QQuickPopupItem);
364 return d->popup->defaultFont();
365}
366
367#if QT_CONFIG(accessibility)
368QAccessible::Role QQuickPopupItem::accessibleRole() const
369{
370 Q_D(const QQuickPopupItem);
371 return d->popup->effectiveAccessibleRole();
372}
373
374void QQuickPopupItem::accessibilityActiveChanged(bool active)
375{
376 Q_D(const QQuickPopupItem);
377 // Can't just use d->popup->accessibleName() here, because that refers to the accessible
378 // name of us, the popup item, which is not what we want.
379 const QQuickAccessibleAttached *popupAccessibleAttached = QQuickControlPrivate::accessibleAttached(d->popup);
380 const QString oldPopupName = popupAccessibleAttached ? popupAccessibleAttached->name() : QString();
381 const bool wasNameExplicitlySetOnPopup = popupAccessibleAttached && popupAccessibleAttached->wasNameExplicitlySet();
382
383 QQuickPage::accessibilityActiveChanged(active);
384
385 QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(this);
386 const QString ourName = accessibleAttached ? accessibleAttached->name() : QString();
387 if (wasNameExplicitlySetOnPopup && accessibleAttached && ourName != oldPopupName) {
388 // The user set Accessible.name on the Popup. Since the Popup and its popup item
389 // have different accessible attached properties, the popup item doesn't know that
390 // a name was set on the Popup by the user, and that it should use that, rather than
391 // whatever QQuickPage sets. That's why we need to do it here.
392 // To avoid it being overridden by the call to accessibilityActiveChanged() below,
393 // we set it explicitly. It's safe to do this as the popup item is an internal implementation detail.
394 accessibleAttached->setName(oldPopupName);
395 }
396
397 // This allows the different popup types to set a name on their popup item accordingly.
398 // For example: Dialog uses its title and ToolTip uses its text.
399 d->popup->accessibilityActiveChanged(active);
400}
401#endif
402
403QT_END_NAMESPACE
404
405#include "moc_qquickpopupitem_p_p.cpp"
Combined button and popup list for selecting options.
static QString contentItemName()