aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick/qquickitem
diff options
context:
space:
mode:
authorIvan Solovev <ivan.solovev@qt.io>2022-05-04 14:20:25 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-05-07 21:26:07 +0000
commit911c015eb178fb14728e7c5c723861f089612eb9 (patch)
treef5f96b155d50d3f7b3a2081e25d7f94cb4c4143a /tests/auto/quick/qquickitem
parent0e83e495de9b3daf71e6efa7d246fb93e901ccfe (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.cpp88
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);