diff options
-rw-r--r-- | src/widgets/widgets/qdialogbuttonbox.cpp | 14 | ||||
-rw-r--r-- | tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp | 49 |
2 files changed, 62 insertions, 1 deletions
diff --git a/src/widgets/widgets/qdialogbuttonbox.cpp b/src/widgets/widgets/qdialogbuttonbox.cpp index 612b283825..7cd4d01d0a 100644 --- a/src/widgets/widgets/qdialogbuttonbox.cpp +++ b/src/widgets/widgets/qdialogbuttonbox.cpp @@ -1015,8 +1015,20 @@ void QDialogButtonBoxPrivate::ensureFirstAcceptIsDefault() break; } } - if (!hasDefault && firstAcceptButton) + if (!hasDefault && firstAcceptButton) { firstAcceptButton->setDefault(true); + // When the QDialogButtonBox is focused, and it doesn't have an + // explicit focus widget, it will transfer focus to its focus + // proxy, which is the first button in the layout. This behavior, + // combined with the behavior that QPushButtons in a QDialog will + // by default have their autoDefault set to true, results in the + // focus proxy/first button stealing the default button status + // immediately when the button box is focused, which is not what + // we want. Account for this by explicitly making the firstAcceptButton + // focused as well, unless an explicit focus widget has been set. + if (dialog && !dialog->focusWidget()) + firstAcceptButton->setFocus(); + } } void QDialogButtonBoxPrivate::disconnectAll() diff --git a/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp b/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp index 3f5ffa687b..9f405a8beb 100644 --- a/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp +++ b/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp @@ -81,6 +81,7 @@ private slots: void task191642_default(); void testDeletedStandardButton(); + void automaticDefaultButton(); private: qint64 timeStamp; @@ -909,5 +910,53 @@ void tst_QDialogButtonBox::testDeletedStandardButton() QVERIFY(!buttonC); } +void tst_QDialogButtonBox::automaticDefaultButton() +{ + // Having a QDialogButtonBox inside a QDialog triggers Qt to + // enable autoDefault for QPushButtons inside the button box. + // Check that the logic for resolving a default button based + // on the Accept role is not overridden by the first button + // in the dialog (the focus proxy) taking focus, and hence + // stealing the default button state. + + { + QDialog dialog; + QDialogButtonBox *bb = new QDialogButtonBox(&dialog); + // Force horizontal orientation, where we know the order between + // Reset and Accept roles are always the same for all layouts. + bb->setOrientation(Qt::Horizontal); + auto *okButton = bb->addButton(QDialogButtonBox::Ok); + auto *resetButton = bb->addButton(QDialogButtonBox::Reset); + // Double check our assumption about Reset being first + QCOMPARE(bb->layout()->itemAt(0)->widget(), resetButton); + + dialog.show(); + QVERIFY(QTest::qWaitForWindowActive(&dialog)); + + QVERIFY(okButton->isDefault()); + QSignalSpy buttonClicked(okButton, &QPushButton::clicked); + QTest::keyPress(&dialog, Qt::Key_Enter); + QCOMPARE(buttonClicked.count(), 1); + } + + // However, if an explicit button has been focused, we respect that. + + { + QDialog dialog; + QDialogButtonBox *bb = new QDialogButtonBox(&dialog); + bb->setOrientation(Qt::Horizontal); + bb->addButton(QDialogButtonBox::Ok); + auto *resetButton = bb->addButton(QDialogButtonBox::Reset); + resetButton->setFocus(); + dialog.show(); + QVERIFY(QTest::qWaitForWindowActive(&dialog)); + + QVERIFY(resetButton->isDefault()); + QSignalSpy buttonClicked(resetButton, &QPushButton::clicked); + QTest::keyPress(&dialog, Qt::Key_Enter); + QCOMPARE(buttonClicked.count(), 1); + } +} + QTEST_MAIN(tst_QDialogButtonBox) #include "tst_qdialogbuttonbox.moc" |