Skip proxy widgets that can't take focus when (back)tabbing

Fixes regression introduced in b4981f9d4c,
due to which it was possible to back-tab into a widget even though it or
its focusProxy had a NoFocus policy.

As a drive-by, split the complicated if-statement up a bit for improved
readability.

Change-Id: Ib0ac2604076e812e340b11534c23ae8ae958d082
Fixes: QTBUG-76924
Pick-to: 5.15 5.12
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
Volker Hilsheimer 2020-06-22 14:26:09 +02:00
parent 75638e258f
commit 0dbd2dd863
2 changed files with 52 additions and 4 deletions

View File

@ -1952,10 +1952,12 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool
// \a next). This is to ensure that we can tab in and out of compound widgets
// without getting stuck in a tab-loop between parent and child.
QWidget *focusProxy = test->d_func()->deepestFocusProxy();
if ((test->focusPolicy() & focus_flag) == focus_flag
&& !(next && focusProxy && focusProxy->isAncestorOf(test))
&& !(!next && focusProxy && test->isAncestorOf(focusProxy))
const bool canTakeFocus = ((focusProxy ? focusProxy->focusPolicy() : test->focusPolicy())
& focus_flag) == focus_flag;
const bool composites = focusProxy ? (next ? focusProxy->isAncestorOf(test)
: test->isAncestorOf(focusProxy))
: false;
if (canTakeFocus && !composites
&& test->isVisibleTo(toplevel) && test->isEnabled()
&& !(w->windowType() == Qt::SubWindow && !w->isAncestorOf(test))
&& (toplevel->windowType() != Qt::SubWindow || toplevel->isAncestorOf(test))

View File

@ -186,6 +186,7 @@ private slots:
void reverseTabOrder();
void tabOrderWithProxy();
void tabOrderWithCompoundWidgets();
void tabOrderWithCompoundWidgetsNoFocusPolicy();
void tabOrderNoChange();
void tabOrderNoChange2();
void appFocusWidgetWithFocusProxyLater();
@ -2124,6 +2125,51 @@ static void dumpFocusChain(QWidget *start, bool bForward, const char *desc = nul
#endif
}
void tst_QWidget::tabOrderWithCompoundWidgetsNoFocusPolicy()
{
Container container;
container.setWindowTitle(QLatin1String(QTest::currentTestFunction()));
QSpinBox spinbox1;
spinbox1.setObjectName("spinbox1");
QSpinBox spinbox2;
spinbox2.setObjectName("spinbox2");
QSpinBox spinbox3;
spinbox3.setObjectName("spinbox3");
spinbox1.setFocusPolicy(Qt::StrongFocus);
spinbox2.setFocusPolicy(Qt::NoFocus);
spinbox3.setFocusPolicy(Qt::StrongFocus);
container.box->addWidget(&spinbox1);
container.box->addWidget(&spinbox2);
container.box->addWidget(&spinbox3);
container.show();
container.activateWindow();
QApplication::setActiveWindow(&container);
if (!QTest::qWaitForWindowActive(&container))
QSKIP("Window failed to activate, skipping test");
QVERIFY2(spinbox1.hasFocus(),
qPrintable(QApplication::focusWidget()->objectName()));
container.tab();
QVERIFY2(!spinbox2.hasFocus(),
qPrintable(QApplication::focusWidget()->objectName()));
QVERIFY2(spinbox3.hasFocus(),
qPrintable(QApplication::focusWidget()->objectName()));
container.tab();
QVERIFY2(spinbox1.hasFocus(),
qPrintable(QApplication::focusWidget()->objectName()));
container.backTab();
QVERIFY2(spinbox3.hasFocus(),
qPrintable(QApplication::focusWidget()->objectName()));
container.backTab();
QVERIFY2(!spinbox2.hasFocus(),
qPrintable(QApplication::focusWidget()->objectName()));
QVERIFY2(spinbox1.hasFocus(),
qPrintable(QApplication::focusWidget()->objectName()));
}
void tst_QWidget::tabOrderNoChange()
{
QWidget w;