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 | |
26 | QT_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 | |
91 | static const QQuickItemPrivate::ChangeTypes ItemChanges = QQuickItemPrivate::Visibility |
92 | | QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight; |
93 | |
94 | class Q_QUICKTEMPLATES2_EXPORT QQuickApplicationWindowPrivate |
95 | : public QQuickWindowQmlImplPrivate |
96 | , public QQuickItemChangeListener |
97 | { |
98 | Q_DECLARE_PUBLIC(QQuickApplicationWindow) |
99 | |
100 | public: |
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 | |
163 | static 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 | |
176 | void 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 | |
186 | void 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 | |
214 | void 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 | |
227 | void QQuickApplicationWindowPrivate::itemVisibilityChanged(QQuickItem *item) |
228 | { |
229 | Q_UNUSED(item); |
230 | relayout(); |
231 | } |
232 | |
233 | void QQuickApplicationWindowPrivate::itemImplicitWidthChanged(QQuickItem *item) |
234 | { |
235 | Q_UNUSED(item); |
236 | relayout(); |
237 | } |
238 | |
239 | void QQuickApplicationWindowPrivate::itemImplicitHeightChanged(QQuickItem *item) |
240 | { |
241 | Q_UNUSED(item); |
242 | relayout(); |
243 | } |
244 | |
245 | void 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 | |
261 | void QQuickApplicationWindowPrivate::resolveFont() |
262 | { |
263 | QFont resolvedFont = font.resolve(QQuickTheme::font(scope: QQuickTheme::System)); |
264 | setFont_helper(resolvedFont); |
265 | } |
266 | |
267 | static 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 | |
278 | void QQuickApplicationWindowPrivate::_q_updateActiveFocus() |
279 | { |
280 | Q_Q(QQuickApplicationWindow); |
281 | setActiveFocusControl(findActiveFocusControl(window: q)); |
282 | } |
283 | |
284 | void QQuickApplicationWindowPrivate::setActiveFocusControl(QQuickItem *control) |
285 | { |
286 | Q_Q(QQuickApplicationWindow); |
287 | if (activeFocusControl != control) { |
288 | activeFocusControl = control; |
289 | emit q->activeFocusControlChanged(); |
290 | } |
291 | } |
292 | |
293 | void 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 | |
302 | void QQuickApplicationWindowPrivate::cancelBackground() |
303 | { |
304 | Q_Q(QQuickApplicationWindow); |
305 | quickCancelDeferred(object: q, property: backgroundName()); |
306 | } |
307 | |
308 | void 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 | |
324 | QQuickApplicationWindow::QQuickApplicationWindow(QWindow *parent) |
325 | : QQuickWindowQmlImpl(*(new QQuickApplicationWindowPrivate), parent) |
326 | { |
327 | connect(sender: this, SIGNAL(activeFocusItemChanged()), receiver: this, SLOT(_q_updateActiveFocus())); |
328 | } |
329 | |
330 | QQuickApplicationWindow::~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 | |
343 | QQuickApplicationWindowAttached *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 | */ |
366 | QQuickItem *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 | |
374 | void 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 | */ |
432 | QQuickItem *QQuickApplicationWindow::header() const |
433 | { |
434 | Q_D(const QQuickApplicationWindow); |
435 | return d->header; |
436 | } |
437 | |
438 | void 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 | */ |
489 | QQuickItem *QQuickApplicationWindow::footer() const |
490 | { |
491 | Q_D(const QQuickApplicationWindow); |
492 | return d->footer; |
493 | } |
494 | |
495 | void 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 | */ |
546 | QQmlListProperty<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 | */ |
567 | QQuickItem *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 | */ |
593 | QQuickItem *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 | */ |
615 | QFont QQuickApplicationWindow::font() const |
616 | { |
617 | Q_D(const QQuickApplicationWindow); |
618 | return d->font; |
619 | } |
620 | |
621 | void 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 | |
631 | void 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 | */ |
650 | QLocale QQuickApplicationWindow::locale() const |
651 | { |
652 | Q_D(const QQuickApplicationWindow); |
653 | return d->locale; |
654 | } |
655 | |
656 | void 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 | |
673 | void 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 | */ |
696 | QQuickItem *QQuickApplicationWindow::menuBar() const |
697 | { |
698 | Q_D(const QQuickApplicationWindow); |
699 | return d->menuBar; |
700 | } |
701 | |
702 | void 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 | |
725 | bool QQuickApplicationWindow::isComponentComplete() const |
726 | { |
727 | Q_D(const QQuickApplicationWindow); |
728 | return d->componentComplete; |
729 | } |
730 | |
731 | void QQuickApplicationWindow::classBegin() |
732 | { |
733 | Q_D(QQuickApplicationWindow); |
734 | d->componentComplete = false; |
735 | QQuickWindowQmlImpl::classBegin(); |
736 | d->resolveFont(); |
737 | } |
738 | |
739 | void QQuickApplicationWindow::componentComplete() |
740 | { |
741 | Q_D(QQuickApplicationWindow); |
742 | d->componentComplete = true; |
743 | d->executeBackground(complete: true); |
744 | QQuickWindowQmlImpl::componentComplete(); |
745 | d->relayout(); |
746 | } |
747 | |
748 | void QQuickApplicationWindow::resizeEvent(QResizeEvent *event) |
749 | { |
750 | Q_D(QQuickApplicationWindow); |
751 | QQuickWindowQmlImpl::resizeEvent(event); |
752 | d->relayout(); |
753 | } |
754 | |
755 | class QQuickApplicationWindowAttachedPrivate : public QObjectPrivate |
756 | { |
757 | public: |
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 | |
767 | void 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 | |
819 | void 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 | |
834 | QQuickApplicationWindowAttached::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 | */ |
866 | QQuickApplicationWindow *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 | */ |
881 | QQuickItem *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 | */ |
899 | QQuickItem *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 | */ |
915 | QQuickItem *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 | */ |
933 | QQuickItem *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 | */ |
952 | QQuickItem *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 | |
960 | QT_END_NAMESPACE |
961 | |
962 | #include "moc_qquickapplicationwindow_p.cpp" |
963 |
Definitions
- ItemChanges
- QQuickApplicationWindowPrivate
- get
- windowPalette
- setFont_helper
- defaultPalette
- updateChildrenPalettes
- layoutItem
- updateHasBackgroundFlags
- relayout
- itemGeometryChanged
- itemVisibilityChanged
- itemImplicitWidthChanged
- itemImplicitHeightChanged
- updateFont
- resolveFont
- findActiveFocusControl
- _q_updateActiveFocus
- setActiveFocusControl
- contentData_append
- cancelBackground
- executeBackground
- QQuickApplicationWindow
- ~QQuickApplicationWindow
- qmlAttachedProperties
- background
- setBackground
- header
- setHeader
- footer
- setFooter
- contentData
- contentItem
- activeFocusControl
- font
- setFont
- resetFont
- locale
- setLocale
- resetLocale
- menuBar
- setMenuBar
- isComponentComplete
- classBegin
- componentComplete
- resizeEvent
- QQuickApplicationWindowAttachedPrivate
- windowChange
- activeFocusChange
- QQuickApplicationWindowAttached
- window
- contentItem
- activeFocusControl
- header
- footer
Start learning QML with our Intro Training
Find out more