Respect roles of buttons added to QMessageBox

When a button added to QMessageBox has AcceptRole or YesRole, the signal
accepted() will be emitted upon click on the button. If the button has
RejectRole or NoRole, the signal rejected() will be emitted upon click
on the button. If a button has a different role, neither accepted() nor
rejected() will be emitted. This works for both standard and custom
buttons.
The signal finished() with result code will be sent regardless of a
clicked button role.
Also added documentation strings for some methods of private classes in
order to have better tooltips in IDE(s).

Task-number: QTBUG-44131
Change-Id: I521a4e5112eb4cf168f6fbb4c002dbe119aeeb09
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
bb10
Vitaly Fanaskov 2018-12-07 16:04:33 +01:00 committed by Tor Arne Vestbø
parent 1606a8aa1c
commit d8bbb5ee0e
4 changed files with 173 additions and 15 deletions

View File

@ -145,6 +145,41 @@ bool QDialogPrivate::canBeNativeDialog() const
return false;
}
/*!
\internal
Properly hides dialog and sets the \p resultCode
*/
void QDialogPrivate::hide(int resultCode)
{
Q_Q(QDialog);
q->setResult(resultCode);
q->hide();
close_helper(QWidgetPrivate::CloseNoEvent);
resetModalitySetByOpen();
}
/*!
\internal
Emits finished() signal with \p resultCode. If the \p dialogCode
is equal to 0 emits rejected(), if the \p dialogCode is equal to
1 emits accepted().
*/
void QDialogPrivate::finalize(int resultCode, int dialogCode)
{
Q_Q(QDialog);
if (dialogCode == QDialog::Accepted)
emit q->accepted();
else if (dialogCode == QDialog::Rejected)
emit q->rejected();
emit q->finished(resultCode);
}
QWindow *QDialogPrivate::transientParentWindow() const
{
Q_Q(const QDialog);
@ -593,17 +628,8 @@ int QDialog::exec()
void QDialog::done(int r)
{
Q_D(QDialog);
setResult(r);
hide();
d->close_helper(QWidgetPrivate::CloseNoEvent);
d->resetModalitySetByOpen();
emit finished(r);
if (r == Accepted)
emit accepted();
else if (r == Rejected)
emit rejected();
d->hide(r);
d->finalize(r, r);
}
/*!

View File

@ -122,6 +122,9 @@ public:
QPlatformDialogHelper *platformHelper() const;
virtual bool canBeNativeDialog() const;
void hide(int resultCode);
void finalize(int resultCode, int dialogCode);
private:
virtual void initHelper(QPlatformDialogHelper *) {}
virtual void helperPrepareShow(QPlatformDialogHelper *) {}

View File

@ -209,6 +209,7 @@ public:
void setupLayout();
void _q_buttonClicked(QAbstractButton *);
void _q_clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role);
void setClickedButton(QAbstractButton *button);
QAbstractButton *findButton(int button0, int button1, int button2, int flags);
void addOldButtons(int button0, int button1, int button2);
@ -216,6 +217,8 @@ public:
QAbstractButton *abstractButtonForId(int id) const;
int execReturnCode(QAbstractButton *button);
int dialogCodeForButton(QAbstractButton *button) const;
void detectEscapeButton();
void updateSize();
int layoutMinimumWidth();
@ -466,6 +469,27 @@ int QMessageBoxPrivate::execReturnCode(QAbstractButton *button)
return ret;
}
/*!
\internal
Returns 0 for RejectedRole and NoRole, 1 for AcceptedRole and YesRole, -1 otherwise
*/
int QMessageBoxPrivate::dialogCodeForButton(QAbstractButton *button) const
{
Q_Q(const QMessageBox);
switch (q->buttonRole(button)) {
case QMessageBox::AcceptRole:
case QMessageBox::YesRole:
return QDialog::Accepted;
case QMessageBox::RejectRole:
case QMessageBox::NoRole:
return QDialog::Rejected;
default:
return -1;
}
}
void QMessageBoxPrivate::_q_buttonClicked(QAbstractButton *button)
{
Q_Q(QMessageBox);
@ -477,20 +501,30 @@ void QMessageBoxPrivate::_q_buttonClicked(QAbstractButton *button)
} else
#endif
{
clickedButton = button;
q->done(execReturnCode(button)); // does not trigger closeEvent
emit q->buttonClicked(button);
setClickedButton(button);
if (receiverToDisconnectOnClose) {
QObject::disconnect(q, signalToDisconnectOnClose, receiverToDisconnectOnClose,
memberToDisconnectOnClose);
receiverToDisconnectOnClose = 0;
receiverToDisconnectOnClose = nullptr;
}
signalToDisconnectOnClose.clear();
memberToDisconnectOnClose.clear();
}
}
void QMessageBoxPrivate::setClickedButton(QAbstractButton *button)
{
Q_Q(QMessageBox);
clickedButton = button;
emit q->buttonClicked(clickedButton);
auto resultCode = execReturnCode(button);
hide(resultCode);
finalize(resultCode, dialogCodeForButton(button));
}
void QMessageBoxPrivate::_q_clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role)
{
Q_Q(QMessageBox);

View File

@ -110,6 +110,10 @@ private slots:
void setInformativeText();
void iconPixmap();
// QTBUG-44131
void acceptedRejectedSignals();
void acceptedRejectedSignals_data();
void cleanup();
};
@ -717,5 +721,96 @@ void tst_QMessageBox::iconPixmap()
QCOMPARE(messageBox.iconPixmap(), QPixmap());
}
using SignalSignature = void(QDialog::*)();
Q_DECLARE_METATYPE(SignalSignature);
Q_DECLARE_METATYPE(QMessageBox::ButtonRole)
using ButtonsCreator = std::function<QVector<QPushButton*>(QMessageBox &)>;
Q_DECLARE_METATYPE(ButtonsCreator);
using RoleSet = QSet<QMessageBox::ButtonRole>;
Q_DECLARE_METATYPE(RoleSet);
void tst_QMessageBox::acceptedRejectedSignals()
{
QMessageBox messageBox(QMessageBox::Information, "Test window", "Test text");
QFETCH(ButtonsCreator, buttonsCreator);
QVERIFY(buttonsCreator);
const auto buttons = buttonsCreator(messageBox);
QVERIFY(!buttons.isEmpty());
QFETCH(RoleSet, roles);
QFETCH(SignalSignature, signalSignature);
for (auto button: buttons) {
QVERIFY(button);
messageBox.show();
QVERIFY(QTest::qWaitForWindowExposed(&messageBox));
QSignalSpy spy(&messageBox, signalSignature);
QVERIFY(spy.isValid());
button->click();
if (roles.contains(messageBox.buttonRole(button)))
QCOMPARE(spy.count(), 1);
else
QVERIFY(spy.isEmpty());
}
}
static void addAcceptedRow(const char *title, ButtonsCreator bc)
{
QTest::newRow(title) << (RoleSet() << QMessageBox::AcceptRole << QMessageBox::YesRole)
<< &QDialog::accepted << bc;
}
static void addRejectedRow(const char *title, ButtonsCreator bc)
{
QTest::newRow(title) << (RoleSet() << QMessageBox::RejectRole << QMessageBox::NoRole)
<< &QDialog::rejected << bc;
}
static void addCustomButtonsData()
{
ButtonsCreator buttonsCreator = [](QMessageBox &messageBox) {
QVector<QPushButton*> buttons(QMessageBox::NRoles);
for (int i = QMessageBox::AcceptRole; i < QMessageBox::NRoles; ++i) {
buttons[i] = messageBox.addButton(
QString("Button role: %1").arg(i), QMessageBox::ButtonRole(i));
}
return buttons;
};
addAcceptedRow("Accepted_CustomButtons", buttonsCreator);
addRejectedRow("Rejected_CustomButtons", buttonsCreator);
}
static void addStandardButtonsData()
{
ButtonsCreator buttonsCreator = [](QMessageBox &messageBox) {
QVector<QPushButton*> buttons;
for (int i = QMessageBox::FirstButton; i <= QMessageBox::LastButton; i <<= 1)
buttons << messageBox.addButton(QMessageBox::StandardButton(i));
return buttons;
};
addAcceptedRow("Accepted_StandardButtons", buttonsCreator);
addRejectedRow("Rejected_StandardButtons", buttonsCreator);
}
void tst_QMessageBox::acceptedRejectedSignals_data()
{
QTest::addColumn<RoleSet>("roles");
QTest::addColumn<SignalSignature>("signalSignature");
QTest::addColumn<ButtonsCreator>("buttonsCreator");
addStandardButtonsData();
addCustomButtonsData();
}
QTEST_MAIN(tst_QMessageBox)
#include "tst_qmessagebox.moc"