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

source code of qtdeclarative/src/quicktemplates/qquickapplicationwindow.cpp