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