diff options
author | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2022-11-21 13:38:05 +0100 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2022-12-04 19:15:37 +0100 |
commit | 31973f3ff32c837fd031d6ed386ebdb2e75cbc1e (patch) | |
tree | 13621ae713bd3751a559b41f066f0a93ac32659f | |
parent | 8a18466e38779b63c19e281e92031cebaedbcba5 (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.cpp | 11 | ||||
-rw-r--r-- | src/gui/kernel/qplatformdialoghelper.h | 4 | ||||
-rw-r--r-- | src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp | 3 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamessagedialog.mm | 16 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qiosmessagedialog.mm | 3 | ||||
-rw-r--r-- | src/widgets/dialogs/qerrormessage.cpp | 69 | ||||
-rw-r--r-- | src/widgets/dialogs/qerrormessage.h | 2 |
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; |