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

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