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