summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@digia.com>2013-02-21 11:38:10 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-03-19 14:00:49 +0100
commit023f4ec1a135d1a3bd9ce659b095bd4ed2e8b806 (patch)
treecee58db4b1ae560ba19fecffce715c8eedfd569c
parent483c11418e27433308e7d127c865efb105868650 (diff)
downloadqtquickcontrols-023f4ec1a135d1a3bd9ce659b095bd4ed2e8b806.tar.gz
Support QQuickItem.activeFocusOnTab in QtQuick.Controls
Change-Id: Ie23b504f590e6c4e7f2a1a9090c2dd8671389937 Reviewed-by: Jens Bache-Wiig <jens.bache-wiig@digia.com>
-rw-r--r--src/controls/Button.qml2
-rw-r--r--src/controls/CheckBox.qml2
-rw-r--r--src/controls/ComboBox.qml2
-rw-r--r--src/controls/GroupBox.qml2
-rw-r--r--src/controls/Label.qml1
-rw-r--r--src/controls/ProgressBar.qml2
-rw-r--r--src/controls/RadioButton.qml2
-rw-r--r--src/controls/ScrollView.qml2
-rw-r--r--src/controls/Slider.qml2
-rw-r--r--src/controls/SpinBox.qml2
-rw-r--r--src/controls/StatusBar.qml1
-rw-r--r--src/controls/Tab.qml2
-rw-r--r--src/controls/TabView.qml2
-rw-r--r--src/controls/TextArea.qml2
-rw-r--r--src/controls/TextField.qml2
-rw-r--r--src/controls/ToolBar.qml1
-rw-r--r--src/controls/ToolButton.qml2
-rw-r--r--src/private/AbstractCheckable.qml2
-rw-r--r--src/private/BasicButton.qml2
-rw-r--r--src/private/Control.qml2
-rw-r--r--src/private/ScrollBar.qml2
-rw-r--r--src/private/TabBar.qml2
-rw-r--r--tests/auto/activeFocusOnTab/activeFocusOnTab.pro12
-rw-r--r--tests/auto/activeFocusOnTab/data/activeFocusOnTab.qml206
-rw-r--r--tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp427
-rw-r--r--tests/auto/auto.pro2
-rw-r--r--tests/auto/shared/util.cpp138
-rw-r--r--tests/auto/shared/util.h111
-rw-r--r--tests/auto/shared/util.pri8
-rw-r--r--tests/auto/shared/visualtestutil.cpp76
-rw-r--r--tests/auto/shared/visualtestutil.h117
31 files changed, 1137 insertions, 1 deletions
diff --git a/src/controls/Button.qml b/src/controls/Button.qml
index 5317e614..6872a143 100644
--- a/src/controls/Button.qml
+++ b/src/controls/Button.qml
@@ -83,6 +83,8 @@ BasicButton {
*/
property url iconSource
+ activeFocusOnTab: true
+
Accessible.name: text
style: Qt.createComponent(Settings.THEME_PATH + "/ButtonStyle.qml", button)
diff --git a/src/controls/CheckBox.qml b/src/controls/CheckBox.qml
index c459e812..16357533 100644
--- a/src/controls/CheckBox.qml
+++ b/src/controls/CheckBox.qml
@@ -132,6 +132,8 @@ AbstractCheckable {
style: Qt.createComponent(Settings.THEME_PATH + "/CheckBoxStyle.qml", checkBox)
+ activeFocusOnTab: true
+
Accessible.role: Accessible.CheckBox
Accessible.name: text
diff --git a/src/controls/ComboBox.qml b/src/controls/ComboBox.qml
index 8942683e..47efb700 100644
--- a/src/controls/ComboBox.qml
+++ b/src/controls/ComboBox.qml
@@ -93,6 +93,8 @@ Control {
style: Qt.createComponent(Settings.THEME_PATH + "/ComboBoxStyle.qml", comboBox)
+ activeFocusOnTab: true
+
Accessible.role: Accessible.ComboBox
MouseArea {
diff --git a/src/controls/GroupBox.qml b/src/controls/GroupBox.qml
index 0571d1fb..16c40d92 100644
--- a/src/controls/GroupBox.qml
+++ b/src/controls/GroupBox.qml
@@ -151,6 +151,8 @@ Item {
Accessible.role: Accessible.Grouping
Accessible.name: title
+ activeFocusOnTab: false
+
Loader {
id: loader
property alias control: groupbox
diff --git a/src/controls/Label.qml b/src/controls/Label.qml
index e983ecc7..db6de97f 100644
--- a/src/controls/Label.qml
+++ b/src/controls/Label.qml
@@ -81,6 +81,7 @@ Text {
id: label
color: pal.text
+ activeFocusOnTab: false
renderType: Text.NativeRendering
SystemPalette {
id: pal
diff --git a/src/controls/ProgressBar.qml b/src/controls/ProgressBar.qml
index e49ae8be..38193654 100644
--- a/src/controls/ProgressBar.qml
+++ b/src/controls/ProgressBar.qml
@@ -112,6 +112,8 @@ Control {
setValue(value)
}
+ activeFocusOnTab: false
+
Accessible.role: Accessible.ProgressBar
Accessible.name: value
diff --git a/src/controls/RadioButton.qml b/src/controls/RadioButton.qml
index bfb37a60..87f57257 100644
--- a/src/controls/RadioButton.qml
+++ b/src/controls/RadioButton.qml
@@ -77,6 +77,8 @@ import "Styles/Settings.js" as Settings
AbstractCheckable {
id: radioButton
+ activeFocusOnTab: true
+
Accessible.role: Accessible.RadioButton
/*!
diff --git a/src/controls/ScrollView.qml b/src/controls/ScrollView.qml
index 8cf5b48a..6bdc7c2a 100644
--- a/src/controls/ScrollView.qml
+++ b/src/controls/ScrollView.qml
@@ -138,6 +138,8 @@ FocusScope {
/*! \internal */
property alias verticalScrollBar: scroller.verticalScrollBar
+ activeFocusOnTab: true
+
/*! \internal */
onContentItemChanged: {
diff --git a/src/controls/Slider.qml b/src/controls/Slider.qml
index 7f7231ac..bb2102ff 100644
--- a/src/controls/Slider.qml
+++ b/src/controls/Slider.qml
@@ -167,6 +167,8 @@ Control {
/*! \internal */
property bool __horizontal: orientation === Qt.Horizontal
+ activeFocusOnTab: true
+
Accessible.role: Accessible.Slider
Accessible.name: value
diff --git a/src/controls/SpinBox.qml b/src/controls/SpinBox.qml
index 576a13c1..de836b24 100644
--- a/src/controls/SpinBox.qml
+++ b/src/controls/SpinBox.qml
@@ -206,6 +206,8 @@ Control {
/*! \internal */
onValueChanged: if (__initialized) input.setValue(value)
+ activeFocusOnTab: true
+
Accessible.name: input.text
Accessible.role: Accessible.SpinBox
diff --git a/src/controls/StatusBar.qml b/src/controls/StatusBar.qml
index f0a6011f..b3987cb4 100644
--- a/src/controls/StatusBar.qml
+++ b/src/controls/StatusBar.qml
@@ -69,6 +69,7 @@ Item {
id: statusbar
implicitHeight: 20
implicitWidth: parent ? parent.width : style.implicitWidth
+ activeFocusOnTab: false
StyleItem {
id: style
anchors.fill: parent
diff --git a/src/controls/Tab.qml b/src/controls/Tab.qml
index b7d4fb7f..3c86cc3c 100644
--- a/src/controls/Tab.qml
+++ b/src/controls/Tab.qml
@@ -60,6 +60,8 @@ Loader {
active: false
visible: false
+ activeFocusOnTab: false
+
/*! \internal */
onVisibleChanged: if (visible) active = true
diff --git a/src/controls/TabView.qml b/src/controls/TabView.qml
index 2248c856..d24e677c 100644
--- a/src/controls/TabView.qml
+++ b/src/controls/TabView.qml
@@ -141,6 +141,8 @@ FocusScope {
count = __tabs.length
}
+ activeFocusOnTab: false
+
Component {
id: tabcomp
Tab {}
diff --git a/src/controls/TextArea.qml b/src/controls/TextArea.qml
index 47401147..c34315c3 100644
--- a/src/controls/TextArea.qml
+++ b/src/controls/TextArea.qml
@@ -616,6 +616,8 @@ ScrollView {
flickableItem.contentWidth: edit.paintedWidth + (2 * documentMargins)
frameVisible: true
+ activeFocusOnTab: true
+
Accessible.role: Accessible.EditableText
/*!
diff --git a/src/controls/TextField.qml b/src/controls/TextField.qml
index 8a9173a9..8fd9353b 100644
--- a/src/controls/TextField.qml
+++ b/src/controls/TextField.qml
@@ -539,6 +539,8 @@ Control {
textInput.forceActiveFocus();
}
+ activeFocusOnTab: true
+
Accessible.name: text
Accessible.role: Accessible.EditableText
Accessible.description: placeholderText
diff --git a/src/controls/ToolBar.qml b/src/controls/ToolBar.qml
index fd2924ac..0c555cb5 100644
--- a/src/controls/ToolBar.qml
+++ b/src/controls/ToolBar.qml
@@ -71,6 +71,7 @@ import QtQuick.Controls.Private 1.0
Item {
implicitHeight: toolbar.implicitHeight
implicitWidth: parent ? parent.width : toolbar.implicitWidth
+ activeFocusOnTab: false
Accessible.role: Accessible.ToolBar
StyleItem {
id: toolbar
diff --git a/src/controls/ToolButton.qml b/src/controls/ToolButton.qml
index 007bbec7..445ab96b 100644
--- a/src/controls/ToolButton.qml
+++ b/src/controls/ToolButton.qml
@@ -74,6 +74,8 @@ BasicButton {
/*! The label text. */
property string text
+ activeFocusOnTab: true
+
Accessible.name: text
style: Qt.createComponent(Settings.THEME_PATH + "/ToolButtonStyle.qml", button)
diff --git a/src/private/AbstractCheckable.qml b/src/private/AbstractCheckable.qml
index f0acf48f..905d4b65 100644
--- a/src/private/AbstractCheckable.qml
+++ b/src/private/AbstractCheckable.qml
@@ -106,6 +106,8 @@ Control {
*/
readonly property alias __containsMouse: mouseArea.containsMouse
+ activeFocusOnTab: true
+
MouseArea {
id: mouseArea
focus: true
diff --git a/src/private/BasicButton.qml b/src/private/BasicButton.qml
index 412028a0..f0d2a9ec 100644
--- a/src/private/BasicButton.qml
+++ b/src/private/BasicButton.qml
@@ -122,6 +122,8 @@ Control {
onTriggered: button.clicked()
}
+ activeFocusOnTab: true
+
Keys.onPressed: {
if (event.key === Qt.Key_Space && !event.isAutoRepeat && !behavior.pressed)
behavior.keyPressed = true;
diff --git a/src/private/Control.qml b/src/private/Control.qml
index e18e83f3..06bcdce6 100644
--- a/src/private/Control.qml
+++ b/src/private/Control.qml
@@ -65,6 +65,8 @@ FocusScope {
/* \internal */
implicitHeight: __panel ? __panel.implicitHeight: 0
+ activeFocusOnTab: false
+
Loader {
id: panelLoader
anchors.fill: parent
diff --git a/src/private/ScrollBar.qml b/src/private/ScrollBar.qml
index a81414e2..d11fcef6 100644
--- a/src/private/ScrollBar.qml
+++ b/src/private/ScrollBar.qml
@@ -59,6 +59,8 @@ Item {
property Component style: Qt.createComponent("../" + Settings.THEME_PATH + "/ScrollBarStyle.qml", scrollbar)
property alias styleItem: loader.item
+ activeFocusOnTab: false
+
Accessible.role: Accessible.ScrollBar
implicitWidth: loader.implicitWidth
implicitHeight: loader.implicitHeight
diff --git a/src/private/TabBar.qml b/src/private/TabBar.qml
index a96ee100..266d20e1 100644
--- a/src/private/TabBar.qml
+++ b/src/private/TabBar.qml
@@ -51,6 +51,8 @@ FocusScope {
height: tabrow.height
width: tabrow.width
+ activeFocusOnTab: true
+
Keys.onRightPressed: {
if (tabView && tabView.currentIndex < tabView.count - 1)
tabView.currentIndex = tabView.currentIndex + 1
diff --git a/tests/auto/activeFocusOnTab/activeFocusOnTab.pro b/tests/auto/activeFocusOnTab/activeFocusOnTab.pro
new file mode 100644
index 00000000..1a32e0e6
--- /dev/null
+++ b/tests/auto/activeFocusOnTab/activeFocusOnTab.pro
@@ -0,0 +1,12 @@
+CONFIG += testcase
+TARGET = tst_activeFocusOnTab
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_activeFocusOnTab.cpp
+
+include (../shared/util.pri)
+
+TESTDATA = data/*
+
+QT += widgets core-private gui-private v8-private qml-private quick-private testlib
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/activeFocusOnTab/data/activeFocusOnTab.qml b/tests/auto/activeFocusOnTab/data/activeFocusOnTab.qml
new file mode 100644
index 00000000..1c95dc50
--- /dev/null
+++ b/tests/auto/activeFocusOnTab/data/activeFocusOnTab.qml
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Digia Plc and its Subsidiary(-ies) 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 2.0
+import QtQuick.Controls 1.0
+
+Item {
+ id: main
+ objectName: "main"
+ width: 800
+ height: 600
+ focus: true
+ Component.onCompleted: button1.focus = true
+ Column {
+ anchors.fill: parent
+ id: column
+ objectName: "column"
+ Button {
+ id: button1
+ objectName: "button1"
+ text: "button 1"
+ }
+ Button {
+ id: button2
+ objectName: "button2"
+ text: "button 2"
+ }
+ Label {
+ id: label
+ objectName: "label"
+ text: "label"
+ }
+ ToolButton {
+ id: toolbutton
+ objectName: "toolbutton"
+ iconSource: "images/testIcon.png"
+ tooltip: "Test Icon"
+ }
+ ListModel {
+ id: choices
+ ListElement { text: "Banana" }
+ ListElement { text: "Orange" }
+ ListElement { text: "Apple" }
+ ListElement { text: "Coconut" }
+ }
+ ComboBox {
+ id: combobox;
+ objectName: "combobox"
+ model: choices;
+ }
+ GroupBox {
+ id: group1
+ objectName: "group1"
+ title: "GroupBox 1"
+ checkable: true
+ __checkbox.objectName: "group1_checkbox"
+ Row {
+ CheckBox {
+ id: checkbox1
+ objectName: "checkbox1"
+ text: "Text frame"
+ checked: true
+ }
+ CheckBox {
+ id: checkbox2
+ objectName: "checkbox2"
+ text: "Tickmarks"
+ checked: false
+ }
+ }
+ }
+ GroupBox {
+ id: group2
+ objectName: "group2"
+ title: "GroupBox 2"
+ Row {
+ RadioButton {
+ id: radiobutton1
+ objectName: "radiobutton1"
+ text: "North"
+ checked: true
+ }
+ RadioButton {
+ id: radiobutton2
+ objectName: "radiobutton2"
+ text: "South"
+ }
+ }
+ }
+ //Page
+ //ProgressBar maybe not need
+ ProgressBar {
+ id: progressbar
+ objectName: "progressbar"
+ indeterminate: true
+ }
+ //ScrollArea
+ Slider {
+ id: slider
+ objectName: "slider"
+ value: 0.5
+ }
+ SpinBox {
+ id: spinbox
+ objectName: "spinbox"
+ width: 70
+ minimumValue: 0
+ maximumValue: 100
+ value: 50
+ }
+ //SplitterColumn and SplitterRow false
+ //StatusBar false
+ TabView {
+ id: tabview
+ objectName: "tabview"
+ width: 200
+ Tab {
+ id: tab1
+ objectName: "tab1"
+ title: "Tab1"
+ Column {
+ id: column_in_tab1
+ objectName: "column_in_tab1"
+ anchors.fill: parent
+ Button {
+ id: tab1_btn1
+ objectName: "tab1_btn1"
+ text: "button 1 in Tab1"
+ }
+ Button {
+ id: tab1_btn2
+ objectName: "tab1_btn2"
+ text: "button 2 in Tab1"
+ }
+ }
+ }
+ Tab {
+ id: tab2
+ objectName: "tab2"
+ title: "Tab2"
+ Column {
+ id: column_in_tab2
+ objectName: "column_in_tab2"
+ anchors.fill: parent
+ Button {
+ id: tab2_btn1
+ objectName: "tab2_btn1"
+ text: "button 1 in Tab2"
+ }
+ Button {
+ id: tab2_btn2
+ objectName: "tab2_btn2"
+ text: "button 2 in Tab2"
+ }
+ }
+ }
+ }
+ TextField {
+ id: textfield
+ objectName: "textfield"
+ text: "abc"
+ }
+ TextArea {
+ id: textarea
+ objectName: "textarea"
+ text: "abc"
+ }
+ }
+}
diff --git a/tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp b/tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp
new file mode 100644
index 00000000..19d0d194
--- /dev/null
+++ b/tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp
@@ -0,0 +1,427 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.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 "../shared/util.h"
+#include "../shared/visualtestutil.h"
+
+using namespace QQuickVisualTestUtil;
+
+class tst_activeFocusOnTab : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_activeFocusOnTab();
+
+private slots:
+ void initTestCase();
+ void cleanup();
+
+ void activeFocusOnTab();
+private:
+ QQmlEngine engine;
+};
+
+tst_activeFocusOnTab::tst_activeFocusOnTab()
+{
+}
+
+void tst_activeFocusOnTab::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+}
+
+void tst_activeFocusOnTab::cleanup()
+{
+}
+
+void tst_activeFocusOnTab::activeFocusOnTab()
+{
+ QQuickView *window = new QQuickView(0);
+ window->setBaseSize(QSize(800,600));
+
+ window->setSource(testFileUrl("activeFocusOnTab.qml"));
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ QVERIFY(QGuiApplication::focusWindow() == window);
+
+ // original: button1
+ QQuickItem *item = findItem<QQuickItem>(window->rootObject(), "button1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: button1->button2
+ QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "button2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: button2->toolbutton
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "toolbutton");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: toolbutton->combobox
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "combobox");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: combobox->group1_checkbox
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "group1");
+ QVERIFY(item);
+ QQuickItem *subitem = findItem<QQuickItem>(item, "group1_checkbox");
+ QVERIFY(subitem);
+ QVERIFY(subitem->hasActiveFocus());
+
+ // Tab: group1->checkbox1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "checkbox1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: checkbox1->checkbox2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "checkbox2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: checkbox2->radiobutton1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "radiobutton1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: radiobutton1->radiobutton2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "radiobutton2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: radiobutton2->slider
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "slider");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: slider->spinbox
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "spinbox");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: spinbox->tab1_btn1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ for (int i = 0; i < 2; ++i) {
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+ }
+
+ item = findItem<QQuickItem>(window->rootObject(), "tab1_btn1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: tab1_btn1->tab1_btn2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "tab1_btn2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: tab1_btn2->textfield
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "textfield");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: textfield->textarea
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "textarea");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: textarea->textfield
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "textfield");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: textfield->tab1_btn2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "tab1_btn2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: tab1_btn2->tab1_btn1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "tab1_btn1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: tab1_btn1->tab1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+/*
+ // Right: tab1->tab2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ // Tab: tab2->tab2_btn1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "tab2_btn1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: tab2_btn1->tab2_btn2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "tab2_btn2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: tab2_btn2->textfield
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "textfield");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: textfield->tab2_btn2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "tab2_btn2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: tab2_btn2->tab2_btn1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "tab2_btn1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: tab2_btn1->tab2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+*/
+ // BackTab: tab2->spinbox
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "spinbox");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: spinbox->slider
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "slider");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: slider->radiobutton2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "radiobutton2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: radiobutton2->radiobutton1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "radiobutton1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: radiobutton1->checkbox2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "checkbox2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: checkbox2->checkbox1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "checkbox1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: checkbox1->group1_checkbox
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "group1_checkbox");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: group1_checkbox->combobox
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "combobox");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: combobox->toolbutton
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "toolbutton");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: toolbutton->button2
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "button2");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: button2->button1
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "button1");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: button1->textarea
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "textarea");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ delete window;
+}
+
+QTEST_MAIN(tst_activeFocusOnTab)
+
+#include "tst_activeFocusOnTab.moc"
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index dcbf1f8b..927b7cca 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -1,3 +1,3 @@
TEMPLATE = subdirs
-SUBDIRS += testplugin controls
+SUBDIRS += testplugin controls activeFocusOnTab
CONFIG += ordered
diff --git a/tests/auto/shared/util.cpp b/tests/auto/shared/util.cpp
new file mode 100644
index 00000000..e0b14d60
--- /dev/null
+++ b/tests/auto/shared/util.cpp
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "util.h"
+
+#include <QtQml/QQmlComponent>
+#include <QtQml/QQmlError>
+#include <QtQml/QQmlContext>
+#include <QtQml/QQmlEngine>
+#include <QtCore/QTextStream>
+#include <QtCore/QDebug>
+#include <QtCore/QMutexLocker>
+
+QQmlDataTest *QQmlDataTest::m_instance = 0;
+
+QQmlDataTest::QQmlDataTest() :
+#ifdef QT_TESTCASE_BUILDDIR
+ m_dataDirectory(QTest::qFindTestData("data", QT_QMLTEST_DATADIR, 0, QT_TESTCASE_BUILDDIR)),
+#else
+ m_dataDirectory(QTest::qFindTestData("data", QT_QMLTEST_DATADIR, 0)),
+#endif
+
+ m_dataDirectoryUrl(QUrl::fromLocalFile(m_dataDirectory + QLatin1Char('/')))
+{
+ m_instance = this;
+}
+
+QQmlDataTest::~QQmlDataTest()
+{
+ m_instance = 0;
+}
+
+void QQmlDataTest::initTestCase()
+{
+ QVERIFY2(!m_dataDirectory.isEmpty(), "'data' directory not found");
+ m_directory = QFileInfo(m_dataDirectory).absolutePath();
+ QVERIFY2(QDir::setCurrent(m_directory), qPrintable(QLatin1String("Could not chdir to ") + m_directory));
+}
+
+QString QQmlDataTest::testFile(const QString &fileName) const
+{
+ if (m_directory.isEmpty())
+ qFatal("QQmlDataTest::initTestCase() not called.");
+ QString result = m_dataDirectory;
+ result += QLatin1Char('/');
+ result += fileName;
+ return result;
+}
+
+QByteArray QQmlDataTest::msgComponentError(const QQmlComponent &c,
+ const QQmlEngine *engine /* = 0 */)
+{
+ QString result;
+ const QList<QQmlError> errors = c.errors();
+ QTextStream str(&result);
+ str << "Component '" << c.url().toString() << "' has " << errors.size()
+ << " errors: '";
+ for (int i = 0; i < errors.size(); ++i) {
+ if (i)
+ str << ", '";
+ str << errors.at(i).toString() << '\'';
+
+ }
+ if (!engine)
+ if (QQmlContext *context = c.creationContext())
+ engine = context->engine();
+ if (engine) {
+ str << " Import paths: (" << engine->importPathList().join(QStringLiteral(", "))
+ << ") Plugin paths: (" << engine->pluginPathList().join(QStringLiteral(", "))
+ << ')';
+ }
+ return result.toLocal8Bit();
+}
+
+Q_GLOBAL_STATIC(QMutex, qQmlTestMessageHandlerMutex)
+
+QQmlTestMessageHandler *QQmlTestMessageHandler::m_instance = 0;
+
+void QQmlTestMessageHandler::messageHandler(QtMsgType, const QMessageLogContext &, const QString &message)
+{
+ QMutexLocker locker(qQmlTestMessageHandlerMutex());
+ if (QQmlTestMessageHandler::m_instance)
+ QQmlTestMessageHandler::m_instance->m_messages.push_back(message);
+}
+
+QQmlTestMessageHandler::QQmlTestMessageHandler()
+{
+ QMutexLocker locker(qQmlTestMessageHandlerMutex());
+ Q_ASSERT(!QQmlTestMessageHandler::m_instance);
+ QQmlTestMessageHandler::m_instance = this;
+ m_oldHandler = qInstallMessageHandler(messageHandler);
+}
+
+QQmlTestMessageHandler::~QQmlTestMessageHandler()
+{
+ QMutexLocker locker(qQmlTestMessageHandlerMutex());
+ Q_ASSERT(QQmlTestMessageHandler::m_instance);
+ qInstallMessageHandler(m_oldHandler);
+ QQmlTestMessageHandler::m_instance = 0;
+}
diff --git a/tests/auto/shared/util.h b/tests/auto/shared/util.h
new file mode 100644
index 00000000..dc930382
--- /dev/null
+++ b/tests/auto/shared/util.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTESTUTILS_H
+#define QQMLTESTUTILS_H
+
+#include <QtCore/QDir>
+#include <QtCore/QUrl>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QStringList>
+#include <QtTest/QTest>
+
+QT_FORWARD_DECLARE_CLASS(QQmlComponent)
+QT_FORWARD_DECLARE_CLASS(QQmlEngine)
+
+/* Base class for tests with data that are located in a "data" subfolder. */
+
+class QQmlDataTest : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlDataTest();
+ virtual ~QQmlDataTest();
+
+ QString testFile(const QString &fileName) const;
+ inline QString testFile(const char *fileName) const
+ { return testFile(QLatin1String(fileName)); }
+ inline QUrl testFileUrl(const QString &fileName) const
+ { return QUrl::fromLocalFile(testFile(fileName)); }
+ inline QUrl testFileUrl(const char *fileName) const
+ { return testFileUrl(QLatin1String(fileName)); }
+
+ inline QString dataDirectory() const { return m_dataDirectory; }
+ inline QUrl dataDirectoryUrl() const { return m_dataDirectoryUrl; }
+ inline QString directory() const { return m_directory; }
+
+ static inline QQmlDataTest *instance() { return m_instance; }
+
+ static QByteArray msgComponentError(const QQmlComponent &,
+ const QQmlEngine *engine = 0);
+
+public slots:
+ virtual void initTestCase();
+
+private:
+ static QQmlDataTest *m_instance;
+
+ const QString m_dataDirectory;
+ const QUrl m_dataDirectoryUrl;
+ QString m_directory;
+};
+
+class QQmlTestMessageHandler
+{
+ Q_DISABLE_COPY(QQmlTestMessageHandler)
+public:
+ QQmlTestMessageHandler();
+ ~QQmlTestMessageHandler();
+
+ const QStringList &messages() const { return m_messages; }
+ const QString messageString() const { return m_messages.join(QLatin1Char('\n')); }
+
+ void clear() { m_messages.clear(); }
+
+private:
+ static void messageHandler(QtMsgType, const QMessageLogContext &, const QString &message);
+
+ static QQmlTestMessageHandler *m_instance;
+ QStringList m_messages;
+ QtMessageHandler m_oldHandler;
+};
+
+#endif // QQMLTESTUTILS_H
diff --git a/tests/auto/shared/util.pri b/tests/auto/shared/util.pri
new file mode 100644
index 00000000..38c2e6a1
--- /dev/null
+++ b/tests/auto/shared/util.pri
@@ -0,0 +1,8 @@
+QT += core-private gui-private v8-private qml-private quick-private
+
+HEADERS += $$PWD/visualtestutil.h \
+ $$PWD/util.h
+SOURCES += $$PWD/visualtestutil.cpp \
+ $$PWD/util.cpp
+
+DEFINES += QT_QMLTEST_DATADIR=\\\"$${_PRO_FILE_PWD_}/data\\\"
diff --git a/tests/auto/shared/visualtestutil.cpp b/tests/auto/shared/visualtestutil.cpp
new file mode 100644
index 00000000..4b5c201a
--- /dev/null
+++ b/tests/auto/shared/visualtestutil.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "visualtestutil.h"
+
+#include <QtQuick/QQuickItem>
+#include <QtCore/QDebug>
+
+bool QQuickVisualTestUtil::delegateVisible(QQuickItem *item)
+{
+ return item->isVisible() && !QQuickItemPrivate::get(item)->culled;
+}
+
+QQuickItem *QQuickVisualTestUtil::findVisibleChild(QQuickItem *parent, const QString &objectName)
+{
+ QQuickItem *item = 0;
+ QList<QQuickItem*> items = parent->findChildren<QQuickItem*>(objectName);
+ for (int i = 0; i < items.count(); ++i) {
+ if (items.at(i)->isVisible() && !QQuickItemPrivate::get(items.at(i))->culled) {
+ item = items.at(i);
+ break;
+ }
+ }
+ return item;
+}
+
+void QQuickVisualTestUtil::dumpTree(QQuickItem *parent, int depth)
+{
+ static QString padding(" ");
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
+ if (!item)
+ continue;
+ qDebug() << padding.left(depth*2) << item;
+ dumpTree(item, depth+1);
+ }
+}
+
diff --git a/tests/auto/shared/visualtestutil.h b/tests/auto/shared/visualtestutil.h
new file mode 100644
index 00000000..5edb5d08
--- /dev/null
+++ b/tests/auto/shared/visualtestutil.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKVISUALTESTUTIL_H
+#define QQUICKVISUALTESTUTIL_H
+
+#include <QtQuick/QQuickItem>
+#include <QtQml/QQmlExpression>
+
+#include <QtQuick/private/qquickitem_p.h>
+
+namespace QQuickVisualTestUtil
+{
+ QQuickItem *findVisibleChild(QQuickItem *parent, const QString &objectName);
+
+ void dumpTree(QQuickItem *parent, int depth = 0);
+
+ bool delegateVisible(QQuickItem *item);
+
+ /*
+ Find an item with the specified objectName. If index is supplied then the
+ item must also evaluate the {index} expression equal to index
+ */
+ template<typename T>
+ T *findItem(QQuickItem *parent, const QString &objectName, int index = -1)
+ {
+ const QMetaObject &mo = T::staticMetaObject;
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
+ if (!item)
+ continue;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ if (index != -1) {
+ QQmlExpression e(qmlContext(item), item, "index");
+ if (e.evaluate().toInt() == index)
+ return static_cast<T*>(item);
+ } else {
+ return static_cast<T*>(item);
+ }
+ }
+ item = findItem<T>(item, objectName, index);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+ }
+
+ template<typename T>
+ QList<T*> findItems(QQuickItem *parent, const QString &objectName, bool visibleOnly = true)
+ {
+ QList<T*> items;
+ const QMetaObject &mo = T::staticMetaObject;
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
+ if (!item || (visibleOnly && (!item->isVisible() || QQuickItemPrivate::get(item)->culled)))
+ continue;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName))
+ items.append(static_cast<T*>(item));
+ items += findItems<T>(item, objectName);
+ }
+
+ return items;
+ }
+
+ template<typename T>
+ QList<T*> findItems(QQuickItem *parent, const QString &objectName, const QList<int> &indexes)
+ {
+ QList<T*> items;
+ for (int i=0; i<indexes.count(); i++)
+ items << qobject_cast<QQuickItem*>(findItem<T>(parent, objectName, indexes[i]));
+ return items;
+ }
+}
+
+#define QQUICK_VERIFY_POLISH(item) \
+ QTRY_COMPARE(QQuickItemPrivate::get(item)->polishScheduled, false)
+
+#endif // QQUICKVISUALTESTUTIL_H