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