diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2022-05-04 14:20:25 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2022-05-07 21:26:07 +0000 |
commit | 911c015eb178fb14728e7c5c723861f089612eb9 (patch) | |
tree | f5f96b155d50d3f7b3a2081e25d7f94cb4c4143a /tests/auto/quick/qquickitem | |
parent | 0e83e495de9b3daf71e6efa7d246fb93e901ccfe (diff) |
QQuickItem: fix the order of activeFocusChanged signals
The signals are emitted from
QQuickDeliveryAgentPrivate::notifyFocusChangesRecur. This method is
recursive, and was designed in such way that recursion was done before
processing of the selected item.
As a result, the input list of modified QQuickItems was processed in
reverse order. So we first received an activeFocusChanged(true) signal
for the new focused element, and only after that
activeFocusChanged(false) signal for the element that lost its focus.
This patch fixes the recursive function, so that the items are now
processed in desired order.
Fixes: QTBUG-78090
Change-Id: Icdbfd0359530a67536af126a07f51374e56ec917
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit fead9e6b2dc78e177c297c38e84b40aea5c2c3bd)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'tests/auto/quick/qquickitem')
-rw-r--r-- | tests/auto/quick/qquickitem/tst_qquickitem.cpp | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index e4fe6df888..43b9b31d9f 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -195,6 +195,7 @@ private slots: void focusSubItemInNonFocusScope(); void parentItemWithFocus(); void reparentFocusedItem(); + void activeFocusChangedOrder(); void constructor(); void setParentItem(); @@ -962,6 +963,93 @@ void tst_qquickitem::reparentFocusedItem() FVERIFY(); } +void tst_qquickitem::activeFocusChangedOrder() +{ + // This test checks that the activeFocusChanged signal first comes for an + // object that has lost focus, and only after that - for an object that + // has received focus. + + { + // Two FocusScopes inside a Window + QQuickWindow window; + QVERIFY(ensureFocus(&window)); + QTRY_COMPARE(QGuiApplication::focusWindow(), &window); + + QQuickFocusScope scope1(window.contentItem()); + QQuickItem scope1Child(&scope1); + + QQuickFocusScope scope2(window.contentItem()); + QQuickItem scope2Child(&scope2); + + scope1Child.forceActiveFocus(); + QTRY_VERIFY(scope1.hasActiveFocus()); + + int counter = 0; + connect(&scope1, &QQuickItem::activeFocusChanged, [&counter, &scope1](bool focus) { + QCOMPARE(scope1.childItems().front()->hasActiveFocus(), focus); + QCOMPARE(counter, 0); + counter++; + }); + connect(&scope2, &QQuickItem::activeFocusChanged, [&counter, &scope2](bool focus) { + QCOMPARE(scope2.childItems().front()->hasActiveFocus(), focus); + QCOMPARE(counter, 1); + counter++; + }); + + // A guard is needed so that connections are destroyed before the items. + // Otherwise the slots will be called during destruction, and test will + // crash (because childItems will be empty). + auto guard = qScopeGuard([&scope1, &scope2]() { + scope1.disconnect(); + scope2.disconnect(); + }); + Q_UNUSED(guard) + + scope2Child.forceActiveFocus(); + QTRY_VERIFY(scope2.hasActiveFocus()); + QCOMPARE(counter, 2); // make sure that both signals are received + } + + { + // Two Items inside a Window (no explicict FocusScopes) + QQuickWindow window; + QVERIFY(ensureFocus(&window)); + QTRY_COMPARE(QGuiApplication::focusWindow(), &window); + + QQuickItem item1(window.contentItem()); + + QQuickItem item2(window.contentItem()); + + item1.forceActiveFocus(); + QTRY_VERIFY(item1.hasActiveFocus()); + + int counter = 0; + connect(&item1, &QQuickItem::activeFocusChanged, [&counter](bool focus) { + QVERIFY(!focus); + QCOMPARE(counter, 0); + counter++; + }); + connect(&item2, &QQuickItem::activeFocusChanged, [&counter](bool focus) { + QVERIFY(focus); + QCOMPARE(counter, 1); + counter++; + }); + + // A guard is needed so that connections are destroyed before the items. + // Otherwise the slots will be called during destruction, and test will + // fail. + auto guard = qScopeGuard([&item1, &item2]() { + item1.disconnect(); + item2.disconnect(); + }); + Q_UNUSED(guard) + + item2.forceActiveFocus(); + QTRY_VERIFY(item2.hasActiveFocus()); + QCOMPARE(counter, 2); // make sure that both signals are received + } +} + void tst_qquickitem::constructor() { QScopedPointer<QQuickItem> root(new QQuickItem); |