1// Copyright (C) 2021 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 <QtWidgets/qmessagebox.h>
5
6#include <QtWidgets/qdialogbuttonbox.h>
7#include "private/qlabel_p.h"
8#include "private/qapplication_p.h"
9#include <QtCore/qlist.h>
10#include <QtCore/qdebug.h>
11#include <QtWidgets/qstyle.h>
12#include <QtWidgets/qstyleoption.h>
13#include <QtWidgets/qgridlayout.h>
14#include <QtWidgets/qpushbutton.h>
15#include <QtWidgets/qcheckbox.h>
16#include <QtGui/qaccessible.h>
17#include <QtGui/qicon.h>
18#include <QtGui/qtextdocument.h>
19#include <QtWidgets/qapplication.h>
20#if QT_CONFIG(textedit)
21#include <QtWidgets/qtextedit.h>
22#endif
23#if QT_CONFIG(menu)
24#include <QtWidgets/qmenu.h>
25#endif
26#include "qdialog_p.h"
27#include <QtGui/qfont.h>
28#include <QtGui/qfontmetrics.h>
29#include <QtGui/qclipboard.h>
30#include "private/qabstractbutton_p.h"
31#include <QtGui/qpa/qplatformtheme.h>
32
33#include <QtCore/qanystringview.h>
34#include <QtCore/qdebug.h>
35#include <QtCore/qpointer.h>
36#include <QtCore/qversionnumber.h>
37
38#ifdef Q_OS_WIN
39# include <QtCore/qt_windows.h>
40#include <qpa/qplatformnativeinterface.h>
41#endif
42
43#include <optional>
44
45QT_BEGIN_NAMESPACE
46
47using namespace Qt::StringLiterals;
48
49#if defined(Q_OS_WIN)
50HMENU qt_getWindowsSystemMenu(const QWidget *w)
51{
52 if (QWindow *window = QApplicationPrivate::windowForWidget(w))
53 if (void *handle = QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", window))
54 return GetSystemMenu(reinterpret_cast<HWND>(handle), false);
55 return 0;
56}
57#endif
58
59static_assert(qToUnderlying(e: QMessageBox::ButtonRole::NRoles) ==
60 qToUnderlying(e: QDialogButtonBox::ButtonRole::NRoles),
61 "QMessageBox::ButtonRole and QDialogButtonBox::ButtonRole out of sync!");
62
63static_assert(std::is_same_v<std::underlying_type_t<QMessageBox::ButtonRole>,
64 std::underlying_type_t<QDialogButtonBox::ButtonRole>>);
65
66// StandardButton enums have different underlying types
67// => qToUnderlying and std::is_same_v won't work
68// ### Qt 7: make them have the same underlying type
69static_assert(static_cast<int>(QMessageBox::StandardButton::LastButton) ==
70 static_cast<int>(QDialogButtonBox::StandardButton::LastButton),
71 "QMessageBox::StandardButton and QDialogButtonBox::StandardButton out of sync!");
72
73enum Button { Old_Ok = 1, Old_Cancel = 2, Old_Yes = 3, Old_No = 4, Old_Abort = 5, Old_Retry = 6,
74 Old_Ignore = 7, Old_YesAll = 8, Old_NoAll = 9, Old_ButtonMask = 0xFF,
75 NewButtonMask = 0xFFFFFC00 };
76
77enum DetailButtonLabel { ShowLabel = 0, HideLabel = 1 };
78#if QT_CONFIG(textedit)
79class QMessageBoxDetailsText : public QWidget
80{
81 Q_OBJECT
82public:
83 class TextEdit : public QTextEdit
84 {
85 public:
86 TextEdit(QWidget *parent=nullptr) : QTextEdit(parent) { }
87#ifndef QT_NO_CONTEXTMENU
88 void contextMenuEvent(QContextMenuEvent * e) override
89 {
90 if (QMenu *menu = createStandardContextMenu()) {
91 menu->setAttribute(Qt::WA_DeleteOnClose);
92 menu->popup(pos: e->globalPos());
93 }
94 }
95#endif // QT_NO_CONTEXTMENU
96 };
97
98 QMessageBoxDetailsText(QWidget *parent=nullptr)
99 : QWidget(parent)
100 , copyAvailable(false)
101 {
102 QVBoxLayout *layout = new QVBoxLayout;
103 layout->setContentsMargins(QMargins());
104 QFrame *line = new QFrame(this);
105 line->setFrameShape(QFrame::HLine);
106 line->setFrameShadow(QFrame::Sunken);
107 layout->addWidget(line);
108 textEdit = new TextEdit();
109 textEdit->setFixedHeight(100);
110 textEdit->setFocusPolicy(Qt::NoFocus);
111 textEdit->setReadOnly(true);
112 layout->addWidget(textEdit);
113 setLayout(layout);
114
115 connect(sender: textEdit, signal: &TextEdit::copyAvailable,
116 context: this, slot: &QMessageBoxDetailsText::textCopyAvailable);
117 }
118 void setText(const QString &text) { textEdit->setPlainText(text); }
119 QString text() const { return textEdit->toPlainText(); }
120
121 bool copy()
122 {
123#ifdef QT_NO_CLIPBOARD
124 return false;
125#else
126 if (!copyAvailable)
127 return false;
128 textEdit->copy();
129 return true;
130#endif
131 }
132
133 void selectAll()
134 {
135 textEdit->selectAll();
136 }
137
138private slots:
139 void textCopyAvailable(bool available)
140 {
141 copyAvailable = available;
142 }
143
144private:
145 bool copyAvailable;
146 TextEdit *textEdit;
147};
148#endif // QT_CONFIG(textedit)
149
150class DetailButton : public QPushButton
151{
152public:
153 DetailButton(QWidget *parent) : QPushButton(label(label: ShowLabel), parent)
154 {
155 setSizePolicy(hor: QSizePolicy::Fixed, ver: QSizePolicy::Fixed);
156 }
157
158 QString label(DetailButtonLabel label) const
159 { return label == ShowLabel ? QMessageBox::tr(s: "Show Details...") : QMessageBox::tr(s: "Hide Details..."); }
160
161 void setLabel(DetailButtonLabel lbl)
162 { setText(label(label: lbl)); }
163
164 QSize sizeHint() const override
165 {
166 ensurePolished();
167 QStyleOptionButton opt;
168 initStyleOption(option: &opt);
169 const QFontMetrics fm = fontMetrics();
170 opt.text = label(label: ShowLabel);
171 QSize sz = fm.size(flags: Qt::TextShowMnemonic, str: opt.text);
172 QSize ret = style()->sizeFromContents(ct: QStyle::CT_PushButton, opt: &opt, contentsSize: sz, w: this);
173 opt.text = label(label: HideLabel);
174 sz = fm.size(flags: Qt::TextShowMnemonic, str: opt.text);
175 ret = ret.expandedTo(otherSize: style()->sizeFromContents(ct: QStyle::CT_PushButton, opt: &opt, contentsSize: sz, w: this));
176 return ret;
177 }
178};
179
180class QMessageBoxPrivate : public QDialogPrivate
181{
182 Q_DECLARE_PUBLIC(QMessageBox)
183
184public:
185 QMessageBoxPrivate() : escapeButton(nullptr), defaultButton(nullptr), checkbox(nullptr), clickedButton(nullptr), detailsButton(nullptr),
186#if QT_CONFIG(textedit)
187 detailsText(nullptr),
188#endif
189 compatMode(false), autoAddOkButton(true),
190 detectedEscapeButton(nullptr), informativeLabel(nullptr),
191 options(QMessageDialogOptions::create()) { }
192
193 void init(const QString &title = QString(), const QString &text = QString());
194 void setupLayout();
195 void buttonClicked(QAbstractButton *);
196 void helperClicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role);
197 void setClickedButton(QAbstractButton *button);
198
199 QAbstractButton *findButton(int button0, int button1, int button2, int flags);
200 void addOldButtons(int button0, int button1, int button2);
201
202 QAbstractButton *abstractButtonForId(int id) const;
203 int execReturnCode(QAbstractButton *button);
204
205 void detectEscapeButton();
206 void updateSize();
207 int layoutMinimumWidth();
208 void retranslateStrings();
209
210 void setVisible(bool visible) override;
211 bool canBeNativeDialog() const override;
212
213 static int showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
214 const QString &title, const QString &text,
215 int button0, int button1, int button2);
216 static int showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
217 const QString &title, const QString &text,
218 const QString &button0Text,
219 const QString &button1Text,
220 const QString &button2Text,
221 int defaultButtonNumber,
222 int escapeButtonNumber);
223
224 static QMessageBox::StandardButton showNewMessageBox(QWidget *parent,
225 QMessageBox::Icon icon, const QString& title, const QString& text,
226 QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
227
228 static QPixmap standardIcon(QMessageBox::Icon icon, QMessageBox *mb);
229 static QMessageBox::StandardButton standardButtonForRole(QMessageBox::ButtonRole role);
230
231 QLabel *label;
232 QMessageBox::Icon icon;
233 QLabel *iconLabel;
234 QDialogButtonBox *buttonBox;
235 QList<QAbstractButton *> customButtonList;
236 QAbstractButton *escapeButton;
237 QPushButton *defaultButton;
238 QCheckBox *checkbox;
239 QAbstractButton *clickedButton;
240 DetailButton *detailsButton;
241#if QT_CONFIG(textedit)
242 QMessageBoxDetailsText *detailsText;
243#endif
244 bool compatMode;
245 bool autoAddOkButton;
246 QAbstractButton *detectedEscapeButton;
247 QLabel *informativeLabel;
248 QPointer<QObject> receiverToDisconnectOnClose;
249 QByteArray memberToDisconnectOnClose;
250 QByteArray signalToDisconnectOnClose;
251 QSharedPointer<QMessageDialogOptions> options;
252private:
253 void initHelper(QPlatformDialogHelper *) override;
254 void helperPrepareShow(QPlatformDialogHelper *) override;
255 int dialogCode() const override;
256};
257
258void QMessageBoxPrivate::init(const QString &title, const QString &text)
259{
260 Q_Q(QMessageBox);
261
262 label = new QLabel;
263 label->setObjectName("qt_msgbox_label"_L1);
264 label->setTextInteractionFlags(Qt::TextInteractionFlags(q->style()->styleHint(stylehint: QStyle::SH_MessageBox_TextInteractionFlags, opt: nullptr, widget: q)));
265 label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
266 label->setOpenExternalLinks(true);
267 iconLabel = new QLabel(q);
268 iconLabel->setObjectName("qt_msgboxex_icon_label"_L1);
269 iconLabel->setSizePolicy(hor: QSizePolicy::Fixed, ver: QSizePolicy::Fixed);
270
271 buttonBox = new QDialogButtonBox;
272 buttonBox->setObjectName("qt_msgbox_buttonbox"_L1);
273 buttonBox->setCenterButtons(q->style()->styleHint(stylehint: QStyle::SH_MessageBox_CenterButtons, opt: nullptr, widget: q));
274 QObjectPrivate::connect(sender: buttonBox, signal: &QDialogButtonBox::clicked,
275 receiverPrivate: this, slot: &QMessageBoxPrivate::buttonClicked);
276 setupLayout();
277 if (!title.isEmpty() || !text.isEmpty()) {
278 q->setWindowTitle(title);
279 q->setText(text);
280 }
281 q->setModal(true);
282#ifdef Q_OS_MAC
283 QFont f = q->font();
284 f.setBold(true);
285 label->setFont(f);
286#endif
287 icon = QMessageBox::NoIcon;
288}
289
290void QMessageBoxPrivate::setupLayout()
291{
292 Q_Q(QMessageBox);
293 delete q->layout();
294 QGridLayout *grid = new QGridLayout;
295 const bool hasIcon = !iconLabel->pixmap().isNull();
296
297 if (hasIcon)
298 grid->addWidget(iconLabel, row: 0, column: 0, rowSpan: 2, columnSpan: 1, Qt::AlignTop);
299 iconLabel->setVisible(hasIcon);
300#ifdef Q_OS_MAC
301 QSpacerItem *indentSpacer = new QSpacerItem(14, 1, QSizePolicy::Fixed, QSizePolicy::Fixed);
302#else
303 QSpacerItem *indentSpacer = new QSpacerItem(hasIcon ? 7 : 15, 1, QSizePolicy::Fixed, QSizePolicy::Fixed);
304#endif
305 grid->addItem(item: indentSpacer, row: 0, column: hasIcon ? 1 : 0, rowSpan: 2, columnSpan: 1);
306 grid->addWidget(label, row: 0, column: hasIcon ? 2 : 1, rowSpan: 1, columnSpan: 1);
307 if (informativeLabel) {
308#ifndef Q_OS_MAC
309 informativeLabel->setContentsMargins(left: 0, top: 7, right: 0, bottom: 7);
310#endif
311 grid->addWidget(informativeLabel, row: 1, column: hasIcon ? 2 : 1, rowSpan: 1, columnSpan: 1);
312 }
313 if (checkbox) {
314 grid->addWidget(checkbox, row: informativeLabel ? 2 : 1, column: hasIcon ? 2 : 1, rowSpan: 1, columnSpan: 1, Qt::AlignLeft);
315#ifdef Q_OS_MAC
316 grid->addItem(new QSpacerItem(1, 15, QSizePolicy::Fixed, QSizePolicy::Fixed), grid->rowCount(), 0);
317#else
318 grid->addItem(item: new QSpacerItem(1, 7, QSizePolicy::Fixed, QSizePolicy::Fixed), row: grid->rowCount(), column: 0);
319#endif
320 }
321#ifdef Q_OS_MAC
322 grid->addWidget(buttonBox, grid->rowCount(), hasIcon ? 2 : 1, 1, 1);
323 grid->setContentsMargins(0, 0, 0, 0);
324 grid->setVerticalSpacing(8);
325 grid->setHorizontalSpacing(0);
326 q->setContentsMargins(24, 15, 24, 20);
327 grid->setRowStretch(1, 100);
328 grid->setRowMinimumHeight(2, 6);
329#else
330 grid->addWidget(buttonBox, row: grid->rowCount(), column: 0, rowSpan: 1, columnSpan: grid->columnCount());
331#endif
332#if QT_CONFIG(textedit)
333 if (detailsText)
334 grid->addWidget(detailsText, row: grid->rowCount(), column: 0, rowSpan: 1, columnSpan: grid->columnCount());
335#endif
336 grid->setSizeConstraint(QLayout::SetNoConstraint);
337 q->setLayout(grid);
338
339 retranslateStrings();
340 updateSize();
341}
342
343int QMessageBoxPrivate::layoutMinimumWidth()
344{
345 layout->activate();
346 return layout->totalMinimumSize().width();
347}
348
349void QMessageBoxPrivate::updateSize()
350{
351 Q_Q(QMessageBox);
352
353 if (!q->isVisible())
354 return;
355
356 const QSize screenSize = q->screen()->availableGeometry().size();
357 int hardLimit = qMin(a: screenSize.width() - 480, b: 1000); // can never get bigger than this
358 // on small screens allows the messagebox be the same size as the screen
359 if (screenSize.width() <= 1024)
360 hardLimit = screenSize.width();
361#ifdef Q_OS_MAC
362 int softLimit = qMin(screenSize.width()/2, 420);
363#else
364 // note: ideally on windows, hard and soft limits but it breaks compat
365 int softLimit = qMin(a: screenSize.width()/2, b: 500);
366#endif
367
368 if (informativeLabel)
369 informativeLabel->setSizePolicy(hor: QSizePolicy::Ignored, ver: QSizePolicy::Ignored);
370
371 label->setWordWrap(false); // makes the label return min size
372 int width = layoutMinimumWidth();
373
374 if (width > softLimit) {
375 label->setWordWrap(true);
376 width = qMax(a: softLimit, b: layoutMinimumWidth());
377
378 if (width > hardLimit) {
379 label->d_func()->ensureTextControl();
380 if (QWidgetTextControl *control = label->d_func()->control) {
381 QTextOption opt = control->document()->defaultTextOption();
382 opt.setWrapMode(QTextOption::WrapAnywhere);
383 control->document()->setDefaultTextOption(opt);
384 }
385 width = hardLimit;
386 }
387 }
388
389 if (informativeLabel) {
390 label->setSizePolicy(hor: QSizePolicy::Ignored, ver: QSizePolicy::Ignored);
391 QSizePolicy policy(QSizePolicy::Minimum, QSizePolicy::Preferred);
392 policy.setHeightForWidth(true);
393 informativeLabel->setSizePolicy(policy);
394 width = qMax(a: width, b: layoutMinimumWidth());
395 if (width > hardLimit) { // longest word is really big, so wrap anywhere
396 informativeLabel->d_func()->ensureTextControl();
397 if (QWidgetTextControl *control = informativeLabel->d_func()->control) {
398 QTextOption opt = control->document()->defaultTextOption();
399 opt.setWrapMode(QTextOption::WrapAnywhere);
400 control->document()->setDefaultTextOption(opt);
401 }
402 width = hardLimit;
403 }
404 policy.setHeightForWidth(label->wordWrap());
405 label->setSizePolicy(policy);
406 }
407
408 QFontMetrics fm(QApplication::font(className: "QMdiSubWindowTitleBar"));
409 int windowTitleWidth = qMin(a: fm.horizontalAdvance(q->windowTitle()) + 50, b: hardLimit);
410 if (windowTitleWidth > width)
411 width = windowTitleWidth;
412
413 layout->activate();
414 int height = (layout->hasHeightForWidth())
415 ? layout->totalHeightForWidth(w: width)
416 : layout->totalMinimumSize().height();
417
418 q->setFixedSize(w: width, h: height);
419 QCoreApplication::removePostedEvents(receiver: q, eventType: QEvent::LayoutRequest);
420}
421
422static int oldButton(int button)
423{
424 switch (button & QMessageBox::ButtonMask) {
425 case QMessageBox::Ok:
426 return Old_Ok;
427 case QMessageBox::Cancel:
428 return Old_Cancel;
429 case QMessageBox::Yes:
430 return Old_Yes;
431 case QMessageBox::No:
432 return Old_No;
433 case QMessageBox::Abort:
434 return Old_Abort;
435 case QMessageBox::Retry:
436 return Old_Retry;
437 case QMessageBox::Ignore:
438 return Old_Ignore;
439 case QMessageBox::YesToAll:
440 return Old_YesAll;
441 case QMessageBox::NoToAll:
442 return Old_NoAll;
443 default:
444 return 0;
445 }
446}
447
448int QMessageBoxPrivate::execReturnCode(QAbstractButton *button)
449{
450 if (int standardButton = buttonBox->standardButton(button)) {
451 // When using a QMessageBox with standard buttons, the return
452 // code is a StandardButton value indicating the standard button
453 // that was clicked.
454 if (compatMode)
455 return oldButton(button: standardButton);
456 else
457 return standardButton;
458 } else {
459 // When using QMessageBox with custom buttons, the return code
460 // is an opaque value, and the user is expected to use clickedButton()
461 // to determine which button was clicked. We make sure to keep the opaque
462 // value out of the QDialog::DialogCode range, so we can distinguish them.
463 auto customButtonIndex = customButtonList.indexOf(t: button);
464 if (customButtonIndex >= 0)
465 return QDialog::DialogCode::Accepted + customButtonIndex + 1;
466 else
467 return customButtonIndex; // Not found, return -1
468 }
469}
470
471int QMessageBoxPrivate::dialogCode() const
472{
473 Q_Q(const QMessageBox);
474
475 if (rescode <= QDialog::Accepted) {
476 return rescode;
477 } else if (clickedButton) {
478 switch (q->buttonRole(button: clickedButton)) {
479 case QMessageBox::AcceptRole:
480 case QMessageBox::YesRole:
481 return QDialog::Accepted;
482 case QMessageBox::RejectRole:
483 case QMessageBox::NoRole:
484 return QDialog::Rejected;
485 default:
486 ;
487 }
488 }
489
490 return QDialogPrivate::dialogCode();
491}
492
493void QMessageBoxPrivate::buttonClicked(QAbstractButton *button)
494{
495 Q_Q(QMessageBox);
496#if QT_CONFIG(textedit)
497 if (detailsButton && detailsText && button == detailsButton) {
498 detailsButton->setLabel(detailsText->isHidden() ? HideLabel : ShowLabel);
499 detailsText->setHidden(!detailsText->isHidden());
500 updateSize();
501 } else
502#endif
503 {
504 setClickedButton(button);
505
506 if (receiverToDisconnectOnClose) {
507 QObject::disconnect(sender: q, signal: signalToDisconnectOnClose, receiver: receiverToDisconnectOnClose,
508 member: memberToDisconnectOnClose);
509 receiverToDisconnectOnClose = nullptr;
510 }
511 signalToDisconnectOnClose.clear();
512 memberToDisconnectOnClose.clear();
513 }
514}
515
516void QMessageBoxPrivate::setClickedButton(QAbstractButton *button)
517{
518 Q_Q(QMessageBox);
519
520 clickedButton = button;
521 emit q->buttonClicked(button: clickedButton);
522
523 auto resultCode = execReturnCode(button);
524 q->done(resultCode);
525}
526
527void QMessageBoxPrivate::helperClicked(QPlatformDialogHelper::StandardButton helperButton, QPlatformDialogHelper::ButtonRole role)
528{
529 Q_UNUSED(role);
530 Q_Q(QMessageBox);
531
532 // Map back to QAbstractButton, so that the message box behaves the same from
533 // the outside, regardless of whether it's backed by a native helper or not.
534 QAbstractButton *dialogButton = helperButton > QPlatformDialogHelper::LastButton ?
535 static_cast<QAbstractButton *>(options->customButton(id: helperButton)->button) :
536 q->button(which: QMessageBox::StandardButton(helperButton));
537
538 Q_ASSERT(dialogButton);
539
540 // Simulate click by explicitly clicking the button. This will ensure that
541 // any logic of the button that responds to the click is respected, including
542 // plumbing back to buttonClicked above based on the clicked() signal.
543 dialogButton->click();
544}
545
546/*!
547 \class QMessageBox
548
549 \brief The QMessageBox class provides a modal dialog for informing
550 the user or for asking the user a question and receiving an answer.
551
552 \ingroup standard-dialogs
553 \inmodule QtWidgets
554
555 A message box displays a primary \l{QMessageBox::text}{text} to
556 alert the user to a situation, an \l{QMessageBox::informativeText}
557 {informative text} to further explain the situation, and an optional
558 \l{QMessageBox::detailedText} {detailed text} to provide even more data
559 if the user requests it.
560
561 A message box can also display an \l{QMessageBox::icon} {icon}
562 and \l{QMessageBox::standardButtons} {standard buttons} for
563 accepting a user response.
564
565 Two APIs for using QMessageBox are provided, the property-based
566 API, and the static functions. Calling one of the static functions
567 is the simpler approach, but it is less flexible than using the
568 property-based API, and the result is less informative. Using the
569 property-based API is recommended.
570
571 \section1 The Property-based API
572
573 To use the property-based API, construct an instance of
574 QMessageBox, set the desired properties, and call exec() to show
575 the message. The simplest configuration is to set only the
576 \l{QMessageBox::text} {message text} property.
577
578 \snippet code/src_gui_dialogs_qmessagebox.cpp 5
579
580 The user must click the \uicontrol{OK} button to dismiss the message
581 box. The rest of the GUI is blocked until the message box is
582 dismissed.
583
584 \image msgbox1.png
585
586 A better approach than just alerting the user to an event is to
587 also ask the user what to do about it.
588
589 Set the \l{QMessageBox::standardButtons} {standard buttons}
590 property to the set of buttons you want as the set of user
591 responses. The buttons are specified by combining values from
592 StandardButtons using the bitwise OR operator. The display order
593 for the buttons is platform-dependent. For example, on Windows,
594 \uicontrol{Save} is displayed to the left of \uicontrol{Cancel}, whereas on
595 \macos, the order is reversed. Mark one of your standard buttons to be your
596 \l{QMessageBox::defaultButton()} {default button}.
597
598 The \l{QMessageBox::informativeText} {informative text} property can
599 be used to add additional context to help the user choose the appropriate action.
600
601 \snippet code/src_gui_dialogs_qmessagebox.cpp 6
602
603 \image msgbox2.png
604
605 The exec() slot returns the StandardButtons value of the button
606 that was clicked.
607
608 \snippet code/src_gui_dialogs_qmessagebox.cpp 7
609
610 To give the user more information to help them choose the appropriate,
611 action, set the \l{QMessageBox::detailedText} {detailed text} property.
612 Depending on the platform the \l{QMessageBox::detailedText} {detailed text},
613 may require the user to click a \uicontrol{Show Details...} button to be shown.
614
615 \image msgbox3.png
616
617 Clicking the \uicontrol{Show Details...} button displays the detailed text.
618
619 \image msgbox4.png
620
621 \section2 Rich Text and the Text Format Property
622
623 The \l{QMessageBox::detailedText} {detailed text} property is
624 always interpreted as plain text. The \l{QMessageBox::text} {main
625 text} and \l{QMessageBox::informativeText} {informative text}
626 properties can be either plain text or rich text. These strings
627 are interpreted according to the setting of the
628 \l{QMessageBox::textFormat} {text format} property. The default
629 setting is \l{Qt::AutoText} {auto-text}.
630
631 Note that for some plain text strings containing XML
632 meta-characters, the auto-text \l{Qt::mightBeRichText()} {rich
633 text detection test} may fail causing your plain text string to be
634 interpreted incorrectly as rich text. In these rare cases, use
635 Qt::convertFromPlainText() to convert your plain text string to a
636 visually equivalent rich text string, or set the
637 \l{QMessageBox::textFormat} {text format} property explicitly with
638 setTextFormat().
639
640 \section2 Severity Levels and the Icon and Pixmap Properties
641
642 QMessageBox supports four predefined message severity levels, or message
643 types, which really only differ in the predefined icon they each show.
644 Specify one of the four predefined message types by setting the
645 \l{QMessageBox::icon}{icon} property to one of the
646 \l{QMessageBox::Icon}{predefined icons}. The following rules are
647 guidelines:
648
649 \table
650 \row
651 \li \image qmessagebox-quest.png
652 \li \l Question
653 \li For asking a question during normal operations.
654 \row
655 \li \image qmessagebox-info.png
656 \li \l Information
657 \li For reporting information about normal operations.
658 \row
659 \li \image qmessagebox-warn.png
660 \li \l Warning
661 \li For reporting non-critical errors.
662 \row
663 \li \image qmessagebox-crit.png
664 \li \l Critical
665 \li For reporting critical errors.
666 \endtable
667
668 \l{QMessageBox::Icon}{Predefined icons} are not defined by QMessageBox, but
669 provided by the style. The default value is \l{QMessageBox::NoIcon}
670 {No Icon}. The message boxes are otherwise the same for all cases. When
671 using a standard icon, use the one recommended in the table, or use the
672 one recommended by the style guidelines for your platform. If none of the
673 standard icons is right for your message box, you can use a custom icon by
674 setting the \l{QMessageBox::iconPixmap}{icon pixmap} property instead of
675 setting the \l{QMessageBox::icon}{icon} property.
676
677 In summary, to set an icon, use \e{either} setIcon() for one of the
678 standard icons, \e{or} setIconPixmap() for a custom icon.
679
680 \section1 The Static Functions API
681
682 Building message boxes with the static functions API, although
683 convenient, is less flexible than using the property-based API,
684 because the static function signatures lack parameters for setting
685 the \l{QMessageBox::informativeText} {informative text} and
686 \l{QMessageBox::detailedText} {detailed text} properties. One
687 work-around for this has been to use the \c{title} parameter as
688 the message box main text and the \c{text} parameter as the
689 message box informative text. Because this has the obvious
690 drawback of making a less readable message box, platform
691 guidelines do not recommend it. The \e{Microsoft Windows User
692 Interface Guidelines} recommend using the
693 \l{QCoreApplication::applicationName} {application name} as the
694 \l{QMessageBox::setWindowTitle()} {window's title}, which means
695 that if you have an informative text in addition to your main
696 text, you must concatenate it to the \c{text} parameter.
697
698 Note that the static function signatures have changed with respect
699 to their button parameters, which are now used to set the
700 \l{QMessageBox::standardButtons} {standard buttons} and the
701 \l{QMessageBox::defaultButton()} {default button}.
702
703 Static functions are available for creating information(),
704 question(), warning(), and critical() message boxes.
705
706 \snippet code/src_gui_dialogs_qmessagebox.cpp 0
707
708 The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
709 how to use QMessageBox and the other built-in Qt dialogs.
710
711 \section1 Advanced Usage
712
713 If the \l{QMessageBox::StandardButtons} {standard buttons} are not
714 flexible enough for your message box, you can use the addButton()
715 overload that takes a text and a ButtonRole to add custom
716 buttons. The ButtonRole is used by QMessageBox to determine the
717 ordering of the buttons on screen (which varies according to the
718 platform). You can test the value of clickedButton() after calling
719 exec(). For example,
720
721 \snippet code/src_gui_dialogs_qmessagebox.cpp 2
722
723 \section1 Default and Escape Keys
724
725 The default button (i.e., the button activated when \uicontrol Enter is
726 pressed) can be specified using setDefaultButton(). If a default
727 button is not specified, QMessageBox tries to find one based on
728 the \l{ButtonRole} {button roles} of the buttons used in the
729 message box.
730
731 The escape button (the button activated when \uicontrol Esc is pressed)
732 can be specified using setEscapeButton(). If an escape button is
733 not specified, QMessageBox tries to find one using these rules:
734
735 \list 1
736
737 \li If there is only one button, it is the button activated when
738 \uicontrol Esc is pressed.
739
740 \li If there is a \l Cancel button, it is the button activated when
741 \uicontrol Esc is pressed.
742
743 \li If there is exactly one button having either
744 \l{QMessageBox::RejectRole} {the Reject role} or the
745 \l{QMessageBox::NoRole} {the No role}, it is the button
746 activated when \uicontrol Esc is pressed.
747
748 \endlist
749
750 When an escape button can't be determined using these rules,
751 pressing \uicontrol Esc has no effect.
752
753 \sa QDialogButtonBox, {Standard Dialogs Example}
754*/
755
756/*!
757 \enum QMessageBox::ButtonRole
758
759 \include qdialogbuttonbox.cpp buttonrole-enum
760*/
761
762/*!
763 \enum QMessageBox::StandardButton
764
765 These enums describe flags for standard buttons. Each button has a
766 defined \l ButtonRole.
767
768 \value Ok An "OK" button defined with the \l AcceptRole.
769 \value Open An "Open" button defined with the \l AcceptRole.
770 \value Save A "Save" button defined with the \l AcceptRole.
771 \value Cancel A "Cancel" button defined with the \l RejectRole.
772 \value Close A "Close" button defined with the \l RejectRole.
773 \value Discard A "Discard" or "Don't Save" button, depending on the platform,
774 defined with the \l DestructiveRole.
775 \value Apply An "Apply" button defined with the \l ApplyRole.
776 \value Reset A "Reset" button defined with the \l ResetRole.
777 \value RestoreDefaults A "Restore Defaults" button defined with the \l ResetRole.
778 \value Help A "Help" button defined with the \l HelpRole.
779 \value SaveAll A "Save All" button defined with the \l AcceptRole.
780 \value Yes A "Yes" button defined with the \l YesRole.
781 \value YesToAll A "Yes to All" button defined with the \l YesRole.
782 \value No A "No" button defined with the \l NoRole.
783 \value NoToAll A "No to All" button defined with the \l NoRole.
784 \value Abort An "Abort" button defined with the \l RejectRole.
785 \value Retry A "Retry" button defined with the \l AcceptRole.
786 \value Ignore An "Ignore" button defined with the \l AcceptRole.
787
788 \value NoButton An invalid button.
789
790 \omitvalue FirstButton
791 \omitvalue LastButton
792
793 The following values are obsolete:
794
795 \value YesAll Use YesToAll instead.
796 \value NoAll Use NoToAll instead.
797 \value Default Use the \c defaultButton argument of
798 information(), warning(), etc. instead, or call
799 setDefaultButton().
800 \value Escape Call setEscapeButton() instead.
801 \value FlagMask
802 \value ButtonMask
803
804 \sa ButtonRole, standardButtons
805*/
806
807/*!
808 \enum QMessageBox::Option
809 \since 6.6
810 \value DontUseNativeDialog Don't use the native message dialog.
811*/
812
813/*!
814 \fn void QMessageBox::buttonClicked(QAbstractButton *button)
815
816 This signal is emitted whenever a button is clicked inside the QMessageBox.
817 The button that was clicked in returned in \a button.
818*/
819
820/*!
821 Constructs an \l{Qt::ApplicationModal} {application modal} message box with no text and no buttons.
822 \a parent is passed to the QDialog constructor.
823
824 The window modality can be overridden via setWindowModality() before calling show().
825
826 \note Using open() or exec() to show the message box affects the window modality.
827 Please see the detailed documentation for each function for more information.
828
829 On \macos, if you want your message box to appear
830 as a Qt::Sheet of its \a parent, set the message box's
831 \l{setWindowModality()} {window modality} to Qt::WindowModal or use open().
832 Otherwise, the message box will be a standard dialog.
833
834 \sa setWindowTitle(), setText(), setIcon(), setStandardButtons(), setWindowModality()
835
836*/
837QMessageBox::QMessageBox(QWidget *parent)
838 : QDialog(*new QMessageBoxPrivate, parent, Qt::MSWindowsFixedSizeDialogHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
839{
840 Q_D(QMessageBox);
841 d->init();
842}
843
844/*!
845 Constructs an \l{Qt::ApplicationModal} {application modal} message box with the given \a icon,
846 \a title, \a text, and standard \a buttons. Standard or custom buttons can be
847 added at any time using addButton(). The \a parent and \a f
848 arguments are passed to the QDialog constructor.
849
850 The window modality can be overridden via setWindowModality() before calling show().
851
852 \note Using open() or exec() to show the message box affects the window modality.
853 Please see the detailed documentation for each function for more information.
854
855 On \macos, if \a parent is not \nullptr and you want your message box
856 to appear as a Qt::Sheet of that parent, set the message box's
857 \l{setWindowModality()} {window modality} to Qt::WindowModal
858 (default). Otherwise, the message box will be a standard dialog.
859
860 \sa setWindowTitle(), setText(), setIcon(), setStandardButtons(), setWindowModality()
861*/
862QMessageBox::QMessageBox(Icon icon, const QString &title, const QString &text,
863 StandardButtons buttons, QWidget *parent,
864 Qt::WindowFlags f)
865: QDialog(*new QMessageBoxPrivate, parent, f | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
866{
867 Q_D(QMessageBox);
868 d->init(title, text);
869 setIcon(icon);
870 if (buttons != NoButton)
871 setStandardButtons(buttons);
872}
873
874/*!
875 Destroys the message box.
876*/
877QMessageBox::~QMessageBox()
878{
879}
880
881/*!
882 Adds the given \a button to the message box with the specified \a
883 role.
884
885 \sa removeButton(), button(), setStandardButtons()
886*/
887void QMessageBox::addButton(QAbstractButton *button, ButtonRole role)
888{
889 Q_D(QMessageBox);
890 if (!button)
891 return;
892 removeButton(button);
893
894 if (button->text().isEmpty()) {
895 if (auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
896 if (auto standardButton = QMessageBoxPrivate::standardButtonForRole(role))
897 button->setText(platformTheme->standardButtonText(button: standardButton));
898 }
899
900 if (button->text().isEmpty()) {
901 qWarning() << "Cannot add" << button << "without title";
902 return;
903 }
904 }
905
906 d->buttonBox->addButton(button, role: (QDialogButtonBox::ButtonRole)role);
907 d->customButtonList.append(t: button);
908 d->autoAddOkButton = false;
909}
910
911QMessageBox::StandardButton QMessageBoxPrivate::standardButtonForRole(QMessageBox::ButtonRole role)
912{
913 switch (role) {
914 case QMessageBox::AcceptRole: return QMessageBox::Ok;
915 case QMessageBox::RejectRole: return QMessageBox::Cancel;
916 case QMessageBox::DestructiveRole: return QMessageBox::Discard;
917 case QMessageBox::HelpRole: return QMessageBox::Help;
918 case QMessageBox::ApplyRole: return QMessageBox::Apply;
919 case QMessageBox::YesRole: return QMessageBox::Yes;
920 case QMessageBox::NoRole: return QMessageBox::No;
921 case QMessageBox::ResetRole: return QMessageBox::Reset;
922 default: return QMessageBox::NoButton;
923 }
924}
925
926/*!
927 \overload
928
929 Creates a button with the given \a text, adds it to the message box for the
930 specified \a role, and returns it.
931*/
932QPushButton *QMessageBox::addButton(const QString& text, ButtonRole role)
933{
934 Q_D(QMessageBox);
935 QPushButton *pushButton = new QPushButton(text);
936 addButton(button: pushButton, role);
937 d->updateSize();
938 return pushButton;
939}
940
941/*!
942 \overload
943
944 Adds a standard \a button to the message box if it is valid to do so, and
945 returns the push button.
946
947 \sa setStandardButtons()
948*/
949QPushButton *QMessageBox::addButton(StandardButton button)
950{
951 Q_D(QMessageBox);
952 QPushButton *pushButton = d->buttonBox->addButton(button: (QDialogButtonBox::StandardButton)button);
953 if (pushButton)
954 d->autoAddOkButton = false;
955 return pushButton;
956}
957
958/*!
959 Removes \a button from the button box without deleting it.
960
961 \sa addButton(), setStandardButtons()
962*/
963void QMessageBox::removeButton(QAbstractButton *button)
964{
965 Q_D(QMessageBox);
966 d->customButtonList.removeAll(t: button);
967 if (d->escapeButton == button)
968 d->escapeButton = nullptr;
969 if (d->defaultButton == button)
970 d->defaultButton = nullptr;
971 d->buttonBox->removeButton(button);
972 d->updateSize();
973}
974
975/*!
976 \property QMessageBox::standardButtons
977 \brief collection of standard buttons in the message box
978
979 This property controls which standard buttons are used by the message box.
980
981 By default, this property contains no standard buttons.
982
983 \sa addButton()
984*/
985void QMessageBox::setStandardButtons(StandardButtons buttons)
986{
987 Q_D(QMessageBox);
988 d->buttonBox->setStandardButtons(QDialogButtonBox::StandardButtons(int(buttons)));
989
990 QList<QAbstractButton *> buttonList = d->buttonBox->buttons();
991 if (!buttonList.contains(t: d->escapeButton))
992 d->escapeButton = nullptr;
993 if (!buttonList.contains(t: d->defaultButton))
994 d->defaultButton = nullptr;
995 d->autoAddOkButton = false;
996 d->updateSize();
997}
998
999QMessageBox::StandardButtons QMessageBox::standardButtons() const
1000{
1001 Q_D(const QMessageBox);
1002 return QMessageBox::StandardButtons(int(d->buttonBox->standardButtons()));
1003}
1004
1005/*!
1006 Returns the standard button enum value corresponding to the given \a button,
1007 or NoButton if the given \a button isn't a standard button.
1008
1009 \sa button(), standardButtons()
1010*/
1011QMessageBox::StandardButton QMessageBox::standardButton(QAbstractButton *button) const
1012{
1013 Q_D(const QMessageBox);
1014 return (QMessageBox::StandardButton)d->buttonBox->standardButton(button);
1015}
1016
1017/*!
1018 Returns a pointer corresponding to the standard button \a which,
1019 or \nullptr if the standard button doesn't exist in this message box.
1020
1021 \note Modifying the properties of the returned button may not be reflected
1022 in native implementations of the message dialog. To customize dialog
1023 buttons add a \l{addButton(QAbstractButton *button, QMessageBox::ButtonRole role)}
1024 {custom button} or \l{addButton(const QString &text, QMessageBox::ButtonRole role)}
1025 {button title} instead, or set the \l Option::DontUseNativeDialog option.
1026
1027 \sa standardButtons, standardButton()
1028*/
1029QAbstractButton *QMessageBox::button(StandardButton which) const
1030{
1031 Q_D(const QMessageBox);
1032 return d->buttonBox->button(which: QDialogButtonBox::StandardButton(which));
1033}
1034
1035/*!
1036 Returns the button that is activated when escape is pressed.
1037
1038 By default, QMessageBox attempts to automatically detect an
1039 escape button as follows:
1040
1041 \list 1
1042 \li If there is only one button, it is made the escape button.
1043 \li If there is a \l Cancel button, it is made the escape button.
1044 \li On \macos only, if there is exactly one button with the role
1045 QMessageBox::RejectRole, it is made the escape button.
1046 \endlist
1047
1048 When an escape button could not be automatically detected, pressing
1049 \uicontrol Esc has no effect.
1050
1051 \sa addButton()
1052*/
1053QAbstractButton *QMessageBox::escapeButton() const
1054{
1055 Q_D(const QMessageBox);
1056 return d->escapeButton;
1057}
1058
1059/*!
1060 Sets the button that gets activated when the \uicontrol Escape key is
1061 pressed to \a button.
1062
1063 \sa addButton(), clickedButton()
1064*/
1065void QMessageBox::setEscapeButton(QAbstractButton *button)
1066{
1067 Q_D(QMessageBox);
1068 if (d->buttonBox->buttons().contains(t: button))
1069 d->escapeButton = button;
1070}
1071
1072/*!
1073 Sets the buttons that gets activated when the \uicontrol Escape key is
1074 pressed to \a button.
1075
1076 \sa addButton(), clickedButton()
1077*/
1078void QMessageBox::setEscapeButton(QMessageBox::StandardButton button)
1079{
1080 Q_D(QMessageBox);
1081 setEscapeButton(d->buttonBox->button(which: QDialogButtonBox::StandardButton(button)));
1082}
1083
1084void QMessageBoxPrivate::detectEscapeButton()
1085{
1086 if (escapeButton) { // escape button explicitly set
1087 detectedEscapeButton = escapeButton;
1088 return;
1089 }
1090
1091 // Cancel button automatically becomes escape button
1092 detectedEscapeButton = buttonBox->button(which: QDialogButtonBox::Cancel);
1093 if (detectedEscapeButton)
1094 return;
1095
1096 // If there is only one button, make it the escape button
1097 const QList<QAbstractButton *> buttons = buttonBox->buttons();
1098 if (buttons.size() == 1) {
1099 detectedEscapeButton = buttons.first();
1100 return;
1101 }
1102
1103 // If there are two buttons and one of them is the "Show Details..."
1104 // button, then make the other one the escape button
1105 if (buttons.size() == 2 && detailsButton) {
1106 auto idx = buttons.indexOf(t: detailsButton);
1107 if (idx != -1) {
1108 detectedEscapeButton = buttons.at(i: 1 - idx);
1109 return;
1110 }
1111 }
1112
1113 // if the message box has one RejectRole button, make it the escape button
1114 for (auto *button : buttons) {
1115 if (buttonBox->buttonRole(button) == QDialogButtonBox::RejectRole) {
1116 if (detectedEscapeButton) { // already detected!
1117 detectedEscapeButton = nullptr;
1118 break;
1119 }
1120 detectedEscapeButton = button;
1121 }
1122 }
1123 if (detectedEscapeButton)
1124 return;
1125
1126 // if the message box has one NoRole button, make it the escape button
1127 for (auto *button : buttons) {
1128 if (buttonBox->buttonRole(button) == QDialogButtonBox::NoRole) {
1129 if (detectedEscapeButton) { // already detected!
1130 detectedEscapeButton = nullptr;
1131 break;
1132 }
1133 detectedEscapeButton = button;
1134 }
1135 }
1136}
1137
1138/*!
1139 Returns the button that was clicked by the user,
1140 or \nullptr if the user hit the \uicontrol Esc key and
1141 no \l{setEscapeButton()}{escape button} was set.
1142
1143 If exec() hasn't been called yet, returns nullptr.
1144
1145 Example:
1146
1147 \snippet code/src_gui_dialogs_qmessagebox.cpp 3
1148
1149 \sa standardButton(), button()
1150*/
1151QAbstractButton *QMessageBox::clickedButton() const
1152{
1153 Q_D(const QMessageBox);
1154 return d->clickedButton;
1155}
1156
1157/*!
1158 Returns the button that should be the message box's
1159 \l{QPushButton::setDefault()}{default button}. Returns nullptr
1160 if no default button was set.
1161
1162 \sa addButton(), QPushButton::setDefault()
1163*/
1164QPushButton *QMessageBox::defaultButton() const
1165{
1166 Q_D(const QMessageBox);
1167 return d->defaultButton;
1168}
1169
1170/*!
1171 Sets the message box's \l{QPushButton::setDefault()}{default button}
1172 to \a button.
1173
1174 \sa addButton(), QPushButton::setDefault()
1175*/
1176void QMessageBox::setDefaultButton(QPushButton *button)
1177{
1178 Q_D(QMessageBox);
1179 if (!d->buttonBox->buttons().contains(t: button))
1180 return;
1181 d->defaultButton = button;
1182 button->setDefault(true);
1183 button->setFocus();
1184}
1185
1186/*!
1187 Sets the message box's \l{QPushButton::setDefault()}{default button}
1188 to \a button.
1189
1190 \sa addButton(), QPushButton::setDefault()
1191*/
1192void QMessageBox::setDefaultButton(QMessageBox::StandardButton button)
1193{
1194 Q_D(QMessageBox);
1195 setDefaultButton(d->buttonBox->button(which: QDialogButtonBox::StandardButton(button)));
1196}
1197
1198/*! \since 5.2
1199
1200 Sets the checkbox \a cb on the message dialog. The message box takes ownership of the checkbox.
1201 The argument \a cb can be \nullptr to remove an existing checkbox from the message box.
1202
1203 \sa checkBox()
1204*/
1205
1206void QMessageBox::setCheckBox(QCheckBox *cb)
1207{
1208 Q_D(QMessageBox);
1209
1210 if (cb == d->checkbox)
1211 return;
1212
1213 if (d->checkbox) {
1214 d->checkbox->hide();
1215 layout()->removeWidget(w: d->checkbox);
1216 if (d->checkbox->parentWidget() == this) {
1217 d->checkbox->setParent(nullptr);
1218 d->checkbox->deleteLater();
1219 }
1220 }
1221 d->checkbox = cb;
1222 if (d->checkbox) {
1223 QSizePolicy sp = d->checkbox->sizePolicy();
1224 sp.setHorizontalPolicy(QSizePolicy::MinimumExpanding);
1225 d->checkbox->setSizePolicy(sp);
1226 }
1227 d->setupLayout();
1228}
1229
1230
1231/*! \since 5.2
1232
1233 Returns the checkbox shown on the dialog. This is \nullptr if no checkbox is set.
1234 \sa setCheckBox()
1235*/
1236
1237QCheckBox* QMessageBox::checkBox() const
1238{
1239 Q_D(const QMessageBox);
1240 return d->checkbox;
1241}
1242
1243/*!
1244 \since 6.6
1245 Sets the given \a option to be enabled if \a on is true; otherwise,
1246 clears the given \a option.
1247
1248 Options (particularly the \l Option::DontUseNativeDialog option) should be set
1249 before showing the dialog.
1250
1251 Setting options while the dialog is visible is not guaranteed to have
1252 an immediate effect on the dialog.
1253
1254 Setting options after changing other properties may cause these
1255 values to have no effect.
1256
1257 \sa options, testOption()
1258*/
1259void QMessageBox::setOption(QMessageBox::Option option, bool on)
1260{
1261 const QMessageBox::Options previousOptions = options();
1262 if (!(previousOptions & option) != !on)
1263 setOptions(previousOptions ^ option);
1264}
1265
1266/*!
1267 \since 6.6
1268
1269 Returns \c true if the given \a option is enabled; otherwise, returns
1270 false.
1271
1272 \sa options, setOption()
1273*/
1274bool QMessageBox::testOption(QMessageBox::Option option) const
1275{
1276 Q_D(const QMessageBox);
1277 return d->options->testOption(option: static_cast<QMessageDialogOptions::Option>(option));
1278}
1279
1280void QMessageBox::setOptions(QMessageBox::Options options)
1281{
1282 Q_D(QMessageBox);
1283
1284 if (QMessageBox::options() == options)
1285 return;
1286
1287 d->options->setOptions(QMessageDialogOptions::Option(int(options)));
1288}
1289
1290QMessageBox::Options QMessageBox::options() const
1291{
1292 Q_D(const QMessageBox);
1293 return QMessageBox::Options(int(d->options->options()));
1294}
1295
1296/*!
1297 \property QMessageBox::options
1298 \brief Options that affect the look and feel of the dialog.
1299 \since 6.6
1300
1301 By default, these options are disabled.
1302
1303 The option \l Option::DontUseNativeDialog should be set
1304 before changing dialog properties or showing the dialog.
1305
1306 Setting options while the dialog is visible is not guaranteed to have
1307 an immediate effect on the dialog.
1308
1309 Setting options after changing other properties may cause these
1310 values to have no effect.
1311
1312 \sa setOption(), testOption()
1313*/
1314
1315/*!
1316 \property QMessageBox::text
1317 \brief the message box text to be displayed.
1318
1319 The text should be a brief sentence or phrase that describes the situation,
1320 ideally formulated as a neutral statement, or a call-to-action question.
1321
1322 The text will be interpreted either as a plain text or as rich text,
1323 depending on the text format setting (\l QMessageBox::textFormat).
1324 The default setting is Qt::AutoText, i.e., the message box will try
1325 to auto-detect the format of the text.
1326
1327 The default value of this property is an empty string.
1328
1329 \sa textFormat, QMessageBox::informativeText, QMessageBox::detailedText
1330*/
1331QString QMessageBox::text() const
1332{
1333 Q_D(const QMessageBox);
1334 return d->label->text();
1335}
1336
1337void QMessageBox::setText(const QString &text)
1338{
1339 Q_D(QMessageBox);
1340 d->label->setText(text);
1341 d->label->setWordWrap(d->label->textFormat() == Qt::RichText
1342 || (d->label->textFormat() == Qt::AutoText && Qt::mightBeRichText(text)));
1343 d->updateSize();
1344}
1345
1346/*!
1347 \enum QMessageBox::Icon
1348
1349 This enum has the following values:
1350
1351 \value NoIcon the message box does not have any icon.
1352
1353 \value Question an icon indicating that
1354 the message is asking a question.
1355
1356 \value Information an icon indicating that
1357 the message is nothing out of the ordinary.
1358
1359 \value Warning an icon indicating that the
1360 message is a warning, but can be dealt with.
1361
1362 \value Critical an icon indicating that
1363 the message represents a critical problem.
1364
1365*/
1366
1367/*!
1368 \property QMessageBox::icon
1369 \brief the message box's icon
1370
1371 The icon of the message box can be specified with one of the
1372 values:
1373
1374 \list
1375 \li QMessageBox::NoIcon
1376 \li QMessageBox::Question
1377 \li QMessageBox::Information
1378 \li QMessageBox::Warning
1379 \li QMessageBox::Critical
1380 \endlist
1381
1382 The default is QMessageBox::NoIcon.
1383
1384 The pixmap used to display the actual icon depends on the current
1385 \l{QWidget::style()} {GUI style}. You can also set a custom pixmap
1386 for the icon by setting the \l{QMessageBox::iconPixmap} {icon
1387 pixmap} property.
1388
1389 \sa iconPixmap
1390*/
1391QMessageBox::Icon QMessageBox::icon() const
1392{
1393 Q_D(const QMessageBox);
1394 return d->icon;
1395}
1396
1397void QMessageBox::setIcon(Icon icon)
1398{
1399 Q_D(QMessageBox);
1400 setIconPixmap(QMessageBoxPrivate::standardIcon(icon: (QMessageBox::Icon)icon,
1401 mb: this));
1402 d->icon = icon;
1403}
1404
1405/*!
1406 \property QMessageBox::iconPixmap
1407 \brief the current icon
1408
1409 The icon currently used by the message box. Note that it's often
1410 hard to draw one pixmap that looks appropriate in all GUI styles;
1411 you may want to supply a different pixmap for each platform.
1412
1413 By default, this property is undefined.
1414
1415 \sa icon
1416*/
1417QPixmap QMessageBox::iconPixmap() const
1418{
1419 Q_D(const QMessageBox);
1420 return d->iconLabel->pixmap();
1421}
1422
1423void QMessageBox::setIconPixmap(const QPixmap &pixmap)
1424{
1425 Q_D(QMessageBox);
1426 d->iconLabel->setPixmap(pixmap);
1427 d->icon = NoIcon;
1428 d->setupLayout();
1429}
1430
1431/*!
1432 \property QMessageBox::textFormat
1433 \brief the format of the text displayed by the message box
1434
1435 The current text format used by the message box. See the \l
1436 Qt::TextFormat enum for an explanation of the possible options.
1437
1438 The default format is Qt::AutoText.
1439
1440 \sa setText()
1441*/
1442Qt::TextFormat QMessageBox::textFormat() const
1443{
1444 Q_D(const QMessageBox);
1445 return d->label->textFormat();
1446}
1447
1448void QMessageBox::setTextFormat(Qt::TextFormat format)
1449{
1450 Q_D(QMessageBox);
1451 d->label->setTextFormat(format);
1452 d->label->setWordWrap(format == Qt::RichText
1453 || (format == Qt::AutoText && Qt::mightBeRichText(d->label->text())));
1454 if (d->informativeLabel)
1455 d->informativeLabel->setTextFormat(format);
1456 d->updateSize();
1457}
1458
1459/*!
1460 \property QMessageBox::textInteractionFlags
1461 \since 5.1
1462
1463 Specifies how the label of the message box should interact with user
1464 input.
1465
1466 The default value depends on the style.
1467
1468 \sa QStyle::SH_MessageBox_TextInteractionFlags
1469*/
1470
1471Qt::TextInteractionFlags QMessageBox::textInteractionFlags() const
1472{
1473 Q_D(const QMessageBox);
1474 return d->label->textInteractionFlags();
1475}
1476
1477void QMessageBox::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1478{
1479 Q_D(QMessageBox);
1480 d->label->setTextInteractionFlags(flags);
1481}
1482
1483/*!
1484 \reimp
1485*/
1486bool QMessageBox::event(QEvent *e)
1487{
1488 bool result =QDialog::event(event: e);
1489 switch (e->type()) {
1490 case QEvent::LayoutRequest:
1491 d_func()->updateSize();
1492 break;
1493 case QEvent::LanguageChange:
1494 d_func()->retranslateStrings();
1495 break;
1496 default:
1497 break;
1498 }
1499 return result;
1500}
1501
1502/*!
1503 \reimp
1504*/
1505void QMessageBox::resizeEvent(QResizeEvent *event)
1506{
1507 QDialog::resizeEvent(event);
1508}
1509
1510/*!
1511 \reimp
1512*/
1513void QMessageBox::closeEvent(QCloseEvent *e)
1514{
1515 Q_D(QMessageBox);
1516 if (!d->detectedEscapeButton) {
1517 e->ignore();
1518 return;
1519 }
1520 QDialog::closeEvent(e);
1521 if (!d->clickedButton) {
1522 d->clickedButton = d->detectedEscapeButton;
1523 setResult(d->execReturnCode(button: d->detectedEscapeButton));
1524 }
1525}
1526
1527/*!
1528 \reimp
1529*/
1530void QMessageBox::changeEvent(QEvent *ev)
1531{
1532 Q_D(QMessageBox);
1533 switch (ev->type()) {
1534 case QEvent::StyleChange:
1535 {
1536 if (d->icon != NoIcon)
1537 setIcon(d->icon);
1538 Qt::TextInteractionFlags flags(style()->styleHint(stylehint: QStyle::SH_MessageBox_TextInteractionFlags, opt: nullptr, widget: this));
1539 d->label->setTextInteractionFlags(flags);
1540 d->buttonBox->setCenterButtons(style()->styleHint(stylehint: QStyle::SH_MessageBox_CenterButtons, opt: nullptr, widget: this));
1541 if (d->informativeLabel)
1542 d->informativeLabel->setTextInteractionFlags(flags);
1543 Q_FALLTHROUGH();
1544 }
1545 case QEvent::FontChange:
1546 case QEvent::ApplicationFontChange:
1547#ifdef Q_OS_MAC
1548 {
1549 QFont f = font();
1550 f.setBold(true);
1551 d->label->setFont(f);
1552 }
1553#endif
1554 Q_FALLTHROUGH();
1555 default:
1556 break;
1557 }
1558 QDialog::changeEvent(ev);
1559}
1560
1561/*!
1562 \reimp
1563*/
1564void QMessageBox::keyPressEvent(QKeyEvent *e)
1565{
1566#if QT_CONFIG(shortcut)
1567 Q_D(QMessageBox);
1568 if (e->matches(key: QKeySequence::Cancel)) {
1569 if (d->detectedEscapeButton) {
1570#ifdef Q_OS_MAC
1571 d->detectedEscapeButton->animateClick();
1572#else
1573 d->detectedEscapeButton->click();
1574#endif
1575 }
1576 return;
1577 }
1578#endif // QT_CONFIG(shortcut)
1579
1580#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
1581
1582#if QT_CONFIG(textedit)
1583 if (e == QKeySequence::Copy) {
1584 if (d->detailsText && d->detailsText->isVisible() && d->detailsText->copy()) {
1585 e->setAccepted(true);
1586 return;
1587 }
1588 } else if (e == QKeySequence::SelectAll && d->detailsText && d->detailsText->isVisible()) {
1589 d->detailsText->selectAll();
1590 e->setAccepted(true);
1591 return;
1592 }
1593#endif // QT_CONFIG(textedit)
1594
1595#if defined(Q_OS_WIN)
1596 if (e == QKeySequence::Copy) {
1597 const auto separator = "---------------------------\n"_L1;
1598 QString textToCopy;
1599 textToCopy += separator + windowTitle() + u'\n' + separator // title
1600 + d->label->text() + u'\n' + separator; // text
1601
1602 if (d->informativeLabel)
1603 textToCopy += d->informativeLabel->text() + u'\n' + separator;
1604
1605 const QList<QAbstractButton *> buttons = d->buttonBox->buttons();
1606 for (const auto *button : buttons)
1607 textToCopy += button->text() + " "_L1;
1608 textToCopy += u'\n' + separator;
1609#if QT_CONFIG(textedit)
1610 if (d->detailsText)
1611 textToCopy += d->detailsText->text() + u'\n' + separator;
1612#endif
1613 QGuiApplication::clipboard()->setText(textToCopy);
1614 return;
1615 }
1616#endif // Q_OS_WIN
1617
1618#endif // !QT_NO_CLIPBOARD && !QT_NO_SHORTCUT
1619
1620#ifndef QT_NO_SHORTCUT
1621 if (!(e->modifiers() & (Qt::AltModifier | Qt::ControlModifier | Qt::MetaModifier))) {
1622 int key = e->key() & ~Qt::MODIFIER_MASK;
1623 if (key) {
1624 const QList<QAbstractButton *> buttons = d->buttonBox->buttons();
1625 for (auto *pb : buttons) {
1626 QKeySequence shortcut = pb->shortcut();
1627 if (!shortcut.isEmpty() && key == shortcut[0].key()) {
1628 pb->animateClick();
1629 return;
1630 }
1631 }
1632 }
1633 }
1634#endif
1635 QDialog::keyPressEvent(e);
1636}
1637
1638/*!
1639 Opens the dialog and connects its finished() or buttonClicked() signal to
1640 the slot specified by \a receiver and \a member. If the slot in \a member
1641 has a pointer for its first parameter the connection is to buttonClicked(),
1642 otherwise the connection is to finished().
1643
1644 The signal will be disconnected from the slot when the dialog is closed.
1645*/
1646void QMessageBox::open(QObject *receiver, const char *member)
1647{
1648 Q_D(QMessageBox);
1649 const char *signal = member && strchr(s: member, c: '*') ? SIGNAL(buttonClicked(QAbstractButton*))
1650 : SIGNAL(finished(int));
1651 connect(sender: this, signal, receiver, member);
1652 d->signalToDisconnectOnClose = signal;
1653 d->receiverToDisconnectOnClose = receiver;
1654 d->memberToDisconnectOnClose = member;
1655 QDialog::open();
1656}
1657
1658void QMessageBoxPrivate::setVisible(bool visible)
1659{
1660 // Last minute setup
1661 if (visible) {
1662 Q_Q(QMessageBox);
1663 if (autoAddOkButton)
1664 q->addButton(button: QMessageBox::Ok);
1665 detectEscapeButton();
1666 }
1667 // On hide, we may be called from ~QDialog(), so prevent accessing
1668 // q_ptr as a QMessageBox!
1669
1670 if (canBeNativeDialog())
1671 setNativeDialogVisible(visible);
1672
1673 // Update WA_DontShowOnScreen based on whether the native dialog was shown,
1674 // so that QDialog::setVisible(visible) below updates the QWidget state correctly,
1675 // but skips showing the non-native version.
1676 static_cast<QWidget*>(q_ptr)->setAttribute(Qt::WA_DontShowOnScreen, on: nativeDialogInUse);
1677
1678 QDialogPrivate::setVisible(visible);
1679}
1680
1681/*!
1682 Returns a list of all the buttons that have been added to the message box.
1683
1684 \sa buttonRole(), addButton(), removeButton()
1685*/
1686QList<QAbstractButton *> QMessageBox::buttons() const
1687{
1688 Q_D(const QMessageBox);
1689 return d->buttonBox->buttons();
1690}
1691
1692/*!
1693 Returns the button role for the specified \a button. This function returns
1694 \l InvalidRole if \a button is \nullptr or has not been added to the message box.
1695
1696 \sa buttons(), addButton()
1697*/
1698QMessageBox::ButtonRole QMessageBox::buttonRole(QAbstractButton *button) const
1699{
1700 Q_D(const QMessageBox);
1701 return QMessageBox::ButtonRole(d->buttonBox->buttonRole(button));
1702}
1703
1704/*!
1705 \reimp
1706*/
1707void QMessageBox::showEvent(QShowEvent *e)
1708{
1709 Q_D(QMessageBox);
1710 d->clickedButton = nullptr;
1711 d->updateSize();
1712
1713#if QT_CONFIG(accessibility)
1714 QAccessibleEvent event(this, QAccessible::Alert);
1715 QAccessible::updateAccessibility(event: &event);
1716#endif
1717#if defined(Q_OS_WIN)
1718 if (const HMENU systemMenu = qt_getWindowsSystemMenu(this)) {
1719 EnableMenuItem(systemMenu, SC_CLOSE, d->detectedEscapeButton ?
1720 MF_BYCOMMAND|MF_ENABLED : MF_BYCOMMAND|MF_GRAYED);
1721 }
1722#endif
1723 QDialog::showEvent(e);
1724}
1725
1726
1727static QMessageBox::StandardButton showNewMessageBox(QWidget *parent,
1728 QMessageBox::Icon icon,
1729 const QString& title, const QString& text,
1730 QMessageBox::StandardButtons buttons,
1731 QMessageBox::StandardButton defaultButton)
1732{
1733 // necessary for source compatibility with Qt 4.0 and 4.1
1734 // handles (Yes, No) and (Yes|Default, No)
1735 if (defaultButton && !(buttons & defaultButton)) {
1736 const int defaultButtons = defaultButton | QMessageBox::Default;
1737 const int otherButtons = buttons.toInt();
1738 const int ret = QMessageBoxPrivate::showOldMessageBox(parent, icon, title,
1739 text, button0: otherButtons,
1740 button1: defaultButtons, button2: 0);
1741 return static_cast<QMessageBox::StandardButton>(ret);
1742 }
1743
1744 QMessageBox msgBox(icon, title, text, QMessageBox::NoButton, parent);
1745 QDialogButtonBox *buttonBox = msgBox.findChild<QDialogButtonBox*>();
1746 Q_ASSERT(buttonBox != nullptr);
1747
1748 uint mask = QMessageBox::FirstButton;
1749 while (mask <= QMessageBox::LastButton) {
1750 uint sb = buttons & mask;
1751 mask <<= 1;
1752 if (!sb)
1753 continue;
1754 QPushButton *button = msgBox.addButton(button: (QMessageBox::StandardButton)sb);
1755 // Choose the first accept role as the default
1756 if (msgBox.defaultButton())
1757 continue;
1758 if ((defaultButton == QMessageBox::NoButton && buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole)
1759 || (defaultButton != QMessageBox::NoButton && sb == uint(defaultButton)))
1760 msgBox.setDefaultButton(button);
1761 }
1762 if (msgBox.exec() == -1)
1763 return QMessageBox::Cancel;
1764 return msgBox.standardButton(button: msgBox.clickedButton());
1765}
1766
1767/*!
1768 Opens an information message box with the given \a title and
1769 \a text in front of the specified \a parent widget.
1770
1771 The standard \a buttons are added to the message box.
1772 \a defaultButton specifies the button used when \uicontrol Enter is pressed.
1773 \a defaultButton must refer to a button that was given in \a buttons.
1774 If \a defaultButton is QMessageBox::NoButton, QMessageBox
1775 chooses a suitable default automatically.
1776
1777 Returns the identity of the standard button that was clicked. If
1778 \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
1779 {escape button} is returned.
1780
1781 The message box is an \l{Qt::ApplicationModal}{application modal}
1782 dialog box.
1783
1784 \warning Do not delete \a parent during the execution of the dialog.
1785 If you want to do this, you should create the dialog
1786 yourself using one of the QMessageBox constructors.
1787
1788 \sa question(), warning(), critical()
1789*/
1790QMessageBox::StandardButton QMessageBox::information(QWidget *parent, const QString &title,
1791 const QString& text, StandardButtons buttons,
1792 StandardButton defaultButton)
1793{
1794 return showNewMessageBox(parent, icon: Information, title, text, buttons,
1795 defaultButton);
1796}
1797
1798
1799/*!
1800 Opens a question message box with the given \a title and \a
1801 text in front of the specified \a parent widget.
1802
1803 The standard \a buttons are added to the message box. \a
1804 defaultButton specifies the button used when \uicontrol Enter is
1805 pressed. \a defaultButton must refer to a button that was given in \a buttons.
1806 If \a defaultButton is QMessageBox::NoButton, QMessageBox
1807 chooses a suitable default automatically.
1808
1809 Returns the identity of the standard button that was clicked. If
1810 \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
1811 {escape button} is returned.
1812
1813 The message box is an \l{Qt::ApplicationModal} {application modal}
1814 dialog box.
1815
1816 \warning Do not delete \a parent during the execution of the dialog.
1817 If you want to do this, you should create the dialog
1818 yourself using one of the QMessageBox constructors.
1819
1820 \sa information(), warning(), critical()
1821*/
1822QMessageBox::StandardButton QMessageBox::question(QWidget *parent, const QString &title,
1823 const QString& text, StandardButtons buttons,
1824 StandardButton defaultButton)
1825{
1826 return showNewMessageBox(parent, icon: Question, title, text, buttons, defaultButton);
1827}
1828
1829/*!
1830 Opens a warning message box with the given \a title and \a
1831 text in front of the specified \a parent widget.
1832
1833 The standard \a buttons are added to the message box. \a
1834 defaultButton specifies the button used when \uicontrol Enter is
1835 pressed. \a defaultButton must refer to a button that was given in \a buttons.
1836 If \a defaultButton is QMessageBox::NoButton, QMessageBox
1837 chooses a suitable default automatically.
1838
1839 Returns the identity of the standard button that was clicked. If
1840 \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
1841 {escape button} is returned.
1842
1843 The message box is an \l{Qt::ApplicationModal} {application modal}
1844 dialog box.
1845
1846 \warning Do not delete \a parent during the execution of the dialog.
1847 If you want to do this, you should create the dialog
1848 yourself using one of the QMessageBox constructors.
1849
1850 \sa question(), information(), critical()
1851*/
1852QMessageBox::StandardButton QMessageBox::warning(QWidget *parent, const QString &title,
1853 const QString& text, StandardButtons buttons,
1854 StandardButton defaultButton)
1855{
1856 return showNewMessageBox(parent, icon: Warning, title, text, buttons, defaultButton);
1857}
1858
1859/*!
1860 Opens a critical message box with the given \a title and \a
1861 text in front of the specified \a parent widget.
1862
1863 The standard \a buttons are added to the message box. \a
1864 defaultButton specifies the button used when \uicontrol Enter is
1865 pressed. \a defaultButton must refer to a button that was given in \a buttons.
1866 If \a defaultButton is QMessageBox::NoButton, QMessageBox
1867 chooses a suitable default automatically.
1868
1869 Returns the identity of the standard button that was clicked. If
1870 \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
1871 {escape button} is returned.
1872
1873 The message box is an \l{Qt::ApplicationModal} {application modal}
1874 dialog box.
1875
1876 \warning Do not delete \a parent during the execution of the dialog.
1877 If you want to do this, you should create the dialog
1878 yourself using one of the QMessageBox constructors.
1879
1880 \sa question(), warning(), information()
1881*/
1882QMessageBox::StandardButton QMessageBox::critical(QWidget *parent, const QString &title,
1883 const QString& text, StandardButtons buttons,
1884 StandardButton defaultButton)
1885{
1886 return showNewMessageBox(parent, icon: Critical, title, text, buttons, defaultButton);
1887}
1888
1889/*!
1890 Displays a simple about box with title \a title and text \a
1891 text. The about box's parent is \a parent.
1892
1893 about() looks for a suitable icon in four locations:
1894
1895 \list 1
1896 \li It prefers \l{QWidget::windowIcon()}{parent->icon()}
1897 if that exists.
1898 \li If not, it tries the top-level widget containing \a parent.
1899 \li If that fails, it tries the \l{QApplication::activeWindow()}{active window.}
1900 \li As a last resort it uses the Information icon.
1901 \endlist
1902
1903 The about box has a single button labelled "OK".
1904
1905 On \macos, the about box is popped up as a modeless window; on
1906 other platforms, it is currently application modal.
1907
1908 \sa QWidget::windowIcon(), QApplication::activeWindow()
1909*/
1910void QMessageBox::about(QWidget *parent, const QString &title, const QString &text)
1911{
1912#ifdef Q_OS_MAC
1913 static QPointer<QMessageBox> oldMsgBox;
1914
1915 if (oldMsgBox && oldMsgBox->text() == text) {
1916 oldMsgBox->show();
1917 oldMsgBox->raise();
1918 oldMsgBox->activateWindow();
1919 return;
1920 }
1921#endif
1922
1923 QMessageBox *msgBox = new QMessageBox(Information, title, text, NoButton, parent
1924#ifdef Q_OS_MAC
1925 , Qt::WindowTitleHint | Qt::WindowSystemMenuHint
1926#endif
1927 );
1928 msgBox->setAttribute(Qt::WA_DeleteOnClose);
1929 QIcon icon = msgBox->windowIcon();
1930 msgBox->setIconPixmap(icon.pixmap(size: QSize(64, 64), devicePixelRatio: msgBox->devicePixelRatio()));
1931
1932 // should perhaps be a style hint
1933#ifdef Q_OS_MAC
1934 oldMsgBox = msgBox;
1935 auto *d = msgBox->d_func();
1936 d->buttonBox->setCenterButtons(true);
1937#ifdef Q_OS_IOS
1938 msgBox->setModal(true);
1939#else
1940 msgBox->setModal(false);
1941#endif
1942 msgBox->show();
1943#else
1944 msgBox->exec();
1945#endif
1946}
1947
1948/*!
1949 Displays a simple message box about Qt, with the given \a title
1950 and centered over \a parent (if \a parent is not \nullptr). The message
1951 includes the version number of Qt being used by the application.
1952
1953 This is useful for inclusion in the \uicontrol Help menu of an application,
1954 as shown in the \l{mainwindows/menus}{Menus} example.
1955
1956 QApplication provides this functionality as a slot.
1957
1958 On \macos, the aboutQt box is popped up as a modeless window; on
1959 other platforms, it is currently application modal.
1960
1961 \sa QApplication::aboutQt()
1962*/
1963void QMessageBox::aboutQt(QWidget *parent, const QString &title)
1964{
1965#ifdef Q_OS_MAC
1966 static QPointer<QMessageBox> oldMsgBox;
1967
1968 if (oldMsgBox) {
1969 oldMsgBox->show();
1970 oldMsgBox->raise();
1971 oldMsgBox->activateWindow();
1972 return;
1973 }
1974#endif
1975
1976 QString translatedTextAboutQtCaption;
1977 translatedTextAboutQtCaption = QMessageBox::tr(
1978 s: "<h3>About Qt</h3>"
1979 "<p>This program uses Qt version %1.</p>"
1980 ).arg(QT_VERSION_STR ""_L1);
1981 //: Leave this text untranslated or include a verbatim copy of it below
1982 //: and note that it is the authoritative version in case of doubt.
1983 const QString translatedTextAboutQtText = QMessageBox::tr(
1984 s: "<p>Qt is a C++ toolkit for cross-platform application "
1985 "development.</p>"
1986 "<p>Qt provides single-source portability across all major desktop "
1987 "operating systems. It is also available for embedded Linux and other "
1988 "embedded and mobile operating systems.</p>"
1989 "<p>Qt is available under multiple licensing options designed "
1990 "to accommodate the needs of our various users.</p>"
1991 "<p>Qt licensed under our commercial license agreement is appropriate "
1992 "for development of proprietary/commercial software where you do not "
1993 "want to share any source code with third parties or otherwise cannot "
1994 "comply with the terms of GNU (L)GPL.</p>"
1995 "<p>Qt licensed under GNU (L)GPL is appropriate for the "
1996 "development of Qt&nbsp;applications provided you can comply with the terms "
1997 "and conditions of the respective licenses.</p>"
1998 "<p>Please see <a href=\"https://%2/\">%2</a> "
1999 "for an overview of Qt licensing.</p>"
2000 "<p>Copyright (C) The Qt Company Ltd. and other "
2001 "contributors.</p>"
2002 "<p>Qt and the Qt logo are trademarks of The Qt Company Ltd.</p>"
2003 "<p>Qt is The Qt Company Ltd. product developed as an open source "
2004 "project. See <a href=\"https://%3/\">%3</a> for more information.</p>"
2005 ).arg(QStringLiteral("qt.io/licensing"),
2006 QStringLiteral("qt.io"));
2007 QMessageBox *msgBox = new QMessageBox(parent);
2008 msgBox->setAttribute(Qt::WA_DeleteOnClose);
2009 msgBox->setWindowTitle(title.isEmpty() ? tr(s: "About Qt") : title);
2010 msgBox->setText(translatedTextAboutQtCaption);
2011 msgBox->setInformativeText(translatedTextAboutQtText);
2012
2013 QPixmap pm(":/qt-project.org/qmessagebox/images/qtlogo-64.png"_L1);
2014 if (!pm.isNull())
2015 msgBox->setIconPixmap(pm);
2016
2017 // should perhaps be a style hint
2018#ifdef Q_OS_MAC
2019 oldMsgBox = msgBox;
2020 auto *d = msgBox->d_func();
2021 d->buttonBox->setCenterButtons(true);
2022#ifdef Q_OS_IOS
2023 msgBox->setModal(true);
2024#else
2025 msgBox->setModal(false);
2026#endif
2027 msgBox->show();
2028#else
2029 msgBox->exec();
2030#endif
2031}
2032
2033/////////////////////////////////////////////////////////////////////////////////////////
2034// Source and binary compatibility routines for 4.0 and 4.1
2035
2036static QMessageBox::StandardButton newButton(int button)
2037{
2038 // this is needed for source compatibility with Qt 4.0 and 4.1
2039 if (button == QMessageBox::NoButton || (button & NewButtonMask))
2040 return QMessageBox::StandardButton(button & QMessageBox::ButtonMask);
2041
2042 return QMessageBox::NoButton;
2043}
2044
2045static bool detectedCompat(int button0, int button1, int button2)
2046{
2047 if (button0 != 0 && !(button0 & NewButtonMask))
2048 return true;
2049 if (button1 != 0 && !(button1 & NewButtonMask))
2050 return true;
2051 if (button2 != 0 && !(button2 & NewButtonMask))
2052 return true;
2053 return false;
2054}
2055
2056QAbstractButton *QMessageBoxPrivate::findButton(int button0, int button1, int button2, int flags)
2057{
2058 Q_Q(QMessageBox);
2059 int button = 0;
2060
2061 if (button0 & flags) {
2062 button = button0;
2063 } else if (button1 & flags) {
2064 button = button1;
2065 } else if (button2 & flags) {
2066 button = button2;
2067 }
2068 return q->button(which: newButton(button));
2069}
2070
2071void QMessageBoxPrivate::addOldButtons(int button0, int button1, int button2)
2072{
2073 Q_Q(QMessageBox);
2074 q->addButton(button: newButton(button: button0));
2075 q->addButton(button: newButton(button: button1));
2076 q->addButton(button: newButton(button: button2));
2077 q->setDefaultButton(
2078 static_cast<QPushButton *>(findButton(button0, button1, button2, flags: QMessageBox::Default)));
2079 q->setEscapeButton(findButton(button0, button1, button2, flags: QMessageBox::Escape));
2080 compatMode = detectedCompat(button0, button1, button2);
2081}
2082
2083QAbstractButton *QMessageBoxPrivate::abstractButtonForId(int id) const
2084{
2085 Q_Q(const QMessageBox);
2086 QAbstractButton *result = customButtonList.value(i: id);
2087 if (result)
2088 return result;
2089 if (id & QMessageBox::FlagMask) // for compatibility with Qt 4.0/4.1 (even if it is silly)
2090 return nullptr;
2091 return q->button(which: newButton(button: id));
2092}
2093
2094int QMessageBoxPrivate::showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
2095 const QString &title, const QString &text,
2096 int button0, int button1, int button2)
2097{
2098 QMessageBox messageBox(icon, title, text, QMessageBox::NoButton, parent);
2099 messageBox.d_func()->addOldButtons(button0, button1, button2);
2100 return messageBox.exec();
2101}
2102
2103int QMessageBoxPrivate::showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
2104 const QString &title, const QString &text,
2105 const QString &button0Text,
2106 const QString &button1Text,
2107 const QString &button2Text,
2108 int defaultButtonNumber,
2109 int escapeButtonNumber)
2110{
2111 QMessageBox messageBox(icon, title, text, QMessageBox::NoButton, parent);
2112 QString myButton0Text = button0Text;
2113 if (myButton0Text.isEmpty())
2114 myButton0Text = QDialogButtonBox::tr(s: "OK");
2115 messageBox.addButton(text: myButton0Text, role: QMessageBox::ActionRole);
2116 if (!button1Text.isEmpty())
2117 messageBox.addButton(text: button1Text, role: QMessageBox::ActionRole);
2118 if (!button2Text.isEmpty())
2119 messageBox.addButton(text: button2Text, role: QMessageBox::ActionRole);
2120
2121 const QList<QAbstractButton *> &buttonList = messageBox.d_func()->customButtonList;
2122 messageBox.setDefaultButton(static_cast<QPushButton *>(buttonList.value(i: defaultButtonNumber)));
2123 messageBox.setEscapeButton(buttonList.value(i: escapeButtonNumber));
2124
2125 messageBox.exec();
2126
2127 // Ignore exec return value and use button index instead,
2128 // as that's what the documentation promises.
2129 return buttonList.indexOf(t: messageBox.clickedButton());
2130}
2131
2132void QMessageBoxPrivate::retranslateStrings()
2133{
2134#if QT_CONFIG(textedit)
2135 if (detailsButton && detailsText)
2136 detailsButton->setLabel(detailsText->isHidden() ? ShowLabel : HideLabel);
2137#endif
2138}
2139
2140#if QT_DEPRECATED_SINCE(6,2)
2141/*!
2142 \deprecated
2143
2144 Constructs a message box with a \a title, a \a text, an \a icon,
2145 and up to three buttons.
2146
2147 The \a icon must be one of the following:
2148 \list
2149 \li QMessageBox::NoIcon
2150 \li QMessageBox::Question
2151 \li QMessageBox::Information
2152 \li QMessageBox::Warning
2153 \li QMessageBox::Critical
2154 \endlist
2155
2156 Each button, \a button0, \a button1 and \a button2, can have one
2157 of the following values:
2158 \list
2159 \li QMessageBox::NoButton
2160 \li QMessageBox::Ok
2161 \li QMessageBox::Cancel
2162 \li QMessageBox::Yes
2163 \li QMessageBox::No
2164 \li QMessageBox::Abort
2165 \li QMessageBox::Retry
2166 \li QMessageBox::Ignore
2167 \li QMessageBox::YesAll
2168 \li QMessageBox::NoAll
2169 \endlist
2170
2171 Use QMessageBox::NoButton for the later parameters to have fewer
2172 than three buttons in your message box. If you don't specify any
2173 buttons at all, QMessageBox will provide an Ok button.
2174
2175 One of the buttons can be OR-ed with the QMessageBox::Default
2176 flag to make it the default button (clicked when Enter is
2177 pressed).
2178
2179 One of the buttons can be OR-ed with the QMessageBox::Escape flag
2180 to make it the cancel or close button (clicked when \uicontrol Esc is
2181 pressed).
2182
2183 \snippet dialogs/dialogs.cpp 2
2184
2185 The message box is an \l{Qt::ApplicationModal} {application modal}
2186 dialog box.
2187
2188 The \a parent and \a f arguments are passed to
2189 the QDialog constructor.
2190
2191 \sa setWindowTitle(), setText(), setIcon()
2192*/
2193QMessageBox::QMessageBox(const QString &title, const QString &text, Icon icon,
2194 int button0, int button1, int button2, QWidget *parent,
2195 Qt::WindowFlags f)
2196 : QDialog(*new QMessageBoxPrivate, parent,
2197 f /*| Qt::MSWindowsFixedSizeDialogHint #### */| Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
2198{
2199 Q_D(QMessageBox);
2200 d->init(title, text);
2201 setIcon(icon);
2202 d->addOldButtons(button0, button1, button2);
2203}
2204
2205/*!
2206 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2207
2208 Opens an information message box with the given \a title and the
2209 \a text. The dialog may have up to three buttons. Each of the
2210 buttons, \a button0, \a button1 and \a button2 may be set to one
2211 of the following values:
2212
2213 \list
2214 \li QMessageBox::NoButton
2215 \li QMessageBox::Ok
2216 \li QMessageBox::Cancel
2217 \li QMessageBox::Yes
2218 \li QMessageBox::No
2219 \li QMessageBox::Abort
2220 \li QMessageBox::Retry
2221 \li QMessageBox::Ignore
2222 \li QMessageBox::YesAll
2223 \li QMessageBox::NoAll
2224 \endlist
2225
2226 If you don't want all three buttons, set the last button, or last
2227 two buttons to QMessageBox::NoButton.
2228
2229 One button can be OR-ed with QMessageBox::Default, and one
2230 button can be OR-ed with QMessageBox::Escape.
2231
2232 Returns the identity (QMessageBox::Ok, or QMessageBox::No, etc.)
2233 of the button that was clicked.
2234
2235 The message box is an \l{Qt::ApplicationModal} {application modal}
2236 dialog box.
2237
2238 \warning Do not delete \a parent during the execution of the dialog.
2239 If you want to do this, you should create the dialog
2240 yourself using one of the QMessageBox constructors.
2241
2242 \sa question(), warning(), critical()
2243*/
2244int QMessageBox::information(QWidget *parent, const QString &title, const QString& text,
2245 int button0, int button1, int button2)
2246{
2247 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Information, title, text,
2248 button0, button1, button2);
2249}
2250
2251/*!
2252 \deprecated [6.2] Use the overload taking StandardButtons instead.
2253 \overload
2254
2255 Displays an information message box with the given \a title and
2256 \a text, as well as one, two or three buttons. Returns the index
2257 of the button that was clicked (0, 1 or 2).
2258
2259 \a button0Text is the text of the first button, and is optional.
2260 If \a button0Text is not supplied, "OK" (translated) will be
2261 used. \a button1Text is the text of the second button, and is
2262 optional. \a button2Text is the text of the third button, and is
2263 optional. \a defaultButtonNumber (0, 1 or 2) is the index of the
2264 default button; pressing Return or Enter is the same as clicking
2265 the default button. It defaults to 0 (the first button). \a
2266 escapeButtonNumber is the index of the escape button; pressing
2267 \uicontrol Esc is the same as clicking this button. It defaults to -1;
2268 supply 0, 1 or 2 to make pressing \uicontrol Esc equivalent to clicking
2269 the relevant button.
2270
2271 The message box is an \l{Qt::ApplicationModal} {application modal}
2272 dialog box.
2273
2274 \warning Do not delete \a parent during the execution of the dialog.
2275 If you want to do this, you should create the dialog
2276 yourself using one of the QMessageBox constructors.
2277
2278 \sa question(), warning(), critical()
2279*/
2280
2281int QMessageBox::information(QWidget *parent, const QString &title, const QString& text,
2282 const QString& button0Text, const QString& button1Text,
2283 const QString& button2Text, int defaultButtonNumber,
2284 int escapeButtonNumber)
2285{
2286 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Information, title, text,
2287 button0Text, button1Text, button2Text,
2288 defaultButtonNumber, escapeButtonNumber);
2289}
2290
2291/*!
2292 \deprecated [6.2]. Use the overload taking StandardButtons
2293 instead.
2294
2295 Opens a question message box with the given \a title and \a text.
2296 The dialog may have up to three buttons. Each of the buttons, \a
2297 button0, \a button1 and \a button2 may be set to one of the
2298 following values:
2299
2300 \list
2301 \li QMessageBox::NoButton
2302 \li QMessageBox::Ok
2303 \li QMessageBox::Cancel
2304 \li QMessageBox::Yes
2305 \li QMessageBox::No
2306 \li QMessageBox::Abort
2307 \li QMessageBox::Retry
2308 \li QMessageBox::Ignore
2309 \li QMessageBox::YesAll
2310 \li QMessageBox::NoAll
2311 \endlist
2312
2313 If you don't want all three buttons, set the last button, or last
2314 two buttons to QMessageBox::NoButton.
2315
2316 One button can be OR-ed with QMessageBox::Default, and one
2317 button can be OR-ed with QMessageBox::Escape.
2318
2319 Returns the identity (QMessageBox::Yes, or QMessageBox::No, etc.)
2320 of the button that was clicked.
2321
2322 The message box is an \l{Qt::ApplicationModal} {application modal}
2323 dialog box.
2324
2325 \warning Do not delete \a parent during the execution of the dialog.
2326 If you want to do this, you should create the dialog
2327 yourself using one of the QMessageBox constructors.
2328
2329 \sa information(), warning(), critical()
2330*/
2331int QMessageBox::question(QWidget *parent, const QString &title, const QString& text,
2332 int button0, int button1, int button2)
2333{
2334 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Question, title, text,
2335 button0, button1, button2);
2336}
2337
2338/*!
2339 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2340 \overload
2341
2342 Displays a question message box with the given \a title and \a
2343 text, as well as one, two or three buttons. Returns the index of
2344 the button that was clicked (0, 1 or 2).
2345
2346 \a button0Text is the text of the first button, and is optional.
2347 If \a button0Text is not supplied, "OK" (translated) will be used.
2348 \a button1Text is the text of the second button, and is optional.
2349 \a button2Text is the text of the third button, and is optional.
2350 \a defaultButtonNumber (0, 1 or 2) is the index of the default
2351 button; pressing Return or Enter is the same as clicking the
2352 default button. It defaults to 0 (the first button). \a
2353 escapeButtonNumber is the index of the Escape button; pressing
2354 Escape is the same as clicking this button. It defaults to -1;
2355 supply 0, 1 or 2 to make pressing Escape equivalent to clicking
2356 the relevant button.
2357
2358 The message box is an \l{Qt::ApplicationModal} {application modal}
2359 dialog box.
2360
2361 \warning Do not delete \a parent during the execution of the dialog.
2362 If you want to do this, you should create the dialog
2363 yourself using one of the QMessageBox constructors.
2364
2365 \sa information(), warning(), critical()
2366*/
2367int QMessageBox::question(QWidget *parent, const QString &title, const QString& text,
2368 const QString& button0Text, const QString& button1Text,
2369 const QString& button2Text, int defaultButtonNumber,
2370 int escapeButtonNumber)
2371{
2372 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Question, title, text,
2373 button0Text, button1Text, button2Text,
2374 defaultButtonNumber, escapeButtonNumber);
2375}
2376
2377
2378/*!
2379 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2380
2381 Opens a warning message box with the given \a title and \a text.
2382 The dialog may have up to three buttons. Each of the button
2383 parameters, \a button0, \a button1 and \a button2 may be set to
2384 one of the following values:
2385
2386 \list
2387 \li QMessageBox::NoButton
2388 \li QMessageBox::Ok
2389 \li QMessageBox::Cancel
2390 \li QMessageBox::Yes
2391 \li QMessageBox::No
2392 \li QMessageBox::Abort
2393 \li QMessageBox::Retry
2394 \li QMessageBox::Ignore
2395 \li QMessageBox::YesAll
2396 \li QMessageBox::NoAll
2397 \endlist
2398
2399 If you don't want all three buttons, set the last button, or last
2400 two buttons to QMessageBox::NoButton.
2401
2402 One button can be OR-ed with QMessageBox::Default, and one
2403 button can be OR-ed with QMessageBox::Escape.
2404
2405 Returns the identity (QMessageBox::Ok or QMessageBox::No or ...)
2406 of the button that was clicked.
2407
2408 The message box is an \l{Qt::ApplicationModal} {application modal}
2409 dialog box.
2410
2411 \warning Do not delete \a parent during the execution of the dialog.
2412 If you want to do this, you should create the dialog
2413 yourself using one of the QMessageBox constructors.
2414
2415 \sa information(), question(), critical()
2416*/
2417int QMessageBox::warning(QWidget *parent, const QString &title, const QString& text,
2418 int button0, int button1, int button2)
2419{
2420 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Warning, title, text,
2421 button0, button1, button2);
2422}
2423
2424/*!
2425 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2426 \overload
2427
2428 Displays a warning message box with the given \a title and \a
2429 text, as well as one, two, or three buttons. Returns the number
2430 of the button that was clicked (0, 1, or 2).
2431
2432 \a button0Text is the text of the first button, and is optional.
2433 If \a button0Text is not supplied, "OK" (translated) will be used.
2434 \a button1Text is the text of the second button, and is optional,
2435 and \a button2Text is the text of the third button, and is
2436 optional. \a defaultButtonNumber (0, 1 or 2) is the index of the
2437 default button; pressing Return or Enter is the same as clicking
2438 the default button. It defaults to 0 (the first button). \a
2439 escapeButtonNumber is the index of the Escape button; pressing
2440 Escape is the same as clicking this button. It defaults to -1;
2441 supply 0, 1, or 2 to make pressing Escape equivalent to clicking
2442 the relevant button.
2443
2444 The message box is an \l{Qt::ApplicationModal} {application modal}
2445 dialog box.
2446
2447 \warning Do not delete \a parent during the execution of the dialog.
2448 If you want to do this, you should create the dialog
2449 yourself using one of the QMessageBox constructors.
2450
2451 \sa information(), question(), critical()
2452*/
2453int QMessageBox::warning(QWidget *parent, const QString &title, const QString& text,
2454 const QString& button0Text, const QString& button1Text,
2455 const QString& button2Text, int defaultButtonNumber,
2456 int escapeButtonNumber)
2457{
2458 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Warning, title, text,
2459 button0Text, button1Text, button2Text,
2460 defaultButtonNumber, escapeButtonNumber);
2461}
2462
2463/*!
2464 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2465
2466 Opens a critical message box with the given \a title and \a text.
2467 The dialog may have up to three buttons. Each of the button
2468 parameters, \a button0, \a button1 and \a button2 may be set to
2469 one of the following values:
2470
2471 \list
2472 \li QMessageBox::NoButton
2473 \li QMessageBox::Ok
2474 \li QMessageBox::Cancel
2475 \li QMessageBox::Yes
2476 \li QMessageBox::No
2477 \li QMessageBox::Abort
2478 \li QMessageBox::Retry
2479 \li QMessageBox::Ignore
2480 \li QMessageBox::YesAll
2481 \li QMessageBox::NoAll
2482 \endlist
2483
2484 If you don't want all three buttons, set the last button, or last
2485 two buttons to QMessageBox::NoButton.
2486
2487 One button can be OR-ed with QMessageBox::Default, and one
2488 button can be OR-ed with QMessageBox::Escape.
2489
2490 Returns the identity (QMessageBox::Ok, or QMessageBox::No, etc.)
2491 of the button that was clicked.
2492
2493 The message box is an \l{Qt::ApplicationModal} {application modal}
2494 dialog box.
2495
2496 \warning Do not delete \a parent during the execution of the dialog.
2497 If you want to do this, you should create the dialog
2498 yourself using one of the QMessageBox constructors.
2499
2500 \sa information(), question(), warning()
2501*/
2502
2503int QMessageBox::critical(QWidget *parent, const QString &title, const QString& text,
2504 int button0, int button1, int button2)
2505{
2506 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Critical, title, text,
2507 button0, button1, button2);
2508}
2509
2510/*!
2511 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2512 \overload
2513
2514 Displays a critical error message box with the given \a title and
2515 \a text, as well as one, two, or three buttons. Returns the
2516 number of the button that was clicked (0, 1 or 2).
2517
2518 \a button0Text is the text of the first button, and is optional.
2519 If \a button0Text is not supplied, "OK" (translated) will be used.
2520 \a button1Text is the text of the second button, and is optional,
2521 and \a button2Text is the text of the third button, and is
2522 optional. \a defaultButtonNumber (0, 1 or 2) is the index of the
2523 default button; pressing Return or Enter is the same as clicking
2524 the default button. It defaults to 0 (the first button). \a
2525 escapeButtonNumber is the index of the Escape button; pressing
2526 Escape is the same as clicking this button. It defaults to -1;
2527 supply 0, 1, or 2 to make pressing Escape equivalent to clicking
2528 the relevant button.
2529
2530 The message box is an \l{Qt::ApplicationModal} {application modal}
2531 dialog box.
2532
2533 \warning Do not delete \a parent during the execution of the dialog.
2534 If you want to do this, you should create the dialog
2535 yourself using one of the QMessageBox constructors.
2536
2537 \sa information(), question(), warning()
2538*/
2539int QMessageBox::critical(QWidget *parent, const QString &title, const QString& text,
2540 const QString& button0Text, const QString& button1Text,
2541 const QString& button2Text, int defaultButtonNumber,
2542 int escapeButtonNumber)
2543{
2544 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Critical, title, text,
2545 button0Text, button1Text, button2Text,
2546 defaultButtonNumber, escapeButtonNumber);
2547}
2548
2549
2550/*!
2551 \deprecated [6.2]
2552
2553 Returns the text of the message box button \a button, or
2554 an empty string if the message box does not contain the button.
2555
2556 Use button() and QPushButton::text() instead.
2557*/
2558QString QMessageBox::buttonText(int button) const
2559{
2560 Q_D(const QMessageBox);
2561
2562 if (QAbstractButton *abstractButton = d->abstractButtonForId(id: button)) {
2563 return abstractButton->text();
2564 } else if (d->buttonBox->buttons().isEmpty() && (button == Ok || button == Old_Ok)) {
2565 // for compatibility with Qt 4.0/4.1
2566 return QDialogButtonBox::tr(s: "OK");
2567 }
2568 return QString();
2569}
2570
2571/*!
2572 \deprecated [6.2]
2573
2574 Sets the text of the message box button \a button to \a text.
2575 Setting the text of a button that is not in the message box is
2576 silently ignored.
2577
2578 Use addButton() instead.
2579*/
2580void QMessageBox::setButtonText(int button, const QString &text)
2581{
2582 Q_D(QMessageBox);
2583 if (QAbstractButton *abstractButton = d->abstractButtonForId(id: button)) {
2584 abstractButton->setText(text);
2585 } else if (d->buttonBox->buttons().isEmpty() && (button == Ok || button == Old_Ok)) {
2586 // for compatibility with Qt 4.0/4.1
2587 addButton(button: QMessageBox::Ok)->setText(text);
2588 }
2589}
2590#endif // QT_DEPRECATED_SINCE(6,2)
2591
2592
2593#if QT_CONFIG(textedit)
2594/*!
2595 \property QMessageBox::detailedText
2596 \brief the text to be displayed in the details area.
2597
2598 The text will be interpreted as a plain text.
2599
2600 By default, this property contains an empty string.
2601
2602 \sa QMessageBox::text, QMessageBox::informativeText
2603*/
2604QString QMessageBox::detailedText() const
2605{
2606 Q_D(const QMessageBox);
2607 return d->detailsText ? d->detailsText->text() : QString();
2608}
2609
2610void QMessageBox::setDetailedText(const QString &text)
2611{
2612 Q_D(QMessageBox);
2613 if (text.isEmpty()) {
2614 if (d->detailsText) {
2615 d->detailsText->hide();
2616 d->detailsText->deleteLater();
2617 }
2618 d->detailsText = nullptr;
2619 removeButton(button: d->detailsButton);
2620 if (d->detailsButton) {
2621 d->detailsButton->hide();
2622 d->detailsButton->deleteLater();
2623 }
2624 d->detailsButton = nullptr;
2625 } else {
2626 if (!d->detailsText) {
2627 d->detailsText = new QMessageBoxDetailsText(this);
2628 d->detailsText->hide();
2629 }
2630 if (!d->detailsButton) {
2631 const bool autoAddOkButton = d->autoAddOkButton; // QTBUG-39334, addButton() clears the flag.
2632 d->detailsButton = new DetailButton(this);
2633 addButton(button: d->detailsButton, role: QMessageBox::ActionRole);
2634 d->autoAddOkButton = autoAddOkButton;
2635 }
2636 d->detailsText->setText(text);
2637 }
2638 d->setupLayout();
2639}
2640#endif // QT_CONFIG(textedit)
2641
2642/*!
2643 \property QMessageBox::informativeText
2644
2645 \brief the informative text that provides a fuller description for
2646 the message
2647
2648 Informative text can be used to expand upon the text() to give more
2649 information to the user, for example describing the consequences of
2650 the situation, or suggestion alternative solutions.
2651
2652 The text will be interpreted either as a plain text or as rich text,
2653 depending on the text format setting (\l QMessageBox::textFormat).
2654 The default setting is Qt::AutoText, i.e., the message box will try
2655 to auto-detect the format of the text.
2656
2657 By default, this property contains an empty string.
2658
2659 \sa textFormat, QMessageBox::text, QMessageBox::detailedText
2660*/
2661QString QMessageBox::informativeText() const
2662{
2663 Q_D(const QMessageBox);
2664 return d->informativeLabel ? d->informativeLabel->text() : QString();
2665}
2666
2667void QMessageBox::setInformativeText(const QString &text)
2668{
2669 Q_D(QMessageBox);
2670 if (text.isEmpty()) {
2671 if (d->informativeLabel) {
2672 d->informativeLabel->hide();
2673 d->informativeLabel->deleteLater();
2674 }
2675 d->informativeLabel = nullptr;
2676 } else {
2677 if (!d->informativeLabel) {
2678 QLabel *label = new QLabel;
2679 label->setObjectName("qt_msgbox_informativelabel"_L1);
2680 label->setTextInteractionFlags(Qt::TextInteractionFlags(style()->styleHint(stylehint: QStyle::SH_MessageBox_TextInteractionFlags, opt: nullptr, widget: this)));
2681 label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
2682 label->setOpenExternalLinks(true);
2683#ifdef Q_OS_MAC
2684 // apply a smaller font the information label on the mac
2685 label->setFont(qt_app_fonts_hash()->value("QTipLabel"));
2686#endif
2687 label->setWordWrap(true);
2688 label->setTextFormat(d->label->textFormat());
2689 d->informativeLabel = label;
2690 }
2691 d->informativeLabel->setText(text);
2692 }
2693 d->setupLayout();
2694}
2695
2696/*!
2697 This function shadows QWidget::setWindowTitle().
2698
2699 Sets the title of the message box to \a title. On \macos,
2700 the window title is ignored (as required by the \macos
2701 Guidelines).
2702*/
2703void QMessageBox::setWindowTitle(const QString &title)
2704{
2705 // Message boxes on the mac do not have a title
2706#ifndef Q_OS_MAC
2707 QDialog::setWindowTitle(title);
2708#else
2709 Q_UNUSED(title);
2710#endif
2711}
2712
2713
2714/*!
2715 This function shadows QWidget::setWindowModality().
2716
2717 Sets the modality of the message box to \a windowModality.
2718
2719 On \macos, if the modality is set to Qt::WindowModal and the message box
2720 has a parent, then the message box will be a Qt::Sheet, otherwise the
2721 message box will be a standard dialog.
2722*/
2723void QMessageBox::setWindowModality(Qt::WindowModality windowModality)
2724{
2725 QDialog::setWindowModality(windowModality);
2726
2727 if (parentWidget() && windowModality == Qt::WindowModal)
2728 setParent(parent: parentWidget(), f: Qt::Sheet);
2729 else
2730 setParent(parent: parentWidget(), f: Qt::Dialog);
2731 setDefaultButton(d_func()->defaultButton);
2732}
2733
2734
2735QPixmap QMessageBoxPrivate::standardIcon(QMessageBox::Icon icon, QMessageBox *mb)
2736{
2737 QStyle *style = mb ? mb->style() : QApplication::style();
2738 int iconSize = style->pixelMetric(metric: QStyle::PM_MessageBoxIconSize, option: nullptr, widget: mb);
2739 QIcon tmpIcon;
2740 switch (icon) {
2741 case QMessageBox::Information:
2742 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxInformation, option: nullptr, widget: mb);
2743 break;
2744 case QMessageBox::Warning:
2745 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxWarning, option: nullptr, widget: mb);
2746 break;
2747 case QMessageBox::Critical:
2748 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxCritical, option: nullptr, widget: mb);
2749 break;
2750 case QMessageBox::Question:
2751 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxQuestion, option: nullptr, widget: mb);
2752 break;
2753 default:
2754 break;
2755 }
2756 if (!tmpIcon.isNull()) {
2757 qreal dpr = mb ? mb->devicePixelRatio() : qApp->devicePixelRatio();
2758 return tmpIcon.pixmap(size: QSize(iconSize, iconSize), devicePixelRatio: dpr);
2759 }
2760 return QPixmap();
2761}
2762
2763void QMessageBoxPrivate::initHelper(QPlatformDialogHelper *h)
2764{
2765 auto *messageDialogHelper = static_cast<QPlatformMessageDialogHelper *>(h);
2766 QObjectPrivate::connect(sender: messageDialogHelper, signal: &QPlatformMessageDialogHelper::clicked,
2767 receiverPrivate: this, slot: &QMessageBoxPrivate::helperClicked);
2768 // Forward state via lambda, so that we can handle addition and removal
2769 // of checkbox via setCheckBox() after initializing helper.
2770 QObject::connect(sender: messageDialogHelper, signal: &QPlatformMessageDialogHelper::checkBoxStateChanged,
2771 context: q_ptr, slot: [this](Qt::CheckState state) {
2772 if (checkbox)
2773 checkbox->setCheckState(state);
2774 }
2775 );
2776 messageDialogHelper->setOptions(options);
2777}
2778
2779static QMessageDialogOptions::StandardIcon helperIcon(QMessageBox::Icon i)
2780{
2781 switch (i) {
2782 case QMessageBox::NoIcon:
2783 return QMessageDialogOptions::NoIcon;
2784 case QMessageBox::Information:
2785 return QMessageDialogOptions::Information;
2786 case QMessageBox::Warning:
2787 return QMessageDialogOptions::Warning;
2788 case QMessageBox::Critical:
2789 return QMessageDialogOptions::Critical;
2790 case QMessageBox::Question:
2791 return QMessageDialogOptions::Question;
2792 }
2793 return QMessageDialogOptions::NoIcon;
2794}
2795
2796static QPlatformDialogHelper::StandardButtons helperStandardButtons(QMessageBox * q)
2797{
2798 QPlatformDialogHelper::StandardButtons buttons(int(q->standardButtons()));
2799 return buttons;
2800}
2801
2802bool QMessageBoxPrivate::canBeNativeDialog() const
2803{
2804 // Don't use Q_Q here! This function is called from ~QDialog,
2805 // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()).
2806 const QDialog * const q = static_cast<const QDialog*>(q_ptr);
2807 if (nativeDialogInUse)
2808 return true;
2809 if (QCoreApplication::testAttribute(attribute: Qt::AA_DontUseNativeDialogs)
2810 || q->testAttribute(attribute: Qt::WA_DontShowOnScreen)
2811 || q->testAttribute(attribute: Qt::WA_StyleSheet)
2812 || (options->options() & QMessageDialogOptions::Option::DontUseNativeDialog)) {
2813 return false;
2814 }
2815
2816 if (strcmp(s1: QMessageBox::staticMetaObject.className(), s2: q->metaObject()->className()) != 0)
2817 return false;
2818
2819#if QT_CONFIG(menu)
2820 for (auto *customButton : buttonBox->buttons()) {
2821 if (QPushButton *pushButton = qobject_cast<QPushButton *>(object: customButton)) {
2822 // We can't support buttons with menus in native dialogs (yet)
2823 if (pushButton->menu())
2824 return false;
2825 }
2826 }
2827#endif
2828
2829 return QDialogPrivate::canBeNativeDialog();
2830}
2831
2832void QMessageBoxPrivate::helperPrepareShow(QPlatformDialogHelper *)
2833{
2834 Q_Q(QMessageBox);
2835 options->setWindowTitle(q->windowTitle());
2836 options->setText(q->text());
2837 options->setInformativeText(q->informativeText());
2838#if QT_CONFIG(textedit)
2839 options->setDetailedText(q->detailedText());
2840#endif
2841 options->setStandardIcon(helperIcon(i: q->icon()));
2842 options->setIconPixmap(q->iconPixmap());
2843
2844 // Clear up front, since we might have prepared earlier
2845 options->clearCustomButtons();
2846
2847 // Add standard buttons and resolve default/escape button
2848 auto standardButtons = helperStandardButtons(q);
2849 for (int button = QDialogButtonBox::StandardButton::FirstButton;
2850 button <= QDialogButtonBox::StandardButton::LastButton; button <<= 1) {
2851 auto *standardButton = buttonBox->button(which: QDialogButtonBox::StandardButton(button));
2852 if (!standardButton)
2853 continue;
2854
2855 if (auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
2856 if (standardButton->text() != platformTheme->standardButtonText(button)) {
2857 // The standard button has been customized, so add it as
2858 // a custom button instead.
2859 const auto buttonRole = buttonBox->buttonRole(button: standardButton);
2860 options->addButton(label: standardButton->text(),
2861 role: static_cast<QPlatformDialogHelper::ButtonRole>(buttonRole),
2862 buttonImpl: standardButton, buttonId: button);
2863 standardButtons &= ~QPlatformDialogHelper::StandardButton(button);
2864 }
2865 }
2866
2867 if (standardButton == defaultButton)
2868 options->setDefaultButton(button);
2869 else if (standardButton == detectedEscapeButton)
2870 options->setEscapeButton(button);
2871 }
2872 options->setStandardButtons(standardButtons);
2873
2874 // Add custom buttons and resolve default/escape button
2875 for (auto *customButton : customButtonList) {
2876 // Unless it's the details button, since we don't do any
2877 // plumbing for the button's action in that case.
2878 if (customButton == detailsButton)
2879 continue;
2880
2881 const auto buttonRole = buttonBox->buttonRole(button: customButton);
2882 const int buttonId = options->addButton(label: customButton->text(),
2883 role: static_cast<QPlatformDialogHelper::ButtonRole>(buttonRole),
2884 buttonImpl: customButton);
2885
2886 if (customButton == defaultButton)
2887 options->setDefaultButton(buttonId);
2888 else if (customButton == detectedEscapeButton)
2889 options->setEscapeButton(buttonId);
2890 }
2891
2892 if (checkbox)
2893 options->setCheckBox(label: checkbox->text(), state: checkbox->checkState());
2894}
2895
2896void qRequireVersion(int argc, char *argv[], QAnyStringView req)
2897{
2898 const auto required = QVersionNumber::fromString(string: req).normalized();
2899 const auto current = QVersionNumber::fromString(string: qVersion()).normalized();
2900 if (current >= required)
2901 return;
2902 std::optional<QApplication> application;
2903 if (!qApp)
2904 application.emplace(args&: argc, args&: argv);
2905 const QString message = QApplication::tr(s: "Application \"%1\" requires Qt %2, found Qt %3.")
2906 .arg(args: qAppName(), args: required.toString(), args: current.toString());
2907 QMessageBox::critical(parent: nullptr, title: QApplication::tr(s: "Incompatible Qt Library Error"),
2908 text: message, buttons: QMessageBox::Abort);
2909 qFatal(msg: "%ls", qUtf16Printable(message));
2910}
2911
2912#if QT_DEPRECATED_SINCE(6,2)
2913/*!
2914 \deprecated [6.2]
2915
2916 Returns the pixmap used for a standard icon. This allows the
2917 pixmaps to be used in more complex message boxes. \a icon
2918 specifies the required icon, e.g. QMessageBox::Question,
2919 QMessageBox::Information, QMessageBox::Warning or
2920 QMessageBox::Critical.
2921
2922 Call QStyle::standardIcon() with QStyle::SP_MessageBoxInformation etc.
2923 instead.
2924*/
2925
2926QPixmap QMessageBox::standardIcon(Icon icon)
2927{
2928 return QMessageBoxPrivate::standardIcon(icon, mb: nullptr);
2929}
2930#endif
2931
2932/*!
2933 \typedef QMessageBox::Button
2934 \deprecated
2935
2936 Use QMessageBox::StandardButton instead.
2937*/
2938
2939/*!
2940 \fn int QMessageBox::information(QWidget *parent, const QString &title,
2941 const QString& text, StandardButton button0,
2942 StandardButton button1)
2943 \fn int QMessageBox::warning(QWidget *parent, const QString &title,
2944 const QString& text, StandardButton button0,
2945 StandardButton button1)
2946 \fn int QMessageBox::critical(QWidget *parent, const QString &title,
2947 const QString& text, StandardButton button0,
2948 StandardButton button1)
2949 \fn int QMessageBox::question(QWidget *parent, const QString &title,
2950 const QString& text, StandardButton button0,
2951 StandardButton button1)
2952 \internal
2953
2954 ### Needed for Qt 4 source compatibility
2955*/
2956
2957/*!
2958 \fn int QMessageBox::exec()
2959
2960 Shows the message box as a \l{QDialog#Modal Dialogs}{modal dialog},
2961 blocking until the user closes it.
2962
2963 When using a QMessageBox with standard buttons, this function returns a
2964 \l StandardButton value indicating the standard button that was clicked.
2965 When using QMessageBox with custom buttons, this function returns an
2966 opaque value; use clickedButton() to determine which button was clicked.
2967
2968 \note The result() function returns also \l StandardButton value instead
2969 of \l QDialog::DialogCode.
2970
2971 Users cannot interact with any other window in the same
2972 application until they close the dialog, either by clicking a
2973 button or by using a mechanism provided by the window system.
2974
2975 \sa show(), result()
2976*/
2977
2978/*!
2979 \macro QT_REQUIRE_VERSION(int argc, char **argv, const char *version)
2980 \relates QMessageBox
2981
2982 This macro can be used to ensure that the application is run
2983 with a recent enough version of Qt. This is especially useful
2984 if your application depends on a specific bug fix introduced in a
2985 bug-fix release (for example, 6.1.2).
2986
2987 The \a argc and \a argv parameters are the \c main() function's
2988 \c argc and \c argv parameters. The \a version parameter is a
2989 string literal that specifies which version of Qt the application
2990 requires (for example, "6.1.2").
2991
2992 Example:
2993
2994 \snippet code/src_gui_dialogs_qmessagebox.cpp 4
2995*/
2996
2997QT_END_NAMESPACE
2998
2999#include "moc_qmessagebox.cpp"
3000#include "qmessagebox.moc"
3001

source code of qtbase/src/widgets/dialogs/qmessagebox.cpp