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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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