From 0dbd2dd86389c0705dbe9f518aed12f609ed09a1 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 22 Jun 2020 14:26:09 +0200 Subject: [PATCH] Skip proxy widgets that can't take focus when (back)tabbing Fixes regression introduced in b4981f9d4ca914c6ecaa49bfdd69e51806a3671a, 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 --- src/widgets/kernel/qapplication.cpp | 10 ++-- .../widgets/kernel/qwidget/tst_qwidget.cpp | 46 +++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index a2862a56e1..e93eaf5b30 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -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)) diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index c029e58acc..5aefc0f7f6 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -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;