Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickdialogbuttonbox.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
10
11#include <QtCore/qpointer.h>
12#include <QtGui/private/qguiapplication_p.h>
13#include <QtGui/qpa/qplatformtheme.h>
14#include <QtQml/qqmlengine.h>
15#include <QtQml/qqmlcontext.h>
16#include <QtQml/qqmlcomponent.h>
17#if QT_CONFIG(accessibility)
18#include <QtQuick/private/qquickaccessibleattached_p.h>
19#endif
20#include <QtQuick/private/qquickitemview_p.h>
21
22#include <algorithm>
23
24QT_BEGIN_NAMESPACE
25
26/*!
27 \qmltype DialogButtonBox
28 \inherits Container
29//! \nativetype QQuickDialogButtonBox
30 \inqmlmodule QtQuick.Controls
31 \ingroup qtquickcontrols-dialogs
32 \brief A button box used in dialogs.
33 \since 5.8
34
35 Dialogs and message boxes typically present buttons in an order that
36 conforms to the interface guidelines for that platform. Invariably,
37 different platforms have their dialog buttons in different orders.
38 DialogButtonBox allows a developer to add buttons to it and will
39 automatically use the appropriate order for the user's platform.
40
41 Most buttons for a dialog follow certain roles. Such roles include:
42
43 \list
44 \li Accepting or rejecting the dialog.
45 \li Asking for help.
46 \li Performing actions on the dialog itself (such as resetting fields or
47 applying changes).
48 \endlist
49
50 There can also be alternate ways of dismissing the dialog which may cause
51 destructive results.
52
53 Most dialogs have buttons that can almost be considered standard (e.g.
54 \uicontrol OK and \uicontrol Cancel buttons). It is sometimes convenient
55 to create these buttons in a standard way.
56
57 There are a couple ways of using DialogButtonBox. One way is to specify
58 the standard buttons (e.g. \uicontrol OK, \uicontrol Cancel, \uicontrol Save)
59 and let the button box setup the buttons.
60
61 \image qtquickcontrols-dialogbuttonbox.png
62 {Dialog button box with OK and Cancel buttons}
63
64 \snippet qtquickcontrols-dialogbuttonbox.qml 1
65
66 Alternatively, buttons and their roles can be specified by hand:
67
68 \snippet qtquickcontrols-dialogbuttonbox-attached.qml 1
69
70 You can also mix and match normal buttons and standard buttons.
71
72 When a button is clicked in the button box, the \l clicked() signal is
73 emitted for the actual button that is pressed. In addition, the
74 following signals are automatically emitted when a button with the
75 respective role(s) is pressed:
76
77 \table
78 \header
79 \li Role
80 \li Signal
81 \row
82 \li \c AcceptRole, \c YesRole
83 \li \l accepted()
84 \row
85 \li \c ApplyRole
86 \li \l applied()
87 \row
88 \li \c DiscardRole
89 \li \l discarded()
90 \row
91 \li \c HelpRole
92 \li \l helpRequested()
93 \row
94 \li \c RejectRole, \c NoRole
95 \li \l rejected()
96 \row
97 \li \c ResetRole
98 \li \l reset()
99 \endtable
100
101 \sa Dialog
102*/
103
104/*!
105 \qmlsignal QtQuick.Controls::DialogButtonBox::accepted()
106
107 This signal is emitted when a button defined with the \c AcceptRole or
108 \c YesRole is clicked.
109
110 \sa rejected(), clicked(), helpRequested()
111*/
112
113/*!
114 \qmlsignal QtQuick.Controls::DialogButtonBox::rejected()
115
116 This signal is emitted when a button defined with the \c RejectRole or
117 \c NoRole is clicked.
118
119 \sa accepted(), helpRequested(), clicked()
120*/
121
122/*!
123 \since QtQuick.Controls 2.3 (Qt 5.10)
124 \qmlsignal QtQuick.Controls::DialogButtonBox::applied()
125
126 This signal is emitted when a button defined with the \c ApplyRole is
127 clicked.
128
129 \sa discarded(), reset()
130*/
131
132/*!
133 \since QtQuick.Controls 2.3 (Qt 5.10)
134 \qmlsignal QtQuick.Controls::DialogButtonBox::reset()
135
136 This signal is emitted when a button defined with the \c ResetRole is
137 clicked.
138
139 \sa discarded(), applied()
140*/
141
142/*!
143 \since QtQuick.Controls 2.3 (Qt 5.10)
144 \qmlsignal QtQuick.Controls::DialogButtonBox::discarded()
145
146 This signal is emitted when a button defined with the \c DiscardRole is
147 clicked.
148
149 \sa reset(), applied()
150*/
151
152/*!
153 \qmlsignal QtQuick.Controls::DialogButtonBox::helpRequested()
154
155 This signal is emitted when a button defined with the \c HelpRole is clicked.
156
157 \sa accepted(), rejected(), clicked()
158*/
159
160/*!
161 \qmlsignal QtQuick.Controls::DialogButtonBox::clicked(AbstractButton button)
162
163 This signal is emitted when a \a button inside the button box is clicked.
164
165 \sa accepted(), rejected(), helpRequested()
166*/
167
168static QPlatformDialogHelper::ButtonLayout platformButtonLayout()
169{
170 return QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::DialogButtonBoxLayout).value<QPlatformDialogHelper::ButtonLayout>();
171}
172
173void QQuickDialogButtonBoxPrivate::itemImplicitWidthChanged(QQuickItem *item)
174{
175 QQuickContainerPrivate::itemImplicitWidthChanged(item);
176 if (item == contentItem)
177 resizeContent();
178 else
179 updateImplicitContentWidth();
180}
181
182void QQuickDialogButtonBoxPrivate::itemImplicitHeightChanged(QQuickItem *item)
183{
184 QQuickContainerPrivate::itemImplicitHeightChanged(item);
185 if (item == contentItem)
186 resizeContent();
187 else
188 updateImplicitContentHeight();
189}
190
191// adapted from QStyle::alignedRect()
192static QRectF alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSizeF &size, const QRectF &rectangle)
193{
194 alignment = QGuiApplicationPrivate::visualAlignment(direction, alignment);
195 qreal x = rectangle.x();
196 qreal y = rectangle.y();
197 qreal w = size.width();
198 qreal h = size.height();
199 // The qMax() calls ensure that the x and y values are never negative, which can happen if the contentWidth is smaller than the width.
200 if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter || (alignment & Qt::AlignVertical_Mask) == 0)
201 y += qMax<qreal>(0, (rectangle.size().height() - h) / 2);
202 else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
203 y += qMax<qreal>(0, rectangle.size().height() - h);
204 if ((alignment & Qt::AlignRight) == Qt::AlignRight)
205 x += qMax<qreal>(0, rectangle.size().width() - w);
206 else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
207 x += qMax<qreal>(0, (rectangle.size().width() - w) / 2);
208 return QRectF(x, y, w, h);
209}
210
211void QQuickDialogButtonBoxPrivate::resizeContent()
212{
213 Q_Q(QQuickDialogButtonBox);
214 if (!contentItem || !contentModel)
215 return;
216
217 QRectF geometry = q->boundingRect().adjusted(q->leftPadding(), q->topPadding(), -q->rightPadding(), -q->bottomPadding());
218 if (alignment != 0)
219 geometry = alignedRect(q->isMirrored() ? Qt::RightToLeft : Qt::LeftToRight, alignment, QSizeF(contentWidth, contentHeight), geometry);
220
221 contentItem->setPosition(geometry.topLeft());
222 contentItem->setSize(geometry.size());
223}
224
225void QQuickDialogButtonBoxPrivate::updateLayout()
226{
227 Q_Q(QQuickDialogButtonBox);
228 const int count = contentModel->count();
229 if (count <= 0)
230 return;
231
232 const int halign = alignment & Qt::AlignHorizontal_Mask;
233 const int valign = alignment & Qt::AlignVertical_Mask;
234
235 QList<QQuickAbstractButton *> buttons;
236 const qreal cw = (alignment & Qt::AlignHorizontal_Mask) == 0 ? q->availableWidth() : contentWidth;
237 const qreal itemWidth = (cw - qMax(0, count - 1) * spacing) / count;
238
239 for (int i = 0; i < count; ++i) {
240 QQuickItem *item = q->itemAt(i);
241 if (item) {
242 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
243 if (!p->widthValid()) {
244 if (!halign)
245 item->setWidth(itemWidth);
246 else
247 item->resetWidth();
248 if (!valign)
249 item->setHeight(contentHeight);
250 else
251 item->resetHeight();
252 p->widthValidFlag = false;
253 }
254 }
255 buttons += static_cast<QQuickAbstractButton *>(item);
256 }
257
258 struct ButtonLayout {
259 ButtonLayout(QPlatformDialogHelper::ButtonLayout layout)
260 : m_layout(QPlatformDialogHelper::buttonLayout(Qt::Horizontal, layout))
261 {
262 }
263
264 bool operator()(QQuickAbstractButton *first, QQuickAbstractButton *second)
265 {
266 const QPlatformDialogHelper::ButtonRole firstRole = QQuickDialogPrivate::buttonRole(first);
267 const QPlatformDialogHelper::ButtonRole secondRole = QQuickDialogPrivate::buttonRole(second);
268
269 if (firstRole != secondRole && firstRole != QPlatformDialogHelper::InvalidRole && secondRole != QPlatformDialogHelper::InvalidRole) {
270 const int *l = m_layout;
271 while (*l != QPlatformDialogHelper::EOL) {
272 // Unset the Reverse flag.
273 const int role = (*l & ~QPlatformDialogHelper::Reverse);
274 if (role == firstRole)
275 return true;
276 if (role == secondRole)
277 return false;
278 ++l;
279 }
280 }
281
282 if (firstRole == secondRole)
283 return false;
284
285 return firstRole != QPlatformDialogHelper::InvalidRole;
286 }
287 const int *m_layout;
288 };
289
290 std::stable_sort(buttons.begin(), buttons.end(), ButtonLayout(static_cast<QPlatformDialogHelper::ButtonLayout>(buttonLayout)));
291
292 for (int i = 0; i < buttons.size() - 1; ++i)
293 q->insertItem(i, buttons.at(i));
294}
295
296void QQuickDialogButtonBoxPrivate::updateFocus()
297{
298 Q_Q(QQuickDialogButtonBox);
299 const int count = contentModel->count();
300 if (count <= 0)
301 return;
302
303 // Give focus to the first default button
304 int indexOfFocusButton = -1;
305 QQuickButton *buttonToHighlight = nullptr;
306 for (int i = 0; i < count; ++i) {
307 QQuickItem *item = q->itemAt(i);
308 if (auto *button = qobject_cast<QQuickButton *>(item)) {
309 const auto stdButton = standardButton(button);
310 const bool isDefaultStdbutton = defaultStandardButton != QPlatformDialogHelper::NoButton && stdButton == defaultStandardButton;
311 const bool isDefaultButton = defaultButton == button;
312 if (isDefaultButton || isDefaultStdbutton) {
313 buttonToHighlight = button;
314 indexOfFocusButton = i;
315 break;
316 }
317 }
318 }
319 // Give focus to the first button with the accept role, if there are no default buttons
320 if (indexOfFocusButton < 0) {
321 for (int i = 0; i < count; ++i) {
322 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->itemAt(i));
323 if (button && QQuickDialogPrivate::buttonRole(button) == QPlatformDialogHelper::ButtonRole::AcceptRole) {
324 indexOfFocusButton = i;
325 break;
326 }
327 }
328 }
329
330 if (QQuickItemView *itemView = qobject_cast<QQuickItemView *>(contentItem)) {
331 // QQuickItemView has the ItemIsFocusScope flag, and also calls setFocus(true) for the first delegate item it creates
332 // In order for the default button to have active focus, we call setFocus(true) for both the item view, and the default button.
333 itemView->setCurrentIndex(indexOfFocusButton);
334 itemView->setFocus(indexOfFocusButton >= 0);
335 }
336
337 for (int i = 0; i < count; ++i) {
338 if (auto *button = qobject_cast<QQuickButton *>(contentModel->get(i))) {
339 button->setFocus(i == indexOfFocusButton);
340 button->setHighlighted(button == buttonToHighlight);
341#if QT_CONFIG(accessibility)
342 if (auto *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(button, true)))
343 accessibleAttached->set_defaultButton(button == buttonToHighlight);
344#endif
345 }
346 }
347}
348
349qreal QQuickDialogButtonBoxPrivate::getContentWidth() const
350{
351 Q_Q(const QQuickDialogButtonBox);
352 if (!contentModel)
353 return 0;
354
355 const int count = contentModel->count();
356 const qreal totalSpacing = qMax(0, count - 1) * spacing;
357 qreal totalWidth = totalSpacing;
358 qreal maxWidth = 0;
359 for (int i = 0; i < count; ++i) {
360 QQuickItem *item = q->itemAt(i);
361 if (item) {
362 totalWidth += item->implicitWidth();
363 maxWidth = qMax(maxWidth, item->implicitWidth());
364 }
365 }
366 if ((alignment & Qt::AlignHorizontal_Mask) == 0)
367 totalWidth = qMax(totalWidth, count * maxWidth + totalSpacing);
368 return totalWidth;
369}
370
371qreal QQuickDialogButtonBoxPrivate::getContentHeight() const
372{
373 Q_Q(const QQuickDialogButtonBox);
374 if (!contentModel)
375 return 0;
376
377 const int count = contentModel->count();
378 qreal maxHeight = 0;
379 for (int i = 0; i < count; ++i) {
380 QQuickItem *item = q->itemAt(i);
381 if (item)
382 maxHeight = qMax(maxHeight, item->implicitHeight());
383 }
384 return maxHeight;
385}
386
387void QQuickDialogButtonBoxPrivate::handleClick()
388{
389 Q_Q(QQuickDialogButtonBox);
390 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->sender());
391 if (!button)
392 return;
393
394 // Can't fetch this *after* emitting clicked, as clicked may destroy the button
395 // or change its role. Now changing the role is not possible yet, but arguably
396 // both clicked and accepted/rejected/etc. should be emitted "atomically"
397 // depending on whatever role the button had at the time of the click.
398 const QPlatformDialogHelper::ButtonRole role = QQuickDialogPrivate::buttonRole(button);
399 QPointer<QQuickDialogButtonBox> guard(q);
400
401 emit q->clicked(button);
402
403 if (!guard)
404 return;
405
406 switch (role) {
407 case QPlatformDialogHelper::AcceptRole:
408 case QPlatformDialogHelper::YesRole:
409 emit q->accepted();
410 break;
411 case QPlatformDialogHelper::RejectRole:
412 case QPlatformDialogHelper::NoRole:
413 emit q->rejected();
414 break;
415 case QPlatformDialogHelper::ApplyRole:
416 emit q->applied();
417 break;
418 case QPlatformDialogHelper::ResetRole:
419 emit q->reset();
420 break;
421 case QPlatformDialogHelper::DestructiveRole:
422 emit q->discarded();
423 break;
424 case QPlatformDialogHelper::HelpRole:
425 emit q->helpRequested();
426 break;
427 default:
428 break;
429 }
430}
431
432QString QQuickDialogButtonBoxPrivate::buttonText(QPlatformDialogHelper::StandardButton standardButton)
433{
434 return QPlatformTheme::removeMnemonics(QGuiApplicationPrivate::platformTheme()->standardButtonText(standardButton));
435}
436
437QQuickAbstractButton *QQuickDialogButtonBoxPrivate::createStandardButton(QPlatformDialogHelper::StandardButton standardButton)
438{
439 Q_Q(QQuickDialogButtonBox);
440 if (!delegate)
441 return nullptr;
442
443 QQmlContext *creationContext = delegate->creationContext();
444 if (!creationContext)
445 creationContext = qmlContext(q);
446
447 QObject *object = delegate->beginCreate(creationContext);
448 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton*>(object);
449 if (button) {
450 QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(button, true));
451 QQuickDialogButtonBoxAttachedPrivate::get(attached)->standardButton = standardButton;
452 attached->setButtonRole(QPlatformDialogHelper::buttonRole(standardButton));
453 button->setText(buttonText(standardButton));
454 delegate->completeCreate();
455 button->setParent(q);
456 return button;
457 }
458
459 delete object;
460 return nullptr;
461}
462
463void QQuickDialogButtonBoxPrivate::removeStandardButtons()
464{
465 Q_Q(QQuickDialogButtonBox);
466 int i = q->count() - 1;
467 while (i >= 0) {
468 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->itemAt(i));
469 if (button) {
470 QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(
471 qmlAttachedPropertiesObject<QQuickDialogButtonBox>(button, false));
472 if (attached) {
473 QQuickDialogButtonBoxAttachedPrivate *p = QQuickDialogButtonBoxAttachedPrivate::get(attached);
474 if (p->standardButton != QPlatformDialogHelper::NoButton) {
475 q->removeItem(button);
476 button->deleteLater();
477 }
478 }
479 }
480 --i;
481 }
482}
483
484void QQuickDialogButtonBoxPrivate::updateLanguage()
485{
486 Q_Q(QQuickDialogButtonBox);
487 int i = q->count() - 1;
488 while (i >= 0) {
489 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(itemAt(i));
490 if (button) {
491 QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(
492 qmlAttachedPropertiesObject<QQuickDialogButtonBox>(button, true));
493 const auto boxAttachedPrivate = QQuickDialogButtonBoxAttachedPrivate::get(attached);
494 const QPlatformDialogHelper::StandardButton standardButton = boxAttachedPrivate->standardButton;
495 // The button might be a custom one with explicitly specified text, so we shouldn't change it in that case.
496 if (standardButton != QPlatformDialogHelper::NoButton) {
497 button->setText(buttonText(standardButton));
498 }
499 }
500 --i;
501 }
502}
503
504QPlatformDialogHelper::StandardButton QQuickDialogButtonBoxPrivate::standardButton(QQuickAbstractButton *button) const {
505 QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(button, false));
506 if (attached)
507 return QQuickDialogButtonBoxAttachedPrivate::get(attached)->standardButton;
508 else
509 return QPlatformDialogHelper::NoButton;
510}
511
512QQuickDialogButtonBox::QQuickDialogButtonBox(QQuickItem *parent)
513 : QQuickContainer(*(new QQuickDialogButtonBoxPrivate), parent)
514{
515 Q_D(QQuickDialogButtonBox);
516 setFlag(ItemIsFocusScope);
517 d->changeTypes |= QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
518 d->buttonLayout = platformButtonLayout();
519 d->setSizePolicy(QLayoutPolicy::Preferred, QLayoutPolicy::Fixed);
520}
521
522QQuickDialogButtonBox::~QQuickDialogButtonBox()
523{
524 Q_D(QQuickDialogButtonBox);
525 // QQuickContainerPrivate does call this, but as our type information has already been
526 // destroyed by that point (since this destructor has already run), it won't call our
527 // implementation. So, we need to make sure our implementation is called. If we don't do this,
528 // the listener we installed on the contentItem won't get removed, possibly resulting in
529 // heap-use-after-frees.
530 contentItemChange(nullptr, d->contentItem);
531}
532
533/*!
534 \qmlproperty enumeration QtQuick.Controls::DialogButtonBox::position
535
536 This property holds the position of the button box.
537
538 \note If the button box is assigned as a header or footer of ApplicationWindow
539 or Page, the appropriate position is set automatically.
540
541 Possible values:
542 \value DialogButtonBox.Header The button box is at the top, as a window or page header.
543 \value DialogButtonBox.Footer The button box is at the bottom, as a window or page footer.
544
545 The default value is \c Footer.
546
547 \sa Dialog::header, Dialog::footer
548*/
549QQuickDialogButtonBox::Position QQuickDialogButtonBox::position() const
550{
551 Q_D(const QQuickDialogButtonBox);
552 return d->position;
553}
554
555void QQuickDialogButtonBox::setPosition(Position position)
556{
557 Q_D(QQuickDialogButtonBox);
558 if (d->position == position)
559 return;
560
561 d->position = position;
562 emit positionChanged();
563}
564
565/*!
566 \qmlproperty flags QtQuick.Controls::DialogButtonBox::alignment
567
568 This property holds the alignment of the buttons.
569
570 Possible values:
571 \value Qt.AlignLeft The buttons are aligned to the left.
572 \value Qt.AlignHCenter The buttons are horizontally centered.
573 \value Qt.AlignRight The buttons are aligned to the right.
574 \value Qt.AlignTop The buttons are aligned to the top.
575 \value Qt.AlignVCenter The buttons are vertically centered.
576 \value Qt.AlignBottom The buttons are aligned to the bottom.
577
578 By default, no specific alignment is set; reading the alignment property yields
579 a default flag value which compares equal to 0. The property can be reset to this
580 value by assigning \c{undefined} to it. In this case, the buttons are resized to
581 fill the available space.
582
583 \note This property assumes a horizontal layout of the buttons.
584 Note that when running the \l {iOS Style}{iOS style}, the DialogButtonBox will use
585 a vertical layout if this property is set to anything other than \c undefined and
586 there are more than two buttons.
587 In all other cases, the buttons will be arranged horizontally.
588*/
589Qt::Alignment QQuickDialogButtonBox::alignment() const
590{
591 Q_D(const QQuickDialogButtonBox);
592 return d->alignment;
593}
594
595void QQuickDialogButtonBox::setAlignment(Qt::Alignment alignment)
596{
597 Q_D(QQuickDialogButtonBox);
598 if (d->alignment == alignment)
599 return;
600
601 d->alignment = alignment;
602 if (isComponentComplete()) {
603 d->resizeContent();
604 polish();
605 }
606 emit alignmentChanged();
607}
608
609void QQuickDialogButtonBox::resetAlignment()
610{
611 setAlignment({});
612}
613
614/*!
615 \qmlproperty enumeration QtQuick.Controls::DialogButtonBox::standardButtons
616
617 This property holds a combination of standard buttons that are used by the button box.
618
619 \snippet qtquickcontrols-dialogbuttonbox.qml 1
620
621 The buttons will be positioned in the appropriate order for the user's platform.
622
623 Possible flags:
624 \value DialogButtonBox.Ok An "OK" button defined with the \c AcceptRole.
625 \value DialogButtonBox.Open An "Open" button defined with the \c AcceptRole.
626 \value DialogButtonBox.Save A "Save" button defined with the \c AcceptRole.
627 \value DialogButtonBox.Cancel A "Cancel" button defined with the \c RejectRole.
628 \value DialogButtonBox.Close A "Close" button defined with the \c RejectRole.
629 \value DialogButtonBox.Discard A "Discard" or "Don't Save" button, depending on the platform, defined with the \c DestructiveRole.
630 \value DialogButtonBox.Apply An "Apply" button defined with the \c ApplyRole.
631 \value DialogButtonBox.Reset A "Reset" button defined with the \c ResetRole.
632 \value DialogButtonBox.RestoreDefaults A "Restore Defaults" button defined with the \c ResetRole.
633 \value DialogButtonBox.Help A "Help" button defined with the \c HelpRole.
634 \value DialogButtonBox.SaveAll A "Save All" button defined with the \c AcceptRole.
635 \value DialogButtonBox.Yes A "Yes" button defined with the \c YesRole.
636 \value DialogButtonBox.YesToAll A "Yes to All" button defined with the \c YesRole.
637 \value DialogButtonBox.No A "No" button defined with the \c NoRole.
638 \value DialogButtonBox.NoToAll A "No to All" button defined with the \c NoRole.
639 \value DialogButtonBox.Abort An "Abort" button defined with the \c RejectRole.
640 \value DialogButtonBox.Retry A "Retry" button defined with the \c AcceptRole.
641 \value DialogButtonBox.Ignore An "Ignore" button defined with the \c AcceptRole.
642 \value DialogButtonBox.NoButton An invalid button.
643
644 \sa standardButton()
645*/
646QPlatformDialogHelper::StandardButtons QQuickDialogButtonBox::standardButtons() const
647{
648 Q_D(const QQuickDialogButtonBox);
649 return d->standardButtons;
650}
651
652void QQuickDialogButtonBox::setStandardButtons(QPlatformDialogHelper::StandardButtons buttons)
653{
654 Q_D(QQuickDialogButtonBox);
655 if (d->standardButtons == buttons)
656 return;
657
658 d->removeStandardButtons();
659
660 for (int i = QPlatformDialogHelper::FirstButton; i <= QPlatformDialogHelper::LastButton; i<<=1) {
661 QPlatformDialogHelper::StandardButton standardButton = static_cast<QPlatformDialogHelper::StandardButton>(i);
662 if (standardButton & buttons) {
663 QQuickAbstractButton *button = d->createStandardButton(standardButton);
664 if (button)
665 addItem(button);
666 }
667 }
668
669 if (isComponentComplete())
670 polish();
671
672 d->standardButtons = buttons;
673 emit standardButtonsChanged();
674}
675
676/*!
677 \qmlmethod AbstractButton QtQuick.Controls::DialogButtonBox::standardButton(StandardButton button)
678
679 Returns the specified standard \a button, or \c null if it does not exist.
680
681 \sa standardButtons
682*/
683QQuickAbstractButton *QQuickDialogButtonBox::standardButton(QPlatformDialogHelper::StandardButton button) const
684{
685 Q_D(const QQuickDialogButtonBox);
686 if (Q_UNLIKELY(!(d->standardButtons & button)))
687 return nullptr;
688 for (int i = 0, n = count(); i < n; ++i) {
689 QQuickAbstractButton *btn = qobject_cast<QQuickAbstractButton *>(d->itemAt(i));
690 if (Q_LIKELY(btn)) {
691 QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(btn, false));
692 if (attached && QQuickDialogButtonBoxAttachedPrivate::get(attached)->standardButton == button)
693 return btn;
694 }
695 }
696 return nullptr;
697}
698
699
700/*!
701 \qmlproperty enumeration QtQuick.Controls::DialogButtonBox::defaultStandardButton
702 \since 6.11
703
704 This property holds the default standard button.
705
706 The default standard button will be
707 \l {QtQuick.Controls::Button::highlighted}{highlighted} and receive focus.
708
709 Only one button in the button box can be made default.
710 This property cannot be used together with the
711 \l {DialogButtonBox::defaultButton} {defaultButton} property.
712
713 \sa standardButtons, defaultButton
714*/
715QPlatformDialogHelper::StandardButton QQuickDialogButtonBox::defaultStandardButton() const
716{
717 Q_D(const QQuickDialogButtonBox);
718 return d->defaultStandardButton;
719}
720
721void QQuickDialogButtonBox::setDefaultStandardButton(QPlatformDialogHelper::StandardButton button)
722{
723 Q_D(QQuickDialogButtonBox);
724 if (d->defaultStandardButton == button)
725 return;
726
727 d->defaultStandardButton = button;
728
729 if (isComponentComplete())
730 polish();
731
732 emit defaultStandardButtonChanged();
733}
734
735/*!
736 \qmlproperty AbstractButton QtQuick.Controls::DialogButtonBox::defaultButton
737 \since 6.11
738
739 This property holds the default button.
740
741 The default button will be
742 \l {QtQuick.Controls::Button::highlighted}{highlighted} and receive focus.
743
744 Only one button in the button box can be made default.
745 This property cannot be used together with the
746 \l {DialogButtonBox::defaultStandardButton} {defaultStandardButton} property.
747
748 \sa standardButtons, defaultStandardButton
749*/
750
751QQuickAbstractButton *QQuickDialogButtonBox::defaultButton() const
752{
753 Q_D(const QQuickDialogButtonBox);
754 return d->defaultButton;
755}
756
757void QQuickDialogButtonBox::setDefaultButton(QQuickAbstractButton *button)
758{
759 Q_D(QQuickDialogButtonBox);
760 if (d->defaultButton == button)
761 return;
762
763 if (d->defaultButton)
764 removeItem(d->defaultButton);
765
766 d->defaultButton = button;
767
768 if (d->defaultButton)
769 addItem(d->defaultButton);
770
771 if (isComponentComplete())
772 polish();
773
774 emit defaultButtonChanged();
775}
776
777/*!
778 \qmlproperty Component QtQuick.Controls::DialogButtonBox::delegate
779
780 This property holds a delegate for creating standard buttons.
781
782 \include delegate-ownership.qdocinc {no-ownership} {DialogButtonBox}
783
784 \sa standardButtons
785*/
786QQmlComponent *QQuickDialogButtonBox::delegate() const
787{
788 Q_D(const QQuickDialogButtonBox);
789 return d->delegate;
790}
791
792void QQuickDialogButtonBox::setDelegate(QQmlComponent* delegate)
793{
794 Q_D(QQuickDialogButtonBox);
795 if (d->delegate == delegate)
796 return;
797
798 d->delegate = delegate;
799 emit delegateChanged();
800}
801
802QQuickDialogButtonBoxAttached *QQuickDialogButtonBox::qmlAttachedProperties(QObject *object)
803{
804 return new QQuickDialogButtonBoxAttached(object);
805}
806
807/*!
808 \since QtQuick.Controls 2.5 (Qt 5.12)
809 \qmlproperty enumeration QtQuick.Controls::DialogButtonBox::buttonLayout
810
811 This property holds the button layout policy to be used when arranging the buttons contained in the button box.
812 The default value is platform-specific.
813
814 Available values:
815 \value DialogButtonBox.WinLayout Use a policy appropriate for applications on Windows.
816 \value DialogButtonBox.MacLayout Use a policy appropriate for applications on macOS.
817 \value DialogButtonBox.KdeLayout Use a policy appropriate for applications on KDE.
818 \value DialogButtonBox.GnomeLayout Use a policy appropriate for applications on GNOME.
819 \value DialogButtonBox.AndroidLayout Use a policy appropriate for applications on Android.
820*/
821QPlatformDialogHelper::ButtonLayout QQuickDialogButtonBox::buttonLayout() const
822{
823 Q_D(const QQuickDialogButtonBox);
824 return d->buttonLayout;
825}
826
827void QQuickDialogButtonBox::setButtonLayout(QPlatformDialogHelper::ButtonLayout layout)
828{
829 Q_D(QQuickDialogButtonBox);
830 if (d->buttonLayout == layout)
831 return;
832
833 d->buttonLayout = layout;
834 if (isComponentComplete())
835 d->updateLayout();
836 emit buttonLayoutChanged();
837}
838
839void QQuickDialogButtonBox::resetButtonLayout()
840{
841 setButtonLayout(platformButtonLayout());
842}
843
844void QQuickDialogButtonBox::updatePolish()
845{
846 Q_D(QQuickDialogButtonBox);
847 QQuickContainer::updatePolish();
848 d->updateLayout();
849 d->updateFocus();
850}
851
852bool QQuickDialogButtonBox::event(QEvent *e)
853{
854 Q_D(QQuickDialogButtonBox);
855 if (e->type() == QEvent::LanguageChange)
856 d->updateLanguage();
857 return QQuickContainer::event(e);
858}
859
860void QQuickDialogButtonBox::componentComplete()
861{
862 Q_D(QQuickDialogButtonBox);
863 QQuickContainer::componentComplete();
864 d->updateLayout();
865 d->updateFocus();
866}
867
868void QQuickDialogButtonBox::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
869{
870 Q_D(QQuickDialogButtonBox);
871 QQuickContainer::geometryChange(newGeometry, oldGeometry);
872 d->updateLayout();
873}
874
875void QQuickDialogButtonBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
876{
877 Q_D(QQuickDialogButtonBox);
878 QQuickContainer::contentItemChange(newItem, oldItem);
879 if (oldItem)
880 QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
881 if (newItem)
882 QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
883}
884
885bool QQuickDialogButtonBox::isContent(QQuickItem *item) const
886{
887 return qobject_cast<QQuickAbstractButton *>(item);
888}
889
890void QQuickDialogButtonBox::itemAdded(int index, QQuickItem *item)
891{
892 Q_D(QQuickDialogButtonBox);
893 Q_UNUSED(index);
894 if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(item))
895 QObjectPrivate::connect(button, &QQuickAbstractButton::clicked, d, &QQuickDialogButtonBoxPrivate::handleClick);
896 if (QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(item, false)))
897 QQuickDialogButtonBoxAttachedPrivate::get(attached)->setButtonBox(this);
898 d->updateImplicitContentSize();
899 if (isComponentComplete())
900 polish();
901}
902
903void QQuickDialogButtonBox::itemRemoved(int index, QQuickItem *item)
904{
905 Q_D(QQuickDialogButtonBox);
906 Q_UNUSED(index);
907 if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(item))
908 QObjectPrivate::disconnect(button, &QQuickAbstractButton::clicked, d, &QQuickDialogButtonBoxPrivate::handleClick);
909 if (QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(item, false)))
910 QQuickDialogButtonBoxAttachedPrivate::get(attached)->setButtonBox(nullptr);
911 d->updateImplicitContentSize();
912 if (isComponentComplete())
913 polish();
914}
915
916void QQuickDialogButtonBox::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
917{
918 QQuickContainer::itemChange(change, data);
919 if (change != QQuickItem::ItemVisibleHasChanged || !isComponentComplete() || !data.boolValue)
920 return;
921
922 Q_D(QQuickDialogButtonBox);
923 d->updateFocus();
924}
925
926#if QT_CONFIG(accessibility)
927QAccessible::Role QQuickDialogButtonBox::accessibleRole() const
928{
929 return QAccessible::Grouping;
930}
931#endif
932
933void QQuickDialogButtonBoxAttachedPrivate::setButtonBox(QQuickDialogButtonBox *box)
934{
935 Q_Q(QQuickDialogButtonBoxAttached);
936 if (buttonBox == box)
937 return;
938
939 buttonBox = box;
940 emit q->buttonBoxChanged();
941}
942
943QQuickDialogButtonBoxAttached::QQuickDialogButtonBoxAttached(QObject *parent)
944 : QObject(*(new QQuickDialogButtonBoxAttachedPrivate), parent)
945{
946 Q_D(QQuickDialogButtonBoxAttached);
947 QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent);
948 while (parentItem && !d->buttonBox) {
949 d->buttonBox = qobject_cast<QQuickDialogButtonBox *>(parentItem);
950 parentItem = parentItem->parentItem();
951 }
952}
953
954/*!
955 \qmlattachedproperty DialogButtonBox QtQuick.Controls::DialogButtonBox::buttonBox
956 \readonly
957
958 This attached property holds the button box that manages this button, or
959 \c null if the button is not in a button box.
960*/
961QQuickDialogButtonBox *QQuickDialogButtonBoxAttached::buttonBox() const
962{
963 Q_D(const QQuickDialogButtonBoxAttached);
964 return d->buttonBox;
965}
966
967/*!
968 \qmlattachedproperty enumeration QtQuick.Controls::DialogButtonBox::buttonRole
969
970 This attached property holds the role of each button in a button box.
971
972 \snippet qtquickcontrols-dialogbuttonbox-attached.qml 1
973
974 Available values:
975 \value DialogButtonBox.InvalidRole The button is invalid.
976 \value DialogButtonBox.AcceptRole Clicking the button causes the dialog to be accepted (e.g. \uicontrol OK).
977 \value DialogButtonBox.RejectRole Clicking the button causes the dialog to be rejected (e.g. \uicontrol Cancel).
978 \value DialogButtonBox.DestructiveRole Clicking the button causes a destructive change (e.g. for discarding changes) and closes the dialog.
979 \value DialogButtonBox.ActionRole Clicking the button causes changes to the elements within the dialog.
980 \value DialogButtonBox.HelpRole The button can be clicked to request help.
981 \value DialogButtonBox.YesRole The button is a "Yes"-like button.
982 \value DialogButtonBox.NoRole The button is a "No"-like button.
983 \value DialogButtonBox.ResetRole The button resets the dialog's fields to default values.
984 \value DialogButtonBox.ApplyRole The button applies current changes.
985*/
986QPlatformDialogHelper::ButtonRole QQuickDialogButtonBoxAttached::buttonRole() const
987{
988 Q_D(const QQuickDialogButtonBoxAttached);
989 return d->buttonRole;
990}
991
992void QQuickDialogButtonBoxAttached::setButtonRole(QPlatformDialogHelper::ButtonRole role)
993{
994 Q_D(QQuickDialogButtonBoxAttached);
995 if (d->buttonRole == role)
996 return;
997
998 d->buttonRole = role;
999 emit buttonRoleChanged();
1000}
1001
1002QT_END_NAMESPACE
1003
1004#include "moc_qquickdialogbuttonbox_p.cpp"
static QRectF alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSizeF &size, const QRectF &rectangle)