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 Q_Q(QMessageBox);
1661
1662 // Last minute setup
1663 if (autoAddOkButton)
1664 q->addButton(button: QMessageBox::Ok);
1665 detectEscapeButton();
1666
1667 if (canBeNativeDialog())
1668 setNativeDialogVisible(visible);
1669
1670 // Update WA_DontShowOnScreen based on whether the native dialog was shown,
1671 // so that QDialog::setVisible(visible) below updates the QWidget state correctly,
1672 // but skips showing the non-native version.
1673 q->setAttribute(Qt::WA_DontShowOnScreen, on: nativeDialogInUse);
1674
1675 QDialogPrivate::setVisible(visible);
1676}
1677
1678/*!
1679 Returns a list of all the buttons that have been added to the message box.
1680
1681 \sa buttonRole(), addButton(), removeButton()
1682*/
1683QList<QAbstractButton *> QMessageBox::buttons() const
1684{
1685 Q_D(const QMessageBox);
1686 return d->buttonBox->buttons();
1687}
1688
1689/*!
1690 Returns the button role for the specified \a button. This function returns
1691 \l InvalidRole if \a button is \nullptr or has not been added to the message box.
1692
1693 \sa buttons(), addButton()
1694*/
1695QMessageBox::ButtonRole QMessageBox::buttonRole(QAbstractButton *button) const
1696{
1697 Q_D(const QMessageBox);
1698 return QMessageBox::ButtonRole(d->buttonBox->buttonRole(button));
1699}
1700
1701/*!
1702 \reimp
1703*/
1704void QMessageBox::showEvent(QShowEvent *e)
1705{
1706 Q_D(QMessageBox);
1707 d->clickedButton = nullptr;
1708 d->updateSize();
1709
1710#if QT_CONFIG(accessibility)
1711 QAccessibleEvent event(this, QAccessible::Alert);
1712 QAccessible::updateAccessibility(event: &event);
1713#endif
1714#if defined(Q_OS_WIN)
1715 if (const HMENU systemMenu = qt_getWindowsSystemMenu(this)) {
1716 EnableMenuItem(systemMenu, SC_CLOSE, d->detectedEscapeButton ?
1717 MF_BYCOMMAND|MF_ENABLED : MF_BYCOMMAND|MF_GRAYED);
1718 }
1719#endif
1720 QDialog::showEvent(e);
1721}
1722
1723
1724static QMessageBox::StandardButton showNewMessageBox(QWidget *parent,
1725 QMessageBox::Icon icon,
1726 const QString& title, const QString& text,
1727 QMessageBox::StandardButtons buttons,
1728 QMessageBox::StandardButton defaultButton)
1729{
1730 // necessary for source compatibility with Qt 4.0 and 4.1
1731 // handles (Yes, No) and (Yes|Default, No)
1732 if (defaultButton && !(buttons & defaultButton)) {
1733 const int defaultButtons = defaultButton | QMessageBox::Default;
1734 const int otherButtons = buttons.toInt();
1735 const int ret = QMessageBoxPrivate::showOldMessageBox(parent, icon, title,
1736 text, button0: otherButtons,
1737 button1: defaultButtons, button2: 0);
1738 return static_cast<QMessageBox::StandardButton>(ret);
1739 }
1740
1741 QMessageBox msgBox(icon, title, text, QMessageBox::NoButton, parent);
1742 QDialogButtonBox *buttonBox = msgBox.findChild<QDialogButtonBox*>();
1743 Q_ASSERT(buttonBox != nullptr);
1744
1745 uint mask = QMessageBox::FirstButton;
1746 while (mask <= QMessageBox::LastButton) {
1747 uint sb = buttons & mask;
1748 mask <<= 1;
1749 if (!sb)
1750 continue;
1751 QPushButton *button = msgBox.addButton(button: (QMessageBox::StandardButton)sb);
1752 // Choose the first accept role as the default
1753 if (msgBox.defaultButton())
1754 continue;
1755 if ((defaultButton == QMessageBox::NoButton && buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole)
1756 || (defaultButton != QMessageBox::NoButton && sb == uint(defaultButton)))
1757 msgBox.setDefaultButton(button);
1758 }
1759 if (msgBox.exec() == -1)
1760 return QMessageBox::Cancel;
1761 return msgBox.standardButton(button: msgBox.clickedButton());
1762}
1763
1764/*!
1765 Opens an information message box with the given \a title and
1766 \a text in front of the specified \a parent widget.
1767
1768 The standard \a buttons are added to the message box.
1769 \a defaultButton specifies the button used when \uicontrol Enter is pressed.
1770 \a defaultButton must refer to a button that was given in \a buttons.
1771 If \a defaultButton is QMessageBox::NoButton, QMessageBox
1772 chooses a suitable default automatically.
1773
1774 Returns the identity of the standard button that was clicked. If
1775 \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
1776 {escape button} is returned.
1777
1778 The message box is an \l{Qt::ApplicationModal}{application modal}
1779 dialog box.
1780
1781 \warning Do not delete \a parent during the execution of the dialog.
1782 If you want to do this, you should create the dialog
1783 yourself using one of the QMessageBox constructors.
1784
1785 \sa question(), warning(), critical()
1786*/
1787QMessageBox::StandardButton QMessageBox::information(QWidget *parent, const QString &title,
1788 const QString& text, StandardButtons buttons,
1789 StandardButton defaultButton)
1790{
1791 return showNewMessageBox(parent, icon: Information, title, text, buttons,
1792 defaultButton);
1793}
1794
1795
1796/*!
1797 Opens a question message box with the given \a title and \a
1798 text in front of the specified \a parent widget.
1799
1800 The standard \a buttons are added to the message box. \a
1801 defaultButton specifies the button used when \uicontrol Enter is
1802 pressed. \a defaultButton must refer to a button that was given in \a buttons.
1803 If \a defaultButton is QMessageBox::NoButton, QMessageBox
1804 chooses a suitable default automatically.
1805
1806 Returns the identity of the standard button that was clicked. If
1807 \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
1808 {escape button} is returned.
1809
1810 The message box is an \l{Qt::ApplicationModal} {application modal}
1811 dialog box.
1812
1813 \warning Do not delete \a parent during the execution of the dialog.
1814 If you want to do this, you should create the dialog
1815 yourself using one of the QMessageBox constructors.
1816
1817 \sa information(), warning(), critical()
1818*/
1819QMessageBox::StandardButton QMessageBox::question(QWidget *parent, const QString &title,
1820 const QString& text, StandardButtons buttons,
1821 StandardButton defaultButton)
1822{
1823 return showNewMessageBox(parent, icon: Question, title, text, buttons, defaultButton);
1824}
1825
1826/*!
1827 Opens a warning message box with the given \a title and \a
1828 text in front of the specified \a parent widget.
1829
1830 The standard \a buttons are added to the message box. \a
1831 defaultButton specifies the button used when \uicontrol Enter is
1832 pressed. \a defaultButton must refer to a button that was given in \a buttons.
1833 If \a defaultButton is QMessageBox::NoButton, QMessageBox
1834 chooses a suitable default automatically.
1835
1836 Returns the identity of the standard button that was clicked. If
1837 \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
1838 {escape button} is returned.
1839
1840 The message box is an \l{Qt::ApplicationModal} {application modal}
1841 dialog box.
1842
1843 \warning Do not delete \a parent during the execution of the dialog.
1844 If you want to do this, you should create the dialog
1845 yourself using one of the QMessageBox constructors.
1846
1847 \sa question(), information(), critical()
1848*/
1849QMessageBox::StandardButton QMessageBox::warning(QWidget *parent, const QString &title,
1850 const QString& text, StandardButtons buttons,
1851 StandardButton defaultButton)
1852{
1853 return showNewMessageBox(parent, icon: Warning, title, text, buttons, defaultButton);
1854}
1855
1856/*!
1857 Opens a critical message box with the given \a title and \a
1858 text in front of the specified \a parent widget.
1859
1860 The standard \a buttons are added to the message box. \a
1861 defaultButton specifies the button used when \uicontrol Enter is
1862 pressed. \a defaultButton must refer to a button that was given in \a buttons.
1863 If \a defaultButton is QMessageBox::NoButton, QMessageBox
1864 chooses a suitable default automatically.
1865
1866 Returns the identity of the standard button that was clicked. If
1867 \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
1868 {escape button} is returned.
1869
1870 The message box is an \l{Qt::ApplicationModal} {application modal}
1871 dialog box.
1872
1873 \warning Do not delete \a parent during the execution of the dialog.
1874 If you want to do this, you should create the dialog
1875 yourself using one of the QMessageBox constructors.
1876
1877 \sa question(), warning(), information()
1878*/
1879QMessageBox::StandardButton QMessageBox::critical(QWidget *parent, const QString &title,
1880 const QString& text, StandardButtons buttons,
1881 StandardButton defaultButton)
1882{
1883 return showNewMessageBox(parent, icon: Critical, title, text, buttons, defaultButton);
1884}
1885
1886/*!
1887 Displays a simple about box with title \a title and text \a
1888 text. The about box's parent is \a parent.
1889
1890 about() looks for a suitable icon in four locations:
1891
1892 \list 1
1893 \li It prefers \l{QWidget::windowIcon()}{parent->icon()}
1894 if that exists.
1895 \li If not, it tries the top-level widget containing \a parent.
1896 \li If that fails, it tries the \l{QApplication::activeWindow()}{active window.}
1897 \li As a last resort it uses the Information icon.
1898 \endlist
1899
1900 The about box has a single button labelled "OK".
1901
1902 On \macos, the about box is popped up as a modeless window; on
1903 other platforms, it is currently application modal.
1904
1905 \sa QWidget::windowIcon(), QApplication::activeWindow()
1906*/
1907void QMessageBox::about(QWidget *parent, const QString &title, const QString &text)
1908{
1909#ifdef Q_OS_MAC
1910 static QPointer<QMessageBox> oldMsgBox;
1911
1912 if (oldMsgBox && oldMsgBox->text() == text) {
1913 oldMsgBox->show();
1914 oldMsgBox->raise();
1915 oldMsgBox->activateWindow();
1916 return;
1917 }
1918#endif
1919
1920 QMessageBox *msgBox = new QMessageBox(Information, title, text, NoButton, parent
1921#ifdef Q_OS_MAC
1922 , Qt::WindowTitleHint | Qt::WindowSystemMenuHint
1923#endif
1924 );
1925 msgBox->setAttribute(Qt::WA_DeleteOnClose);
1926 QIcon icon = msgBox->windowIcon();
1927 QSize size = icon.actualSize(size: QSize(64, 64));
1928 msgBox->setIconPixmap(icon.pixmap(size));
1929
1930 // should perhaps be a style hint
1931#ifdef Q_OS_MAC
1932 oldMsgBox = msgBox;
1933 auto *d = msgBox->d_func();
1934 d->buttonBox->setCenterButtons(true);
1935#ifdef Q_OS_IOS
1936 msgBox->setModal(true);
1937#else
1938 msgBox->setModal(false);
1939#endif
1940 msgBox->show();
1941#else
1942 msgBox->exec();
1943#endif
1944}
1945
1946/*!
1947 Displays a simple message box about Qt, with the given \a title
1948 and centered over \a parent (if \a parent is not \nullptr). The message
1949 includes the version number of Qt being used by the application.
1950
1951 This is useful for inclusion in the \uicontrol Help menu of an application,
1952 as shown in the \l{mainwindows/menus}{Menus} example.
1953
1954 QApplication provides this functionality as a slot.
1955
1956 On \macos, the aboutQt box is popped up as a modeless window; on
1957 other platforms, it is currently application modal.
1958
1959 \sa QApplication::aboutQt()
1960*/
1961void QMessageBox::aboutQt(QWidget *parent, const QString &title)
1962{
1963#ifdef Q_OS_MAC
1964 static QPointer<QMessageBox> oldMsgBox;
1965
1966 if (oldMsgBox) {
1967 oldMsgBox->show();
1968 oldMsgBox->raise();
1969 oldMsgBox->activateWindow();
1970 return;
1971 }
1972#endif
1973
1974 QString translatedTextAboutQtCaption;
1975 translatedTextAboutQtCaption = QMessageBox::tr(
1976 s: "<h3>About Qt</h3>"
1977 "<p>This program uses Qt version %1.</p>"
1978 ).arg(QT_VERSION_STR ""_L1);
1979 //: Leave this text untranslated or include a verbatim copy of it below
1980 //: and note that it is the authoritative version in case of doubt.
1981 const QString translatedTextAboutQtText = QMessageBox::tr(
1982 s: "<p>Qt is a C++ toolkit for cross-platform application "
1983 "development.</p>"
1984 "<p>Qt provides single-source portability across all major desktop "
1985 "operating systems. It is also available for embedded Linux and other "
1986 "embedded and mobile operating systems.</p>"
1987 "<p>Qt is available under multiple licensing options designed "
1988 "to accommodate the needs of our various users.</p>"
1989 "<p>Qt licensed under our commercial license agreement is appropriate "
1990 "for development of proprietary/commercial software where you do not "
1991 "want to share any source code with third parties or otherwise cannot "
1992 "comply with the terms of GNU (L)GPL.</p>"
1993 "<p>Qt licensed under GNU (L)GPL is appropriate for the "
1994 "development of Qt&nbsp;applications provided you can comply with the terms "
1995 "and conditions of the respective licenses.</p>"
1996 "<p>Please see <a href=\"https://%2/\">%2</a> "
1997 "for an overview of Qt licensing.</p>"
1998 "<p>Copyright (C) The Qt Company Ltd. and other "
1999 "contributors.</p>"
2000 "<p>Qt and the Qt logo are trademarks of The Qt Company Ltd.</p>"
2001 "<p>Qt is The Qt Company Ltd. product developed as an open source "
2002 "project. See <a href=\"https://%3/\">%3</a> for more information.</p>"
2003 ).arg(QStringLiteral("qt.io/licensing"),
2004 QStringLiteral("qt.io"));
2005 QMessageBox *msgBox = new QMessageBox(parent);
2006 msgBox->setAttribute(Qt::WA_DeleteOnClose);
2007 msgBox->setWindowTitle(title.isEmpty() ? tr(s: "About Qt") : title);
2008 msgBox->setText(translatedTextAboutQtCaption);
2009 msgBox->setInformativeText(translatedTextAboutQtText);
2010
2011 QPixmap pm(":/qt-project.org/qmessagebox/images/qtlogo-64.png"_L1);
2012 if (!pm.isNull())
2013 msgBox->setIconPixmap(pm);
2014
2015 // should perhaps be a style hint
2016#ifdef Q_OS_MAC
2017 oldMsgBox = msgBox;
2018 auto *d = msgBox->d_func();
2019 d->buttonBox->setCenterButtons(true);
2020#ifdef Q_OS_IOS
2021 msgBox->setModal(true);
2022#else
2023 msgBox->setModal(false);
2024#endif
2025 msgBox->show();
2026#else
2027 msgBox->exec();
2028#endif
2029}
2030
2031/////////////////////////////////////////////////////////////////////////////////////////
2032// Source and binary compatibility routines for 4.0 and 4.1
2033
2034static QMessageBox::StandardButton newButton(int button)
2035{
2036 // this is needed for source compatibility with Qt 4.0 and 4.1
2037 if (button == QMessageBox::NoButton || (button & NewButtonMask))
2038 return QMessageBox::StandardButton(button & QMessageBox::ButtonMask);
2039
2040 return QMessageBox::NoButton;
2041}
2042
2043static bool detectedCompat(int button0, int button1, int button2)
2044{
2045 if (button0 != 0 && !(button0 & NewButtonMask))
2046 return true;
2047 if (button1 != 0 && !(button1 & NewButtonMask))
2048 return true;
2049 if (button2 != 0 && !(button2 & NewButtonMask))
2050 return true;
2051 return false;
2052}
2053
2054QAbstractButton *QMessageBoxPrivate::findButton(int button0, int button1, int button2, int flags)
2055{
2056 Q_Q(QMessageBox);
2057 int button = 0;
2058
2059 if (button0 & flags) {
2060 button = button0;
2061 } else if (button1 & flags) {
2062 button = button1;
2063 } else if (button2 & flags) {
2064 button = button2;
2065 }
2066 return q->button(which: newButton(button));
2067}
2068
2069void QMessageBoxPrivate::addOldButtons(int button0, int button1, int button2)
2070{
2071 Q_Q(QMessageBox);
2072 q->addButton(button: newButton(button: button0));
2073 q->addButton(button: newButton(button: button1));
2074 q->addButton(button: newButton(button: button2));
2075 q->setDefaultButton(
2076 static_cast<QPushButton *>(findButton(button0, button1, button2, flags: QMessageBox::Default)));
2077 q->setEscapeButton(findButton(button0, button1, button2, flags: QMessageBox::Escape));
2078 compatMode = detectedCompat(button0, button1, button2);
2079}
2080
2081QAbstractButton *QMessageBoxPrivate::abstractButtonForId(int id) const
2082{
2083 Q_Q(const QMessageBox);
2084 QAbstractButton *result = customButtonList.value(i: id);
2085 if (result)
2086 return result;
2087 if (id & QMessageBox::FlagMask) // for compatibility with Qt 4.0/4.1 (even if it is silly)
2088 return nullptr;
2089 return q->button(which: newButton(button: id));
2090}
2091
2092int QMessageBoxPrivate::showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
2093 const QString &title, const QString &text,
2094 int button0, int button1, int button2)
2095{
2096 QMessageBox messageBox(icon, title, text, QMessageBox::NoButton, parent);
2097 messageBox.d_func()->addOldButtons(button0, button1, button2);
2098 return messageBox.exec();
2099}
2100
2101int QMessageBoxPrivate::showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
2102 const QString &title, const QString &text,
2103 const QString &button0Text,
2104 const QString &button1Text,
2105 const QString &button2Text,
2106 int defaultButtonNumber,
2107 int escapeButtonNumber)
2108{
2109 QMessageBox messageBox(icon, title, text, QMessageBox::NoButton, parent);
2110 QString myButton0Text = button0Text;
2111 if (myButton0Text.isEmpty())
2112 myButton0Text = QDialogButtonBox::tr(s: "OK");
2113 messageBox.addButton(text: myButton0Text, role: QMessageBox::ActionRole);
2114 if (!button1Text.isEmpty())
2115 messageBox.addButton(text: button1Text, role: QMessageBox::ActionRole);
2116 if (!button2Text.isEmpty())
2117 messageBox.addButton(text: button2Text, role: QMessageBox::ActionRole);
2118
2119 const QList<QAbstractButton *> &buttonList = messageBox.d_func()->customButtonList;
2120 messageBox.setDefaultButton(static_cast<QPushButton *>(buttonList.value(i: defaultButtonNumber)));
2121 messageBox.setEscapeButton(buttonList.value(i: escapeButtonNumber));
2122
2123 messageBox.exec();
2124
2125 // Ignore exec return value and use button index instead,
2126 // as that's what the documentation promises.
2127 return buttonList.indexOf(t: messageBox.clickedButton());
2128}
2129
2130void QMessageBoxPrivate::retranslateStrings()
2131{
2132#if QT_CONFIG(textedit)
2133 if (detailsButton && detailsText)
2134 detailsButton->setLabel(detailsText->isHidden() ? ShowLabel : HideLabel);
2135#endif
2136}
2137
2138#if QT_DEPRECATED_SINCE(6,2)
2139/*!
2140 \deprecated
2141
2142 Constructs a message box with a \a title, a \a text, an \a icon,
2143 and up to three buttons.
2144
2145 The \a icon must be one of the following:
2146 \list
2147 \li QMessageBox::NoIcon
2148 \li QMessageBox::Question
2149 \li QMessageBox::Information
2150 \li QMessageBox::Warning
2151 \li QMessageBox::Critical
2152 \endlist
2153
2154 Each button, \a button0, \a button1 and \a button2, can have one
2155 of the following values:
2156 \list
2157 \li QMessageBox::NoButton
2158 \li QMessageBox::Ok
2159 \li QMessageBox::Cancel
2160 \li QMessageBox::Yes
2161 \li QMessageBox::No
2162 \li QMessageBox::Abort
2163 \li QMessageBox::Retry
2164 \li QMessageBox::Ignore
2165 \li QMessageBox::YesAll
2166 \li QMessageBox::NoAll
2167 \endlist
2168
2169 Use QMessageBox::NoButton for the later parameters to have fewer
2170 than three buttons in your message box. If you don't specify any
2171 buttons at all, QMessageBox will provide an Ok button.
2172
2173 One of the buttons can be OR-ed with the QMessageBox::Default
2174 flag to make it the default button (clicked when Enter is
2175 pressed).
2176
2177 One of the buttons can be OR-ed with the QMessageBox::Escape flag
2178 to make it the cancel or close button (clicked when \uicontrol Esc is
2179 pressed).
2180
2181 \snippet dialogs/dialogs.cpp 2
2182
2183 The message box is an \l{Qt::ApplicationModal} {application modal}
2184 dialog box.
2185
2186 The \a parent and \a f arguments are passed to
2187 the QDialog constructor.
2188
2189 \sa setWindowTitle(), setText(), setIcon()
2190*/
2191QMessageBox::QMessageBox(const QString &title, const QString &text, Icon icon,
2192 int button0, int button1, int button2, QWidget *parent,
2193 Qt::WindowFlags f)
2194 : QDialog(*new QMessageBoxPrivate, parent,
2195 f /*| Qt::MSWindowsFixedSizeDialogHint #### */| Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
2196{
2197 Q_D(QMessageBox);
2198 d->init(title, text);
2199 setIcon(icon);
2200 d->addOldButtons(button0, button1, button2);
2201}
2202
2203/*!
2204 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2205
2206 Opens an information message box with the given \a title and the
2207 \a text. The dialog may have up to three buttons. Each of the
2208 buttons, \a button0, \a button1 and \a button2 may be set to one
2209 of the following values:
2210
2211 \list
2212 \li QMessageBox::NoButton
2213 \li QMessageBox::Ok
2214 \li QMessageBox::Cancel
2215 \li QMessageBox::Yes
2216 \li QMessageBox::No
2217 \li QMessageBox::Abort
2218 \li QMessageBox::Retry
2219 \li QMessageBox::Ignore
2220 \li QMessageBox::YesAll
2221 \li QMessageBox::NoAll
2222 \endlist
2223
2224 If you don't want all three buttons, set the last button, or last
2225 two buttons to QMessageBox::NoButton.
2226
2227 One button can be OR-ed with QMessageBox::Default, and one
2228 button can be OR-ed with QMessageBox::Escape.
2229
2230 Returns the identity (QMessageBox::Ok, or QMessageBox::No, etc.)
2231 of the button that was clicked.
2232
2233 The message box is an \l{Qt::ApplicationModal} {application modal}
2234 dialog box.
2235
2236 \warning Do not delete \a parent during the execution of the dialog.
2237 If you want to do this, you should create the dialog
2238 yourself using one of the QMessageBox constructors.
2239
2240 \sa question(), warning(), critical()
2241*/
2242int QMessageBox::information(QWidget *parent, const QString &title, const QString& text,
2243 int button0, int button1, int button2)
2244{
2245 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Information, title, text,
2246 button0, button1, button2);
2247}
2248
2249/*!
2250 \deprecated [6.2] Use the overload taking StandardButtons instead.
2251 \overload
2252
2253 Displays an information message box with the given \a title and
2254 \a text, as well as one, two or three buttons. Returns the index
2255 of the button that was clicked (0, 1 or 2).
2256
2257 \a button0Text is the text of the first button, and is optional.
2258 If \a button0Text is not supplied, "OK" (translated) will be
2259 used. \a button1Text is the text of the second button, and is
2260 optional. \a button2Text is the text of the third button, and is
2261 optional. \a defaultButtonNumber (0, 1 or 2) is the index of the
2262 default button; pressing Return or Enter is the same as clicking
2263 the default button. It defaults to 0 (the first button). \a
2264 escapeButtonNumber is the index of the escape button; pressing
2265 \uicontrol Esc is the same as clicking this button. It defaults to -1;
2266 supply 0, 1 or 2 to make pressing \uicontrol Esc equivalent to clicking
2267 the relevant button.
2268
2269 The message box is an \l{Qt::ApplicationModal} {application modal}
2270 dialog box.
2271
2272 \warning Do not delete \a parent during the execution of the dialog.
2273 If you want to do this, you should create the dialog
2274 yourself using one of the QMessageBox constructors.
2275
2276 \sa question(), warning(), critical()
2277*/
2278
2279int QMessageBox::information(QWidget *parent, const QString &title, const QString& text,
2280 const QString& button0Text, const QString& button1Text,
2281 const QString& button2Text, int defaultButtonNumber,
2282 int escapeButtonNumber)
2283{
2284 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Information, title, text,
2285 button0Text, button1Text, button2Text,
2286 defaultButtonNumber, escapeButtonNumber);
2287}
2288
2289/*!
2290 \deprecated [6.2]. Use the overload taking StandardButtons
2291 instead.
2292
2293 Opens a question message box with the given \a title and \a text.
2294 The dialog may have up to three buttons. Each of the buttons, \a
2295 button0, \a button1 and \a button2 may be set to one of the
2296 following values:
2297
2298 \list
2299 \li QMessageBox::NoButton
2300 \li QMessageBox::Ok
2301 \li QMessageBox::Cancel
2302 \li QMessageBox::Yes
2303 \li QMessageBox::No
2304 \li QMessageBox::Abort
2305 \li QMessageBox::Retry
2306 \li QMessageBox::Ignore
2307 \li QMessageBox::YesAll
2308 \li QMessageBox::NoAll
2309 \endlist
2310
2311 If you don't want all three buttons, set the last button, or last
2312 two buttons to QMessageBox::NoButton.
2313
2314 One button can be OR-ed with QMessageBox::Default, and one
2315 button can be OR-ed with QMessageBox::Escape.
2316
2317 Returns the identity (QMessageBox::Yes, or QMessageBox::No, etc.)
2318 of the button that was clicked.
2319
2320 The message box is an \l{Qt::ApplicationModal} {application modal}
2321 dialog box.
2322
2323 \warning Do not delete \a parent during the execution of the dialog.
2324 If you want to do this, you should create the dialog
2325 yourself using one of the QMessageBox constructors.
2326
2327 \sa information(), warning(), critical()
2328*/
2329int QMessageBox::question(QWidget *parent, const QString &title, const QString& text,
2330 int button0, int button1, int button2)
2331{
2332 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Question, title, text,
2333 button0, button1, button2);
2334}
2335
2336/*!
2337 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2338 \overload
2339
2340 Displays a question message box with the given \a title and \a
2341 text, as well as one, two or three buttons. Returns the index of
2342 the button that was clicked (0, 1 or 2).
2343
2344 \a button0Text is the text of the first button, and is optional.
2345 If \a button0Text is not supplied, "OK" (translated) will be used.
2346 \a button1Text is the text of the second button, and is optional.
2347 \a button2Text is the text of the third button, and is optional.
2348 \a defaultButtonNumber (0, 1 or 2) is the index of the default
2349 button; pressing Return or Enter is the same as clicking the
2350 default button. It defaults to 0 (the first button). \a
2351 escapeButtonNumber is the index of the Escape button; pressing
2352 Escape is the same as clicking this button. It defaults to -1;
2353 supply 0, 1 or 2 to make pressing Escape equivalent to clicking
2354 the relevant button.
2355
2356 The message box is an \l{Qt::ApplicationModal} {application modal}
2357 dialog box.
2358
2359 \warning Do not delete \a parent during the execution of the dialog.
2360 If you want to do this, you should create the dialog
2361 yourself using one of the QMessageBox constructors.
2362
2363 \sa information(), warning(), critical()
2364*/
2365int QMessageBox::question(QWidget *parent, const QString &title, const QString& text,
2366 const QString& button0Text, const QString& button1Text,
2367 const QString& button2Text, int defaultButtonNumber,
2368 int escapeButtonNumber)
2369{
2370 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Question, title, text,
2371 button0Text, button1Text, button2Text,
2372 defaultButtonNumber, escapeButtonNumber);
2373}
2374
2375
2376/*!
2377 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2378
2379 Opens a warning message box with the given \a title and \a text.
2380 The dialog may have up to three buttons. Each of the button
2381 parameters, \a button0, \a button1 and \a button2 may be set to
2382 one of the following values:
2383
2384 \list
2385 \li QMessageBox::NoButton
2386 \li QMessageBox::Ok
2387 \li QMessageBox::Cancel
2388 \li QMessageBox::Yes
2389 \li QMessageBox::No
2390 \li QMessageBox::Abort
2391 \li QMessageBox::Retry
2392 \li QMessageBox::Ignore
2393 \li QMessageBox::YesAll
2394 \li QMessageBox::NoAll
2395 \endlist
2396
2397 If you don't want all three buttons, set the last button, or last
2398 two buttons to QMessageBox::NoButton.
2399
2400 One button can be OR-ed with QMessageBox::Default, and one
2401 button can be OR-ed with QMessageBox::Escape.
2402
2403 Returns the identity (QMessageBox::Ok or QMessageBox::No or ...)
2404 of the button that was clicked.
2405
2406 The message box is an \l{Qt::ApplicationModal} {application modal}
2407 dialog box.
2408
2409 \warning Do not delete \a parent during the execution of the dialog.
2410 If you want to do this, you should create the dialog
2411 yourself using one of the QMessageBox constructors.
2412
2413 \sa information(), question(), critical()
2414*/
2415int QMessageBox::warning(QWidget *parent, const QString &title, const QString& text,
2416 int button0, int button1, int button2)
2417{
2418 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Warning, title, text,
2419 button0, button1, button2);
2420}
2421
2422/*!
2423 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2424 \overload
2425
2426 Displays a warning message box with the given \a title and \a
2427 text, as well as one, two, or three buttons. Returns the number
2428 of the button that was clicked (0, 1, or 2).
2429
2430 \a button0Text is the text of the first button, and is optional.
2431 If \a button0Text is not supplied, "OK" (translated) will be used.
2432 \a button1Text is the text of the second button, and is optional,
2433 and \a button2Text is the text of the third button, and is
2434 optional. \a defaultButtonNumber (0, 1 or 2) is the index of the
2435 default button; pressing Return or Enter is the same as clicking
2436 the default button. It defaults to 0 (the first button). \a
2437 escapeButtonNumber is the index of the Escape button; pressing
2438 Escape is the same as clicking this button. It defaults to -1;
2439 supply 0, 1, or 2 to make pressing Escape equivalent to clicking
2440 the relevant button.
2441
2442 The message box is an \l{Qt::ApplicationModal} {application modal}
2443 dialog box.
2444
2445 \warning Do not delete \a parent during the execution of the dialog.
2446 If you want to do this, you should create the dialog
2447 yourself using one of the QMessageBox constructors.
2448
2449 \sa information(), question(), critical()
2450*/
2451int QMessageBox::warning(QWidget *parent, const QString &title, const QString& text,
2452 const QString& button0Text, const QString& button1Text,
2453 const QString& button2Text, int defaultButtonNumber,
2454 int escapeButtonNumber)
2455{
2456 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Warning, title, text,
2457 button0Text, button1Text, button2Text,
2458 defaultButtonNumber, escapeButtonNumber);
2459}
2460
2461/*!
2462 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2463
2464 Opens a critical message box with the given \a title and \a text.
2465 The dialog may have up to three buttons. Each of the button
2466 parameters, \a button0, \a button1 and \a button2 may be set to
2467 one of the following values:
2468
2469 \list
2470 \li QMessageBox::NoButton
2471 \li QMessageBox::Ok
2472 \li QMessageBox::Cancel
2473 \li QMessageBox::Yes
2474 \li QMessageBox::No
2475 \li QMessageBox::Abort
2476 \li QMessageBox::Retry
2477 \li QMessageBox::Ignore
2478 \li QMessageBox::YesAll
2479 \li QMessageBox::NoAll
2480 \endlist
2481
2482 If you don't want all three buttons, set the last button, or last
2483 two buttons to QMessageBox::NoButton.
2484
2485 One button can be OR-ed with QMessageBox::Default, and one
2486 button can be OR-ed with QMessageBox::Escape.
2487
2488 Returns the identity (QMessageBox::Ok, or QMessageBox::No, etc.)
2489 of the button that was clicked.
2490
2491 The message box is an \l{Qt::ApplicationModal} {application modal}
2492 dialog box.
2493
2494 \warning Do not delete \a parent during the execution of the dialog.
2495 If you want to do this, you should create the dialog
2496 yourself using one of the QMessageBox constructors.
2497
2498 \sa information(), question(), warning()
2499*/
2500
2501int QMessageBox::critical(QWidget *parent, const QString &title, const QString& text,
2502 int button0, int button1, int button2)
2503{
2504 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Critical, title, text,
2505 button0, button1, button2);
2506}
2507
2508/*!
2509 \deprecated [6.2]. Use the overload taking StandardButtons instead.
2510 \overload
2511
2512 Displays a critical error message box with the given \a title and
2513 \a text, as well as one, two, or three buttons. Returns the
2514 number of the button that was clicked (0, 1 or 2).
2515
2516 \a button0Text is the text of the first button, and is optional.
2517 If \a button0Text is not supplied, "OK" (translated) will be used.
2518 \a button1Text is the text of the second button, and is optional,
2519 and \a button2Text is the text of the third button, and is
2520 optional. \a defaultButtonNumber (0, 1 or 2) is the index of the
2521 default button; pressing Return or Enter is the same as clicking
2522 the default button. It defaults to 0 (the first button). \a
2523 escapeButtonNumber is the index of the Escape button; pressing
2524 Escape is the same as clicking this button. It defaults to -1;
2525 supply 0, 1, or 2 to make pressing Escape equivalent to clicking
2526 the relevant button.
2527
2528 The message box is an \l{Qt::ApplicationModal} {application modal}
2529 dialog box.
2530
2531 \warning Do not delete \a parent during the execution of the dialog.
2532 If you want to do this, you should create the dialog
2533 yourself using one of the QMessageBox constructors.
2534
2535 \sa information(), question(), warning()
2536*/
2537int QMessageBox::critical(QWidget *parent, const QString &title, const QString& text,
2538 const QString& button0Text, const QString& button1Text,
2539 const QString& button2Text, int defaultButtonNumber,
2540 int escapeButtonNumber)
2541{
2542 return QMessageBoxPrivate::showOldMessageBox(parent, icon: Critical, title, text,
2543 button0Text, button1Text, button2Text,
2544 defaultButtonNumber, escapeButtonNumber);
2545}
2546
2547
2548/*!
2549 \deprecated [6.2]
2550
2551 Returns the text of the message box button \a button, or
2552 an empty string if the message box does not contain the button.
2553
2554 Use button() and QPushButton::text() instead.
2555*/
2556QString QMessageBox::buttonText(int button) const
2557{
2558 Q_D(const QMessageBox);
2559
2560 if (QAbstractButton *abstractButton = d->abstractButtonForId(id: button)) {
2561 return abstractButton->text();
2562 } else if (d->buttonBox->buttons().isEmpty() && (button == Ok || button == Old_Ok)) {
2563 // for compatibility with Qt 4.0/4.1
2564 return QDialogButtonBox::tr(s: "OK");
2565 }
2566 return QString();
2567}
2568
2569/*!
2570 \deprecated [6.2]
2571
2572 Sets the text of the message box button \a button to \a text.
2573 Setting the text of a button that is not in the message box is
2574 silently ignored.
2575
2576 Use addButton() instead.
2577*/
2578void QMessageBox::setButtonText(int button, const QString &text)
2579{
2580 Q_D(QMessageBox);
2581 if (QAbstractButton *abstractButton = d->abstractButtonForId(id: button)) {
2582 abstractButton->setText(text);
2583 } else if (d->buttonBox->buttons().isEmpty() && (button == Ok || button == Old_Ok)) {
2584 // for compatibility with Qt 4.0/4.1
2585 addButton(button: QMessageBox::Ok)->setText(text);
2586 }
2587}
2588#endif // QT_DEPRECATED_SINCE(6,2)
2589
2590
2591#if QT_CONFIG(textedit)
2592/*!
2593 \property QMessageBox::detailedText
2594 \brief the text to be displayed in the details area.
2595
2596 The text will be interpreted as a plain text.
2597
2598 By default, this property contains an empty string.
2599
2600 \sa QMessageBox::text, QMessageBox::informativeText
2601*/
2602QString QMessageBox::detailedText() const
2603{
2604 Q_D(const QMessageBox);
2605 return d->detailsText ? d->detailsText->text() : QString();
2606}
2607
2608void QMessageBox::setDetailedText(const QString &text)
2609{
2610 Q_D(QMessageBox);
2611 if (text.isEmpty()) {
2612 if (d->detailsText) {
2613 d->detailsText->hide();
2614 d->detailsText->deleteLater();
2615 }
2616 d->detailsText = nullptr;
2617 removeButton(button: d->detailsButton);
2618 if (d->detailsButton) {
2619 d->detailsButton->hide();
2620 d->detailsButton->deleteLater();
2621 }
2622 d->detailsButton = nullptr;
2623 } else {
2624 if (!d->detailsText) {
2625 d->detailsText = new QMessageBoxDetailsText(this);
2626 d->detailsText->hide();
2627 }
2628 if (!d->detailsButton) {
2629 const bool autoAddOkButton = d->autoAddOkButton; // QTBUG-39334, addButton() clears the flag.
2630 d->detailsButton = new DetailButton(this);
2631 addButton(button: d->detailsButton, role: QMessageBox::ActionRole);
2632 d->autoAddOkButton = autoAddOkButton;
2633 }
2634 d->detailsText->setText(text);
2635 }
2636 d->setupLayout();
2637}
2638#endif // QT_CONFIG(textedit)
2639
2640/*!
2641 \property QMessageBox::informativeText
2642
2643 \brief the informative text that provides a fuller description for
2644 the message
2645
2646 Informative text can be used to expand upon the text() to give more
2647 information to the user, for example describing the consequences of
2648 the situation, or suggestion alternative solutions.
2649
2650 The text will be interpreted either as a plain text or as rich text,
2651 depending on the text format setting (\l QMessageBox::textFormat).
2652 The default setting is Qt::AutoText, i.e., the message box will try
2653 to auto-detect the format of the text.
2654
2655 By default, this property contains an empty string.
2656
2657 \sa textFormat, QMessageBox::text, QMessageBox::detailedText
2658*/
2659QString QMessageBox::informativeText() const
2660{
2661 Q_D(const QMessageBox);
2662 return d->informativeLabel ? d->informativeLabel->text() : QString();
2663}
2664
2665void QMessageBox::setInformativeText(const QString &text)
2666{
2667 Q_D(QMessageBox);
2668 if (text.isEmpty()) {
2669 if (d->informativeLabel) {
2670 d->informativeLabel->hide();
2671 d->informativeLabel->deleteLater();
2672 }
2673 d->informativeLabel = nullptr;
2674 } else {
2675 if (!d->informativeLabel) {
2676 QLabel *label = new QLabel;
2677 label->setObjectName("qt_msgbox_informativelabel"_L1);
2678 label->setTextInteractionFlags(Qt::TextInteractionFlags(style()->styleHint(stylehint: QStyle::SH_MessageBox_TextInteractionFlags, opt: nullptr, widget: this)));
2679 label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
2680 label->setOpenExternalLinks(true);
2681#ifdef Q_OS_MAC
2682 // apply a smaller font the information label on the mac
2683 label->setFont(qt_app_fonts_hash()->value("QTipLabel"));
2684#endif
2685 label->setWordWrap(true);
2686 label->setTextFormat(d->label->textFormat());
2687 d->informativeLabel = label;
2688 }
2689 d->informativeLabel->setText(text);
2690 }
2691 d->setupLayout();
2692}
2693
2694/*!
2695 This function shadows QWidget::setWindowTitle().
2696
2697 Sets the title of the message box to \a title. On \macos,
2698 the window title is ignored (as required by the \macos
2699 Guidelines).
2700*/
2701void QMessageBox::setWindowTitle(const QString &title)
2702{
2703 // Message boxes on the mac do not have a title
2704#ifndef Q_OS_MAC
2705 QDialog::setWindowTitle(title);
2706#else
2707 Q_UNUSED(title);
2708#endif
2709}
2710
2711
2712/*!
2713 This function shadows QWidget::setWindowModality().
2714
2715 Sets the modality of the message box to \a windowModality.
2716
2717 On \macos, if the modality is set to Qt::WindowModal and the message box
2718 has a parent, then the message box will be a Qt::Sheet, otherwise the
2719 message box will be a standard dialog.
2720*/
2721void QMessageBox::setWindowModality(Qt::WindowModality windowModality)
2722{
2723 QDialog::setWindowModality(windowModality);
2724
2725 if (parentWidget() && windowModality == Qt::WindowModal)
2726 setParent(parent: parentWidget(), f: Qt::Sheet);
2727 else
2728 setParent(parent: parentWidget(), f: Qt::Dialog);
2729 setDefaultButton(d_func()->defaultButton);
2730}
2731
2732
2733QPixmap QMessageBoxPrivate::standardIcon(QMessageBox::Icon icon, QMessageBox *mb)
2734{
2735 QStyle *style = mb ? mb->style() : QApplication::style();
2736 int iconSize = style->pixelMetric(metric: QStyle::PM_MessageBoxIconSize, option: nullptr, widget: mb);
2737 QIcon tmpIcon;
2738 switch (icon) {
2739 case QMessageBox::Information:
2740 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxInformation, option: nullptr, widget: mb);
2741 break;
2742 case QMessageBox::Warning:
2743 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxWarning, option: nullptr, widget: mb);
2744 break;
2745 case QMessageBox::Critical:
2746 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxCritical, option: nullptr, widget: mb);
2747 break;
2748 case QMessageBox::Question:
2749 tmpIcon = style->standardIcon(standardIcon: QStyle::SP_MessageBoxQuestion, option: nullptr, widget: mb);
2750 break;
2751 default:
2752 break;
2753 }
2754 if (!tmpIcon.isNull()) {
2755 qreal dpr = mb ? mb->devicePixelRatio() : qApp->devicePixelRatio();
2756 return tmpIcon.pixmap(size: QSize(iconSize, iconSize), devicePixelRatio: dpr);
2757 }
2758 return QPixmap();
2759}
2760
2761void QMessageBoxPrivate::initHelper(QPlatformDialogHelper *h)
2762{
2763 auto *messageDialogHelper = static_cast<QPlatformMessageDialogHelper *>(h);
2764 QObjectPrivate::connect(sender: messageDialogHelper, signal: &QPlatformMessageDialogHelper::clicked,
2765 receiverPrivate: this, slot: &QMessageBoxPrivate::helperClicked);
2766 // Forward state via lambda, so that we can handle addition and removal
2767 // of checkbox via setCheckBox() after initializing helper.
2768 QObject::connect(sender: messageDialogHelper, signal: &QPlatformMessageDialogHelper::checkBoxStateChanged,
2769 context: q_ptr, slot: [this](Qt::CheckState state) {
2770 if (checkbox)
2771 checkbox->setCheckState(state);
2772 }
2773 );
2774 messageDialogHelper->setOptions(options);
2775}
2776
2777static QMessageDialogOptions::StandardIcon helperIcon(QMessageBox::Icon i)
2778{
2779 switch (i) {
2780 case QMessageBox::NoIcon:
2781 return QMessageDialogOptions::NoIcon;
2782 case QMessageBox::Information:
2783 return QMessageDialogOptions::Information;
2784 case QMessageBox::Warning:
2785 return QMessageDialogOptions::Warning;
2786 case QMessageBox::Critical:
2787 return QMessageDialogOptions::Critical;
2788 case QMessageBox::Question:
2789 return QMessageDialogOptions::Question;
2790 }
2791 return QMessageDialogOptions::NoIcon;
2792}
2793
2794static QPlatformDialogHelper::StandardButtons helperStandardButtons(QMessageBox * q)
2795{
2796 QPlatformDialogHelper::StandardButtons buttons(int(q->standardButtons()));
2797 return buttons;
2798}
2799
2800bool QMessageBoxPrivate::canBeNativeDialog() const
2801{
2802 // Don't use Q_Q here! This function is called from ~QDialog,
2803 // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()).
2804 const QDialog * const q = static_cast<const QMessageBox*>(q_ptr);
2805 if (nativeDialogInUse)
2806 return true;
2807 if (QCoreApplication::testAttribute(attribute: Qt::AA_DontUseNativeDialogs)
2808 || q->testAttribute(attribute: Qt::WA_DontShowOnScreen)
2809 || q->testAttribute(attribute: Qt::WA_StyleSheet)
2810 || (options->options() & QMessageDialogOptions::Option::DontUseNativeDialog)) {
2811 return false;
2812 }
2813
2814 if (strcmp(s1: QMessageBox::staticMetaObject.className(), s2: q->metaObject()->className()) != 0)
2815 return false;
2816
2817#if QT_CONFIG(menu)
2818 for (auto *customButton : buttonBox->buttons()) {
2819 if (QPushButton *pushButton = qobject_cast<QPushButton *>(object: customButton)) {
2820 // We can't support buttons with menus in native dialogs (yet)
2821 if (pushButton->menu())
2822 return false;
2823 }
2824 }
2825#endif
2826
2827 return QDialogPrivate::canBeNativeDialog();
2828}
2829
2830void QMessageBoxPrivate::helperPrepareShow(QPlatformDialogHelper *)
2831{
2832 Q_Q(QMessageBox);
2833 options->setWindowTitle(q->windowTitle());
2834 options->setText(q->text());
2835 options->setInformativeText(q->informativeText());
2836#if QT_CONFIG(textedit)
2837 options->setDetailedText(q->detailedText());
2838#endif
2839 options->setStandardIcon(helperIcon(i: q->icon()));
2840 options->setIconPixmap(q->iconPixmap());
2841
2842 // Clear up front, since we might have prepared earlier
2843 options->clearCustomButtons();
2844
2845 // Add standard buttons and resolve default/escape button
2846 auto standardButtons = helperStandardButtons(q);
2847 for (int button = QDialogButtonBox::StandardButton::FirstButton;
2848 button <= QDialogButtonBox::StandardButton::LastButton; button <<= 1) {
2849 auto *standardButton = buttonBox->button(which: QDialogButtonBox::StandardButton(button));
2850 if (!standardButton)
2851 continue;
2852
2853 if (auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
2854 if (standardButton->text() != platformTheme->standardButtonText(button)) {
2855 // The standard button has been customized, so add it as
2856 // a custom button instead.
2857 const auto buttonRole = buttonBox->buttonRole(button: standardButton);
2858 options->addButton(label: standardButton->text(),
2859 role: static_cast<QPlatformDialogHelper::ButtonRole>(buttonRole),
2860 buttonImpl: standardButton, buttonId: button);
2861 standardButtons &= ~QPlatformDialogHelper::StandardButton(button);
2862 }
2863 }
2864
2865 if (standardButton == defaultButton)
2866 options->setDefaultButton(button);
2867 else if (standardButton == detectedEscapeButton)
2868 options->setEscapeButton(button);
2869 }
2870 options->setStandardButtons(standardButtons);
2871
2872 // Add custom buttons and resolve default/escape button
2873 for (auto *customButton : customButtonList) {
2874 // Unless it's the details button, since we don't do any
2875 // plumbing for the button's action in that case.
2876 if (customButton == detailsButton)
2877 continue;
2878
2879 const auto buttonRole = buttonBox->buttonRole(button: customButton);
2880 const int buttonId = options->addButton(label: customButton->text(),
2881 role: static_cast<QPlatformDialogHelper::ButtonRole>(buttonRole),
2882 buttonImpl: customButton);
2883
2884 if (customButton == defaultButton)
2885 options->setDefaultButton(buttonId);
2886 else if (customButton == detectedEscapeButton)
2887 options->setEscapeButton(buttonId);
2888 }
2889
2890 if (checkbox)
2891 options->setCheckBox(label: checkbox->text(), state: checkbox->checkState());
2892}
2893
2894void qRequireVersion(int argc, char *argv[], QAnyStringView req)
2895{
2896 const auto required = QVersionNumber::fromString(string: req).normalized();
2897 const auto current = QVersionNumber::fromString(string: qVersion()).normalized();
2898 if (current >= required)
2899 return;
2900 std::optional<QApplication> application;
2901 if (!qApp)
2902 application.emplace(args&: argc, args&: argv);
2903 const QString message = QApplication::tr(s: "Application \"%1\" requires Qt %2, found Qt %3.")
2904 .arg(args: qAppName(), args: required.toString(), args: current.toString());
2905 QMessageBox::critical(parent: nullptr, title: QApplication::tr(s: "Incompatible Qt Library Error"),
2906 text: message, buttons: QMessageBox::Abort);
2907 qFatal(msg: "%ls", qUtf16Printable(message));
2908}
2909
2910#if QT_DEPRECATED_SINCE(6,2)
2911/*!
2912 \deprecated [6.2]
2913
2914 Returns the pixmap used for a standard icon. This allows the
2915 pixmaps to be used in more complex message boxes. \a icon
2916 specifies the required icon, e.g. QMessageBox::Question,
2917 QMessageBox::Information, QMessageBox::Warning or
2918 QMessageBox::Critical.
2919
2920 Call QStyle::standardIcon() with QStyle::SP_MessageBoxInformation etc.
2921 instead.
2922*/
2923
2924QPixmap QMessageBox::standardIcon(Icon icon)
2925{
2926 return QMessageBoxPrivate::standardIcon(icon, mb: nullptr);
2927}
2928#endif
2929
2930/*!
2931 \typedef QMessageBox::Button
2932 \deprecated
2933
2934 Use QMessageBox::StandardButton instead.
2935*/
2936
2937/*!
2938 \fn int QMessageBox::information(QWidget *parent, const QString &title,
2939 const QString& text, StandardButton button0,
2940 StandardButton button1)
2941 \fn int QMessageBox::warning(QWidget *parent, const QString &title,
2942 const QString& text, StandardButton button0,
2943 StandardButton button1)
2944 \fn int QMessageBox::critical(QWidget *parent, const QString &title,
2945 const QString& text, StandardButton button0,
2946 StandardButton button1)
2947 \fn int QMessageBox::question(QWidget *parent, const QString &title,
2948 const QString& text, StandardButton button0,
2949 StandardButton button1)
2950 \internal
2951
2952 ### Needed for Qt 4 source compatibility
2953*/
2954
2955/*!
2956 \fn int QMessageBox::exec()
2957
2958 Shows the message box as a \l{QDialog#Modal Dialogs}{modal dialog},
2959 blocking until the user closes it.
2960
2961 When using a QMessageBox with standard buttons, this function returns a
2962 \l StandardButton value indicating the standard button that was clicked.
2963 When using QMessageBox with custom buttons, this function returns an
2964 opaque value; use clickedButton() to determine which button was clicked.
2965
2966 \note The result() function returns also \l StandardButton value instead
2967 of \l QDialog::DialogCode.
2968
2969 Users cannot interact with any other window in the same
2970 application until they close the dialog, either by clicking a
2971 button or by using a mechanism provided by the window system.
2972
2973 \sa show(), result()
2974*/
2975
2976/*!
2977 \macro QT_REQUIRE_VERSION(int argc, char **argv, const char *version)
2978 \relates QMessageBox
2979
2980 This macro can be used to ensure that the application is run
2981 with a recent enough version of Qt. This is especially useful
2982 if your application depends on a specific bug fix introduced in a
2983 bug-fix release (for example, 6.1.2).
2984
2985 The \a argc and \a argv parameters are the \c main() function's
2986 \c argc and \c argv parameters. The \a version parameter is a
2987 string literal that specifies which version of Qt the application
2988 requires (for example, "6.1.2").
2989
2990 Example:
2991
2992 \snippet code/src_gui_dialogs_qmessagebox.cpp 4
2993*/
2994
2995QT_END_NAMESPACE
2996
2997#include "moc_qmessagebox.cpp"
2998#include "qmessagebox.moc"
2999

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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