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 Change-Id: Ied9fc34383fe79fbd8437592ad1c1993b9396178 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit a0313c85a9b8ab6ba0ec273f0c8638e2f7b8cc18) Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
dcf7247e05
commit
ec3aac74a4
@ -776,7 +776,8 @@ public:
|
|||||||
QList<QMessageDialogOptions::CustomButton> customButtons;
|
QList<QMessageDialogOptions::CustomButton> customButtons;
|
||||||
int nextCustomButtonId;
|
int nextCustomButtonId;
|
||||||
QPixmap iconPixmap;
|
QPixmap iconPixmap;
|
||||||
bool enableSupressionCheckBox = false;
|
QString checkBoxLabel;
|
||||||
|
Qt::CheckState checkBoxState = Qt::Unchecked;
|
||||||
};
|
};
|
||||||
|
|
||||||
QMessageDialogOptions::QMessageDialogOptions(QMessageDialogOptionsPrivate *dd)
|
QMessageDialogOptions::QMessageDialogOptions(QMessageDialogOptionsPrivate *dd)
|
||||||
@ -907,14 +908,20 @@ const QMessageDialogOptions::CustomButton *QMessageDialogOptions::customButton(i
|
|||||||
return (i < 0 ? nullptr : &d->customButtons.at(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)
|
QPlatformDialogHelper::ButtonRole QPlatformDialogHelper::buttonRole(QPlatformDialogHelper::StandardButton button)
|
||||||
|
@ -451,8 +451,9 @@ public:
|
|||||||
const QList<CustomButton> &customButtons();
|
const QList<CustomButton> &customButtons();
|
||||||
const CustomButton *customButton(int id);
|
const CustomButton *customButton(int id);
|
||||||
|
|
||||||
void setSupressionCheckBoxEnabled(bool enabled);
|
void setCheckBox(const QString &label, Qt::CheckState state);
|
||||||
bool supressionCheckBoxEnabled() const;
|
QString checkBoxLabel() const;
|
||||||
|
Qt::CheckState checkBoxState() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMessageDialogOptionsPrivate *d;
|
QMessageDialogOptionsPrivate *d;
|
||||||
@ -467,7 +468,7 @@ public:
|
|||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role);
|
void clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role);
|
||||||
void supressionCheckBoxChanged(bool checked);
|
void checkBoxStateChanged(Qt::CheckState state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSharedPointer<QMessageDialogOptions> m_options;
|
QSharedPointer<QMessageDialogOptions> m_options;
|
||||||
|
@ -54,7 +54,7 @@ bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags,
|
|||||||
if (!opt.data())
|
if (!opt.data())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (opt->supressionCheckBoxEnabled())
|
if (!opt->checkBoxLabel().isNull())
|
||||||
return false; // Can't support
|
return false; // Can't support
|
||||||
|
|
||||||
m_javaMessageDialog.callMethod<void>("setIcon", "(I)V", opt->icon());
|
m_javaMessageDialog.callMethod<void>("setIcon", "(I)V", opt->icon());
|
||||||
|
@ -46,6 +46,16 @@ static QString toPlainText(const QString &text)
|
|||||||
return textDocument.toPlainText();
|
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
|
Called from QDialogPrivate::setNativeDialogVisible() when the message box
|
||||||
is ready to be shown.
|
is ready to be shown.
|
||||||
@ -185,7 +195,14 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w
|
|||||||
StandardButton::Ok, ButtonRole::AcceptRole);
|
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;
|
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
|
// Custom modal response code to record that the dialog was hidden by us
|
||||||
static const NSInteger kModalResponseDialogHidden = NSAlertThirdButtonReturn + 1;
|
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)
|
void QCocoaMessageDialog::processResponse(NSModalResponse response)
|
||||||
{
|
{
|
||||||
qCDebug(lcQpaDialogs) << "Processing response" << response << "for" << m_alert;
|
qCDebug(lcQpaDialogs) << "Processing response" << response << "for" << m_alert;
|
||||||
@ -244,7 +271,7 @@ void QCocoaMessageDialog::processResponse(NSModalResponse response)
|
|||||||
[alert autorelease];
|
[alert autorelease];
|
||||||
|
|
||||||
if (alert.showsSuppressionButton)
|
if (alert.showsSuppressionButton)
|
||||||
emit supressionCheckBoxChanged(alert.suppressionButton.state == NSControlStateValueOn);
|
emit checkBoxStateChanged(checkStateFor(alert.suppressionButton.state));
|
||||||
|
|
||||||
if (response >= NSAlertFirstButtonReturn) {
|
if (response >= NSAlertFirstButtonReturn) {
|
||||||
// Safe range for user-defined modal responses
|
// Safe range for user-defined modal responses
|
||||||
|
@ -92,7 +92,7 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win
|
|||||||
|| windowModality == Qt::NonModal) // We can only do modal dialogs
|
|| windowModality == Qt::NonModal) // We can only do modal dialogs
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (options()->supressionCheckBoxEnabled())
|
if (!options()->checkBoxLabel().isNull())
|
||||||
return false; // Can't support
|
return false; // Can't support
|
||||||
|
|
||||||
m_alertController = [[UIAlertController
|
m_alertController = [[UIAlertController
|
||||||
|
@ -63,9 +63,9 @@ void QErrorMessagePrivate::initHelper(QPlatformDialogHelper *helper)
|
|||||||
{
|
{
|
||||||
Q_Q(QErrorMessage);
|
Q_Q(QErrorMessage);
|
||||||
auto *messageDialogHelper = static_cast<QPlatformMessageDialogHelper *>(helper);
|
auto *messageDialogHelper = static_cast<QPlatformMessageDialogHelper *>(helper);
|
||||||
QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::supressionCheckBoxChanged, q,
|
QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::checkBoxStateChanged, q,
|
||||||
[this](bool supressionChecked) {
|
[this](Qt::CheckState state) {
|
||||||
again->setChecked(!supressionChecked);
|
again->setCheckState(state);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::clicked, q,
|
QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::clicked, q,
|
||||||
@ -86,7 +86,7 @@ void QErrorMessagePrivate::helperPrepareShow(QPlatformDialogHelper *helper)
|
|||||||
options->setText(QErrorMessage::tr("An error occurred"));
|
options->setText(QErrorMessage::tr("An error occurred"));
|
||||||
options->setInformativeText(currentMessage);
|
options->setInformativeText(currentMessage);
|
||||||
options->setIcon(QMessageDialogOptions::Critical);
|
options->setIcon(QMessageDialogOptions::Critical);
|
||||||
options->setSupressionCheckBoxEnabled(true);
|
options->setCheckBox(again->text(), again->checkState());
|
||||||
messageDialogHelper->setOptions(options);
|
messageDialogHelper->setOptions(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2682,6 +2682,15 @@ void QMessageBoxPrivate::initHelper(QPlatformDialogHelper *h)
|
|||||||
Q_Q(QMessageBox);
|
Q_Q(QMessageBox);
|
||||||
QObject::connect(h, SIGNAL(clicked(QPlatformDialogHelper::StandardButton,QPlatformDialogHelper::ButtonRole)),
|
QObject::connect(h, SIGNAL(clicked(QPlatformDialogHelper::StandardButton,QPlatformDialogHelper::ButtonRole)),
|
||||||
q, SLOT(_q_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);
|
static_cast<QPlatformMessageDialogHelper *>(h)->setOptions(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2720,6 +2729,8 @@ void QMessageBoxPrivate::helperPrepareShow(QPlatformDialogHelper *)
|
|||||||
options->setIcon(helperIcon(q->icon()));
|
options->setIcon(helperIcon(q->icon()));
|
||||||
options->setIconPixmap(q->iconPixmap());
|
options->setIconPixmap(q->iconPixmap());
|
||||||
options->setStandardButtons(helperStandardButtons(q));
|
options->setStandardButtons(helperStandardButtons(q));
|
||||||
|
if (checkbox)
|
||||||
|
options->setCheckBox(checkbox->text(), checkbox->checkState());
|
||||||
}
|
}
|
||||||
|
|
||||||
void QMessageBoxPrivate::helperDone(QDialog::DialogCode code, QPlatformDialogHelper *)
|
void QMessageBoxPrivate::helperDone(QDialog::DialogCode code, QPlatformDialogHelper *)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user