QMessageBox: Detect modifications to standard button text

The addButton(StandardButton) and button(StandardButton) APIs return
a QAbstractButton, that the user can in theory modify to their heart's
content. This causes problems when the native dialog backend is not
aware of these modifications.

We documented this limitation in e9a1c5321, but it turns out to be
more common than we first though. In particular, a typical case is
modifying the text of the button.

We now try to detect if the button has a non-standard text, and if
so turn it into a custom button when passing it on to the native
backend. From the point of view of QMessageBox it's still a standard
button, and will be reported as such in the result of exec().

To make this work the QMessageDialogOptions::CustomButton needs to
learn about custom button identifiers, so we can pass the original
standard button though.

This moves us closer to a world where the QMessageDialogOptions
represent both standard buttons and custom buttons using the same
structure, which is what we want anyways, so that we e.g. respect
the added order of standard buttons with the same role.

Fixes: QTBUG-118241
Pick-to: 6.5
Change-Id: Ifb7f7bd537fe71293f14ef6a006999e350bd0b52
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
(cherry picked from commit bafeffff9d1b9b2c8108e74cb6857899f7dd5b5e)
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Tor Arne Vestbø 2023-10-24 17:47:12 +02:00
parent c62c335be4
commit 77dff1f5ed
3 changed files with 20 additions and 5 deletions

View File

@ -883,9 +883,9 @@ QPlatformDialogHelper::StandardButtons QMessageDialogOptions::standardButtons()
}
int QMessageDialogOptions::addButton(const QString &label, QPlatformDialogHelper::ButtonRole role,
void *buttonImpl)
void *buttonImpl, int buttonId)
{
const CustomButton b(d->nextCustomButtonId++, label, role, buttonImpl);
const CustomButton b(buttonId ? buttonId : d->nextCustomButtonId++, label, role, buttonImpl);
d->customButtons.append(b);
return b.id;
}

View File

@ -458,7 +458,7 @@ public:
};
int addButton(const QString &label, QPlatformDialogHelper::ButtonRole role,
void *buttonImpl = nullptr);
void *buttonImpl = nullptr, int buttonId = 0);
void removeButton(int id);
const QList<CustomButton> &customButtons();
const CustomButton *customButton(int id);

View File

@ -2841,22 +2841,37 @@ void QMessageBoxPrivate::helperPrepareShow(QPlatformDialogHelper *)
options->setStandardIcon(helperIcon(q->icon()));
options->setIconPixmap(q->iconPixmap());
// Clear up front, since we might have prepared earlier
options->clearCustomButtons();
// Add standard buttons and resolve default/escape button
options->setStandardButtons(helperStandardButtons(q));
auto standardButtons = helperStandardButtons(q);
for (int button = QDialogButtonBox::StandardButton::FirstButton;
button <= QDialogButtonBox::StandardButton::LastButton; button <<= 1) {
auto *standardButton = buttonBox->button(QDialogButtonBox::StandardButton(button));
if (!standardButton)
continue;
if (auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
if (standardButton->text() != platformTheme->standardButtonText(button)) {
// The standard button has been customized, so add it as
// a custom button instead.
const auto buttonRole = buttonBox->buttonRole(standardButton);
options->addButton(standardButton->text(),
static_cast<QPlatformDialogHelper::ButtonRole>(buttonRole),
standardButton, button);
standardButtons &= ~QPlatformDialogHelper::StandardButton(button);
}
}
if (standardButton == defaultButton)
options->setDefaultButton(button);
else if (standardButton == detectedEscapeButton)
options->setEscapeButton(button);
}
options->setStandardButtons(standardButtons);
// Add custom buttons and resolve default/escape button
options->clearCustomButtons();
for (auto *customButton : customButtonList) {
// Unless it's the details button, since we don't do any
// plumbing for the button's action in that case.