summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2022-11-21 13:38:05 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2022-12-04 19:15:37 +0100
commit31973f3ff32c837fd031d6ed386ebdb2e75cbc1e (patch)
tree13621ae713bd3751a559b41f066f0a93ac32659f
parent8a18466e38779b63c19e281e92031cebaedbcba5 (diff)
Teach QErrorMessage to use native dialog helper if available
And implement for macOS. The default modality of the QErrorMessage on macOS now depends on whether the dialog has a parent or not. The QErrorMessage must be hidden and re-shown again after each message, so that the native dialog has a chance to recreate itself. Change-Id: I474ed35d6271118834fac8e97f6f540a6fb89b8c Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--src/gui/kernel/qplatformdialoghelper.cpp11
-rw-r--r--src/gui/kernel/qplatformdialoghelper.h4
-rw-r--r--src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp3
-rw-r--r--src/plugins/platforms/cocoa/qcocoamessagedialog.mm16
-rw-r--r--src/plugins/platforms/ios/qiosmessagedialog.mm3
-rw-r--r--src/widgets/dialogs/qerrormessage.cpp69
-rw-r--r--src/widgets/dialogs/qerrormessage.h2
7 files changed, 101 insertions, 7 deletions
diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp
index fbc635cc93..de0d4f43d7 100644
--- a/src/gui/kernel/qplatformdialoghelper.cpp
+++ b/src/gui/kernel/qplatformdialoghelper.cpp
@@ -776,6 +776,7 @@ public:
QList<QMessageDialogOptions::CustomButton> customButtons;
int nextCustomButtonId;
QPixmap iconPixmap;
+ bool enableSupressionCheckBox = false;
};
QMessageDialogOptions::QMessageDialogOptions(QMessageDialogOptionsPrivate *dd)
@@ -906,6 +907,16 @@ const QMessageDialogOptions::CustomButton *QMessageDialogOptions::customButton(i
return (i < 0 ? nullptr : &d->customButtons.at(i));
}
+void QMessageDialogOptions::setSupressionCheckBoxEnabled(bool enabled)
+{
+ d->enableSupressionCheckBox = enabled;
+}
+
+bool QMessageDialogOptions::supressionCheckBoxEnabled() const
+{
+ return d->enableSupressionCheckBox;
+}
+
QPlatformDialogHelper::ButtonRole QPlatformDialogHelper::buttonRole(QPlatformDialogHelper::StandardButton button)
{
switch (button) {
diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h
index 2d3138270f..b7aa02cc7c 100644
--- a/src/gui/kernel/qplatformdialoghelper.h
+++ b/src/gui/kernel/qplatformdialoghelper.h
@@ -451,6 +451,9 @@ public:
const QList<CustomButton> &customButtons();
const CustomButton *customButton(int id);
+ void setSupressionCheckBoxEnabled(bool enabled);
+ bool supressionCheckBoxEnabled() const;
+
private:
QMessageDialogOptionsPrivate *d;
};
@@ -464,6 +467,7 @@ public:
Q_SIGNALS:
void clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role);
+ void supressionCheckBoxChanged(bool checked);
private:
QSharedPointer<QMessageDialogOptions> m_options;
diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
index 97ae5064bd..05dd671122 100644
--- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
+++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
@@ -54,6 +54,9 @@ bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags,
if (!opt.data())
return false;
+ if (opt->supressionCheckBoxEnabled())
+ return false; // Can't support
+
m_javaMessageDialog.callMethod<void>("setIcon", "(I)V", opt->icon());
QString str = htmlText(opt->windowTitle());
diff --git a/src/plugins/platforms/cocoa/qcocoamessagedialog.mm b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm
index 3d3970953d..84aea950c3 100644
--- a/src/plugins/platforms/cocoa/qcocoamessagedialog.mm
+++ b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm
@@ -180,6 +180,8 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w
StandardButton::Ok, ButtonRole::AcceptRole);
}
+ m_alert.showsSuppressionButton = options()->supressionCheckBoxEnabled();
+
qCDebug(lcQpaDialogs) << "Showing" << m_alert;
if (windowModality == Qt::WindowModal) {
@@ -230,6 +232,15 @@ void QCocoaMessageDialog::processResponse(NSModalResponse response)
{
qCDebug(lcQpaDialogs) << "Processing response" << response << "for" << m_alert;
+ // We can't re-use the same dialog for the next show() anyways,
+ // since the options may have changed, so get rid of it now,
+ // before we emit anything that might recurse back to hide/show/etc.
+ auto alert = std::exchange(m_alert, nil);
+ [alert autorelease];
+
+ if (alert.showsSuppressionButton)
+ emit supressionCheckBoxChanged(alert.suppressionButton.state == NSControlStateValueOn);
+
if (response >= NSAlertFirstButtonReturn) {
// Safe range for user-defined modal responses
if (response == kModalResponseDialogHidden) {
@@ -270,11 +281,6 @@ void QCocoaMessageDialog::processResponse(NSModalResponse response)
if (m_eventLoop)
m_eventLoop->exit(response);
-
- // We can't re-use the same dialog for the next show() anyways,
- // since the options may have changed, so get rid of it now.
- [m_alert release];
- m_alert = nil;
}
void QCocoaMessageDialog::hide()
diff --git a/src/plugins/platforms/ios/qiosmessagedialog.mm b/src/plugins/platforms/ios/qiosmessagedialog.mm
index 1ac1bd0b97..1f39a94172 100644
--- a/src/plugins/platforms/ios/qiosmessagedialog.mm
+++ b/src/plugins/platforms/ios/qiosmessagedialog.mm
@@ -92,6 +92,9 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win
|| windowModality == Qt::NonModal) // We can only do modal dialogs
return false;
+ if (options()->supressionCheckBoxEnabled())
+ return false; // Can't support
+
m_alertController = [[UIAlertController
alertControllerWithTitle:options()->windowTitle().toNSString()
message:messageTextPlain().toNSString()
diff --git a/src/widgets/dialogs/qerrormessage.cpp b/src/widgets/dialogs/qerrormessage.cpp
index ddadf8b336..2c36e535c7 100644
--- a/src/widgets/dialogs/qerrormessage.cpp
+++ b/src/widgets/dialogs/qerrormessage.cpp
@@ -52,8 +52,44 @@ public:
bool isMessageToBeShown(const QString &message, const QString &type) const;
bool nextPending();
void retranslateStrings();
+
+private:
+ void initHelper(QPlatformDialogHelper *) override;
+ void helperPrepareShow(QPlatformDialogHelper *) override;
};
+
+void QErrorMessagePrivate::initHelper(QPlatformDialogHelper *helper)
+{
+ Q_Q(QErrorMessage);
+ auto *messageDialogHelper = static_cast<QPlatformMessageDialogHelper *>(helper);
+ QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::supressionCheckBoxChanged, q,
+ [this](bool supressionChecked) {
+ again->setChecked(!supressionChecked);
+ }
+ );
+ QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::clicked, q,
+ [this](QPlatformDialogHelper::StandardButton, QPlatformDialogHelper::ButtonRole) {
+ Q_Q(QErrorMessage);
+ q->accept();
+ }
+ );
+}
+
+void QErrorMessagePrivate::helperPrepareShow(QPlatformDialogHelper *helper)
+{
+ Q_Q(QErrorMessage);
+ auto *messageDialogHelper = static_cast<QPlatformMessageDialogHelper *>(helper);
+ QSharedPointer<QMessageDialogOptions> options = QMessageDialogOptions::create();
+ options->setText(currentMessage);
+ options->setWindowTitle(q->windowTitle());
+ options->setText(QErrorMessage::tr("An error occurred"));
+ options->setInformativeText(currentMessage);
+ options->setIcon(QMessageDialogOptions::Critical);
+ options->setSupressionCheckBoxEnabled(true);
+ messageDialogHelper->setOptions(options);
+}
+
namespace {
class QErrorMessageTextView : public QTextEdit
{
@@ -190,6 +226,10 @@ static void jump(QtMsgType t, const QMessageLogContext &context, const QString &
/*!
Constructs and installs an error handler window with the given \a
parent.
+
+ The default \l{Qt::WindowModality} {window modality} of the dialog
+ depends on the platform. The window modality can be overridden via
+ setWindowModality() before calling showMessage().
*/
QErrorMessage::QErrorMessage(QWidget * parent)
@@ -197,6 +237,10 @@ QErrorMessage::QErrorMessage(QWidget * parent)
{
Q_D(QErrorMessage);
+#if defined(Q_OS_MACOS)
+ setWindowModality(parent ? Qt::WindowModal : Qt::ApplicationModal);
+#endif
+
d->icon = new QLabel(this);
d->errors = new QErrorMessageTextView(this);
d->again = new QCheckBox(this);
@@ -256,8 +300,12 @@ void QErrorMessage::done(int a)
}
d->currentMessage.clear();
d->currentType.clear();
- if (!d->nextPending()) {
- QDialog::done(a);
+
+ QDialog::done(a);
+
+ if (d->nextPending()) {
+ show();
+ } else {
if (this == qtMessageHandler && metFatal)
exit(1);
}
@@ -355,6 +403,23 @@ void QErrorMessage::showMessage(const QString &message, const QString &type)
show();
}
+void QErrorMessage::setVisible(bool visible)
+{
+ if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) != visible)
+ return;
+
+ Q_D(QErrorMessage);
+ if (d->canBeNativeDialog())
+ d->setNativeDialogVisible(visible);
+
+ // Update WA_DontShowOnScreen based on whether the native dialog was shown,
+ // so that QDialog::setVisible(visible) below updates the QWidget state correctly,
+ // but skips showing the non-native version.
+ setAttribute(Qt::WA_DontShowOnScreen, d->nativeDialogInUse);
+
+ QDialog::setVisible(visible);
+}
+
/*!
\reimp
*/
diff --git a/src/widgets/dialogs/qerrormessage.h b/src/widgets/dialogs/qerrormessage.h
index 55f0ac058e..c2e68fdb51 100644
--- a/src/widgets/dialogs/qerrormessage.h
+++ b/src/widgets/dialogs/qerrormessage.h
@@ -28,6 +28,8 @@ public Q_SLOTS:
void showMessage(const QString &message);
void showMessage(const QString &message, const QString &type);
+ void setVisible(bool) override;
+
protected:
void done(int) override;
void changeEvent(QEvent *e) override;