diff options
Diffstat (limited to 'tests/auto/quick/qquickitem2')
12 files changed, 725 insertions, 106 deletions
diff --git a/tests/auto/quick/qquickitem2/CMakeLists.txt b/tests/auto/quick/qquickitem2/CMakeLists.txt index 44620cacd6..6b115efd2e 100644 --- a/tests/auto/quick/qquickitem2/CMakeLists.txt +++ b/tests/auto/quick/qquickitem2/CMakeLists.txt @@ -7,6 +7,12 @@ ## tst_qquickitem2 Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qquickitem2 LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # Collect test data file(GLOB_RECURSE test_data_glob RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} @@ -31,6 +37,11 @@ qt_internal_add_test(tst_qquickitem2 ## Scopes: ##################################################################### +qt_internal_extend_target(tst_qquickitem2 CONDITION TARGET Qt::Widgets + LIBRARIES + Qt::Widgets +) + qt_internal_extend_target(tst_qquickitem2 CONDITION ANDROID OR IOS DEFINES QT_QMLTEST_DATADIR=":/data" diff --git a/tests/auto/quick/qquickitem2/data/embedded.qml b/tests/auto/quick/qquickitem2/data/embedded.qml new file mode 100644 index 0000000000..a9cf115699 --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/embedded.qml @@ -0,0 +1,30 @@ +import QtQuick + +Rectangle { + width: 300 + height: 300 + + Column { + anchors.fill: parent + anchors.rightMargin: 2 + anchors.leftMargin: 2 + anchors.topMargin: 10 + spacing: 20 + Rectangle { + objectName: "rect1" + width: parent.width + height: 30 + border.width: 1 + border.color: activeFocus ? "blue" : "black" + focusPolicy: Qt.TabFocus + } + Rectangle { + objectName: "rect2" + width: parent.width + height: 30 + border.width: 1 + border.color: activeFocus ? "blue" : "black" + focusPolicy: Qt.TabFocus + } + } +} diff --git a/tests/auto/quick/qquickitem2/data/embedded_FocusScope.qml b/tests/auto/quick/qquickitem2/data/embedded_FocusScope.qml new file mode 100644 index 0000000000..0d154f76e5 --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/embedded_FocusScope.qml @@ -0,0 +1,37 @@ +import QtQuick + +Rectangle { + width: 300 + height: 300 + + FocusScope { + width: parent.width + height: parent.height + focus: true + + Column { + anchors.fill: parent + anchors.rightMargin: 2 + anchors.leftMargin: 2 + anchors.topMargin: 10 + spacing: 20 + Rectangle { + objectName: "rect1" + width: parent.width + height: 30 + border.width: 1 + border.color: activeFocus ? "blue" : "black" + focusPolicy: Qt.TabFocus + } + Rectangle { + objectName: "rect2" + width: parent.width + height: 30 + border.width: 1 + border.color: activeFocus ? "blue" : "black" + focusPolicy: Qt.TabFocus + focus: true + } + } + } +} diff --git a/tests/auto/quick/qquickitem2/data/focusInScopeChanges.qml b/tests/auto/quick/qquickitem2/data/focusInScopeChanges.qml new file mode 100644 index 0000000000..3bf765a29d --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/focusInScopeChanges.qml @@ -0,0 +1,31 @@ +import QtQuick + +Item { + id: main + objectName: "main" + width: 800 + height: 600 + + FocusScope { + objectName: "focusScope" + + Column { + Rectangle { + id: rectangle + focus: true + objectName: "rect" + width: textInput.width + height: textInput.height + border.width: 1 + onActiveFocusChanged: textInput.forceActiveFocus() + } + + TextInput { + id: textInput + objectName: "textInput" + font.pixelSize: 40 + text: "focus me" + } + } + } +} diff --git a/tests/auto/quick/qquickitem2/data/focusReason.qml b/tests/auto/quick/qquickitem2/data/focusReason.qml new file mode 100644 index 0000000000..7f9e303dba --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/focusReason.qml @@ -0,0 +1,85 @@ +import QtQuick + +Item { + Component.onCompleted: item.focus = true + width: 640 + height: 480 + + Column { + anchors.top: parent.top + anchors.topMargin: 10 + spacing: 10 + objectName: "column" + focusPolicy: Qt.ClickFocus + + Item { + id: item + implicitWidth: 100 + implicitHeight: 20 + objectName: "item" + focusPolicy: Qt.TabFocus + + Rectangle { + id: rect + anchors.fill: parent + color: "yellow" + opacity: 0.5 + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton + onClicked: function onClicked(mouseEvent) { + if (mouseEvent.button == Qt.RightButton) + rect.color = "pink" + } + } + } + + Item { + id: customText + objectName: "customText" + implicitWidth: 100 + implicitHeight: 50 + TextInput { + anchors.fill: parent + objectName: "textInputChild" + text: parent.activeFocus ? "focus" : "no focus" + } + activeFocusOnTab: true + } + + Item { + id: customItem + objectName: "customItem" + implicitWidth: 100 + implicitHeight: 50 + Rectangle { + anchors.fill: parent + color: parent.activeFocus ? "red" : "blue" + opacity: 0.3 + } + focusPolicy: Qt.WheelFocus + } + + Text { + id: hyperlink + objectName: "hyperlink" + color: "blue" + onLinkActivated: { text = "Clicked"; } + textFormat: Text.RichText + text: "<a href=\"http://qt-project.org\">Qt Project website</a>" + focusPolicy: Qt.StrongFocus + + MouseArea { + id: mouseArea + anchors.fill: parent + acceptedButtons: Qt.NoButton // Don't eat the mouse clicks + cursorShape: Qt.PointingHandCursor + // the acceptedButtons will take precedence + // and the click focus policy will be ignored + focusPolicy: Qt.ClickFocus + } + } + } +} diff --git a/tests/auto/quick/qquickitem2/data/grabToImage.qml b/tests/auto/quick/qquickitem2/data/grabToImage.qml index 7df6d097a6..1298a3c6a9 100644 --- a/tests/auto/quick/qquickitem2/data/grabToImage.qml +++ b/tests/auto/quick/qquickitem2/data/grabToImage.qml @@ -1,5 +1,5 @@ // Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only import QtQuick 2.0 diff --git a/tests/auto/quick/qquickitem2/data/keysforward.qml b/tests/auto/quick/qquickitem2/data/keysforward.qml index 8ea2d96022..09a0f926ed 100644 --- a/tests/auto/quick/qquickitem2/data/keysforward.qml +++ b/tests/auto/quick/qquickitem2/data/keysforward.qml @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only import QtQuick 2.0 diff --git a/tests/auto/quick/qquickitem2/data/mapCoordinates.qml b/tests/auto/quick/qquickitem2/data/mapCoordinates.qml index 1db5a4219d..29cfdd73cb 100644 --- a/tests/auto/quick/qquickitem2/data/mapCoordinates.qml +++ b/tests/auto/quick/qquickitem2/data/mapCoordinates.qml @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only import QtQuick 2.0 diff --git a/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml b/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml index 2cd48adc06..06f625624a 100644 --- a/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml +++ b/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only import QtQuick 2.0 diff --git a/tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml b/tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml new file mode 100644 index 0000000000..98fc0e77af --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml @@ -0,0 +1,51 @@ +import QtQuick + +QtObject { + id: root + + property Window windowA: Window { + visible: true + flags: Qt.FramelessWindowHint + color: "green" + x: 100; y: 100 + width: 300; height: 300 + + Rectangle { + objectName: "childItem" + x: 50; y: 50 + width: 100; height: 100 + color: "red" + } + + WindowContainer { + x: 100; y: 100 + width: 100; height: 100 + window: Window { + objectName: "childWindow" + color: "blue" + + Rectangle { + objectName: "childItemInChildWindow" + x: 30; y: 30 + width: 50; height: 50 + color: "orange" + } + } + } + } + + property Window windowB: Window { + visible: true + flags: Qt.FramelessWindowHint + color: "magenta" + x: 500; y: 200 + width: 200; height: 200 + + Rectangle { + objectName: "childItem" + x: 50; y: 50 + width: 100; height: 100 + color: "cyan" + } + } +} diff --git a/tests/auto/quick/qquickitem2/data/standardkeys.qml b/tests/auto/quick/qquickitem2/data/standardkeys.qml index 68ee185e87..e19b0705c1 100644 --- a/tests/auto/quick/qquickitem2/data/standardkeys.qml +++ b/tests/auto/quick/qquickitem2/data/standardkeys.qml @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only import QtQuick 2.2 diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp index f7601cade1..56271ec3f2 100644 --- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + #include <qtest.h> #include <QtTest/QSignalSpy> #include <QtQml/qqmlengine.h> @@ -16,11 +17,17 @@ #include <QtQuick/private/qquickanchors_p.h> #include <QtGui/qstylehints.h> #include <private/qquickitem_p.h> +#include <QtQuickTest/QtQuickTest> #include <QtQuickTestUtils/private/qmlutils_p.h> #include <QtQuickTestUtils/private/visualtestutils_p.h> #include <QtQuickTestUtils/private/viewtestutils_p.h> #include <QtQuickTestUtils/private/platforminputcontext_p.h> #include <QtTest/private/qpropertytesthelper_p.h> +#ifdef QT_WIDGETS_LIB +#include <QtWidgets/qwidget.h> +#include <QtWidgets/qboxlayout.h> +#include <QtWidgets/qlineedit.h> +#endif using namespace QQuickVisualTestUtils; @@ -87,6 +94,7 @@ private slots: void mapCoordinates_data(); void mapCoordinatesRect(); void mapCoordinatesRect_data(); + void mapCoordinatesWithWindows(); void propertyChanges(); void nonexistentPropertyConnection(); void transforms(); @@ -128,6 +136,14 @@ private slots: void signalsOnDestruction(); void visibleChanged(); + void lastFocusChangeReason(); + void focusInScopeChanges(); + +#ifdef QT_WIDGETS_LIB + void embeddedInWidgetsFocus_data(); + void embeddedInWidgetsFocus(); +#endif + private: QQmlEngine engine; bool qt_tab_all_widgets() { @@ -1873,90 +1889,90 @@ void tst_QQuickItem::layoutMirroring() QQuickItemPrivate *rootPrivate = QQuickItemPrivate::get(rootItem); QVERIFY(rootPrivate); - QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "mirrored2")->effectiveLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false); - QCOMPARE(childPrivate(rootItem, "notMirrored2")->effectiveLayoutMirror, false); - QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, true); - - QCOMPARE(anchorsMirrored(rootItem, "mirrored1"), true); - QCOMPARE(anchorsMirrored(rootItem, "mirrored2"), true); - QCOMPARE(anchorsMirrored(rootItem, "notMirrored1"), false); - QCOMPARE(anchorsMirrored(rootItem, "notMirrored2"), false); - QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror1"), true); - QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror2"), true); - - QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritedLayoutMirror, false); - QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritedLayoutMirror, false); - QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, true); - - QCOMPARE(childPrivate(rootItem, "mirrored1")->isMirrorImplicit, false); - QCOMPARE(childPrivate(rootItem, "mirrored2")->isMirrorImplicit, false); - QCOMPARE(childPrivate(rootItem, "notMirrored1")->isMirrorImplicit, false); - QCOMPARE(childPrivate(rootItem, "notMirrored2")->isMirrorImplicit, true); - QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->isMirrorImplicit, true); - QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->isMirrorImplicit, true); - - QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritMirrorFromParent, true); - QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritMirrorFromParent, false); - QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromParent, true); - QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritMirrorFromParent, false); - QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromParent, true); - QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromParent, true); - - QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritMirrorFromItem, true); - QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritMirrorFromItem, false); - QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromItem, false); - QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritMirrorFromItem, false); - QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromItem, false); - QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromItem, false); + QVERIFY(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror); + QVERIFY(childPrivate(rootItem, "mirrored2")->effectiveLayoutMirror); + QVERIFY(!childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror); + QVERIFY(!childPrivate(rootItem, "notMirrored2")->effectiveLayoutMirror); + QVERIFY(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror); + QVERIFY(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror); + + QVERIFY(anchorsMirrored(rootItem, "mirrored1")); + QVERIFY(anchorsMirrored(rootItem, "mirrored2")); + QVERIFY(!anchorsMirrored(rootItem, "notMirrored1")); + QVERIFY(!anchorsMirrored(rootItem, "notMirrored2")); + QVERIFY(anchorsMirrored(rootItem, "inheritedMirror1")); + QVERIFY(anchorsMirrored(rootItem, "inheritedMirror2")); + + QVERIFY(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror); + QVERIFY(!childPrivate(rootItem, "mirrored2")->inheritedLayoutMirror); + QVERIFY(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror); + QVERIFY(!childPrivate(rootItem, "notMirrored2")->inheritedLayoutMirror); + QVERIFY(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror); + QVERIFY(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror); + + QVERIFY(!childPrivate(rootItem, "mirrored1")->isMirrorImplicit); + QVERIFY(!childPrivate(rootItem, "mirrored2")->isMirrorImplicit); + QVERIFY(!childPrivate(rootItem, "notMirrored1")->isMirrorImplicit); + QVERIFY(childPrivate(rootItem, "notMirrored2")->isMirrorImplicit); + QVERIFY(childPrivate(rootItem, "inheritedMirror1")->isMirrorImplicit); + QVERIFY(childPrivate(rootItem, "inheritedMirror2")->isMirrorImplicit); + + QVERIFY(childPrivate(rootItem, "mirrored1")->inheritMirrorFromParent); + QVERIFY(!childPrivate(rootItem, "mirrored2")->inheritMirrorFromParent); + QVERIFY(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromParent); + QVERIFY(!childPrivate(rootItem, "notMirrored2")->inheritMirrorFromParent); + QVERIFY(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromParent); + QVERIFY(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromParent); + + QVERIFY(childPrivate(rootItem, "mirrored1")->inheritMirrorFromItem); + QVERIFY(!childPrivate(rootItem, "mirrored2")->inheritMirrorFromItem); + QVERIFY(!childPrivate(rootItem, "notMirrored1")->inheritMirrorFromItem); + QVERIFY(!childPrivate(rootItem, "notMirrored2")->inheritMirrorFromItem); + QVERIFY(!childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromItem); + QVERIFY(!childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromItem); // load dynamic content using Loader that needs to inherit mirroring rootItem->setProperty("state", "newContent"); - QCOMPARE(childPrivate(rootItem, "notMirrored3")->effectiveLayoutMirror, false); - QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->effectiveLayoutMirror, true); + QVERIFY(!childPrivate(rootItem, "notMirrored3")->effectiveLayoutMirror); + QVERIFY(childPrivate(rootItem, "inheritedMirror3")->effectiveLayoutMirror); - QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritedLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritedLayoutMirror, true); + QVERIFY(childPrivate(rootItem, "notMirrored3")->inheritedLayoutMirror); + QVERIFY(childPrivate(rootItem, "inheritedMirror3")->inheritedLayoutMirror); - QCOMPARE(childPrivate(rootItem, "notMirrored3")->isMirrorImplicit, false); - QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->isMirrorImplicit, true); + QVERIFY(!childPrivate(rootItem, "notMirrored3")->isMirrorImplicit); + QVERIFY(childPrivate(rootItem, "inheritedMirror3")->isMirrorImplicit); - QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromParent, true); - QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritMirrorFromParent, true); + QVERIFY(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromParent); + QVERIFY(childPrivate(rootItem, "inheritedMirror3")->inheritMirrorFromParent); - QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false); - QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false); + QVERIFY(!childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem); + QVERIFY(!childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem); // disable inheritance rootItem->setProperty("childrenInherit", false); - QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, false); - QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, false); - QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false); + QVERIFY(!childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror); + QVERIFY(!childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror); + QVERIFY(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror); + QVERIFY(!childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror); - QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, false); - QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, false); - QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, false); - QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, false); + QVERIFY(!childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror); + QVERIFY(!childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror); + QVERIFY(!childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror); + QVERIFY(!childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror); // re-enable inheritance rootItem->setProperty("childrenInherit", true); - QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false); + QVERIFY(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror); + QVERIFY(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror); + QVERIFY(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror); + QVERIFY(!childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror); - QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, true); - QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, true); + QVERIFY(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror); + QVERIFY(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror); + QVERIFY(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror); + QVERIFY(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror); // // dynamic parenting @@ -1969,24 +1985,24 @@ void tst_QQuickItem::layoutMirroring() // inherit in constructor QQuickItem *childItem1 = new QQuickItem(parentItem1); - QCOMPARE(QQuickItemPrivate::get(childItem1)->effectiveLayoutMirror, true); - QCOMPARE(QQuickItemPrivate::get(childItem1)->inheritMirrorFromParent, true); + QVERIFY(QQuickItemPrivate::get(childItem1)->effectiveLayoutMirror); + QVERIFY(QQuickItemPrivate::get(childItem1)->inheritMirrorFromParent); // inherit through a parent change QQuickItem *childItem2 = new QQuickItem(); - QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, false); - QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, false); + QVERIFY(!QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror); + QVERIFY(!QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent); childItem2->setParentItem(parentItem1); - QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, true); - QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, true); + QVERIFY(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror); + QVERIFY(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent); // stop inherting through a parent change QQuickItem *parentItem2 = new QQuickItem(); QQuickItemPrivate::get(parentItem2)->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true QQuickItemPrivate::get(parentItem2)->resolveLayoutMirror(); childItem2->setParentItem(parentItem2); - QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, false); - QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, false); + QVERIFY(!QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror); + QVERIFY(!QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent); delete parentItem1; delete parentItem2; @@ -2002,11 +2018,11 @@ void tst_QQuickItem::layoutMirroringWindow() window->show(); QQuickItemPrivate *content = QQuickItemPrivate::get(window->contentItem()); - QCOMPARE(content->effectiveLayoutMirror, true); - QCOMPARE(content->inheritedLayoutMirror, true); - QCOMPARE(content->isMirrorImplicit, false); - QCOMPARE(content->inheritMirrorFromParent, true); - QCOMPARE(content->inheritMirrorFromItem, true); + QVERIFY(content->effectiveLayoutMirror); + QVERIFY(content->inheritedLayoutMirror); + QVERIFY(!content->isMirrorImplicit); + QVERIFY(content->inheritMirrorFromParent); + QVERIFY(content->inheritMirrorFromItem); } void tst_QQuickItem::layoutMirroringIllegalParent() @@ -2797,6 +2813,76 @@ void tst_QQuickItem::mapCoordinatesRect_data() QTest::newRow(QTest::toString(i)) << i << i << i << i; } +void tst_QQuickItem::mapCoordinatesWithWindows() +{ + QQmlComponent component(&engine, testFileUrl("mapCoordinatesWithWindows.qml")); + std::unique_ptr<QObject> root(component.create()); + QVERIFY(root); + + auto *windowA = root->property("windowA").value<QQuickWindow*>(); + QVERIFY(windowA); + + // The window container geometry, parenting, etc, is applied + // during polish, so to test these we need to wait for one. + QVERIFY(QQuickTest::qWaitForPolish(windowA)); + + auto *childItem = windowA->findChild<QQuickItem*>("childItem"); + QVERIFY(childItem); + + QPoint itemPos = childItem->position().toPoint(); + QCOMPARE(childItem->mapToScene({0, 0}), itemPos); + QCOMPARE(childItem->mapToGlobal({0, 0}), windowA->position() + itemPos); + + auto *childItemInChildWindow = windowA->findChild<QQuickItem*>("childItemInChildWindow"); + QVERIFY(childItemInChildWindow); + + QPoint windowItemPos = childItemInChildWindow->position().toPoint(); + QCOMPARE(childItemInChildWindow->mapToScene({0, 0}), windowItemPos); + QCOMPARE(childItemInChildWindow->mapToGlobal({0, 0}), windowA->position() + + childItemInChildWindow->window()->position() + windowItemPos); + + QCOMPARE(childItemInChildWindow->mapToItem(nullptr, {0, 0}), windowItemPos); + + auto globalItemOffset = [](QQuickItem *a, QQuickItem *b) { + return a->mapToGlobal({0, 0}) - b->mapToGlobal({0, 0}); + }; + + QCOMPARE(childItemInChildWindow->mapToItem(childItem, {0, 0}), + globalItemOffset(childItemInChildWindow, childItem)); + QCOMPARE(childItemInChildWindow->mapFromItem(childItem, {0, 0}), + globalItemOffset(childItem, childItemInChildWindow)); + + QCOMPARE(childItem->mapToItem(childItemInChildWindow, {0, 0}), + globalItemOffset(childItem, childItemInChildWindow)); + QCOMPARE(childItem->mapFromItem(childItemInChildWindow, {0, 0}), + globalItemOffset(childItemInChildWindow, childItem)); + + auto *windowB = root->property("windowB").value<QQuickWindow*>(); + QVERIFY(windowA); + auto *childItemInOtherWindow = windowB->findChild<QQuickItem*>("childItem"); + QVERIFY(childItemInOtherWindow); + + QCOMPARE(childItemInOtherWindow->mapToItem(childItem, {0, 0}), + globalItemOffset(childItemInOtherWindow, childItem)); + QCOMPARE(childItemInOtherWindow->mapFromItem(childItem, {0, 0}), + globalItemOffset(childItem, childItemInOtherWindow)); + + QCOMPARE(childItem->mapToItem(childItemInOtherWindow, {0, 0}), + globalItemOffset(childItem, childItemInOtherWindow)); + QCOMPARE(childItem->mapFromItem(childItemInOtherWindow, {0, 0}), + globalItemOffset(childItemInOtherWindow, childItem)); + + QCOMPARE(childItemInOtherWindow->mapToItem(childItemInChildWindow, {0, 0}), + globalItemOffset(childItemInOtherWindow, childItemInChildWindow)); + QCOMPARE(childItemInOtherWindow->mapFromItem(childItemInChildWindow, {0, 0}), + globalItemOffset(childItemInChildWindow, childItemInOtherWindow)); + + QCOMPARE(childItemInChildWindow->mapToItem(childItemInOtherWindow, {0, 0}), + globalItemOffset(childItemInChildWindow, childItemInOtherWindow)); + QCOMPARE(childItemInChildWindow->mapFromItem(childItemInOtherWindow, {0, 0}), + globalItemOffset(childItemInOtherWindow, childItemInChildWindow)); +} + void tst_QQuickItem::transforms_data() { QTest::addColumn<QByteArray>("qml"); @@ -3268,93 +3354,93 @@ void tst_QQuickItem::changeListener() listeners << new TestListener(true); // itemVisibilityChanged x 5 - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Visibility); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size()); parent->setVisible(false); - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QCOMPARE(listener->count(QQuickItemPrivate::Visibility), 1); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0); // itemRotationChanged x 5 - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Rotation); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size()); parent->setRotation(90); - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QCOMPARE(listener->count(QQuickItemPrivate::Rotation), 1); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0); // itemOpacityChanged x 5 - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Opacity); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size()); parent->setOpacity(0.5); - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QCOMPARE(listener->count(QQuickItemPrivate::Opacity), 1); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0); // itemChildAdded() x 5 - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size()); child1 = new QQuickItem(parent); - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QCOMPARE(listener->count(QQuickItemPrivate::Children), 1); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0); // itemParentChanged() x 5 - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QQuickItemPrivate::get(child1)->addItemChangeListener(listener, QQuickItemPrivate::Parent); QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.size(), listeners.size()); child1->setParentItem(nullptr); - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QCOMPARE(listener->count(QQuickItemPrivate::Parent), 1); QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.size(), 0); // itemImplicitWidthChanged() x 5 - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitWidth); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size()); parent->setImplicitWidth(parent->implicitWidth() + 1); - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QCOMPARE(listener->count(QQuickItemPrivate::ImplicitWidth), 1); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0); // itemImplicitHeightChanged() x 5 - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitHeight); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size()); parent->setImplicitHeight(parent->implicitHeight() + 1); - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QCOMPARE(listener->count(QQuickItemPrivate::ImplicitHeight), 1); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0); // itemGeometryChanged() x 5 - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Geometry); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size()); parent->setWidth(parent->width() + 1); - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QCOMPARE(listener->count(QQuickItemPrivate::Geometry), 1); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0); // itemChildRemoved() x 5 child1->setParentItem(parent); - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size()); delete child1; - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QCOMPARE(listener->count(QQuickItemPrivate::Children), 2); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0); // itemDestroyed() x 5 - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Destroyed); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size()); delete parent; - foreach (TestListener *listener, listeners) + for (TestListener *listener : std::as_const(listeners)) QCOMPARE(listener->count(QQuickItemPrivate::Destroyed), 1); } @@ -4139,6 +4225,294 @@ void tst_QQuickItem::visibleChanged() QCOMPARE(childItemSpy.count(), 1); } +void tst_QQuickItem::lastFocusChangeReason() +{ + std::unique_ptr<QQuickView> window = std::make_unique<QQuickView>(); + window->setSource(testFileUrl("focusReason.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.get())); + + QQuickItem *item = window->findChild<QQuickItem *>("item"); + QQuickItem *customText = window->findChild<QQuickItem *>("customText"); + QQuickItem *customItem = window->findChild<QQuickItem *>("customItem"); + QQuickItem *hyperlink = window->findChild<QQuickItem *>("hyperlink"); + QQuickItem *textInputChild = window->findChild<QQuickItem *>("textInputChild"); + + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + QQuickItemPrivate *customTextPrivate = QQuickItemPrivate::get(customText); + QQuickItemPrivate *customItemPrivate = QQuickItemPrivate::get(customItem); + QQuickItemPrivate *hyperlinkPrivate = QQuickItemPrivate::get(hyperlink); + QQuickItemPrivate *textInputChildPrivate = QQuickItemPrivate::get(textInputChild); + + QVERIFY(item); + QVERIFY(customText); + QVERIFY(customItem); + QVERIFY(hyperlink); + QVERIFY(textInputChild); + + QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusAllControls); + auto resetTabFocusBehavior = qScopeGuard([]{ + QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusBehavior(-1)); + }); + + // helper for clicking into an item + const auto itemCenter = [](const QQuickItem *item) -> QPoint { + return item->mapToScene(item->clipRect().center()).toPoint(); + }; + + // setting focusPolicy to Strong/WheelFocus doesn't implicitly turn on event delivery + customText->setAcceptedMouseButtons(Qt::LeftButton); + customItem->setAcceptedMouseButtons(Qt::LeftButton); + customItem->setAcceptTouchEvents(true); + customText->setAcceptTouchEvents(true); + hyperlink->setAcceptTouchEvents(true); + + // window activation -> ActiveWindowFocusReason + QVERIFY(item->hasFocus()); + QVERIFY(item->hasActiveFocus()); + if (itemPrivate->lastFocusChangeReason() != Qt::ActiveWindowFocusReason + && QStringList{"windows", "offscreen"}.contains(QGuiApplication::platformName())) { + QEXPECT_FAIL("", "On Windows and offscreen platforms, window activation does not set focus reason", Continue); + } + QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::ActiveWindowFocusReason); + + // test setter/getter + item->setFocus(false, Qt::MouseFocusReason); + QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); + item->setFocus(true, Qt::TabFocusReason); + QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::TabFocusReason); + item->setFocus(false, Qt::BacktabFocusReason); + QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason); + item->forceActiveFocus(Qt::ShortcutFocusReason); + QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::ShortcutFocusReason); + item->setFocus(false, Qt::NoFocusReason); + QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::NoFocusReason); + QVERIFY(!item->hasFocus()); + + // programmatic focus changes + item->setFocus(true, Qt::OtherFocusReason); + QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::OtherFocusReason); + + QVERIFY(item->hasFocus()); + QVERIFY(item->hasActiveFocus()); + QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::OtherFocusReason); + + // tab focus -> TabFocusReason + QTest::keyClick(window.get(), Qt::Key_Tab); + QVERIFY(customText->hasFocus()); + QVERIFY(customText->hasActiveFocus()); + QCOMPARE(qApp->focusObject(), customText); + QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::TabFocusReason); + QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::TabFocusReason); + + QTest::keyClick(window.get(), Qt::Key_Tab); + QVERIFY(customItem->hasFocus()); + QVERIFY(customItem->hasActiveFocus()); + QCOMPARE(qApp->focusObject(), customItem); + QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::TabFocusReason); + QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::TabFocusReason); + + QTest::keyClick(window.get(), Qt::Key_Tab); + QVERIFY(hyperlink->hasFocus()); + QVERIFY(hyperlink->hasActiveFocus()); + QCOMPARE(qApp->focusObject(), hyperlink); + QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::TabFocusReason); + QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::TabFocusReason); + + QTest::keyClick(window.get(), Qt::Key_Tab); + QVERIFY(item->hasFocus()); + QVERIFY(item->hasActiveFocus()); + QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::TabFocusReason); + QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::TabFocusReason); + + // backtab -> BacktabFocusReason + QTest::keyClick(window.get(), Qt::Key_Tab, Qt::ShiftModifier); + QVERIFY(hyperlink->hasFocus()); + QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason); + QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason); + + QTest::keyClick(window.get(), Qt::Key_Tab, Qt::ShiftModifier); + QVERIFY(customItem->hasFocus()); + QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason); + QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason); + + QTest::keyClick(window.get(), Qt::Key_Tab, Qt::ShiftModifier); + QVERIFY(customText->hasFocus()); + QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason); + QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason); + + // click focus -> MouseFocusReason + QTest::mouseClick(window.get(), Qt::LeftButton, {}, itemCenter(customItem)); + QVERIFY(customItem->hasFocus()); + QVERIFY(customItem->hasActiveFocus()); + QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); + QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); + + QTest::mouseClick(window.get(), Qt::LeftButton, {}, itemCenter(hyperlink)); + QVERIFY(hyperlink->hasFocus()); + QVERIFY(hyperlink->hasActiveFocus()); + QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); + QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); + + QTest::mouseClick(window.get(), Qt::LeftButton, {}, itemCenter(customText)); + QCOMPARE(textInputChild, textInputChild); + QVERIFY(textInputChild->hasFocus()); + QVERIFY(textInputChild->hasActiveFocus()); + QCOMPARE(textInputChildPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); + QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); + + // touch focus -> MouseFocusReason + std::unique_ptr<QPointingDevice> touchDevice(QTest::createTouchDevice()); + + QTest::touchEvent(window.get(), touchDevice.get()).press(0, itemCenter(customItem)); + QTest::touchEvent(window.get(), touchDevice.get()).press(0, itemCenter(customItem)); + QTest::touchEvent(window.get(), touchDevice.get()).release(0, itemCenter(customItem)); + QVERIFY(customItem->hasFocus()); + QVERIFY(customItem->hasActiveFocus()); + QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); + QCOMPARE(textInputChildPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); + + QTest::touchEvent(window.get(), touchDevice.get()).press(0, itemCenter(hyperlink)); + QTest::touchEvent(window.get(), touchDevice.get()).release(0, itemCenter(hyperlink)); + QVERIFY(hyperlink->hasFocus()); + QVERIFY(hyperlink->hasActiveFocus()); + QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); + QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); + + // Wheel focus -> MouseFocusReason + QWheelEvent wheelEvent(QPointF(customItem->width() / 2, customItem->height() / 2), QPointF(), + QPoint(), QPoint(0, 10), Qt::NoButton, Qt::NoModifier, + Qt::NoScrollPhase, false); + QGuiApplication::sendEvent(customItem, &wheelEvent); + QVERIFY(customItem->hasActiveFocus()); + QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason); +} + +void tst_QQuickItem::focusInScopeChanges() +{ + std::unique_ptr<QQuickView> window = std::make_unique<QQuickView>(); + window->setSource(testFileUrl("focusInScopeChanges.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowFocused(window.get())); + + QQuickItem *main = window->rootObject(); + QVERIFY(main); + QQuickItem *focusScope = main->findChild<QQuickItem *>("focusScope"); + QQuickItem *rect = main->findChild<QQuickItem *>("rect"); + QQuickItem *textInput = main->findChild<QQuickItem *>("textInput"); + + QVERIFY(focusScope); + QVERIFY(rect); + QVERIFY(textInput); + QVERIFY(window->contentItem()); + + QSignalSpy fsActiveFocusSpy(focusScope, SIGNAL(activeFocusChanged(bool))); + QSignalSpy rectActiveFocusSpy(rect, SIGNAL(activeFocusChanged(bool))); + QSignalSpy textInputActiveFocusSpy(textInput, SIGNAL(activeFocusChanged(bool))); + + // The window's content item will have activeFocus if window is focused + QTRY_VERIFY(window->contentItem()->hasActiveFocus()); + + QVERIFY(!focusScope->hasActiveFocus()); + QVERIFY(!rect->hasActiveFocus()); + QVERIFY(!textInput->hasActiveFocus()); + QCOMPARE(fsActiveFocusSpy.size(), 0); + QCOMPARE(rectActiveFocusSpy.size(), 0); + QCOMPARE(textInputActiveFocusSpy.size(), 0); + + // setting focus to rect shouldn't affect activeFocus as long as its + // parent focus scope doesn't have the activeFocus + rect->setFocus(true); + QCOMPARE(fsActiveFocusSpy.size(), 0); + QCOMPARE(rectActiveFocusSpy.size(), 0); + QCOMPARE(textInputActiveFocusSpy.size(), 0); + + // focusScope is the only child with focus in the parent + // scope, so it will gain activeFocus + focusScope->setFocus(true); + QCOMPARE(fsActiveFocusSpy.size(), 1); + QVERIFY(fsActiveFocusSpy.first().at(0).toBool()); + // rect loses activeFocus because textInput gains it (as a result of code in signal handler) + QCOMPARE(rectActiveFocusSpy.size(), 2); + QVERIFY(!rect->hasActiveFocus()); + QCOMPARE(textInputActiveFocusSpy.size(), 1); + QVERIFY(textInput->hasActiveFocus()); +} + +#ifdef QT_WIDGETS_LIB +void tst_QQuickItem::embeddedInWidgetsFocus_data() +{ + QTest::addColumn<QUrl>("source"); + QTest::newRow("Embedded") << testFileUrl("embedded.qml"); + QTest::newRow("Embedded Focus Scope") << testFileUrl("embedded_FocusScope.qml"); +} + +void tst_QQuickItem::embeddedInWidgetsFocus() +{ + QFETCH(QUrl, source); + QWidget root; + QVBoxLayout *layout = new QVBoxLayout(&root); + + QLineEdit *lineEdit1 = new QLineEdit(&root); + lineEdit1->setFocusPolicy(Qt::FocusPolicy::TabFocus); + + QQuickView *quickView = new QQuickView; + quickView->setSource(source); + QWidget *container = QWidget::createWindowContainer(quickView, &root); + container->setMinimumSize(quickView->size()); + container->setFocusPolicy(Qt::TabFocus); + + QLineEdit *lineEdit2 = new QLineEdit(&root); + lineEdit2->setFocusPolicy(Qt::FocusPolicy::TabFocus); + + layout->addWidget(lineEdit1); + layout->addWidget(container); + layout->addWidget(lineEdit2); + + QQuickItem *rect1 = findItem<QQuickItem>(quickView->rootObject(), "rect1"); + QQuickItem *rect2 = findItem<QQuickItem>(quickView->rootObject(), "rect2"); + QVERIFY(rect1); + QVERIFY(rect2); + + root.show(); + QTRY_VERIFY(root.isVisible()); + QVERIFY(QTest::qWaitForWindowExposed(&root)); + QVERIFY(QTest::qWaitForWindowFocused(root.windowHandle())); + + lineEdit1->setFocus(); + QTRY_VERIFY(lineEdit1->hasFocus()); + + // Tab forward + QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab); + QTRY_VERIFY(container->hasFocus()); + QVERIFY(QTest::qWaitForWindowFocused(quickView)); + QVERIFY(rect1->hasActiveFocus()); + + QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab); + QTRY_VERIFY(rect2->hasActiveFocus()); + + QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab); + QVERIFY(QTest::qWaitForWindowFocused(root.windowHandle())); + QVERIFY(lineEdit2->hasFocus()); + QVERIFY(!rect2->hasActiveFocus()); + + // Tab backwards + QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab, Qt::ShiftModifier); + QTRY_VERIFY(container->hasFocus()); + QVERIFY(QTest::qWaitForWindowFocused(quickView)); + QVERIFY(rect2->hasActiveFocus()); + + QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab, Qt::ShiftModifier); + QVERIFY(rect1->hasActiveFocus()); + + QTest::keyClick(QGuiApplication::focusWindow(), Qt::Key_Tab, Qt::ShiftModifier); + QVERIFY(QTest::qWaitForWindowFocused(root.windowHandle())); + QVERIFY(lineEdit1->hasFocus()); +} +#endif + QTEST_MAIN(tst_QQuickItem) #include "tst_qquickitem.moc" |