1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qquickpopupitem_p_p.h"
38#include "qquickapplicationwindow_p.h"
39#include "qquickshortcutcontext_p_p.h"
40#include "qquickpage_p_p.h"
41#include "qquickcontentitem_p.h"
42#include "qquickpopup_p_p.h"
43#include "qquickdeferredexecute_p_p.h"
44
45#if QT_CONFIG(shortcut)
46# include <QtGui/private/qshortcutmap_p.h>
47#endif
48#include <QtGui/private/qguiapplication_p.h>
49
50#if QT_CONFIG(accessibility)
51#include <QtQuick/private/qquickaccessibleattached_p.h>
52#endif
53
54QT_BEGIN_NAMESPACE
55
56class QQuickPopupItemPrivate : public QQuickPagePrivate
57{
58 Q_DECLARE_PUBLIC(QQuickPopupItem)
59
60public:
61 QQuickPopupItemPrivate(QQuickPopup *popup);
62
63 void implicitWidthChanged() override;
64 void implicitHeightChanged() override;
65
66 void resolveFont() override;
67 void resolvePalette() override;
68
69 QQuickItem *getContentItem() override;
70
71 void cancelContentItem() override;
72 void executeContentItem(bool complete = false) override;
73
74 void cancelBackground() override;
75 void executeBackground(bool complete = false) override;
76
77 int backId = 0;
78 int escapeId = 0;
79 QQuickPopup *popup = nullptr;
80};
81
82QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup)
83 : popup(popup)
84{
85 isTabFence = true;
86}
87
88void QQuickPopupItemPrivate::implicitWidthChanged()
89{
90 QQuickPagePrivate::implicitWidthChanged();
91 emit popup->implicitWidthChanged();
92}
93
94void QQuickPopupItemPrivate::implicitHeightChanged()
95{
96 QQuickPagePrivate::implicitHeightChanged();
97 emit popup->implicitHeightChanged();
98}
99
100void QQuickPopupItemPrivate::resolveFont()
101{
102 if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(object: popup->window()))
103 inheritFont(font: window->font());
104 else
105 inheritFont(font: QQuickTheme::font(scope: QQuickTheme::System));
106}
107
108void QQuickPopupItemPrivate::resolvePalette()
109{
110 if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(object: popup->window()))
111 inheritPalette(palette: window->palette());
112 else
113 inheritPalette(palette: QQuickTheme::palette(scope: QQuickTheme::System));
114}
115
116QQuickItem *QQuickPopupItemPrivate::getContentItem()
117{
118 Q_Q(QQuickPopupItem);
119 if (QQuickItem *item = QQuickPagePrivate::getContentItem())
120 return item;
121
122 return new QQuickContentItem(popup, q);
123}
124
125static inline QString contentItemName() { return QStringLiteral("contentItem"); }
126
127void QQuickPopupItemPrivate::cancelContentItem()
128{
129 quickCancelDeferred(object: popup, property: contentItemName());
130}
131
132void QQuickPopupItemPrivate::executeContentItem(bool complete)
133{
134 if (contentItem.wasExecuted())
135 return;
136
137 if (!contentItem || complete)
138 quickBeginDeferred(object: popup, property: contentItemName(), delegate&: contentItem);
139 if (complete)
140 quickCompleteDeferred(object: popup, property: contentItemName(), delegate&: contentItem);
141}
142
143static inline QString backgroundName() { return QStringLiteral("background"); }
144
145void QQuickPopupItemPrivate::cancelBackground()
146{
147 quickCancelDeferred(object: popup, property: backgroundName());
148}
149
150void QQuickPopupItemPrivate::executeBackground(bool complete)
151{
152 if (background.wasExecuted())
153 return;
154
155 if (!background || complete)
156 quickBeginDeferred(object: popup, property: backgroundName(), delegate&: background);
157 if (complete)
158 quickCompleteDeferred(object: popup, property: backgroundName(), delegate&: background);
159}
160
161QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup)
162 : QQuickPage(*(new QQuickPopupItemPrivate(popup)), nullptr)
163{
164 setParent(popup);
165 setFlag(flag: ItemIsFocusScope);
166 setAcceptedMouseButtons(Qt::AllButtons);
167#if QT_CONFIG(quicktemplates2_multitouch)
168 setAcceptTouchEvents(true);
169#endif
170#if QT_CONFIG(cursor)
171 setCursor(Qt::ArrowCursor);
172#endif
173
174#if QT_CONFIG(quicktemplates2_hover)
175 // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8
176 setHoverEnabled(true);
177 // setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects());
178 // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, this, &QQuickItem::setAcceptHoverEvents);
179#endif
180}
181
182void QQuickPopupItem::grabShortcut()
183{
184#if QT_CONFIG(shortcut)
185 Q_D(QQuickPopupItem);
186 QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance();
187 if (!d->backId)
188 d->backId = pApp->shortcutMap.addShortcut(owner: this, key: Qt::Key_Back, context: Qt::WindowShortcut, matcher: QQuickShortcutContext::matcher);
189 if (!d->escapeId)
190 d->escapeId = pApp->shortcutMap.addShortcut(owner: this, key: Qt::Key_Escape, context: Qt::WindowShortcut, matcher: QQuickShortcutContext::matcher);
191#endif
192}
193
194void QQuickPopupItem::ungrabShortcut()
195{
196#if QT_CONFIG(shortcut)
197 Q_D(QQuickPopupItem);
198 QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance();
199 if (d->backId) {
200 pApp->shortcutMap.removeShortcut(id: d->backId, owner: this);
201 d->backId = 0;
202 }
203 if (d->escapeId) {
204 pApp->shortcutMap.removeShortcut(id: d->escapeId, owner: this);
205 d->escapeId = 0;
206 }
207#endif
208}
209
210void QQuickPopupItem::updatePolish()
211{
212 Q_D(QQuickPopupItem);
213 return QQuickPopupPrivate::get(popup: d->popup)->reposition();
214}
215
216bool QQuickPopupItem::event(QEvent *event)
217{
218#if QT_CONFIG(shortcut)
219 Q_D(QQuickPopupItem);
220 if (event->type() == QEvent::Shortcut) {
221 QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
222 if (se->shortcutId() == d->escapeId || se->shortcutId() == d->backId) {
223 QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup: d->popup);
224 if (p->interactive) {
225 p->closeOrReject();
226 return true;
227 }
228 }
229 }
230#endif
231 return QQuickItem::event(event);
232}
233
234bool QQuickPopupItem::childMouseEventFilter(QQuickItem *child, QEvent *event)
235{
236 Q_D(QQuickPopupItem);
237 return d->popup->childMouseEventFilter(child, event);
238}
239
240void QQuickPopupItem::focusInEvent(QFocusEvent *event)
241{
242 Q_D(QQuickPopupItem);
243 d->popup->focusInEvent(event);
244}
245
246void QQuickPopupItem::focusOutEvent(QFocusEvent *event)
247{
248 Q_D(QQuickPopupItem);
249 d->popup->focusOutEvent(event);
250}
251
252void QQuickPopupItem::keyPressEvent(QKeyEvent *event)
253{
254 Q_D(QQuickPopupItem);
255 d->popup->keyPressEvent(event);
256}
257
258void QQuickPopupItem::keyReleaseEvent(QKeyEvent *event)
259{
260 Q_D(QQuickPopupItem);
261 d->popup->keyReleaseEvent(event);
262}
263
264void QQuickPopupItem::mousePressEvent(QMouseEvent *event)
265{
266 Q_D(QQuickPopupItem);
267 d->popup->mousePressEvent(event);
268}
269
270void QQuickPopupItem::mouseMoveEvent(QMouseEvent *event)
271{
272 Q_D(QQuickPopupItem);
273 d->popup->mouseMoveEvent(event);
274}
275
276void QQuickPopupItem::mouseReleaseEvent(QMouseEvent *event)
277{
278 Q_D(QQuickPopupItem);
279 d->popup->mouseReleaseEvent(event);
280}
281
282void QQuickPopupItem::mouseDoubleClickEvent(QMouseEvent *event)
283{
284 Q_D(QQuickPopupItem);
285 d->popup->mouseDoubleClickEvent(event);
286}
287
288void QQuickPopupItem::mouseUngrabEvent()
289{
290 Q_D(QQuickPopupItem);
291 d->popup->mouseUngrabEvent();
292}
293
294#if QT_CONFIG(quicktemplates2_multitouch)
295void QQuickPopupItem::touchEvent(QTouchEvent *event)
296{
297 Q_D(QQuickPopupItem);
298 d->popup->touchEvent(event);
299}
300
301void QQuickPopupItem::touchUngrabEvent()
302{
303 Q_D(QQuickPopupItem);
304 d->popup->touchUngrabEvent();
305}
306#endif
307
308#if QT_CONFIG(wheelevent)
309void QQuickPopupItem::wheelEvent(QWheelEvent *event)
310{
311 Q_D(QQuickPopupItem);
312 d->popup->wheelEvent(event);
313}
314#endif
315
316void QQuickPopupItem::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
317{
318 Q_D(QQuickPopupItem);
319 QQuickPage::contentItemChange(newItem, oldItem);
320 d->popup->contentItemChange(newItem, oldItem);
321}
322
323void QQuickPopupItem::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
324{
325 Q_D(QQuickPopupItem);
326 QQuickPage::contentSizeChange(newSize, oldSize);
327 d->popup->contentSizeChange(newSize, oldSize);
328}
329
330void QQuickPopupItem::fontChange(const QFont &newFont, const QFont &oldFont)
331{
332 Q_D(QQuickPopupItem);
333 QQuickPage::fontChange(newFont, oldFont);
334 d->popup->fontChange(newFont, oldFont);
335}
336
337void QQuickPopupItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
338{
339 Q_D(QQuickPopupItem);
340 QQuickPage::geometryChanged(newGeometry, oldGeometry);
341 d->popup->geometryChanged(newGeometry, oldGeometry);
342}
343
344void QQuickPopupItem::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
345{
346 Q_D(QQuickPopupItem);
347 QQuickPage::localeChange(newLocale, oldLocale);
348 d->popup->localeChange(newLocale, oldLocale);
349}
350
351void QQuickPopupItem::mirrorChange()
352{
353 Q_D(QQuickPopupItem);
354 emit d->popup->mirroredChanged();
355}
356
357void QQuickPopupItem::itemChange(ItemChange change, const ItemChangeData &data)
358{
359 Q_D(QQuickPopupItem);
360 QQuickPage::itemChange(change, value: data);
361 d->popup->itemChange(change, data);
362}
363
364void QQuickPopupItem::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
365{
366 Q_D(QQuickPopupItem);
367 QQuickPage::paddingChange(newPadding, oldPadding);
368 d->popup->paddingChange(newPadding, oldPadding);
369}
370
371void QQuickPopupItem::paletteChange(const QPalette &newPalette, const QPalette &oldPalette)
372{
373 Q_D(QQuickPopupItem);
374 QQuickPage::paletteChange(newPalette, oldPalette);
375 d->popup->paletteChange(newPalette, oldPalette);
376}
377
378void QQuickPopupItem::enabledChange()
379{
380 Q_D(QQuickPopupItem);
381 // Just having QQuickPopup connect our QQuickItem::enabledChanged() signal
382 // to its enabledChanged() signal is enough for the enabled property to work,
383 // but we must also ensure that its paletteChanged() signal is emitted
384 // so that bindings to palette are re-evaluated, because QQuickControl::palette()
385 // returns a different palette depending on whether or not the control is enabled.
386 // To save a connection, we also emit enabledChanged here.
387 emit d->popup->enabledChanged();
388 emit d->popup->paletteChanged();
389}
390
391QFont QQuickPopupItem::defaultFont() const
392{
393 Q_D(const QQuickPopupItem);
394 return d->popup->defaultFont();
395}
396
397QPalette QQuickPopupItem::defaultPalette() const
398{
399 Q_D(const QQuickPopupItem);
400 return d->popup->defaultPalette();
401}
402
403#if QT_CONFIG(accessibility)
404QAccessible::Role QQuickPopupItem::accessibleRole() const
405{
406 Q_D(const QQuickPopupItem);
407 return d->popup->accessibleRole();
408}
409
410void QQuickPopupItem::accessibilityActiveChanged(bool active)
411{
412 Q_D(const QQuickPopupItem);
413 // Can't just use d->popup->accessibleName() here, because that refers to the accessible
414 // name of us, the popup item, which is not what we want.
415 const QQuickAccessibleAttached *popupAccessibleAttached = QQuickControlPrivate::accessibleAttached(object: d->popup);
416 const QString oldPopupName = popupAccessibleAttached ? popupAccessibleAttached->name() : QString();
417 const bool wasNameExplicitlySetOnPopup = popupAccessibleAttached && popupAccessibleAttached->wasNameExplicitlySet();
418
419 QQuickPage::accessibilityActiveChanged(active);
420
421 QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(object: this);
422 const QString ourName = accessibleAttached ? accessibleAttached->name() : QString();
423 if (wasNameExplicitlySetOnPopup && accessibleAttached && ourName != oldPopupName) {
424 // The user set Accessible.name on the Popup. Since the Popup and its popup item
425 // have different accessible attached properties, the popup item doesn't know that
426 // a name was set on the Popup by the user, and that it should use that, rather than
427 // whatever QQuickPage sets. That's why we need to do it here.
428 // To avoid it being overridden by the call to accessibilityActiveChanged() below,
429 // we set it explicitly. It's safe to do this as the popup item is an internal implementation detail.
430 accessibleAttached->setName(oldPopupName);
431 }
432
433 // This allows the different popup types to set a name on their popup item accordingly.
434 // For example: Dialog uses its title and ToolTip uses its text.
435 d->popup->accessibilityActiveChanged(active);
436}
437#endif
438
439QT_END_NAMESPACE
440

source code of qtquickcontrols2/src/quicktemplates2/qquickpopupitem.cpp