aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/utils/checkablemessagebox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/utils/checkablemessagebox.cpp')
-rw-r--r--src/libs/utils/checkablemessagebox.cpp548
1 files changed, 137 insertions, 411 deletions
diff --git a/src/libs/utils/checkablemessagebox.cpp b/src/libs/utils/checkablemessagebox.cpp
index 4420fc66cb..d3ede7d4e7 100644
--- a/src/libs/utils/checkablemessagebox.cpp
+++ b/src/libs/utils/checkablemessagebox.cpp
@@ -3,6 +3,7 @@
#include "checkablemessagebox.h"
+#include "hostosinfo.h"
#include "qtcassert.h"
#include "utilstr.h"
@@ -17,10 +18,11 @@
/*!
\class Utils::CheckableMessageBox
+ \inmodule QtCreator
\brief The CheckableMessageBox class implements a message box suitable for
- questions with a
- "Do not ask me again" checkbox.
+ questions with a \uicontrol {Do not ask again} or \uicontrol {Do not show again}
+ checkbox.
Emulates the QMessageBox API with
static conveniences. The message label can open external URLs.
@@ -30,435 +32,155 @@ static const char kDoNotAskAgainKey[] = "DoNotAskAgain";
namespace Utils {
-class CheckableMessageBoxPrivate
-{
-public:
- CheckableMessageBoxPrivate(QDialog *q)
- {
- QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
-
- pixmapLabel = new QLabel(q);
- sizePolicy.setHorizontalStretch(0);
- sizePolicy.setVerticalStretch(0);
- sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth());
- pixmapLabel->setSizePolicy(sizePolicy);
- pixmapLabel->setVisible(false);
- pixmapLabel->setFocusPolicy(Qt::NoFocus);
-
- auto pixmapSpacer =
- new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding);
-
- messageLabel = new QLabel(q);
- messageLabel->setMinimumSize(QSize(300, 0));
- messageLabel->setWordWrap(true);
- messageLabel->setOpenExternalLinks(true);
- messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse);
- messageLabel->setFocusPolicy(Qt::NoFocus);
- messageLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
-
- checkBox = new QCheckBox(q);
- checkBox->setText(Tr::tr("Do not ask again"));
-
- const QString showText = Tr::tr("Show Details...");
- detailsButton = new QPushButton(showText, q);
- detailsButton->setAutoDefault(false);
- detailsButton->hide();
- detailsText = new QTextEdit(q);
- detailsText->hide();
- QObject::connect(detailsButton, &QPushButton::clicked, detailsText, [this, showText] {
- detailsText->setVisible(!detailsText->isVisible());
- detailsButton->setText(
- detailsText->isVisible() ? Tr::tr("Hide Details...") : showText);
- });
-
- buttonBox = new QDialogButtonBox(q);
- buttonBox->setOrientation(Qt::Horizontal);
- buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
-
- auto verticalLayout = new QVBoxLayout();
- verticalLayout->addWidget(pixmapLabel);
- verticalLayout->addItem(pixmapSpacer);
-
- auto horizontalLayout_2 = new QHBoxLayout();
- horizontalLayout_2->addLayout(verticalLayout);
- horizontalLayout_2->addWidget(messageLabel, 10);
-
- auto horizontalLayout = new QHBoxLayout();
- horizontalLayout->addWidget(checkBox);
- horizontalLayout->addStretch(10);
-
- auto detailsButtonLayout = new QHBoxLayout;
- detailsButtonLayout->addWidget(detailsButton);
- detailsButtonLayout->addStretch(10);
-
- auto verticalLayout_2 = new QVBoxLayout(q);
- verticalLayout_2->addLayout(horizontalLayout_2);
- verticalLayout_2->addLayout(horizontalLayout);
- verticalLayout_2->addLayout(detailsButtonLayout);
- verticalLayout_2->addWidget(detailsText, 10);
- verticalLayout_2->addStretch(1);
- verticalLayout_2->addWidget(buttonBox);
- }
-
- QLabel *pixmapLabel = nullptr;
- QLabel *messageLabel = nullptr;
- QCheckBox *checkBox = nullptr;
- QDialogButtonBox *buttonBox = nullptr;
- QAbstractButton *clickedButton = nullptr;
- QPushButton *detailsButton = nullptr;
- QTextEdit *detailsText = nullptr;
- QMessageBox::Icon icon = QMessageBox::NoIcon;
-};
-
-CheckableMessageBox::CheckableMessageBox(QWidget *parent) :
- QDialog(parent),
- d(new CheckableMessageBoxPrivate(this))
-{
- setModal(true);
- connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
- connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
- connect(d->buttonBox, &QDialogButtonBox::clicked,
- this, [this](QAbstractButton *b) { d->clickedButton = b; });
-}
-
-CheckableMessageBox::~CheckableMessageBox()
-{
- delete d;
-}
-
-QAbstractButton *CheckableMessageBox::clickedButton() const
-{
- return d->clickedButton;
-}
-
-QDialogButtonBox::StandardButton CheckableMessageBox::clickedStandardButton() const
-{
- if (d->clickedButton)
- return d->buttonBox->standardButton(d->clickedButton);
- return QDialogButtonBox::NoButton;
-}
-
-QString CheckableMessageBox::text() const
-{
- return d->messageLabel->text();
-}
-
-void CheckableMessageBox::setText(const QString &t)
-{
- d->messageLabel->setText(t);
-}
-
-QMessageBox::Icon CheckableMessageBox::icon() const
-{
- return d->icon;
-}
-
-// See QMessageBoxPrivate::standardIcon
-static QPixmap pixmapForIcon(QMessageBox::Icon icon, QWidget *w)
-{
- const QStyle *style = w ? w->style() : QApplication::style();
- const int iconSize = style->pixelMetric(QStyle::PM_MessageBoxIconSize, nullptr, w);
- QIcon tmpIcon;
- switch (icon) {
- case QMessageBox::Information:
- tmpIcon = style->standardIcon(QStyle::SP_MessageBoxInformation, nullptr, w);
- break;
- case QMessageBox::Warning:
- tmpIcon = style->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, w);
- break;
- case QMessageBox::Critical:
- tmpIcon = style->standardIcon(QStyle::SP_MessageBoxCritical, nullptr, w);
- break;
- case QMessageBox::Question:
- tmpIcon = style->standardIcon(QStyle::SP_MessageBoxQuestion, nullptr, w);
- break;
- default:
- break;
- }
- if (!tmpIcon.isNull()) {
- QWindow *window = nullptr;
- if (w) {
- window = w->windowHandle();
- if (!window) {
- if (const QWidget *nativeParent = w->nativeParentWidget())
- window = nativeParent->windowHandle();
- }
+static QSettings *theSettings;
+
+static QMessageBox::StandardButton exec(
+ QWidget *parent,
+ QMessageBox::Icon icon,
+ const QString &title,
+ const QString &text,
+ const CheckableDecider &decider,
+ QMessageBox::StandardButtons buttons,
+ QMessageBox::StandardButton defaultButton,
+ QMessageBox::StandardButton acceptButton,
+ QMap<QMessageBox::StandardButton, QString> buttonTextOverrides,
+ const QString &msg)
+{
+ QMessageBox msgBox(parent);
+ msgBox.setWindowTitle(title);
+ msgBox.setIcon(icon);
+ msgBox.setText(text);
+ msgBox.setTextFormat(Qt::RichText);
+ msgBox.setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
+
+ if (HostOsInfo::isMacHost()) {
+ // Message boxes on macOS cannot display links.
+ // If the message contains a link, we need to disable native dialogs.
+ if (text.contains("<a ")) {
+#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
+ msgBox.setOptions(QMessageBox::Option::DontUseNativeDialog);
+#endif
}
- return tmpIcon.pixmap(window, QSize(iconSize, iconSize));
- }
- return QPixmap();
-}
-
-void CheckableMessageBox::setIcon(QMessageBox::Icon icon)
-{
- d->icon = icon;
- const QPixmap pixmap = pixmapForIcon(icon, this);
- d->pixmapLabel->setPixmap(pixmap);
- d->pixmapLabel->setVisible(!pixmap.isNull());
-}
-
-bool CheckableMessageBox::isChecked() const
-{
- return d->checkBox->isChecked();
-}
-
-void CheckableMessageBox::setChecked(bool s)
-{
- d->checkBox->setChecked(s);
-}
-
-QString CheckableMessageBox::checkBoxText() const
-{
- return d->checkBox->text();
-}
-
-void CheckableMessageBox::setCheckBoxText(const QString &t)
-{
- d->checkBox->setText(t);
-}
-
-bool CheckableMessageBox::isCheckBoxVisible() const
-{
- return d->checkBox->isVisible();
-}
-
-void CheckableMessageBox::setCheckBoxVisible(bool v)
-{
- d->checkBox->setVisible(v);
-}
-
-QString CheckableMessageBox::detailedText() const
-{
- return d->detailsText->toPlainText();
-}
-
-void CheckableMessageBox::setDetailedText(const QString &text)
-{
- d->detailsText->setText(text);
- if (!text.isEmpty())
- d->detailsButton->setVisible(true);
-}
-
-QDialogButtonBox::StandardButtons CheckableMessageBox::standardButtons() const
-{
- return d->buttonBox->standardButtons();
-}
-
-void CheckableMessageBox::setStandardButtons(QDialogButtonBox::StandardButtons s)
-{
- d->buttonBox->setStandardButtons(s);
-}
-
-QPushButton *CheckableMessageBox::button(QDialogButtonBox::StandardButton b) const
-{
- return d->buttonBox->button(b);
-}
-
-QPushButton *CheckableMessageBox::addButton(const QString &text, QDialogButtonBox::ButtonRole role)
-{
- return d->buttonBox->addButton(text, role);
-}
-
-QDialogButtonBox::StandardButton CheckableMessageBox::defaultButton() const
-{
- const QList<QAbstractButton *> buttons = d->buttonBox->buttons();
- for (QAbstractButton *b : buttons)
- if (auto *pb = qobject_cast<QPushButton *>(b))
- if (pb->isDefault())
- return d->buttonBox->standardButton(pb);
- return QDialogButtonBox::NoButton;
-}
-
-void CheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s)
-{
- if (QPushButton *b = d->buttonBox->button(s)) {
- b->setDefault(true);
- b->setFocus();
}
-}
-QDialogButtonBox::StandardButton
-CheckableMessageBox::question(QWidget *parent,
- const QString &title,
- const QString &question,
- const QString &checkBoxText,
- bool *checkBoxSetting,
- QDialogButtonBox::StandardButtons buttons,
- QDialogButtonBox::StandardButton defaultButton)
-{
- CheckableMessageBox mb(parent);
- mb.setWindowTitle(title);
- mb.setIcon(QMessageBox::Question);
- mb.setText(question);
- mb.setCheckBoxText(checkBoxText);
- mb.setChecked(*checkBoxSetting);
- mb.setStandardButtons(buttons);
- mb.setDefaultButton(defaultButton);
- mb.exec();
- *checkBoxSetting = mb.isChecked();
- return mb.clickedStandardButton();
-}
-
-QDialogButtonBox::StandardButton
-CheckableMessageBox::information(QWidget *parent,
- const QString &title,
- const QString &text,
- const QString &checkBoxText,
- bool *checkBoxSetting,
- QDialogButtonBox::StandardButtons buttons,
- QDialogButtonBox::StandardButton defaultButton)
-{
- CheckableMessageBox mb(parent);
- mb.setWindowTitle(title);
- mb.setIcon(QMessageBox::Information);
- mb.setText(text);
- mb.setCheckBoxText(checkBoxText);
- mb.setChecked(*checkBoxSetting);
- mb.setStandardButtons(buttons);
- mb.setDefaultButton(defaultButton);
- mb.exec();
- *checkBoxSetting = mb.isChecked();
- return mb.clickedStandardButton();
-}
-
-QMessageBox::StandardButton CheckableMessageBox::dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton db)
-{
- return static_cast<QMessageBox::StandardButton>(int(db));
-}
+ if (decider.shouldAskAgain) {
+ if (!decider.shouldAskAgain())
+ return acceptButton;
-bool CheckableMessageBox::shouldAskAgain(QSettings *settings, const QString &settingsSubKey)
-{
- if (QTC_GUARD(settings)) {
- settings->beginGroup(QLatin1String(kDoNotAskAgainKey));
- bool shouldNotAsk = settings->value(settingsSubKey, false).toBool();
- settings->endGroup();
- if (shouldNotAsk)
- return false;
+ msgBox.setCheckBox(new QCheckBox);
+ msgBox.checkBox()->setChecked(false);
+ msgBox.checkBox()->setText(msg);
}
- return true;
-}
-
-enum DoNotAskAgainType{Question, Information};
-
-void initDoNotAskAgainMessageBox(CheckableMessageBox &messageBox, const QString &title,
- const QString &text, QDialogButtonBox::StandardButtons buttons,
- QDialogButtonBox::StandardButton defaultButton,
- DoNotAskAgainType type)
-{
- messageBox.setWindowTitle(title);
- messageBox.setIcon(type == Information ? QMessageBox::Information : QMessageBox::Question);
- messageBox.setText(text);
- messageBox.setCheckBoxVisible(true);
- messageBox.setCheckBoxText(type == Information ? CheckableMessageBox::msgDoNotShowAgain()
- : CheckableMessageBox::msgDoNotAskAgain());
- messageBox.setChecked(false);
- messageBox.setStandardButtons(buttons);
- messageBox.setDefaultButton(defaultButton);
-}
-
-void CheckableMessageBox::doNotAskAgain(QSettings *settings, const QString &settingsSubKey)
-{
- if (!settings)
- return;
- settings->beginGroup(QLatin1String(kDoNotAskAgainKey));
- settings->setValue(settingsSubKey, true);
- settings->endGroup();
+ msgBox.setStandardButtons(buttons);
+ msgBox.setDefaultButton(defaultButton);
+ for (auto it = buttonTextOverrides.constBegin(); it != buttonTextOverrides.constEnd(); ++it)
+ msgBox.button(it.key())->setText(it.value());
+ msgBox.exec();
+
+ QMessageBox::StandardButton clickedBtn = msgBox.standardButton(msgBox.clickedButton());
+
+ if (decider.doNotAskAgain && msgBox.checkBox()->isChecked()
+ && (acceptButton == QMessageBox::NoButton || clickedBtn == acceptButton))
+ decider.doNotAskAgain();
+ return clickedBtn;
+}
+
+CheckableDecider::CheckableDecider(const QString &settingsSubKey)
+{
+ QTC_ASSERT(theSettings, return);
+ shouldAskAgain = [settingsSubKey] {
+ theSettings->beginGroup(QLatin1String(kDoNotAskAgainKey));
+ bool shouldNotAsk = theSettings->value(settingsSubKey, false).toBool();
+ theSettings->endGroup();
+ return !shouldNotAsk;
+ };
+ doNotAskAgain = [settingsSubKey] {
+ theSettings->beginGroup(QLatin1String(kDoNotAskAgainKey));
+ theSettings->setValue(settingsSubKey, true);
+ theSettings->endGroup();
+ };
+}
+
+CheckableDecider::CheckableDecider(bool *storage)
+{
+ shouldAskAgain = [storage] { return !*storage; };
+ doNotAskAgain = [storage] { *storage = true; };
+}
+
+QMessageBox::StandardButton CheckableMessageBox::question(
+ QWidget *parent,
+ const QString &title,
+ const QString &question,
+ const CheckableDecider &decider,
+ QMessageBox::StandardButtons buttons,
+ QMessageBox::StandardButton defaultButton,
+ QMessageBox::StandardButton acceptButton,
+ QMap<QMessageBox::StandardButton, QString> buttonTextOverrides,
+ const QString &msg)
+{
+ return exec(parent,
+ QMessageBox::Question,
+ title,
+ question,
+ decider,
+ buttons,
+ defaultButton,
+ acceptButton,
+ buttonTextOverrides,
+ msg.isEmpty() ? msgDoNotAskAgain() : msg);
+}
+
+QMessageBox::StandardButton CheckableMessageBox::information(
+ QWidget *parent,
+ const QString &title,
+ const QString &text,
+ const CheckableDecider &decider,
+ QMessageBox::StandardButtons buttons,
+ QMessageBox::StandardButton defaultButton,
+ QMap<QMessageBox::StandardButton, QString> buttonTextOverrides,
+ const QString &msg)
+{
+ return exec(parent,
+ QMessageBox::Information,
+ title,
+ text,
+ decider,
+ buttons,
+ defaultButton,
+ QMessageBox::NoButton,
+ buttonTextOverrides,
+ msg.isEmpty() ? msgDoNotShowAgain() : msg);
}
/*!
- Shows a message box with given \a title and \a text, and a \gui {Do not ask again} check box.
- If the user checks the check box and accepts the dialog with the \a acceptButton,
- further invocations of this function with the same \a settings and \a settingsSubKey will not
- show the dialog, but instantly return \a acceptButton.
-
- Returns the clicked button, or QDialogButtonBox::NoButton if the user rejects the dialog
- with the escape key, or \a acceptButton if the dialog is suppressed.
-*/
-QDialogButtonBox::StandardButton
-CheckableMessageBox::doNotAskAgainQuestion(QWidget *parent, const QString &title,
- const QString &text, QSettings *settings,
- const QString &settingsSubKey,
- QDialogButtonBox::StandardButtons buttons,
- QDialogButtonBox::StandardButton defaultButton,
- QDialogButtonBox::StandardButton acceptButton)
-
-{
- if (!shouldAskAgain(settings, settingsSubKey))
- return acceptButton;
-
- CheckableMessageBox messageBox(parent);
- initDoNotAskAgainMessageBox(messageBox, title, text, buttons, defaultButton, Question);
- messageBox.exec();
- if (messageBox.isChecked() && (messageBox.clickedStandardButton() == acceptButton))
- doNotAskAgain(settings, settingsSubKey);
-
- return messageBox.clickedStandardButton();
-}
-
-/*!
- Shows a message box with given \a title and \a text, and a \gui {Do not show again} check box.
- If the user checks the check box and quits the dialog, further invocations of this
- function with the same \a settings and \a settingsSubKey will not show the dialog, but instantly return.
-
- Returns the clicked button, or QDialogButtonBox::NoButton if the user rejects the dialog
- with the escape key, or \a defaultButton if the dialog is suppressed.
-*/
-QDialogButtonBox::StandardButton
-CheckableMessageBox::doNotShowAgainInformation(QWidget *parent, const QString &title,
- const QString &text, QSettings *settings,
- const QString &settingsSubKey,
- QDialogButtonBox::StandardButtons buttons,
- QDialogButtonBox::StandardButton defaultButton)
-
-{
- if (!shouldAskAgain(settings, settingsSubKey))
- return defaultButton;
-
- CheckableMessageBox messageBox(parent);
- initDoNotAskAgainMessageBox(messageBox, title, text, buttons, defaultButton, Information);
- messageBox.exec();
- if (messageBox.isChecked())
- doNotAskAgain(settings, settingsSubKey);
-
- return messageBox.clickedStandardButton();
-}
-
-/*!
- Resets all suppression settings for doNotAskAgainQuestion() found in \a settings,
+ Resets all suppression settings for doNotAskAgainQuestion()
so all these message boxes are shown again.
*/
-void CheckableMessageBox::resetAllDoNotAskAgainQuestions(QSettings *settings)
+void CheckableMessageBox::resetAllDoNotAskAgainQuestions()
{
- QTC_ASSERT(settings, return);
- settings->beginGroup(QLatin1String(kDoNotAskAgainKey));
- settings->remove(QString());
- settings->endGroup();
+ QTC_ASSERT(theSettings, return);
+ theSettings->beginGroup(QLatin1String(kDoNotAskAgainKey));
+ theSettings->remove(QString());
+ theSettings->endGroup();
}
/*!
Returns whether any message boxes from doNotAskAgainQuestion() are suppressed
- in the \a settings.
+ in the settings.
*/
-bool CheckableMessageBox::hasSuppressedQuestions(QSettings *settings)
+bool CheckableMessageBox::hasSuppressedQuestions()
{
- QTC_ASSERT(settings, return false);
- bool hasSuppressed = false;
- settings->beginGroup(QLatin1String(kDoNotAskAgainKey));
- const QStringList childKeys = settings->childKeys();
- for (const QString &subKey : childKeys) {
- if (settings->value(subKey, false).toBool()) {
- hasSuppressed = true;
- break;
- }
- }
- settings->endGroup();
+ QTC_ASSERT(theSettings, return false);
+ theSettings->beginGroup(QLatin1String(kDoNotAskAgainKey));
+ const bool hasSuppressed = !theSettings->childKeys().isEmpty()
+ || !theSettings->childGroups().isEmpty();
+ theSettings->endGroup();
return hasSuppressed;
}
/*!
- Returns the standard \gui {Do not ask again} check box text.
- \sa doNotAskAgainQuestion()
+ Returns the standard \uicontrol {Do not ask again} check box text.
*/
QString CheckableMessageBox::msgDoNotAskAgain()
{
@@ -466,12 +188,16 @@ QString CheckableMessageBox::msgDoNotAskAgain()
}
/*!
- Returns the standard \gui {Do not show again} check box text.
- \sa doNotShowAgainInformation()
+ Returns the standard \uicontrol {Do not show again} check box text.
*/
QString CheckableMessageBox::msgDoNotShowAgain()
{
return Tr::tr("Do not &show again");
}
+void CheckableMessageBox::initialize(QSettings *settings)
+{
+ theSettings = settings;
+}
+
} // namespace Utils