diff options
author | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2023-03-08 10:27:48 +0100 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2023-03-09 09:41:33 +0100 |
commit | a0313c85a9b8ab6ba0ec273f0c8638e2f7b8cc18 (patch) | |
tree | 514e55d3c4bbd60e766b78db22f84107d9b9bae9 /src | |
parent | 9255820ad591645897d261b795b5649b8d9a313f (diff) |
Plumb QMessageBox::setCheckBox() through QPlatformMessageDialogHelper
Without this plumbing we have no way of knowing if the QMessageBox
has a checkbox set, and can't decide to skip the native dialog,
leaving the user without the expected checkbox.
As the suppression checkbox on macOS can be customized, we can use
this plumbing to actually provide native dialog support for generic
check boxes.
This mechanism can also be used by QErrorMessage, which now matches
behavior between native and non-native dialogs in terms of the label
of the checkbox and its initial state. We might want to tweak this
in the future, since user's might expect the suppression label and
state to match the system default, but that's something we can
expose from the platform theme if so, and should apply equally
to the non-native dialog.
Fixes: QTBUG-111803
Pick-to: 6.5.0 6.5
Change-Id: Ied9fc34383fe79fbd8437592ad1c1993b9396178
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/gui/kernel/qplatformdialoghelper.cpp | 17 | ||||
-rw-r--r-- | src/gui/kernel/qplatformdialoghelper.h | 7 | ||||
-rw-r--r-- | src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamessagedialog.mm | 31 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qiosmessagedialog.mm | 2 | ||||
-rw-r--r-- | src/widgets/dialogs/qerrormessage.cpp | 8 | ||||
-rw-r--r-- | src/widgets/dialogs/qmessagebox.cpp | 11 |
7 files changed, 62 insertions, 16 deletions
diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp index f1370a07b8..7038954ea0 100644 --- a/src/gui/kernel/qplatformdialoghelper.cpp +++ b/src/gui/kernel/qplatformdialoghelper.cpp @@ -776,7 +776,8 @@ public: QList<QMessageDialogOptions::CustomButton> customButtons; int nextCustomButtonId; QPixmap iconPixmap; - bool enableSupressionCheckBox = false; + QString checkBoxLabel; + Qt::CheckState checkBoxState = Qt::Unchecked; }; QMessageDialogOptions::QMessageDialogOptions(QMessageDialogOptionsPrivate *dd) @@ -907,14 +908,20 @@ const QMessageDialogOptions::CustomButton *QMessageDialogOptions::customButton(i return (i < 0 ? nullptr : &d->customButtons.at(i)); } -void QMessageDialogOptions::setSupressionCheckBoxEnabled(bool enabled) +void QMessageDialogOptions::setCheckBox(const QString &label, Qt::CheckState state) { - d->enableSupressionCheckBox = enabled; + d->checkBoxLabel = label; + d->checkBoxState = state; } -bool QMessageDialogOptions::supressionCheckBoxEnabled() const +QString QMessageDialogOptions::checkBoxLabel() const { - return d->enableSupressionCheckBox; + return d->checkBoxLabel; +} + +Qt::CheckState QMessageDialogOptions::checkBoxState() const +{ + return d->checkBoxState; } QPlatformDialogHelper::ButtonRole QPlatformDialogHelper::buttonRole(QPlatformDialogHelper::StandardButton button) diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h index 43d3dfe358..25543a70b8 100644 --- a/src/gui/kernel/qplatformdialoghelper.h +++ b/src/gui/kernel/qplatformdialoghelper.h @@ -451,8 +451,9 @@ public: const QList<CustomButton> &customButtons(); const CustomButton *customButton(int id); - void setSupressionCheckBoxEnabled(bool enabled); - bool supressionCheckBoxEnabled() const; + void setCheckBox(const QString &label, Qt::CheckState state); + QString checkBoxLabel() const; + Qt::CheckState checkBoxState() const; private: QMessageDialogOptionsPrivate *d; @@ -467,7 +468,7 @@ public: Q_SIGNALS: void clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role); - void supressionCheckBoxChanged(bool checked); + void checkBoxStateChanged(Qt::CheckState state); private: QSharedPointer<QMessageDialogOptions> m_options; diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp index 81c6b41d65..25427d5ede 100644 --- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp +++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp @@ -54,7 +54,7 @@ bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags, if (!opt.data()) return false; - if (opt->supressionCheckBoxEnabled()) + if (!opt->checkBoxLabel().isNull()) return false; // Can't support m_javaMessageDialog.callMethod<void>("setStandardIcon", "(I)V", opt->standardIcon()); diff --git a/src/plugins/platforms/cocoa/qcocoamessagedialog.mm b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm index 8dcc5fab53..f19146c60c 100644 --- a/src/plugins/platforms/cocoa/qcocoamessagedialog.mm +++ b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm @@ -46,6 +46,16 @@ static QString toPlainText(const QString &text) return textDocument.toPlainText(); } +static NSControlStateValue controlStateFor(Qt::CheckState state) +{ + switch (state) { + case Qt::Checked: return NSControlStateValueOn; + case Qt::Unchecked: return NSControlStateValueOff; + case Qt::PartiallyChecked: return NSControlStateValueMixed; + } + Q_UNREACHABLE(); +} + /* Called from QDialogPrivate::setNativeDialogVisible() when the message box is ready to be shown. @@ -185,7 +195,14 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w StandardButton::Ok, ButtonRole::AcceptRole); } - m_alert.showsSuppressionButton = options()->supressionCheckBoxEnabled(); + if (auto checkBoxLabel = options()->checkBoxLabel(); !checkBoxLabel.isNull()) { + checkBoxLabel = QPlatformTheme::removeMnemonics(checkBoxLabel); + m_alert.suppressionButton.title = checkBoxLabel.toNSString(); + auto state = options()->checkBoxState(); + m_alert.suppressionButton.allowsMixedState = state == Qt::PartiallyChecked; + m_alert.suppressionButton.state = controlStateFor(state); + m_alert.showsSuppressionButton = YES; + } qCDebug(lcQpaDialogs) << "Showing" << m_alert; @@ -233,6 +250,16 @@ void QCocoaMessageDialog::exec() // Custom modal response code to record that the dialog was hidden by us static const NSInteger kModalResponseDialogHidden = NSAlertThirdButtonReturn + 1; +static Qt::CheckState checkStateFor(NSControlStateValue state) +{ + switch (state) { + case NSControlStateValueOn: return Qt::Checked; + case NSControlStateValueOff: return Qt::Unchecked; + case NSControlStateValueMixed: return Qt::PartiallyChecked; + } + Q_UNREACHABLE(); +} + void QCocoaMessageDialog::processResponse(NSModalResponse response) { qCDebug(lcQpaDialogs) << "Processing response" << response << "for" << m_alert; @@ -244,7 +271,7 @@ void QCocoaMessageDialog::processResponse(NSModalResponse response) [alert autorelease]; if (alert.showsSuppressionButton) - emit supressionCheckBoxChanged(alert.suppressionButton.state == NSControlStateValueOn); + emit checkBoxStateChanged(checkStateFor(alert.suppressionButton.state)); if (response >= NSAlertFirstButtonReturn) { // Safe range for user-defined modal responses diff --git a/src/plugins/platforms/ios/qiosmessagedialog.mm b/src/plugins/platforms/ios/qiosmessagedialog.mm index 1f39a94172..b95cfada60 100644 --- a/src/plugins/platforms/ios/qiosmessagedialog.mm +++ b/src/plugins/platforms/ios/qiosmessagedialog.mm @@ -92,7 +92,7 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win || windowModality == Qt::NonModal) // We can only do modal dialogs return false; - if (options()->supressionCheckBoxEnabled()) + if (!options()->checkBoxLabel().isNull()) return false; // Can't support m_alertController = [[UIAlertController diff --git a/src/widgets/dialogs/qerrormessage.cpp b/src/widgets/dialogs/qerrormessage.cpp index 374cdb53cc..5a6d529fc2 100644 --- a/src/widgets/dialogs/qerrormessage.cpp +++ b/src/widgets/dialogs/qerrormessage.cpp @@ -63,9 +63,9 @@ 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::checkBoxStateChanged, q, + [this](Qt::CheckState state) { + again->setCheckState(state); } ); QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::clicked, q, @@ -86,7 +86,7 @@ void QErrorMessagePrivate::helperPrepareShow(QPlatformDialogHelper *helper) options->setText(QErrorMessage::tr("An error occurred")); options->setInformativeText(currentMessage); options->setStandardIcon(QMessageDialogOptions::Critical); - options->setSupressionCheckBoxEnabled(true); + options->setCheckBox(again->text(), again->checkState()); messageDialogHelper->setOptions(options); } diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp index cf731b2961..cdd073350b 100644 --- a/src/widgets/dialogs/qmessagebox.cpp +++ b/src/widgets/dialogs/qmessagebox.cpp @@ -2682,6 +2682,15 @@ void QMessageBoxPrivate::initHelper(QPlatformDialogHelper *h) Q_Q(QMessageBox); QObject::connect(h, SIGNAL(clicked(QPlatformDialogHelper::StandardButton,QPlatformDialogHelper::ButtonRole)), q, SLOT(_q_clicked(QPlatformDialogHelper::StandardButton,QPlatformDialogHelper::ButtonRole))); + + auto *messageDialogHelper = static_cast<QPlatformMessageDialogHelper *>(h); + QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::checkBoxStateChanged, q, + [this](Qt::CheckState state) { + if (checkbox) + checkbox->setCheckState(state); + } + ); + static_cast<QPlatformMessageDialogHelper *>(h)->setOptions(options); } @@ -2720,6 +2729,8 @@ void QMessageBoxPrivate::helperPrepareShow(QPlatformDialogHelper *) options->setStandardIcon(helperIcon(q->icon())); options->setIconPixmap(q->iconPixmap()); options->setStandardButtons(helperStandardButtons(q)); + if (checkbox) + options->setCheckBox(checkbox->text(), checkbox->checkState()); } void QMessageBoxPrivate::helperDone(QDialog::DialogCode code, QPlatformDialogHelper *) |