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 | |
27 | QT_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 | |
92 | static const QQuickItemPrivate::ChangeTypes ItemChanges = QQuickItemPrivate::Visibility |
93 | | QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight; |
94 | |
95 | class Q_QUICKTEMPLATES2_EXPORT QQuickApplicationWindowPrivate |
96 | : public QQuickWindowQmlImplPrivate |
97 | , public QQuickItemChangeListener |
98 | { |
99 | Q_DECLARE_PUBLIC(QQuickApplicationWindow) |
100 | |
101 | public: |
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 * = 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 * = nullptr; |
154 | QQuickItem * = nullptr; |
155 | QQuickItem * = 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 | |
164 | static 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 | |
177 | void 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 | |
187 | void 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 | |
215 | void 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 | |
228 | void QQuickApplicationWindowPrivate::itemVisibilityChanged(QQuickItem *item) |
229 | { |
230 | Q_UNUSED(item); |
231 | relayout(); |
232 | } |
233 | |
234 | void QQuickApplicationWindowPrivate::itemImplicitWidthChanged(QQuickItem *item) |
235 | { |
236 | Q_UNUSED(item); |
237 | relayout(); |
238 | } |
239 | |
240 | void QQuickApplicationWindowPrivate::itemImplicitHeightChanged(QQuickItem *item) |
241 | { |
242 | Q_UNUSED(item); |
243 | relayout(); |
244 | } |
245 | |
246 | void 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 *> = q->findChildren<QQuickPopup *>(); |
255 | for (QQuickPopup * : popups) |
256 | QQuickControlPrivate::get(control: static_cast<QQuickControl *>(popup->popupItem()))->inheritFont(font: f); |
257 | |
258 | if (changed) |
259 | emit q->fontChanged(); |
260 | } |
261 | |
262 | void QQuickApplicationWindowPrivate::resolveFont() |
263 | { |
264 | QFont resolvedFont = font.resolve(QQuickTheme::font(scope: QQuickTheme::System)); |
265 | setFont_helper(resolvedFont); |
266 | } |
267 | |
268 | static 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 | |
279 | void QQuickApplicationWindowPrivate::_q_updateActiveFocus() |
280 | { |
281 | Q_Q(QQuickApplicationWindow); |
282 | setActiveFocusControl(findActiveFocusControl(window: q)); |
283 | } |
284 | |
285 | void QQuickApplicationWindowPrivate::setActiveFocusControl(QQuickItem *control) |
286 | { |
287 | Q_Q(QQuickApplicationWindow); |
288 | if (activeFocusControl != control) { |
289 | activeFocusControl = control; |
290 | emit q->activeFocusControlChanged(); |
291 | } |
292 | } |
293 | |
294 | void 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 * = qobject_cast<QQuickPopup *>(object: obj)) |
300 | QQuickPopupPrivate::get(popup)->setWindow(static_cast<QQuickApplicationWindow *>(prop->data)); |
301 | } |
302 | |
303 | void QQuickApplicationWindowPrivate::cancelBackground() |
304 | { |
305 | Q_Q(QQuickApplicationWindow); |
306 | quickCancelDeferred(object: q, property: backgroundName()); |
307 | } |
308 | |
309 | void 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 | |
325 | QQuickApplicationWindow::QQuickApplicationWindow(QWindow *parent) |
326 | : QQuickWindowQmlImpl(*(new QQuickApplicationWindowPrivate), parent) |
327 | { |
328 | connect(sender: this, SIGNAL(activeFocusItemChanged()), receiver: this, SLOT(_q_updateActiveFocus())); |
329 | } |
330 | |
331 | QQuickApplicationWindow::~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 | |
344 | QQuickApplicationWindowAttached *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 | */ |
367 | QQuickItem *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 | |
375 | void 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 | */ |
433 | QQuickItem *QQuickApplicationWindow::() const |
434 | { |
435 | Q_D(const QQuickApplicationWindow); |
436 | return d->header; |
437 | } |
438 | |
439 | void QQuickApplicationWindow::(QQuickItem *) |
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 | */ |
490 | QQuickItem *QQuickApplicationWindow::() const |
491 | { |
492 | Q_D(const QQuickApplicationWindow); |
493 | return d->footer; |
494 | } |
495 | |
496 | void QQuickApplicationWindow::(QQuickItem *) |
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 | */ |
547 | QQmlListProperty<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 | */ |
568 | QQuickItem *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 | */ |
594 | QQuickItem *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 | */ |
616 | QFont QQuickApplicationWindow::font() const |
617 | { |
618 | Q_D(const QQuickApplicationWindow); |
619 | return d->font; |
620 | } |
621 | |
622 | void 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 | |
632 | void 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 | */ |
651 | QLocale QQuickApplicationWindow::locale() const |
652 | { |
653 | Q_D(const QQuickApplicationWindow); |
654 | return d->locale; |
655 | } |
656 | |
657 | void 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 *> = QQuickWindow::contentItem()->findChildren<QQuickPopup *>(); |
668 | for (QQuickPopup * : popups) |
669 | QQuickControlPrivate::get(control: static_cast<QQuickControl *>(popup->popupItem()))->updateLocale(l: locale, e: false); // explicit=false |
670 | |
671 | emit localeChanged(); |
672 | } |
673 | |
674 | void 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 | */ |
697 | QQuickItem *QQuickApplicationWindow::() const |
698 | { |
699 | Q_D(const QQuickApplicationWindow); |
700 | return d->menuBar; |
701 | } |
702 | |
703 | void QQuickApplicationWindow::(QQuickItem *) |
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 | |
726 | bool QQuickApplicationWindow::isComponentComplete() const |
727 | { |
728 | Q_D(const QQuickApplicationWindow); |
729 | return d->componentComplete; |
730 | } |
731 | |
732 | void QQuickApplicationWindow::classBegin() |
733 | { |
734 | Q_D(QQuickApplicationWindow); |
735 | d->componentComplete = false; |
736 | QQuickWindowQmlImpl::classBegin(); |
737 | d->resolveFont(); |
738 | } |
739 | |
740 | void QQuickApplicationWindow::componentComplete() |
741 | { |
742 | Q_D(QQuickApplicationWindow); |
743 | d->componentComplete = true; |
744 | d->executeBackground(complete: true); |
745 | QQuickWindowQmlImpl::componentComplete(); |
746 | d->relayout(); |
747 | } |
748 | |
749 | void QQuickApplicationWindow::resizeEvent(QResizeEvent *event) |
750 | { |
751 | Q_D(QQuickApplicationWindow); |
752 | QQuickWindowQmlImpl::resizeEvent(event); |
753 | d->relayout(); |
754 | } |
755 | |
756 | class QQuickApplicationWindowAttachedPrivate : public QObjectPrivate |
757 | { |
758 | public: |
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 | |
768 | void 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 | |
820 | void 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 | |
835 | QQuickApplicationWindowAttached::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 * = 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 * = 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 | */ |
867 | QQuickApplicationWindow *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 | */ |
882 | QQuickItem *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 | */ |
900 | QQuickItem *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 | */ |
916 | QQuickItem *QQuickApplicationWindowAttached::() 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 | */ |
934 | QQuickItem *QQuickApplicationWindowAttached::() 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 | */ |
953 | QQuickItem *QQuickApplicationWindowAttached::() 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 | |
961 | QT_END_NAMESPACE |
962 | |
963 | #include "moc_qquickapplicationwindow_p.cpp" |
964 | |