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