aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quickcontrols2/focus
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quickcontrols2/focus')
-rw-r--r--tests/auto/quickcontrols2/focus/BLACKLIST3
-rw-r--r--tests/auto/quickcontrols2/focus/CMakeLists.txt46
-rw-r--r--tests/auto/quickcontrols2/focus/data/activeFocusOnTab.qml203
-rw-r--r--tests/auto/quickcontrols2/focus/data/keyNavigation.qml260
-rw-r--r--tests/auto/quickcontrols2/focus/data/visualFocus.qml64
-rw-r--r--tests/auto/quickcontrols2/focus/tst_focus.cpp396
6 files changed, 972 insertions, 0 deletions
diff --git a/tests/auto/quickcontrols2/focus/BLACKLIST b/tests/auto/quickcontrols2/focus/BLACKLIST
new file mode 100644
index 0000000000..730d384475
--- /dev/null
+++ b/tests/auto/quickcontrols2/focus/BLACKLIST
@@ -0,0 +1,3 @@
+# QTBUG-78261
+[policy]
+opensuse-leap
diff --git a/tests/auto/quickcontrols2/focus/CMakeLists.txt b/tests/auto/quickcontrols2/focus/CMakeLists.txt
new file mode 100644
index 0000000000..74738cc2a5
--- /dev/null
+++ b/tests/auto/quickcontrols2/focus/CMakeLists.txt
@@ -0,0 +1,46 @@
+# Generated from focus.pro.
+
+#####################################################################
+## tst_focus Test:
+#####################################################################
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_focus
+ SOURCES
+ ../shared/qtest_quickcontrols.h
+ ../shared/util.cpp ../shared/util.h
+ ../shared/visualtestutil.cpp ../shared/visualtestutil.h
+ tst_focus.cpp
+ DEFINES
+ QQC2_IMPORT_PATH=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/quickcontrols2\\\"
+ PUBLIC_LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2
+ Qt::QuickControls2Private
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+ Qt::QuickTest
+ Qt::TestPrivate
+ TESTDATA ${test_data}
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_focus CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=\\\":/data\\\"
+)
+
+qt_internal_extend_target(tst_focus CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+)
diff --git a/tests/auto/quickcontrols2/focus/data/activeFocusOnTab.qml b/tests/auto/quickcontrols2/focus/data/activeFocusOnTab.qml
new file mode 100644
index 0000000000..6b57f39b1e
--- /dev/null
+++ b/tests/auto/quickcontrols2/focus/data/activeFocusOnTab.qml
@@ -0,0 +1,203 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ id: main
+ objectName: "main"
+ width: 400
+ height: 800
+ focus: true
+ Component.onCompleted: button1.focus = true
+ Column {
+ anchors.fill: parent
+ id: column
+ objectName: "column"
+ BusyIndicator {
+ id: busyindicator
+ objectName: "busyindicator"
+ }
+ Button {
+ id: button1
+ objectName: "button1"
+ text: "button1"
+ }
+ Button {
+ id: button2
+ objectName: "button2"
+ text: "button2"
+ }
+ CheckBox {
+ id: checkbox
+ objectName: "checkbox"
+ text: "checkbox"
+ }
+ GroupBox {
+ id: groupbox1
+ objectName: "groupbox1"
+ title: "grouppox1"
+ Column {
+ anchors.fill: parent
+ CheckBox {
+ id: checkbox1
+ objectName: "checkbox1"
+ text: "checkbox1"
+ }
+ CheckBox {
+ id: checkbox2
+ objectName: "checkbox2"
+ text: "checkbox2"
+ }
+ }
+ }
+ Label {
+ id: label
+ objectName: "label"
+ text: "label"
+ }
+ PageIndicator {
+ id: pageindicator
+ objectName: "pageindicator"
+ }
+ ProgressBar {
+ id: progressbar
+ objectName: "progressbar"
+ indeterminate: true
+ }
+ RadioButton {
+ id: radiobutton
+ objectName: "radiobutton"
+ text: "radiobutton"
+ }
+ GroupBox {
+ id: groupbox2
+ objectName: "groupbox2"
+ title: "groupbox2"
+ Column {
+ anchors.fill: parent
+ RadioButton {
+ id: radiobutton1
+ objectName: "radiobutton1"
+ text: "radiobutton1"
+ }
+ RadioButton {
+ id: radiobutton2
+ objectName: "radiobutton2"
+ text: "radiobutton2"
+ }
+ }
+ }
+ RangeSlider {
+ id: rangeslider
+ objectName: "rangeslider"
+ first.handle.objectName: "rangeslider.first"
+ second.handle.objectName: "rangeslider.second"
+ }
+ // ScrollBar
+ ScrollIndicator {
+ id: scrollindicator
+ objectName: "scrollindicator"
+ }
+ Slider {
+ id: slider
+ objectName: "slider"
+ value: 0.5
+ }
+ SpinBox {
+ id: spinbox
+ objectName: "spinbox"
+ editable: true
+ value: 50
+ }
+ // StackView
+ Switch {
+ id: swtich // switch
+ objectName: "switch"
+ text: "switch"
+ }
+ TabBar {
+ width: parent.width
+ id: tabbar
+ objectName: "tabbar"
+ TabButton {
+ id: tabbutton1
+ objectName: "tabbutton1"
+ text: "tabbutton1"
+ }
+ TabButton {
+ id: tabbutton2
+ objectName: "tabbutton2"
+ text: "tabbutton2"
+ }
+ }
+ TextField {
+ id: textfield
+ objectName: "textfield"
+ text: "abc"
+ }
+ ToolBar {
+ width: parent.width
+ id: toolbar
+ objectName: "toolbar"
+ ToolButton {
+ id: toolbutton
+ objectName: "toolbutton"
+ text: "toolbutton"
+ }
+ }
+ TextArea {
+ id: textarea
+ objectName: "textarea"
+ text: "abc"
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols2/focus/data/keyNavigation.qml b/tests/auto/quickcontrols2/focus/data/keyNavigation.qml
new file mode 100644
index 0000000000..7ac8e014cd
--- /dev/null
+++ b/tests/auto/quickcontrols2/focus/data/keyNavigation.qml
@@ -0,0 +1,260 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ id: main
+ objectName: "main"
+ width: 400
+ height: 800
+ focus: true
+ Component.onCompleted: button1.focus = true
+ Column {
+ anchors.fill: parent
+ id: column
+ objectName: "column"
+ BusyIndicator {
+ id: busyindicator
+ objectName: "busyindicator"
+ }
+ Button {
+ id: button1
+ objectName: "button1"
+ text: "button1"
+ KeyNavigation.up: textarea
+ KeyNavigation.down: button2
+ KeyNavigation.left: toolbutton
+ KeyNavigation.right: button2
+ }
+ Button {
+ id: button2
+ objectName: "button2"
+ text: "button2"
+ KeyNavigation.up: button1
+ KeyNavigation.down: checkbox
+ KeyNavigation.left: button1
+ KeyNavigation.right: checkbox
+ }
+ CheckBox {
+ id: checkbox
+ objectName: "checkbox"
+ text: "checkbox"
+ KeyNavigation.up: button2
+ KeyNavigation.down: checkbox1
+ KeyNavigation.left: button2
+ KeyNavigation.right: checkbox1
+ }
+ GroupBox {
+ id: groupbox1
+ objectName: "groupbox1"
+ title: "grouppox1"
+ Column {
+ anchors.fill: parent
+ CheckBox {
+ id: checkbox1
+ objectName: "checkbox1"
+ text: "checkbox1"
+ KeyNavigation.up: checkbox
+ KeyNavigation.down: checkbox2
+ KeyNavigation.left: checkbox
+ KeyNavigation.right: checkbox2
+ }
+ CheckBox {
+ id: checkbox2
+ objectName: "checkbox2"
+ text: "checkbox2"
+ KeyNavigation.up: checkbox1
+ KeyNavigation.down: radiobutton
+ KeyNavigation.left: checkbox1
+ KeyNavigation.right: radiobutton
+ }
+ }
+ }
+ Label {
+ id: label
+ objectName: "label"
+ text: "label"
+ }
+ PageIndicator {
+ id: pageindicator
+ objectName: "pageindicator"
+ }
+ ProgressBar {
+ id: progressbar
+ objectName: "progressbar"
+ indeterminate: true
+ }
+ RadioButton {
+ id: radiobutton
+ objectName: "radiobutton"
+ text: "radiobutton"
+ KeyNavigation.up: checkbox2
+ KeyNavigation.down: radiobutton1
+ KeyNavigation.left: checkbox2
+ KeyNavigation.right: radiobutton1
+ }
+ GroupBox {
+ id: groupbox2
+ objectName: "groupbox2"
+ title: "groupbox2"
+ Column {
+ anchors.fill: parent
+ RadioButton {
+ id: radiobutton1
+ objectName: "radiobutton1"
+ text: "radiobutton1"
+ KeyNavigation.up: radiobutton
+ KeyNavigation.down: radiobutton2
+ KeyNavigation.left: radiobutton
+ KeyNavigation.right: radiobutton2
+ }
+ RadioButton {
+ id: radiobutton2
+ objectName: "radiobutton2"
+ text: "radiobutton2"
+ KeyNavigation.up: radiobutton1
+ KeyNavigation.down: rangeslider
+ KeyNavigation.left: radiobutton1
+ KeyNavigation.right: spinbox
+ }
+ }
+ }
+ RangeSlider {
+ id: rangeslider
+ objectName: "rangeslider"
+ first.handle.objectName: "rangeslider.first"
+ second.handle.objectName: "rangeslider.second"
+ KeyNavigation.up: radiobutton2
+ KeyNavigation.down: slider
+ }
+ // ScrollBar
+ ScrollIndicator {
+ id: scrollindicator
+ objectName: "scrollindicator"
+ }
+ Slider {
+ id: slider
+ objectName: "slider"
+ value: 0.5
+ KeyNavigation.up: rangeslider
+ KeyNavigation.down: swtich
+ }
+ SpinBox {
+ id: spinbox
+ objectName: "spinbox"
+ value: 50
+ KeyNavigation.left: radiobutton2
+ KeyNavigation.right: swtich
+ }
+ // StackView
+ Switch {
+ id: swtich // switch
+ objectName: "switch"
+ text: "switch"
+ KeyNavigation.up: slider
+ KeyNavigation.down: tabbutton1
+ KeyNavigation.left: spinbox
+ KeyNavigation.right: tabbutton1
+ }
+ TabBar {
+ width: parent.width
+ id: tabbar
+ objectName: "tabbar"
+ TabButton {
+ id: tabbutton1
+ objectName: "tabbutton1"
+ text: "tabbutton1"
+ KeyNavigation.up: swtich
+ KeyNavigation.down: tabbutton2
+ KeyNavigation.left: swtich
+ KeyNavigation.right: tabbutton2
+ }
+ TabButton {
+ id: tabbutton2
+ objectName: "tabbutton2"
+ text: "tabbutton2"
+ KeyNavigation.up: tabbutton1
+ KeyNavigation.down: textfield
+ KeyNavigation.left: tabbutton1
+ KeyNavigation.right: toolbutton
+ }
+ }
+ TextField {
+ id: textfield
+ objectName: "textfield"
+ text: "abc"
+ KeyNavigation.up: tabbutton2
+ KeyNavigation.down: toolbutton
+ }
+ ToolBar {
+ width: parent.width
+ id: toolbar
+ objectName: "toolbar"
+ ToolButton {
+ id: toolbutton
+ objectName: "toolbutton"
+ text: "toolbutton"
+ KeyNavigation.up: textfield
+ KeyNavigation.down: textarea
+ KeyNavigation.left: tabbutton2
+ KeyNavigation.right: button1
+ }
+ }
+ TextArea {
+ id: textarea
+ objectName: "textarea"
+ text: "abc"
+ KeyNavigation.up: toolbutton
+ KeyNavigation.down: button1
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols2/focus/data/visualFocus.qml b/tests/auto/quickcontrols2/focus/data/visualFocus.qml
new file mode 100644
index 0000000000..2f516be767
--- /dev/null
+++ b/tests/auto/quickcontrols2/focus/data/visualFocus.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Column {
+ width: 400
+ height: 400
+ Button {
+ text: "Button"
+ property bool showFocus: visualFocus
+ }
+ TextField {
+ text: "TextField"
+ }
+}
diff --git a/tests/auto/quickcontrols2/focus/tst_focus.cpp b/tests/auto/quickcontrols2/focus/tst_focus.cpp
new file mode 100644
index 0000000000..92df4665be
--- /dev/null
+++ b/tests/auto/quickcontrols2/focus/tst_focus.cpp
@@ -0,0 +1,396 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QtTest/QSignalSpy>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQuick/qquickview.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpointingdevice.h>
+#include <QtGui/qstylehints.h>
+#include "../shared/util.h"
+#include "../shared/visualtestutil.h"
+
+using namespace QQuickVisualTestUtil;
+
+class tst_focus : public QQmlDataTest
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase() override;
+
+ void navigation_data();
+ void navigation();
+
+ void policy_data();
+ void policy();
+
+ void reason_data();
+ void reason();
+
+ void visualFocus();
+
+ void scope_data();
+ void scope();
+};
+
+void tst_focus::initTestCase()
+{
+ QQuickStyle::setStyle("Basic");
+ QQmlDataTest::initTestCase();
+}
+
+void tst_focus::navigation_data()
+{
+ QTest::addColumn<Qt::Key>("key");
+ QTest::addColumn<QString>("testFile");
+ QTest::addColumn<Qt::TabFocusBehavior>("behavior");
+ QTest::addColumn<QStringList>("order");
+
+ QTest::newRow("tab-all-controls") << Qt::Key_Tab << QString("activeFocusOnTab.qml") << Qt::TabFocusAllControls << (QStringList() << "button2" << "checkbox" << "checkbox1" << "checkbox2" << "radiobutton" << "radiobutton1" << "radiobutton2" << "rangeslider.first" << "rangeslider.second" << "slider" << "spinbox" << "switch" << "tabbutton1" << "tabbutton2" << "textfield" << "toolbutton" << "textarea" << "button1");
+ QTest::newRow("backtab-all-controls") << Qt::Key_Backtab << QString("activeFocusOnTab.qml") << Qt::TabFocusAllControls << (QStringList() << "textarea" << "toolbutton" << "textfield" << "tabbutton2" << "tabbutton1" << "switch" << "spinbox" << "slider" << "rangeslider.second" << "rangeslider.first" << "radiobutton2" << "radiobutton1" << "radiobutton" << "checkbox2" << "checkbox1" << "checkbox" << "button2" << "button1");
+
+ QTest::newRow("tab-text-controls") << Qt::Key_Tab << QString("activeFocusOnTab.qml") << Qt::TabFocusTextControls << (QStringList() << "spinbox" << "textfield" << "textarea");
+ QTest::newRow("backtab-text-controls") << Qt::Key_Backtab << QString("activeFocusOnTab.qml") << Qt::TabFocusTextControls << (QStringList() << "textarea" << "textfield" << "spinbox");
+
+ QTest::newRow("key-up") << Qt::Key_Up << QString("keyNavigation.qml") << Qt::TabFocusAllControls << (QStringList() << "textarea" << "toolbutton" << "textfield" << "tabbutton2" << "tabbutton1" << "switch" << "slider" << "rangeslider.first" << "radiobutton2" << "radiobutton1" << "radiobutton" << "checkbox2" << "checkbox1" << "checkbox" << "button2" << "button1");
+ QTest::newRow("key-down") << Qt::Key_Down << QString("keyNavigation.qml") << Qt::TabFocusAllControls << (QStringList() << "button2" << "checkbox" << "checkbox1" << "checkbox2" << "radiobutton" << "radiobutton1" << "radiobutton2" << "rangeslider.first" << "slider" << "switch" << "tabbutton1" << "tabbutton2" << "textfield" << "toolbutton" << "textarea" << "button1");
+ QTest::newRow("key-left") << Qt::Key_Left << QString("keyNavigation.qml") << Qt::TabFocusAllControls << (QStringList() << "toolbutton" << "tabbutton2" << "tabbutton1" << "switch" << "spinbox" << "radiobutton2" << "radiobutton1" << "radiobutton" << "checkbox2" << "checkbox1" << "checkbox" << "button2" << "button1");
+ QTest::newRow("key-right") << Qt::Key_Right << QString("keyNavigation.qml") << Qt::TabFocusAllControls << (QStringList() << "button2" << "checkbox" << "checkbox1" << "checkbox2" << "radiobutton" << "radiobutton1" << "radiobutton2" << "spinbox" << "switch" << "tabbutton1" << "tabbutton2" << "toolbutton" << "button1");
+}
+
+void tst_focus::navigation()
+{
+ QFETCH(Qt::Key, key);
+ QFETCH(QString, testFile);
+ QFETCH(Qt::TabFocusBehavior, behavior);
+ QFETCH(QStringList, order);
+
+ QGuiApplication::styleHints()->setTabFocusBehavior(behavior);
+
+ QQuickView view;
+ view.contentItem()->setObjectName("contentItem");
+
+ view.setSource(testFileUrl(testFile));
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+ QVERIFY(QGuiApplication::focusWindow() == &view);
+
+ for (const QString &name : qAsConst(order)) {
+ QKeyEvent event(QEvent::KeyPress, key, Qt::NoModifier);
+ QGuiApplication::sendEvent(&view, &event);
+ QVERIFY(event.isAccepted());
+
+ QQuickItem *item = findItem<QQuickItem>(view.rootObject(), name);
+ QVERIFY2(item, qPrintable(name));
+ QVERIFY2(item->hasActiveFocus(), qPrintable(QString("expected: '%1', actual: '%2'").arg(name).arg(view.activeFocusItem() ? view.activeFocusItem()->objectName() : "null")));
+ }
+
+ QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusBehavior(-1));
+}
+
+void tst_focus::policy_data()
+{
+ QTest::addColumn<QString>("name");
+
+ QTest::newRow("Control") << "Control";
+ QTest::newRow("ComboBox") << "ComboBox";
+ QTest::newRow("Button") << "Button";
+ QTest::newRow("Slider") << "Slider";
+ QTest::newRow("ScrollBar") << "ScrollBar";
+}
+
+void tst_focus::policy()
+{
+ QFETCH(QString, name);
+
+ QQmlEngine engine;
+ QScopedPointer<QPointingDevice> device(QTest::createTouchDevice());
+ QQmlComponent component(&engine);
+ component.setData(QString("import QtQuick.Controls; ApplicationWindow { width: 100; height: 100; %1 { anchors.fill: parent } }").arg(name).toUtf8(), QUrl());
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(component.create()));
+ QVERIFY(window);
+
+ QQuickControl *control = qobject_cast<QQuickControl *>(window->contentItem()->childItems().first());
+ QVERIFY(control);
+
+ QVERIFY(!control->hasActiveFocus());
+ QVERIFY(!control->hasVisualFocus());
+
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ control->setFocusPolicy(Qt::NoFocus);
+ QCOMPARE(control->focusPolicy(), Qt::NoFocus);
+
+ // Qt::TabFocus vs. QQuickItem::activeFocusOnTab
+ control->setActiveFocusOnTab(true);
+ QCOMPARE(control->focusPolicy(), Qt::TabFocus);
+ control->setActiveFocusOnTab(false);
+ QCOMPARE(control->focusPolicy(), Qt::NoFocus);
+
+ control->setFocusPolicy(Qt::TabFocus);
+ QCOMPARE(control->focusPolicy(), Qt::TabFocus);
+ QCOMPARE(control->activeFocusOnTab(), true);
+
+ // Qt::TabFocus
+ QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusAllControls);
+ QTest::keyClick(window.data(), Qt::Key_Tab);
+ QVERIFY(control->hasActiveFocus());
+ QVERIFY(control->hasVisualFocus());
+ QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusBehavior(-1));
+
+ // reset
+ control->setFocus(false);
+ QVERIFY(!control->hasActiveFocus());
+
+ // Qt::ClickFocus (mouse)
+ control->setFocusPolicy(Qt::NoFocus);
+ control->setAcceptedMouseButtons(Qt::LeftButton);
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(control->width() / 2, control->height() / 2));
+ QVERIFY(!control->hasActiveFocus());
+ QVERIFY(!control->hasVisualFocus());
+
+ control->setFocusPolicy(Qt::ClickFocus);
+ QCOMPARE(control->focusPolicy(), Qt::ClickFocus);
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(control->width() / 2, control->height() / 2));
+ QVERIFY(control->hasActiveFocus());
+ QVERIFY(!control->hasVisualFocus());
+
+ // reset
+ control->setFocus(false);
+ QVERIFY(!control->hasActiveFocus());
+
+ // Qt::ClickFocus (touch)
+ control->setFocusPolicy(Qt::NoFocus);
+ QTest::touchEvent(window.data(), device.data()).press(0, QPoint(control->width() / 2, control->height() / 2));
+ QTest::touchEvent(window.data(), device.data()).release(0, QPoint(control->width() / 2, control->height() / 2));
+ QVERIFY(!control->hasActiveFocus());
+ QVERIFY(!control->hasVisualFocus());
+
+ control->setFocusPolicy(Qt::ClickFocus);
+ QCOMPARE(control->focusPolicy(), Qt::ClickFocus);
+ QTest::touchEvent(window.data(), device.data()).press(0, QPoint(control->width() / 2, control->height() / 2));
+ QTest::touchEvent(window.data(), device.data()).release(0, QPoint(control->width() / 2, control->height() / 2));
+ QVERIFY(control->hasActiveFocus());
+ QVERIFY(!control->hasVisualFocus());
+
+ // reset
+ control->setFocus(false);
+ QVERIFY(!control->hasActiveFocus());
+
+ // Qt::WheelFocus
+ QWheelEvent wheelEvent(QPointF(control->width() / 2, control->height() / 2), QPointF(),
+ QPoint(), QPoint(0, 10), Qt::NoButton, Qt::NoModifier,
+ Qt::NoScrollPhase, false);
+ QGuiApplication::sendEvent(control, &wheelEvent);
+ QVERIFY(!control->hasActiveFocus());
+ QVERIFY(!control->hasVisualFocus());
+
+ control->setFocusPolicy(Qt::WheelFocus);
+ QCOMPARE(control->focusPolicy(), Qt::WheelFocus);
+
+ QGuiApplication::sendEvent(control, &wheelEvent);
+ QVERIFY(control->hasActiveFocus());
+ QVERIFY(!control->hasVisualFocus());
+}
+
+void tst_focus::reason_data()
+{
+ QTest::addColumn<QString>("name");
+
+ QTest::newRow("Control") << "Control";
+ QTest::newRow("TextField") << "TextField";
+ QTest::newRow("TextArea") << "TextArea";
+ QTest::newRow("SpinBox") << "SpinBox";
+ QTest::newRow("ComboBox") << "ComboBox";
+}
+
+void tst_focus::reason()
+{
+ QFETCH(QString, name);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(QString("import QtQuick.Controls; ApplicationWindow { width: 100; height: 100; %1 { anchors.fill: parent } }").arg(name).toUtf8(), QUrl());
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(component.create()));
+ QVERIFY(window.data());
+
+ QQuickItem *control = window->contentItem()->childItems().first();
+ QVERIFY(control);
+
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ QCOMPARE(control->property("focusReason").toInt(), int(Qt::OtherFocusReason));
+ control->forceActiveFocus(Qt::MouseFocusReason);
+ QVERIFY(control->hasActiveFocus());
+ QCOMPARE(control->property("focusReason").toInt(), int(Qt::MouseFocusReason));
+
+ QEXPECT_FAIL("TextArea", "TODO: TextArea::visualFocus?", Continue);
+ QEXPECT_FAIL("TextField", "TODO: TextField::visualFocus?", Continue);
+ QCOMPARE(control->property("visualFocus"), QVariant(false));
+
+ window->contentItem()->setFocus(false, Qt::TabFocusReason);
+ QVERIFY(!control->hasActiveFocus());
+ QCOMPARE(control->property("focusReason").toInt(), int(Qt::TabFocusReason));
+
+ QEXPECT_FAIL("TextArea", "", Continue);
+ QEXPECT_FAIL("TextField", "", Continue);
+ QCOMPARE(control->property("visualFocus"), QVariant(false));
+
+ control->forceActiveFocus(Qt::TabFocusReason);
+ QVERIFY(control->hasActiveFocus());
+ QCOMPARE(control->property("focusReason").toInt(), int(Qt::TabFocusReason));
+
+ QEXPECT_FAIL("TextArea", "", Continue);
+ QEXPECT_FAIL("TextField", "", Continue);
+ QCOMPARE(control->property("visualFocus"), QVariant(true));
+}
+
+void tst_focus::visualFocus()
+{
+ QQuickView view;
+ view.setSource(testFileUrl("visualFocus.qml"));
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QQuickItem *column = view.rootObject();
+ QVERIFY(column);
+ QCOMPARE(column->childItems().count(), 2);
+
+ QQuickControl *button = qobject_cast<QQuickControl *>(column->childItems().first());
+ QVERIFY(button);
+
+ QQuickItem *textfield = column->childItems().last();
+ QVERIFY(textfield);
+
+ button->forceActiveFocus(Qt::TabFocusReason);
+ QVERIFY(button->hasActiveFocus());
+ QVERIFY(button->hasVisualFocus());
+ QVERIFY(button->property("showFocus").toBool());
+
+ QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, QPoint(textfield->x() + textfield->width() / 2, textfield->y() + textfield->height() / 2));
+ QVERIFY(!button->hasActiveFocus());
+ QVERIFY(!button->hasVisualFocus());
+ QVERIFY(!button->property("showFocus").toBool());
+}
+
+void tst_focus::scope_data()
+{
+ QTest::addColumn<QString>("name");
+
+ QTest::newRow("Frame") << "Frame";
+ QTest::newRow("GroupBox") << "Frame";
+ QTest::newRow("Page") << "Page";
+ QTest::newRow("Pane") << "Pane";
+ QTest::newRow("StackView") << "StackView";
+}
+
+void tst_focus::scope()
+{
+ QFETCH(QString, name);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(QString("import QtQuick; import QtQuick.Controls; ApplicationWindow { property alias child: child; width: 100; height: 100; %1 { anchors.fill: parent; Item { id: child; width: 10; height: 10 } } }").arg(name).toUtf8(), QUrl());
+
+ QScopedPointer<QPointingDevice> device(QTest::createTouchDevice());
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(component.create()));
+ QVERIFY2(window, qPrintable(component.errorString()));
+
+ QQuickControl *control = qobject_cast<QQuickControl *>(window->contentItem()->childItems().first());
+ QVERIFY(control);
+
+ control->setFocusPolicy(Qt::WheelFocus);
+ control->setAcceptedMouseButtons(Qt::LeftButton);
+
+ QQuickItem *child = window->property("child").value<QQuickItem *>();
+ QVERIFY(child);
+
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+
+ child->forceActiveFocus();
+ QVERIFY(child->hasActiveFocus());
+ QVERIFY(control->hasActiveFocus());
+
+ // Qt::ClickFocus (mouse)
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(control->width() / 2, control->height() / 2));
+ QVERIFY(!child->hasActiveFocus());
+ QVERIFY(control->hasActiveFocus());
+
+ // reset
+ child->forceActiveFocus();
+ QVERIFY(child->hasActiveFocus());
+ QVERIFY(control->hasActiveFocus());
+
+ // Qt::ClickFocus (touch)
+ QTest::touchEvent(window.data(), device.data()).press(0, QPoint(control->width() / 2, control->height() / 2));
+ QTest::touchEvent(window.data(), device.data()).release(0, QPoint(control->width() / 2, control->height() / 2));
+ QVERIFY(!child->hasActiveFocus());
+ QVERIFY(control->hasActiveFocus());
+
+ // reset
+ child->forceActiveFocus();
+ QVERIFY(child->hasActiveFocus());
+ QVERIFY(control->hasActiveFocus());
+
+ // Qt::WheelFocus
+ QWheelEvent wheelEvent(QPointF(control->width() / 2, control->height() / 2), QPointF(),
+ QPoint(), QPoint(0, 10), Qt::NoButton, Qt::NoModifier,
+ Qt::NoScrollPhase, false);
+ QGuiApplication::sendEvent(control, &wheelEvent);
+ QVERIFY(!child->hasActiveFocus());
+ QVERIFY(control->hasActiveFocus());
+}
+
+QTEST_MAIN(tst_focus)
+
+#include "tst_focus.moc"