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
qquickapplicationwindow.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#include <private/qtquicktemplates2-config_p.h>
12#if QT_CONFIG(quicktemplates2_container)
13#include "qquicktabbar_p.h"
14#include "qquickdialogbuttonbox_p.h"
15#endif
18
19#include <QtCore/private/qobject_p.h>
20#include <QtCore/qscopedvaluerollback.h>
21#include <QtQml/private/qqmlpropertytopropertybinding_p.h>
22#include <QtQuick/private/qquickitem_p.h>
23#include <QtQuick/private/qquicksafearea_p.h>
24#include <QtQuick/private/qquickitemchangelistener_p.h>
25#include <QtQuick/private/qquickwindowmodule_p_p.h>
26
28
29using namespace Qt::StringLiterals;
30
31/*!
32 \qmltype ApplicationWindow
33 \inherits Window
34//! \nativetype QQuickApplicationWindow
35 \inqmlmodule QtQuick.Controls
36 \since 5.7
37 \ingroup qtquickcontrols-containers
38 \ingroup qtquickcontrols-focusscopes
39 \brief Styled top-level window with support for a header and footer.
40
41 ApplicationWindow is a \l Window which makes it convenient to add
42 a \l {menuBar}{menu bar}, \l header and \l footer item to the window.
43
44 You can declare ApplicationWindow as the root item of your application,
45 and run it by using \l QQmlApplicationEngine. In this way you can control
46 the window's properties, appearance and layout from QML.
47
48 \image qtquickcontrols-applicationwindow-wireframe.png
49
50 \qml
51 import QtQuick.Controls 2.12
52
53 ApplicationWindow {
54 visible: true
55
56 menuBar: MenuBar {
57 // ...
58 }
59
60 header: ToolBar {
61 // ...
62 }
63
64 footer: TabBar {
65 // ...
66 }
67
68 StackView {
69 anchors.fill: parent
70 }
71 }
72 \endqml
73
74 \note By default, an ApplicationWindow is not visible.
75
76 \section2 Attached ApplicationWindow Properties
77
78 Due to how \l {Scope and Naming Resolution} works in QML, it is possible
79 to reference the \c id of the application root element anywhere in its
80 child QML objects. Even though this approach is fine for many applications
81 and use cases, for a generic QML component it may not be acceptable as it
82 creates a dependency to the surrounding environment.
83
84 ApplicationWindow provides a set of attached properties that can be used
85 to access the window and its building blocks from places where no direct
86 access to the window is available, without creating a dependency to a
87 certain window \c id. A QML component that uses the ApplicationWindow
88 attached properties works in any window regardless of its \c id.
89
90 \section2 Safe Areas
91
92 Since Qt 6.9 ApplicationWindow will automatically add padding to the
93 contentItem for any \l{SafeArea} {safe area margins} reported by the
94 window. This ensures that the contentItem stays inside the safe area
95 of the window, while the background item covers the entire window.
96
97 If you are manually handing safe area margins in the window's contentItem
98 you can override the default via the topPadding, leftPadding, rightPadding
99 and bottomPadding properties:
100
101 \snippet qtquickcontrols-appwindow-safeareas.qml 0
102 \snippet qtquickcontrols-appwindow-safeareas.qml 1
103 \snippet qtquickcontrols-appwindow-safeareas.qml 2
104
105 The \l{header}, \l{footer}, and \l{menuBar} properties do not receive
106 any automatic padding for the safe area margins. However, depending on
107 the style in use, the style may take safe areas into account in its
108 implementation of ToolBar, TabBar, and MenuBar.
109
110 \sa {Customizing ApplicationWindow}, Overlay, Page, {Container Controls},
111 {Focus Management in Qt Quick Controls}
112*/
113
114static const QQuickItemPrivate::ChangeTypes ItemChanges = QQuickItemPrivate::Visibility
115 | QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
116
117static void layoutItem(QQuickItem *item, qreal y, qreal width)
118{
119 if (!item)
120 return;
121
122 item->setY(y);
123 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
124 if (!p->widthValid()) {
125 item->setWidth(width);
126 p->widthValidFlag = false;
127 }
128}
129
130void QQuickApplicationWindowPrivate::updateHasBackgroundFlags()
131{
132 if (!background)
133 return;
134
135 QQuickItemPrivate *backgroundPrivate = QQuickItemPrivate::get(background);
136 hasBackgroundWidth = backgroundPrivate->widthValid();
137 hasBackgroundHeight = backgroundPrivate->heightValid();
138}
139
140void QQuickApplicationWindowPrivate::relayout()
141{
142 Q_Q(QQuickApplicationWindow);
143 if (!componentComplete)
144 return;
145
146 // Note: We track whether we are inside relayout, but we do
147 // allow nested relayouts, as those are necessary to compute
148 // the height and position of footers when using safe areas.
149 QScopedValueRollback<bool> guard(insideRelayout, true);
150
151 // Re-evaluate component heights for each use, as they
152 // may change between each use due to recursive layouts.
153 auto menuBarHeight = [this]{ return menuBar && menuBar->isVisible() ? menuBar->height() : 0; };
154 auto headerheight = [this]{ return header && header->isVisible() ? header->height() : 0; };
155 auto footerHeight = [this]{ return footer && footer->isVisible() ? footer->height() : 0; };
156
157 control->setSize(q->size());
158
159 layoutItem(menuBar, 0, q->width());
160 layoutItem(header, menuBarHeight(), q->width());
161 layoutItem(footer, control->height() - footerHeight(), q->width());
162
163 if (background) {
164 if (!hasBackgroundWidth && qFuzzyIsNull(background->x()))
165 background->setWidth(q->width());
166 if (!hasBackgroundHeight && qFuzzyIsNull(background->y()))
167 background->setHeight(q->height());
168 }
169
170 // Install additional margins on the control, which get reflected
171 // to the content item, but not to the header/footer/menuBar, as
172 // these are siblings of the control
173 auto *controlSafeArea = static_cast<QQuickSafeArea*>(qmlAttachedPropertiesObject<QQuickSafeArea>(control));
174 auto *windowSafeArea = static_cast<QQuickSafeArea*>(qmlAttachedPropertiesObject<QQuickSafeArea>(q));
175 const auto inheritedMargins = windowSafeArea->margins();
176 controlSafeArea->setAdditionalMargins(QMarginsF(
177 0, (menuBarHeight() + headerheight()) - inheritedMargins.top(),
178 0, footerHeight() - inheritedMargins.bottom()));
179}
180
181void QQuickApplicationWindowPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
182{
183 Q_UNUSED(diff);
184
185 if (!insideRelayout && item == background && change.sizeChange()) {
186 // Any time the background is resized (excluding our own resizing),
187 // we should respect it if it's explicit by storing the values of the flags.
188 updateHasBackgroundFlags();
189 }
190
191 relayout();
192}
193
194void QQuickApplicationWindowPrivate::itemVisibilityChanged(QQuickItem *item)
195{
196 Q_UNUSED(item);
197 relayout();
198}
199
200void QQuickApplicationWindowPrivate::itemImplicitWidthChanged(QQuickItem *item)
201{
202 Q_UNUSED(item);
203 relayout();
204}
205
206void QQuickApplicationWindowPrivate::itemImplicitHeightChanged(QQuickItem *item)
207{
208 Q_UNUSED(item);
209 relayout();
210}
211
212void QQuickApplicationWindowPrivate::updateFont(const QFont &f)
213{
214 Q_Q(QQuickApplicationWindow);
215 const bool changed = font != f;
216 font = f;
217
218 QQuickControlPrivate::updateFontRecur(q->QQuickWindow::contentItem(), f);
219
220 const QList<QQuickPopup *> popups = q->findChildren<QQuickPopup *>();
221 for (QQuickPopup *popup : popups)
222 QQuickControlPrivate::get(static_cast<QQuickControl *>(popup->popupItem()))->inheritFont(f);
223
224 if (changed)
225 emit q->fontChanged();
226}
227
228void QQuickApplicationWindowPrivate::resolveFont()
229{
230 QFont resolvedFont = font.resolve(QQuickTheme::font(QQuickTheme::System));
231 setFont_helper(resolvedFont);
232}
233
234static QQuickItem *findActiveFocusControl(QQuickWindow *window)
235{
236 auto *appWindow = qobject_cast<QQuickApplicationWindow *>(window);
237 auto *appWindowPriv = appWindow ? QQuickApplicationWindowPrivate::get(appWindow) : nullptr;
238
239 QQuickItem *item = window->activeFocusItem();
240 while (item) {
241 // The content control is an implementation detail and if
242 // we hit it we've hit the root item, so no controls can exist
243 if (appWindow && item == appWindowPriv->control)
244 return nullptr;
246 return item;
247 item = item->parentItem();
248 }
249 return item;
250}
251
252void QQuickApplicationWindowPrivate::_q_updateActiveFocus()
253{
254 Q_Q(QQuickApplicationWindow);
255 setActiveFocusControl(findActiveFocusControl(q));
256}
257
258void QQuickApplicationWindowPrivate::setActiveFocusControl(QQuickItem *control)
259{
260 Q_Q(QQuickApplicationWindow);
261 if (activeFocusControl != control) {
262 activeFocusControl = control;
263 emit q->activeFocusControlChanged();
264 }
265}
266
267void QQuickApplicationWindowPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
268{
269 QQuickItemPrivate::data_append(prop, obj);
270
271 // associate "top-level" popups with the window as soon as they are added to the default property
272 if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(obj))
273 QQuickPopupPrivate::get(popup)->setWindow(static_cast<QQuickApplicationWindow *>(prop->data));
274}
275
276void QQuickApplicationWindowPrivate::cancelBackground()
277{
278 Q_Q(QQuickApplicationWindow);
279 quickCancelDeferred(q, backgroundName());
280}
281
282void QQuickApplicationWindowPrivate::executeBackground(bool complete)
283{
284 Q_Q(QQuickApplicationWindow);
285 if (background.wasExecuted())
286 return;
287
288 if (!background || complete)
289 quickBeginDeferred(q, backgroundName(), background);
290 if (complete) {
291 quickCompleteDeferred(q, backgroundName(), background);
292 // See comment in setBackground for why we do this here.
293 updateHasBackgroundFlags();
294 relayout();
295 }
296}
297
298QQuickApplicationWindow::QQuickApplicationWindow(QWindow *parent)
299 : QQuickWindowQmlImpl(*(new QQuickApplicationWindowPrivate), parent)
300{
301 connect(this, SIGNAL(activeFocusItemChanged()), this, SLOT(_q_updateActiveFocus()));
302}
303
304QQuickApplicationWindow::~QQuickApplicationWindow()
305{
306 Q_D(QQuickApplicationWindow);
307 d->setActiveFocusControl(nullptr);
308 disconnect(this, SIGNAL(activeFocusItemChanged()), this, SLOT(_q_updateActiveFocus()));
309 if (d->menuBar)
310 QQuickItemPrivate::get(d->menuBar)->removeItemChangeListener(d, ItemChanges);
311 if (d->header)
312 QQuickItemPrivate::get(d->header)->removeItemChangeListener(d, ItemChanges);
313 if (d->footer)
314 QQuickItemPrivate::get(d->footer)->removeItemChangeListener(d, ItemChanges);
315}
316
317QQuickApplicationWindowAttached *QQuickApplicationWindow::qmlAttachedProperties(QObject *object)
318{
319 return new QQuickApplicationWindowAttached(object);
320}
321
322/*!
323 \qmlproperty Item QtQuick.Controls::ApplicationWindow::background
324
325 This property holds the background item.
326
327 The background item is stacked under the \l {contentItem}{content item},
328 but above the \l {Window::color}{background color} of the window.
329
330 The background item is useful for images and gradients, for example,
331 but the \l {Window::}{color} property is preferable for solid colors,
332 as it doesn't need to create an item.
333
334 \note If the background item has no explicit size specified, it automatically
335 follows the control's size. In most cases, there is no need to specify
336 width or height for a background item.
337
338 \sa {Customizing ApplicationWindow}, contentItem, header, footer
339*/
340QQuickItem *QQuickApplicationWindow::background() const
341{
342 QQuickApplicationWindowPrivate *d = const_cast<QQuickApplicationWindowPrivate *>(d_func());
343 if (!d->background)
344 d->executeBackground();
345 return d->background;
346}
347
348void QQuickApplicationWindow::setBackground(QQuickItem *background)
349{
350 Q_D(QQuickApplicationWindow);
351 if (d->background == background)
352 return;
353
354 if (!d->background.isExecuting())
355 d->cancelBackground();
356
357 if (d->background) {
358 d->hasBackgroundWidth = false;
359 d->hasBackgroundHeight = false;
360 }
361 QQuickControlPrivate::hideOldItem(d->background);
362
363 d->background = background;
364
365 if (background) {
366 background->setParentItem(QQuickWindow::contentItem());
367
368 if (qFuzzyIsNull(background->z()))
369 background->setZ(-1);
370
371 // If the background hasn't finished executing then we don't know if its width and height
372 // are valid or not, and so relayout would see that they haven't been set yet and override
373 // any bindings the user might have.
374 if (!d->background.isExecuting()) {
375 d->updateHasBackgroundFlags();
376
377 if (isComponentComplete())
378 d->relayout();
379 }
380 }
381 if (!d->background.isExecuting())
382 emit backgroundChanged();
383}
384
385/*!
386 \qmlproperty Item QtQuick.Controls::ApplicationWindow::header
387
388 This property holds the window header item. The header item is positioned at the
389 top of the window, below the menu bar, and resized to the width of the window.
390 The default value is \c null.
391
392 \code
393 ApplicationWindow {
394 header: TabBar {
395 // ...
396 }
397 }
398 \endcode
399
400 \note Assigning a ToolBar, TabBar, or DialogButtonBox as a window header
401 automatically sets the respective \l ToolBar::position, \l TabBar::position,
402 or \l DialogButtonBox::position property to \c Header.
403
404 \sa menuBar, footer, Page::header
405*/
406QQuickItem *QQuickApplicationWindow::header() const
407{
408 Q_D(const QQuickApplicationWindow);
409 return d->header;
410}
411
412void QQuickApplicationWindow::setHeader(QQuickItem *header)
413{
414 Q_D(QQuickApplicationWindow);
415 if (d->header == header)
416 return;
417
418 if (d->header) {
419 QQuickItemPrivate::get(d->header)->removeItemChangeListener(d, ItemChanges);
420 d->header->setParentItem(nullptr);
421 }
422 d->header = header;
423 if (header) {
424 header->setParentItem(QQuickWindow::contentItem());
425 QQuickItemPrivate *p = QQuickItemPrivate::get(header);
426 p->addItemChangeListener(d, ItemChanges);
427 if (qFuzzyIsNull(header->z()))
428 header->setZ(1);
429 if (QQuickToolBar *toolBar = qobject_cast<QQuickToolBar *>(header))
430 toolBar->setPosition(QQuickToolBar::Header);
431#if QT_CONFIG(quicktemplates2_container)
432 else if (QQuickTabBar *tabBar = qobject_cast<QQuickTabBar *>(header))
433 tabBar->setPosition(QQuickTabBar::Header);
434 else if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(header))
435 buttonBox->setPosition(QQuickDialogButtonBox::Header);
436#endif
437
438 header->stackBefore(d->control);
439 }
440 if (isComponentComplete())
441 d->relayout();
442 emit headerChanged();
443}
444
445/*!
446 \qmlproperty Item QtQuick.Controls::ApplicationWindow::footer
447
448 This property holds the window footer item. The footer item is positioned to
449 the bottom, and resized to the width of the window. The default value is \c null.
450
451 \code
452 ApplicationWindow {
453 footer: ToolBar {
454 // ...
455 }
456 }
457 \endcode
458
459 \note Assigning a ToolBar, TabBar, or DialogButtonBox as a window footer
460 automatically sets the respective \l ToolBar::position, \l TabBar::position,
461 or \l DialogButtonBox::position property to \c Footer.
462
463 \sa menuBar, header, Page::footer
464*/
465QQuickItem *QQuickApplicationWindow::footer() const
466{
467 Q_D(const QQuickApplicationWindow);
468 return d->footer;
469}
470
471void QQuickApplicationWindow::setFooter(QQuickItem *footer)
472{
473 Q_D(QQuickApplicationWindow);
474 if (d->footer == footer)
475 return;
476
477 if (d->footer) {
478 QQuickItemPrivate::get(d->footer)->removeItemChangeListener(d, ItemChanges);
479 d->footer->setParentItem(nullptr);
480 }
481 d->footer = footer;
482 if (footer) {
483 footer->setParentItem(QQuickWindow::contentItem());
484 QQuickItemPrivate *p = QQuickItemPrivate::get(footer);
485 p->addItemChangeListener(d, ItemChanges);
486 if (qFuzzyIsNull(footer->z()))
487 footer->setZ(1);
488 if (QQuickToolBar *toolBar = qobject_cast<QQuickToolBar *>(footer))
489 toolBar->setPosition(QQuickToolBar::Footer);
490#if QT_CONFIG(quicktemplates2_container)
491 else if (QQuickTabBar *tabBar = qobject_cast<QQuickTabBar *>(footer))
492 tabBar->setPosition(QQuickTabBar::Footer);
493 else if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(footer))
494 buttonBox->setPosition(QQuickDialogButtonBox::Footer);
495
496 footer->stackAfter(d->control);
497#endif
498 }
499 if (isComponentComplete())
500 d->relayout();
501 emit footerChanged();
502}
503
504/*!
505 \qmlproperty list<QtObject> QtQuick.Controls::ApplicationWindow::contentData
506 \qmldefault
507
508 This default property holds the list of all objects declared as children of
509 the window.
510
511 The data property allows you to freely mix visual children, resources and
512 other windows in an ApplicationWindow.
513
514 If you assign an Item to the contentData list, it becomes a child of the
515 window's contentItem, so that it appears inside the window. The item's
516 parent will be the window's \l contentItem.
517
518 It should not generally be necessary to refer to the contentData property,
519 as it is the default property for ApplicationWindow and thus all child
520 items are automatically assigned to this property.
521
522 \sa contentItem
523*/
524QQmlListProperty<QObject> QQuickApplicationWindowPrivate::contentData()
525{
526 Q_Q(QQuickApplicationWindow);
527 return QQmlListProperty<QObject>(q->contentItem(), q,
528 QQuickApplicationWindowPrivate::contentData_append,
529 QQuickItemPrivate::data_count,
530 QQuickItemPrivate::data_at,
531 QQuickItemPrivate::data_clear);
532}
533
534/*!
535 \qmlproperty Item QtQuick.Controls::ApplicationWindow::contentItem
536 \readonly
537
538 This property holds the window content item.
539
540 The content item is stacked above the \l background item, and under the
541 \l menuBar, \l header, and \l footer items.
542
543 Since Qt 6.9 ApplicationWindow will automatically add padding to the
544 contentItem for any \l{SafeArea} {safe area margins} reported by the
545 window. To override the padding use the individual padding properties.
546
547 \sa background, menuBar, header, footer,
548 topPadding, bottomPadding, leftPadding, rightPadding
549*/
550QQuickItem *QQuickApplicationWindow::contentItem() const
551{
552 Q_D(const QQuickApplicationWindow);
553 return d->control->contentItem();
554}
555
556/*!
557 \qmlproperty real QtQuick.Controls::ApplicationWindow::topPadding
558 \since 6.9
559
560 This property holds the top padding of the window's content item.
561 Unless explicitly set, the value reflects the window's \l{SafeArea}
562 {safe area margins}.
563
564 \sa bottomPadding, leftPadding, rightPadding
565*/
566
567/*!
568 \qmlproperty real QtQuick.Controls::ApplicationWindow::leftPadding
569 \since 6.9
570
571 This property holds the left padding of the window's content item.
572 Unless explicitly set, the value reflects the window's \l{SafeArea}
573 {safe area margins}.
574
575 \sa bottomPadding, topPadding, rightPadding
576*/
577
578/*!
579 \qmlproperty real QtQuick.Controls::ApplicationWindow::rightPadding
580 \since 6.9
581
582 This property holds the right padding of the window's content item.
583 Unless explicitly set, the value reflects the window's \l{SafeArea}
584 {safe area margins}.
585
586 \sa bottomPadding, leftPadding, topPadding
587*/
588
589/*!
590 \qmlproperty real QtQuick.Controls::ApplicationWindow::bottomPadding
591 \since 6.9
592
593 This property holds the bottom padding of the window's content item.
594 Unless explicitly set, the value reflects the window's \l{SafeArea}
595 {safe area margins}.
596
597 \sa topPadding, leftPadding, rightPadding
598*/
599
600/*!
601 \qmlproperty Control QtQuick.Controls::ApplicationWindow::activeFocusControl
602 \readonly
603
604 This property holds the control that currently has active focus, or \c null if there is
605 no control with active focus.
606
607 The difference between \l Window::activeFocusItem and ApplicationWindow::activeFocusControl
608 is that the former may point to a building block of a control, whereas the latter points
609 to the enclosing control. For example, when SpinBox has focus, activeFocusItem points to
610 the editor and activeFocusControl to the SpinBox itself.
611
612 \sa Window::activeFocusItem
613*/
614QQuickItem *QQuickApplicationWindow::activeFocusControl() const
615{
616 Q_D(const QQuickApplicationWindow);
617 return d->activeFocusControl;
618}
619
620/*!
621 \qmlproperty font QtQuick.Controls::ApplicationWindow::font
622
623 This property holds the font currently set for the window.
624
625 The default font depends on the system environment. QGuiApplication maintains a system/theme
626 font which serves as a default for all application windows. You can also set the default font
627 for windows by passing a custom font to QGuiApplication::setFont(), before loading any QML.
628 Finally, the font is matched against Qt's font database to find the best match.
629
630 ApplicationWindow propagates explicit font properties to child controls. If you change a specific
631 property on the window's font, that property propagates to all child controls in the window,
632 overriding any system defaults for that property.
633
634 \sa Control::font
635*/
636QFont QQuickApplicationWindow::font() const
637{
638 Q_D(const QQuickApplicationWindow);
639 return d->font;
640}
641
642void QQuickApplicationWindow::setFont(const QFont &font)
643{
644 Q_D(QQuickApplicationWindow);
645 if (d->font.resolveMask() == font.resolveMask() && d->font == font)
646 return;
647
648 QFont resolvedFont = font.resolve(QQuickTheme::font(QQuickTheme::System));
649 d->setFont_helper(resolvedFont);
650}
651
652void QQuickApplicationWindow::resetFont()
653{
654 setFont(QFont());
655}
656
657/*!
658 \qmlproperty Locale QtQuick.Controls::ApplicationWindow::locale
659
660 This property holds the locale of the window.
661
662 The default locale depends on the system environment. You can set the
663 default locale by calling QLocale::setDefault(), before loading any QML.
664
665 ApplicationWindow propagates the locale to child controls. If you change
666 the window's locale, that locale propagates to all child controls in the
667 window, overriding the system default locale.
668
669 \sa Control::locale
670*/
671QLocale QQuickApplicationWindow::locale() const
672{
673 Q_D(const QQuickApplicationWindow);
674 return d->locale;
675}
676
677void QQuickApplicationWindow::setLocale(const QLocale &locale)
678{
679 Q_D(QQuickApplicationWindow);
680 if (d->locale == locale)
681 return;
682
683 d->locale = locale;
684 QQuickControlPrivate::updateLocaleRecur(QQuickWindow::contentItem(), locale);
685
686 // TODO: internal QQuickPopupManager that provides reliable access to all QQuickPopup instances
687 const QList<QQuickPopup *> popups = QQuickWindow::contentItem()->findChildren<QQuickPopup *>();
688 for (QQuickPopup *popup : popups)
689 QQuickControlPrivate::get(static_cast<QQuickControl *>(popup->popupItem()))->updateLocale(locale, false); // explicit=false
690
691 emit localeChanged();
692}
693
694void QQuickApplicationWindow::resetLocale()
695{
696 setLocale(QLocale());
697}
698
699/*!
700 \since QtQuick.Controls 2.3 (Qt 5.10)
701 \qmlproperty Item QtQuick.Controls::ApplicationWindow::menuBar
702
703 This property holds the window menu bar. The menu bar is positioned at the
704 top of the window, above the header, and resized to the width of the window.
705 The default value is \c null.
706
707 \code
708 ApplicationWindow {
709 menuBar: MenuBar {
710 // ...
711 }
712 }
713 \endcode
714
715 \sa header, footer, MenuBar
716*/
717QQuickItem *QQuickApplicationWindow::menuBar() const
718{
719 Q_D(const QQuickApplicationWindow);
720 return d->menuBar;
721}
722
723void QQuickApplicationWindow::setMenuBar(QQuickItem *menuBar)
724{
725 Q_D(QQuickApplicationWindow);
726 if (d->menuBar == menuBar)
727 return;
728
729 if (d->menuBar) {
730 QQuickItemPrivate::get(d->menuBar)->removeItemChangeListener(d, ItemChanges);
731 d->menuBar->setParentItem(nullptr);
732 }
733 d->menuBar = menuBar;
734 if (menuBar) {
735 menuBar->setParentItem(QQuickWindow::contentItem());
736 QQuickItemPrivate *p = QQuickItemPrivate::get(menuBar);
737 p->addItemChangeListener(d, ItemChanges);
738 if (qFuzzyIsNull(menuBar->z()))
739 menuBar->setZ(2);
740
741 if (header())
742 menuBar->stackBefore(header());
743 else
744 menuBar->stackBefore(d->control);
745 }
746 if (isComponentComplete())
747 d->relayout();
748 emit menuBarChanged();
749}
750
751bool QQuickApplicationWindow::isComponentComplete() const
752{
753 Q_D(const QQuickApplicationWindow);
754 return d->componentComplete;
755}
756
757void QQuickApplicationWindow::classBegin()
758{
759 Q_D(QQuickApplicationWindow);
760 d->componentComplete = false;
761 QQuickWindowQmlImpl::classBegin();
762 d->resolveFont();
763
764 /*
765 Create the control up front, rather than lazily, as we have
766 to set the default padding before any user-bindings override
767 them.
768
769 The hierarchy is:
770
771 contentItem (QQuickRootItem)
772 ├── menuBar
773 ├── header
774 ├── control (QQuickControl)
775 │ └── control->contentItem() (QQuickContentItem)
776 ├── footer
777 └── background
778 */
779 d->control = new QQuickControl(QQuickWindow::contentItem());
780 d->control->setObjectName("ApplicationWindowContentControl");
781 auto *contentItem = new QQuickContentItem(this, d->control);
782 // The content item can't be its own focus scope here, as that
783 // will detach focus of items inside the content item from focus
784 // in the menubar, header and footer. Nor can set set the content
785 // item as focused, as that will prevent child items of the content
786 // item from getting the initial focus when they are reparented
787 // into the content item.
788 d->control->setContentItem(contentItem);
789
790 auto *context = qmlContext(this);
791 auto installPropertyBinding = [&](QObject *targetObject, const QString &targetPropertyName,
792 QObject *sourceObject, const QString &sourcePropertyName) {
793 const QQmlProperty targetProperty(targetObject, targetPropertyName);
794 QQmlAnyBinding binding = QQmlPropertyToPropertyBinding::create(
795 context->engine(), QQmlProperty(sourceObject, sourcePropertyName), targetProperty);
796 binding.installOn(targetProperty);
797 };
798
799 // Pick up safe area margins from the control, which reflects both
800 // margins coming from the QWindow, additional margins added by the
801 // user to the QQuickWindow's content item, as well the additional
802 // margins we add to the control directly to account for the header,
803 // footer and menu bar.
804 auto *controlSafeArea = qmlAttachedPropertiesObject<QQuickSafeArea>(d->control);
805 installPropertyBinding(this, "leftPadding"_L1, controlSafeArea, "margins.left"_L1);
806 installPropertyBinding(this, "topPadding"_L1, controlSafeArea, "margins.top"_L1);
807 installPropertyBinding(this, "rightPadding"_L1, controlSafeArea, "margins.right"_L1);
808 installPropertyBinding(this, "bottomPadding"_L1, controlSafeArea, "margins.bottom"_L1);
809
810 // The additional margins for our header, footer and menu bar depend on the window margins
811 auto *windowSafeArea = static_cast<QQuickSafeArea*>(qmlAttachedPropertiesObject<QQuickSafeArea>(this));
812 QObject::connect(windowSafeArea, &QQuickSafeArea::marginsChanged, this, [d]{
813 d->relayout();
814 });
815}
816
817void QQuickApplicationWindow::componentComplete()
818{
819 Q_D(QQuickApplicationWindow);
820 d->componentComplete = true;
821 QQuickWindow::contentItem()->setObjectName(QQmlMetaType::prettyTypeName(this));
822 d->executeBackground(true);
823 QQuickWindowQmlImpl::componentComplete();
824 d->relayout();
825}
826
827void QQuickApplicationWindow::resizeEvent(QResizeEvent *event)
828{
829 Q_D(QQuickApplicationWindow);
830 QQuickWindowQmlImpl::resizeEvent(event);
831 d->relayout();
832}
833
835{
836public:
837 Q_DECLARE_PUBLIC(QQuickApplicationWindowAttached)
838
841
844};
845
846void QQuickApplicationWindowAttachedPrivate::windowChange(QQuickWindow *wnd)
847{
848 Q_Q(QQuickApplicationWindowAttached);
849 if (window == wnd)
850 return;
851
852 QQuickApplicationWindow *oldWindow = qobject_cast<QQuickApplicationWindow *>(window);
853 if (oldWindow && !QQuickApplicationWindowPrivate::get(oldWindow))
854 oldWindow = nullptr; // being deleted (QTBUG-52731)
855
856 if (oldWindow) {
857 disconnect(oldWindow, &QQuickApplicationWindow::activeFocusControlChanged,
858 this, &QQuickApplicationWindowAttachedPrivate::activeFocusChange);
859 QObject::disconnect(oldWindow, &QQuickApplicationWindow::menuBarChanged,
860 q, &QQuickApplicationWindowAttached::menuBarChanged);
861 QObject::disconnect(oldWindow, &QQuickApplicationWindow::headerChanged,
862 q, &QQuickApplicationWindowAttached::headerChanged);
863 QObject::disconnect(oldWindow, &QQuickApplicationWindow::footerChanged,
864 q, &QQuickApplicationWindowAttached::footerChanged);
865 } else if (window) {
866 disconnect(window, &QQuickWindow::activeFocusItemChanged,
867 this, &QQuickApplicationWindowAttachedPrivate::activeFocusChange);
868 }
869
870 QQuickApplicationWindow *newWindow = qobject_cast<QQuickApplicationWindow *>(wnd);
871 if (newWindow) {
872 connect(newWindow, &QQuickApplicationWindow::activeFocusControlChanged,
873 this, &QQuickApplicationWindowAttachedPrivate::activeFocusChange);
874 QObject::connect(newWindow, &QQuickApplicationWindow::menuBarChanged,
875 q, &QQuickApplicationWindowAttached::menuBarChanged);
876 QObject::connect(newWindow, &QQuickApplicationWindow::headerChanged,
877 q, &QQuickApplicationWindowAttached::headerChanged);
878 QObject::connect(newWindow, &QQuickApplicationWindow::footerChanged,
879 q, &QQuickApplicationWindowAttached::footerChanged);
880 } else if (wnd) {
881 connect(wnd, &QQuickWindow::activeFocusItemChanged,
882 this, &QQuickApplicationWindowAttachedPrivate::activeFocusChange);
883 }
884
885 window = wnd;
886 emit q->windowChanged();
887 emit q->contentItemChanged();
888
890 if ((oldWindow && oldWindow->menuBar()) || (newWindow && newWindow->menuBar()))
891 emit q->menuBarChanged();
892 if ((oldWindow && oldWindow->header()) || (newWindow && newWindow->header()))
893 emit q->headerChanged();
894 if ((oldWindow && oldWindow->footer()) || (newWindow && newWindow->footer()))
895 emit q->footerChanged();
896}
897
899{
900 Q_Q(QQuickApplicationWindowAttached);
901 QQuickItem *control = nullptr;
902 if (QQuickApplicationWindow *appWindow = qobject_cast<QQuickApplicationWindow *>(window))
903 control = appWindow->activeFocusControl();
904 else if (window)
905 control = findActiveFocusControl(window);
906 if (activeFocusControl == control)
907 return;
908
909 activeFocusControl = control;
910 emit q->activeFocusControlChanged();
911}
912
913QQuickApplicationWindowAttached::QQuickApplicationWindowAttached(QObject *parent)
914 : QObject(*(new QQuickApplicationWindowAttachedPrivate), parent)
915{
916 Q_D(QQuickApplicationWindowAttached);
917 if (QQuickItem *item = qobject_cast<QQuickItem *>(parent)) {
918 d->windowChange(item->window());
919 QObjectPrivate::connect(item, &QQuickItem::windowChanged, d, &QQuickApplicationWindowAttachedPrivate::windowChange);
920 if (!d->window) {
921 QQuickItem *p = item;
922 while (p) {
923 if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(p->parent())) {
924 d->windowChange(popup->window());
925 QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickApplicationWindowAttachedPrivate::windowChange);
926 }
927 p = p->parentItem();
928 }
929 }
930 } else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent)) {
931 d->windowChange(popup->window());
932 QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickApplicationWindowAttachedPrivate::windowChange);
933 }
934}
935
936/*!
937 \qmlattachedproperty ApplicationWindow QtQuick.Controls::ApplicationWindow::window
938 \readonly
939
940 This attached property holds the application window. The property can be attached
941 to any item. The value is \c null if the item is not in an ApplicationWindow.
942
943 \sa {Attached ApplicationWindow Properties}
944*/
945QQuickApplicationWindow *QQuickApplicationWindowAttached::window() const
946{
947 Q_D(const QQuickApplicationWindowAttached);
948 return qobject_cast<QQuickApplicationWindow *>(d->window);
949}
950
951/*!
952 \qmlattachedproperty Item QtQuick.Controls::ApplicationWindow::contentItem
953 \readonly
954
955 This attached property holds the window content item. The property can be attached
956 to any item. The value is \c null if the item is not in an ApplicationWindow.
957
958 \sa {Attached ApplicationWindow Properties}
959*/
960QQuickItem *QQuickApplicationWindowAttached::contentItem() const
961{
962 Q_D(const QQuickApplicationWindowAttached);
963 if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(d->window))
964 return window->contentItem();
965 return nullptr;
966}
967
968/*!
969 \qmlattachedproperty Control QtQuick.Controls::ApplicationWindow::activeFocusControl
970 \readonly
971
972 This attached property holds the control that currently has active focus, or \c null
973 if there is no control with active focus. The property can be attached to any item.
974 The value is \c null if the item is not in a window, or the window has no active focus.
975
976 \sa Window::activeFocusItem, {Attached ApplicationWindow Properties}
977*/
978QQuickItem *QQuickApplicationWindowAttached::activeFocusControl() const
979{
980 Q_D(const QQuickApplicationWindowAttached);
981 return d->activeFocusControl;
982}
983
984/*!
985 \qmlattachedproperty Item QtQuick.Controls::ApplicationWindow::header
986 \readonly
987
988 This attached property holds the window header item. The property can be attached
989 to any item. The value is \c null if the item is not in an ApplicationWindow, or
990 the window has no header item.
991
992 \sa {Attached ApplicationWindow Properties}
993*/
994QQuickItem *QQuickApplicationWindowAttached::header() const
995{
996 Q_D(const QQuickApplicationWindowAttached);
997 if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(d->window))
998 return window->header();
999 return nullptr;
1000}
1001
1002/*!
1003 \qmlattachedproperty Item QtQuick.Controls::ApplicationWindow::footer
1004 \readonly
1005
1006 This attached property holds the window footer item. The property can be attached
1007 to any item. The value is \c null if the item is not in an ApplicationWindow, or
1008 the window has no footer item.
1009
1010 \sa {Attached ApplicationWindow Properties}
1011*/
1012QQuickItem *QQuickApplicationWindowAttached::footer() const
1013{
1014 Q_D(const QQuickApplicationWindowAttached);
1015 if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(d->window))
1016 return window->footer();
1017 return nullptr;
1018}
1019
1020/*!
1021 \since QtQuick.Controls 2.3 (Qt 5.10)
1022 \qmlattachedproperty Item QtQuick.Controls::ApplicationWindow::menuBar
1023 \readonly
1024
1025 This attached property holds the window menu bar. The property can be attached
1026 to any item. The value is \c null if the item is not in an ApplicationWindow, or
1027 the window has no menu bar.
1028
1029 \sa {Attached ApplicationWindow Properties}
1030*/
1031QQuickItem *QQuickApplicationWindowAttached::menuBar() const
1032{
1033 Q_D(const QQuickApplicationWindowAttached);
1034 if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(d->window))
1035 return window->menuBar();
1036 return nullptr;
1037}
1038
1039QT_END_NAMESPACE
1040
1041#include "moc_qquickapplicationwindow_p.cpp"
bool isInteractiveControlType(const QQuickItem *item)
static void layoutItem(QQuickItem *item, qreal y, qreal width)
static const QQuickItemPrivate::ChangeTypes ItemChanges
Styled top-level window with support for a header and footer.
static QQuickItem * findActiveFocusControl(QQuickWindow *window)