diff options
Diffstat (limited to 'tests/auto/controls/data')
48 files changed, 2326 insertions, 174 deletions
diff --git a/tests/auto/controls/data/TumblerDatePicker.qml b/tests/auto/controls/data/TumblerDatePicker.qml index 18d7fb97..e5340493 100644 --- a/tests/auto/controls/data/TumblerDatePicker.qml +++ b/tests/auto/controls/data/TumblerDatePicker.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2016 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.6 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 Row { id: datePicker diff --git a/tests/auto/controls/data/TumblerListView.qml b/tests/auto/controls/data/TumblerListView.qml new file mode 100644 index 00000000..cccf8adf --- /dev/null +++ b/tests/auto/controls/data/TumblerListView.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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: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 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 2.6 + +ListView { + anchors.fill: parent + model: parent.model + delegate: parent.delegate + + snapMode: ListView.SnapToItem + highlightRangeMode: ListView.StrictlyEnforceRange + preferredHighlightBegin: height / 2 - (height / parent.visibleItemCount / 2) + preferredHighlightEnd: height / 2 + (height / parent.visibleItemCount / 2) + clip: true +} diff --git a/tests/auto/controls/data/TumblerPathView.qml b/tests/auto/controls/data/TumblerPathView.qml new file mode 100644 index 00000000..e325faf6 --- /dev/null +++ b/tests/auto/controls/data/TumblerPathView.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2015 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: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 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 2.6 + +PathView { + id: pathView + model: parent.model + delegate: parent.delegate + clip: true + pathItemCount: parent.visibleItemCount + 1 + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + dragMargin: width / 2 + + path: Path { + startX: pathView.width / 2 + startY: -pathView.delegateHeight / 2 + PathLine { + x: pathView.width / 2 + y: pathView.pathItemCount * pathView.delegateHeight - pathView.delegateHeight / 2 + } + } + + property real delegateHeight: parent.availableHeight / parent.visibleItemCount +} diff --git a/tests/auto/controls/data/tst_abstractbutton.qml b/tests/auto/controls/data/tst_abstractbutton.qml index ba5ee94c..27fc4525 100644 --- a/tests/auto/controls/data/tst_abstractbutton.qml +++ b/tests/auto/controls/data/tst_abstractbutton.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_busyindicator.qml b/tests/auto/controls/data/tst_busyindicator.qml index 142ec70a..c456a2e8 100644 --- a/tests/auto/controls/data/tst_busyindicator.qml +++ b/tests/auto/controls/data/tst_busyindicator.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_button.qml b/tests/auto/controls/data/tst_button.qml index 1de43426..16d1bb94 100644 --- a/tests/auto/controls/data/tst_button.qml +++ b/tests/auto/controls/data/tst_button.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -213,8 +213,11 @@ TestCase { control.spy.expectedSequence = repeatSequence mousePress(control) compare(control.pressed, true) - tryCompare(clickSpy, "count", repeatCount) - verify(control.spy.success) + tryVerify(function() { return clickSpy.count >= repeatCount }) + if (clickSpy.count > repeatCount) + warn("Expected auto-repeat count " + repeatCount + " exceeded (" + clickSpy.count + ") - busy CI?") + else + verify(control.spy.success) control.spy.expectedSequence = [["pressedChanged", { "pressed": false }], ["downChanged", { "down": false }], @@ -229,8 +232,11 @@ TestCase { control.spy.expectedSequence = repeatSequence keyPress(Qt.Key_Space) compare(control.pressed, true) - tryCompare(clickSpy, "count", repeatCount) - verify(control.spy.success) + tryVerify(function() { return clickSpy.count >= repeatCount }) + if (clickSpy.count > repeatCount) + warn("Expected auto-repeat count " + repeatCount + " exceeded (" + clickSpy.count + ") - busy CI?") + else + verify(control.spy.success) control.spy.expectedSequence = [["pressedChanged", { "pressed": false }], ["downChanged", { "down": false }], diff --git a/tests/auto/controls/data/tst_buttongroup.qml b/tests/auto/controls/data/tst_buttongroup.qml index 754e4f0b..186eb9d1 100644 --- a/tests/auto/controls/data/tst_buttongroup.qml +++ b/tests/auto/controls/data/tst_buttongroup.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -196,6 +196,32 @@ TestCase { group.destroy() } + function test_clicked() { + var group = buttonGroup.createObject(testCase) + verify(group) + + var clickedSpy = signalSpy.createObject(testCase, {target: group, signalName: "clicked"}) + verify(clickedSpy.valid) + + var button1 = button.createObject(testCase) + var button2 = button.createObject(testCase) + + group.addButton(button1) + group.addButton(button2) + + button1.clicked() + compare(clickedSpy.count, 1) + compare(clickedSpy.signalArguments[0][0], button1) + + button2.clicked() + compare(clickedSpy.count, 2) + compare(clickedSpy.signalArguments[1][0], button2) + + group.destroy() + button1.destroy() + button2.destroy() + } + Component { id: checkBoxes Item { diff --git a/tests/auto/controls/data/tst_checkbox.qml b/tests/auto/controls/data/tst_checkbox.qml index 7969b589..d1b590e4 100644 --- a/tests/auto/controls/data/tst_checkbox.qml +++ b/tests/auto/controls/data/tst_checkbox.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_checkdelegate.qml b/tests/auto/controls/data/tst_checkdelegate.qml index a471b1d6..2fa8b4be 100644 --- a/tests/auto/controls/data/tst_checkdelegate.qml +++ b/tests/auto/controls/data/tst_checkdelegate.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_combobox.qml b/tests/auto/controls/data/tst_combobox.qml index 97ba7ea4..b74911c7 100644 --- a/tests/auto/controls/data/tst_combobox.qml +++ b/tests/auto/controls/data/tst_combobox.qml @@ -41,7 +41,7 @@ import QtQuick 2.2 import QtQuick.Window 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -76,6 +76,7 @@ TestCase { compare(control.count, 0) compare(control.model, undefined) + compare(control.flat, false) compare(control.pressed, false) compare(control.currentIndex, -1) compare(control.highlightedIndex, -1) diff --git a/tests/auto/controls/data/tst_container.qml b/tests/auto/controls/data/tst_container.qml index d1ff54e0..3c7032c7 100644 --- a/tests/auto/controls/data/tst_container.qml +++ b/tests/auto/controls/data/tst_container.qml @@ -40,8 +40,8 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 -import QtQuick.Templates 2.0 as T +import QtQuick.Controls 2.1 +import QtQuick.Templates 2.1 as T TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_control.qml b/tests/auto/controls/data/tst_control.qml index 3018498e..1b60eb73 100644 --- a/tests/auto/controls/data/tst_control.qml +++ b/tests/auto/controls/data/tst_control.qml @@ -40,8 +40,8 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 -import QtQuick.Templates 2.0 as T +import QtQuick.Controls 2.1 +import QtQuick.Templates 2.1 as T TestCase { id: testCase @@ -859,7 +859,9 @@ TestCase { verify(control) compare(control.hovered, false) - compare(control.hoverEnabled, false) + compare(control.hoverEnabled, Qt.styleHints.useHoverEffects) + + control.hoverEnabled = false mouseMove(control, control.width / 2, control.height / 2) compare(control.hovered, false) @@ -891,6 +893,42 @@ TestCase { control.destroy() } + function test_hoverEnabled() { + var control = component.createObject(testCase) + compare(control.hoverEnabled, Qt.styleHints.useHoverEffects) + + var child = component.createObject(control) + var grandChild = component.createObject(child) + + var childExplicitHoverEnabled = component.createObject(control, {hoverEnabled: true}) + var grandChildExplicitHoverDisabled = component.createObject(childExplicitHoverEnabled, {hoverEnabled: false}) + + var childExplicitHoverDisabled = component.createObject(control, {hoverEnabled: false}) + var grandChildExplicitHoverEnabled = component.createObject(childExplicitHoverDisabled, {hoverEnabled: true}) + + control.hoverEnabled = false + compare(control.hoverEnabled, false) + compare(grandChild.hoverEnabled, false) + + compare(childExplicitHoverEnabled.hoverEnabled, true) + compare(grandChildExplicitHoverDisabled.hoverEnabled, false) + + compare(childExplicitHoverDisabled.hoverEnabled, false) + compare(grandChildExplicitHoverEnabled.hoverEnabled, true) + + control.hoverEnabled = true + compare(control.hoverEnabled, true) + compare(grandChild.hoverEnabled, true) + + compare(childExplicitHoverEnabled.hoverEnabled, true) + compare(grandChildExplicitHoverDisabled.hoverEnabled, false) + + compare(childExplicitHoverDisabled.hoverEnabled, false) + compare(grandChildExplicitHoverEnabled.hoverEnabled, true) + + control.destroy() + } + function test_implicitSize() { var control = component.createObject(testCase) verify(control) diff --git a/tests/auto/controls/data/tst_dial.qml b/tests/auto/controls/data/tst_dial.qml index a2ebf192..e6446d3e 100644 --- a/tests/auto/controls/data/tst_dial.qml +++ b/tests/auto/controls/data/tst_dial.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_dialog.qml b/tests/auto/controls/data/tst_dialog.qml new file mode 100644 index 00000000..d4cbc222 --- /dev/null +++ b/tests/auto/controls/data/tst_dialog.qml @@ -0,0 +1,297 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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: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 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 2.4 +import QtTest 1.0 +import QtQuick.Controls 2.1 +import QtQuick.Templates 2.1 as T + +TestCase { + id: testCase + width: 400 + height: 400 + visible: true + when: windowShown + name: "Dialog" + + Component { + id: dialog + Dialog { } + } + + Component { + id: buttonBox + DialogButtonBox { } + } + + Component { + id: headerBox + DialogButtonBox { position: DialogButtonBox.Header } + } + + Component { + id: footerBox + DialogButtonBox { position: DialogButtonBox.Footer } + } + + Component { + id: signalSpy + SignalSpy { } + } + + function test_defaults() { + var control = dialog.createObject(testCase) + verify(control) + verify(!control.header) + verify(!control.footer) + verify(control.buttonBox) + compare(control.standardButtons, 0) + control.destroy() + } + + function test_accept() { + var control = dialog.createObject(testCase) + + control.open() + waitForRendering(control.contentItem) + verify(control.visible) + + var acceptedSpy = signalSpy.createObject(testCase, {target: control, signalName: "accepted"}) + verify(acceptedSpy.valid) + control.accept() + compare(acceptedSpy.count, 1) + + tryCompare(control, "visible", false) + + control.destroy() + } + + function test_reject() { + var control = dialog.createObject(testCase) + + control.open() + waitForRendering(control.contentItem) + verify(control.visible) + + var rejectedSpy = signalSpy.createObject(testCase, {target: control, signalName: "rejected"}) + verify(rejectedSpy.valid) + control.reject() + compare(rejectedSpy.count, 1) + + tryCompare(control, "visible", false) + + control.destroy() + } + + function test_buttonBox_data() { + return [ + { tag: "default header", property: "header", buttonBox: headerBox }, + { tag: "default footer", property: "footer", buttonBox: footerBox }, + { tag: "custom header", property: "header", position: DialogButtonBox.Header }, + { tag: "custom footer", property: "footer", position: DialogButtonBox.Footer } + ] + } + + function test_buttonBox(data) { + var control = dialog.createObject(testCase) + + if (data.buttonBox) + control.buttonBox = data.buttonBox + else + control[data.property] = buttonBox.createObject(testCase, {position: data.position}) + control.standardButtons = Dialog.Ok | Dialog.Cancel + var box = control[data.property] + verify(box) + compare(box.standardButtons, Dialog.Ok | Dialog.Cancel) + + var acceptedSpy = signalSpy.createObject(testCase, {target: control, signalName: "accepted"}) + verify(acceptedSpy.valid) + box.accepted() + compare(acceptedSpy.count, 1) + + var rejectedSpy = signalSpy.createObject(testCase, {target: control, signalName: "rejected"}) + verify(rejectedSpy.valid) + box.rejected() + compare(rejectedSpy.count, 1) + + control.destroy() + } + + function test_standardButtons() { + var control = dialog.createObject(testCase) + + control.standardButtons = Dialog.Ok + + var box = control.footer ? control.footer : control.header + verify(box) + compare(box.count, 1) + var okButton = box.itemAt(0) + verify(okButton) + compare(okButton.text.toUpperCase(), "OK") + + control.standardButtons = Dialog.Cancel + compare(box.count, 1) + var cancelButton = control.footer.itemAt(0) + verify(cancelButton) + compare(cancelButton.text.toUpperCase(), "CANCEL") + + control.standardButtons = Dialog.Ok | Dialog.Cancel + compare(box.count, 2) + if (box.itemAt(0).text.toUpperCase() === "OK") { + okButton = box.itemAt(0) + cancelButton = box.itemAt(1) + } else { + okButton = box.itemAt(1) + cancelButton = box.itemAt(0) + } + verify(okButton) + verify(cancelButton) + compare(okButton.text.toUpperCase(), "OK") + compare(cancelButton.text.toUpperCase(), "CANCEL") + + control.standardButtons = 0 + compare(box.count, 0) + + control.destroy() + } + + function test_warnings() { + var control = dialog.createObject(testCase) + verify(control) + + var testComponent = Qt.createComponent("TestItem.qml") + verify(testComponent) + + control.buttonBox = headerBox + control.header = testComponent.createObject(testCase) + ignoreWarning(Qt.resolvedUrl("tst_dialog.qml") + ":56:9: QML Dialog: Custom header detected. Cannot assign buttonBox as a header. No standard buttons will appear in the header.") + control.standardButtons = Dialog.Apply + + control.buttonBox = footerBox + control.footer = testComponent.createObject(testCase) + ignoreWarning(Qt.resolvedUrl("tst_dialog.qml") + ":56:9: QML Dialog: Custom footer detected. Cannot assign buttonBox as a footer. No standard buttons will appear in the footer.") + control.standardButtons = Dialog.Cancel + + control.buttonBox = testComponent + ignoreWarning(Qt.resolvedUrl("tst_dialog.qml") + ":56:9: QML Dialog: buttonBox must be an instance of DialogButtonBox") + control.standardButtons = Dialog.Ok + + control.destroy() + } + + function test_layout() { + var control = dialog.createObject(testCase, {width: 100, height: 100}) + verify(control) + + control.open() + waitForRendering(control.contentItem) + verify(control.visible) + + compare(control.width, 100) + compare(control.height, 100) + compare(control.contentItem.width, control.availableWidth) + compare(control.contentItem.height, control.availableHeight) + + control.header = buttonBox.createObject(control.contentItem) + compare(control.header.width, control.width) + verify(control.header.height > 0) + compare(control.contentItem.width, control.availableWidth) + compare(control.contentItem.height, control.availableHeight - control.header.height) + + control.footer = buttonBox.createObject(control.contentItem) + compare(control.footer.width, control.width) + verify(control.footer.height > 0) + compare(control.contentItem.width, control.availableWidth) + compare(control.contentItem.height, control.availableHeight - control.header.height - control.footer.height) + + control.topPadding = 9 + control.leftPadding = 2 + control.rightPadding = 6 + control.bottomPadding = 7 + + compare(control.header.x, 0) + compare(control.header.y, 0) + compare(control.header.width, control.width) + verify(control.header.height > 0) + + compare(control.footer.x, 0) + compare(control.footer.y, control.height - control.footer.height) + compare(control.footer.width, control.width) + verify(control.footer.height > 0) + + compare(control.contentItem.x, control.leftPadding) + compare(control.contentItem.y, control.topPadding + control.header.height) + compare(control.contentItem.width, control.availableWidth) + compare(control.contentItem.height, control.availableHeight - control.header.height - control.footer.height) + + control.header.visible = false + compare(control.contentItem.x, control.leftPadding) + compare(control.contentItem.y, control.topPadding) + compare(control.contentItem.width, control.availableWidth) + compare(control.contentItem.height, control.availableHeight - control.footer.height) + + control.footer.visible = false + compare(control.contentItem.x, control.leftPadding) + compare(control.contentItem.y, control.topPadding) + compare(control.contentItem.width, control.availableWidth) + compare(control.contentItem.height, control.availableHeight) + + control.contentItem.implicitWidth = 50 + control.contentItem.implicitHeight = 60 + compare(control.implicitWidth, control.contentItem.implicitWidth + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentItem.implicitHeight + control.topPadding + control.bottomPadding) + + control.header.visible = true + compare(control.implicitHeight, control.contentItem.implicitHeight + control.topPadding + control.bottomPadding + + control.header.implicitHeight) + + control.footer.visible = true + compare(control.implicitHeight, control.contentItem.implicitHeight + control.topPadding + control.bottomPadding + + control.header.implicitHeight + control.footer.implicitHeight) + + control.header.implicitWidth = 150 + compare(control.implicitWidth, control.header.implicitWidth) + + control.footer.implicitWidth = 160 + compare(control.implicitWidth, control.footer.implicitWidth) + + control.destroy() + } +} diff --git a/tests/auto/controls/data/tst_dialogbuttonbox.qml b/tests/auto/controls/data/tst_dialogbuttonbox.qml new file mode 100644 index 00000000..8474e89b --- /dev/null +++ b/tests/auto/controls/data/tst_dialogbuttonbox.qml @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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: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 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 2.2 +import QtTest 1.0 +import QtQuick.Controls 2.1 + +TestCase { + id: testCase + width: 200 + height: 200 + visible: true + when: windowShown + name: "DialogButtonBox" + + Component { + id: buttonBox + DialogButtonBox { } + } + + Component { + id: button + Button { } + } + + Component { + id: signalSpy + SignalSpy { } + } + + function test_defaults() { + var control = buttonBox.createObject(testCase) + verify(control) + compare(control.count, 0) + verify(control.delegate) + compare(control.standardButtons, 0) + control.destroy() + } + + function test_standardButtons() { + var control = buttonBox.createObject(testCase) + + compare(control.count, 0) + + control.standardButtons = DialogButtonBox.Ok + compare(control.count, 1) + var okButton = control.itemAt(0) + verify(okButton) + compare(okButton.text.toUpperCase(), "OK") + + control.standardButtons = DialogButtonBox.Cancel + compare(control.count, 1) + var cancelButton = control.itemAt(0) + verify(cancelButton) + compare(cancelButton.text.toUpperCase(), "CANCEL") + + control.standardButtons = DialogButtonBox.Ok | DialogButtonBox.Cancel + compare(control.count, 2) + if (control.itemAt(0).text.toUpperCase() === "OK") { + okButton = control.itemAt(0) + cancelButton = control.itemAt(1) + } else { + okButton = control.itemAt(1) + cancelButton = control.itemAt(0) + } + verify(okButton) + verify(cancelButton) + compare(okButton.text.toUpperCase(), "OK") + compare(cancelButton.text.toUpperCase(), "CANCEL") + + control.standardButtons = 0 + compare(control.count, 0) + + control.destroy() + } + + function test_attached() { + var control = buttonBox.createObject(testCase) + + control.standardButtons = DialogButtonBox.Ok + var okButton = control.itemAt(0) + compare(okButton.DialogButtonBox.buttonBox, control) + compare(okButton.DialogButtonBox.buttonRole, DialogButtonBox.AcceptRole) + + var saveButton = button.createObject(control, {text: "Save"}) + compare(saveButton.DialogButtonBox.buttonBox, control) + compare(saveButton.DialogButtonBox.buttonRole, DialogButtonBox.InvalidRole) + saveButton.DialogButtonBox.buttonRole = DialogButtonBox.AcceptRole + compare(saveButton.DialogButtonBox.buttonRole, DialogButtonBox.AcceptRole) + + var closeButton = button.createObject(null, {text: "Save"}) + compare(closeButton.DialogButtonBox.buttonBox, null) + compare(closeButton.DialogButtonBox.buttonRole, DialogButtonBox.InvalidRole) + closeButton.DialogButtonBox.buttonRole = DialogButtonBox.DestructiveRole + compare(closeButton.DialogButtonBox.buttonRole, DialogButtonBox.DestructiveRole) + control.addItem(closeButton) + compare(closeButton.DialogButtonBox.buttonBox, control) + + control.contentModel.clear() + compare(okButton.DialogButtonBox.buttonBox, null) + compare(saveButton.DialogButtonBox.buttonBox, null) + compare(closeButton.DialogButtonBox.buttonBox, null) + + control.destroy() + } + + function test_signals_data() { + return [ + { tag: "Ok", standardButton: DialogButtonBox.Ok, buttonRole: DialogButtonBox.AcceptRole, signalName: "accepted" }, + { tag: "Open", standardButton: DialogButtonBox.Open, buttonRole: DialogButtonBox.AcceptRole, signalName: "accepted" }, + { tag: "Save", standardButton: DialogButtonBox.Save, buttonRole: DialogButtonBox.AcceptRole, signalName: "accepted" }, + { tag: "Cancel", standardButton: DialogButtonBox.Cancel, buttonRole: DialogButtonBox.RejectRole, signalName: "rejected" }, + { tag: "Close", standardButton: DialogButtonBox.Close, buttonRole: DialogButtonBox.RejectRole, signalName: "rejected" }, + { tag: "Discard", standardButton: DialogButtonBox.Discard, buttonRole: DialogButtonBox.DestructiveRole }, + { tag: "Apply", standardButton: DialogButtonBox.Apply, buttonRole: DialogButtonBox.ApplyRole }, + { tag: "Reset", standardButton: DialogButtonBox.Reset, buttonRole: DialogButtonBox.ResetRole }, + { tag: "RestoreDefaults", standardButton: DialogButtonBox.RestoreDefaults, buttonRole: DialogButtonBox.ResetRole }, + { tag: "Help", standardButton: DialogButtonBox.Help, buttonRole: DialogButtonBox.HelpRole, signalName: "helpRequested" }, + { tag: "SaveAll", standardButton: DialogButtonBox.SaveAll, buttonRole: DialogButtonBox.AcceptRole, signalName: "accepted" }, + { tag: "Yes", standardButton: DialogButtonBox.Yes, buttonRole: DialogButtonBox.YesRole, signalName: "accepted" }, + { tag: "YesToAll", standardButton: DialogButtonBox.YesToAll, buttonRole: DialogButtonBox.YesRole, signalName: "accepted" }, + { tag: "No", standardButton: DialogButtonBox.No, buttonRole: DialogButtonBox.NoRole, signalName: "rejected" }, + { tag: "NoToAll", standardButton: DialogButtonBox.NoToAll, buttonRole: DialogButtonBox.NoRole, signalName: "rejected" }, + { tag: "Abort", standardButton: DialogButtonBox.Abort, buttonRole: DialogButtonBox.RejectRole, signalName: "rejected" }, + { tag: "Retry", standardButton: DialogButtonBox.Retry, buttonRole: DialogButtonBox.AcceptRole, signalName: "accepted" }, + { tag: "Ignore", standardButton: DialogButtonBox.Ignore, buttonRole: DialogButtonBox.AcceptRole, signalName: "accepted" } + ] + } + + function test_signals(data) { + var control = buttonBox.createObject(testCase) + + control.standardButtons = data.standardButton + compare(control.count, 1) + var button = control.itemAt(0) + verify(button) + compare(button.DialogButtonBox.buttonRole, data.buttonRole) + + var clickedSpy = signalSpy.createObject(control, {target: control, signalName: "clicked"}) + verify(clickedSpy.valid) + var roleSpy = signalSpy.createObject(control, {target: control, signalName: data.signalName}) + compare(roleSpy.valid, !!data.signalName) + + button.clicked() + compare(clickedSpy.count, 1) + compare(clickedSpy.signalArguments[0][0], button) + compare(roleSpy.count, !!data.signalName ? 1 : 0) + + control.destroy() + } +} diff --git a/tests/auto/controls/data/tst_drawer.qml b/tests/auto/controls/data/tst_drawer.qml index 021afdb2..2e1f32dc 100644 --- a/tests/auto/controls/data/tst_drawer.qml +++ b/tests/auto/controls/data/tst_drawer.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_frame.qml b/tests/auto/controls/data/tst_frame.qml index a96397de..c64b0048 100644 --- a/tests/auto/controls/data/tst_frame.qml +++ b/tests/auto/controls/data/tst_frame.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_groupbox.qml b/tests/auto/controls/data/tst_groupbox.qml index 0181ea6b..41f1c780 100644 --- a/tests/auto/controls/data/tst_groupbox.qml +++ b/tests/auto/controls/data/tst_groupbox.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_itemdelegate.qml b/tests/auto/controls/data/tst_itemdelegate.qml index 37b0db2a..8eafad57 100644 --- a/tests/auto/controls/data/tst_itemdelegate.qml +++ b/tests/auto/controls/data/tst_itemdelegate.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_label.qml b/tests/auto/controls/data/tst_label.qml index 6dae0992..b3350cf5 100644 --- a/tests/auto/controls/data/tst_label.qml +++ b/tests/auto/controls/data/tst_label.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_menuitem.qml b/tests/auto/controls/data/tst_menuitem.qml index be0c0652..b5e08866 100644 --- a/tests/auto/controls/data/tst_menuitem.qml +++ b/tests/auto/controls/data/tst_menuitem.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_page.qml b/tests/auto/controls/data/tst_page.qml index bc7afa50..a1cdbf8e 100644 --- a/tests/auto/controls/data/tst_page.qml +++ b/tests/auto/controls/data/tst_page.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -56,6 +56,40 @@ TestCase { } Component { + id: oneChildPage + Page { + Item { + implicitWidth: 100 + implicitHeight: 30 + } + } + } + + Component { + id: twoChildrenPage + Page { + Item { + implicitWidth: 100 + implicitHeight: 30 + } + Item { + implicitWidth: 200 + implicitHeight: 60 + } + } + } + + Component { + id: contentPage + Page { + contentItem: Item { + implicitWidth: 100 + implicitHeight: 30 + } + } + } + + Component { id: toolBar ToolBar { } } @@ -71,6 +105,53 @@ TestCase { control.destroy() } + function test_empty() { + var control = page.createObject(testCase) + verify(control) + + verify(control.contentItem) + compare(control.contentWidth, 0) + compare(control.contentHeight, 0) + + control.destroy() + } + + function test_oneChild() { + var control = oneChildPage.createObject(testCase) + verify(control) + + compare(control.contentWidth, 100) + compare(control.contentHeight, 30) + compare(control.implicitWidth, 100 + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, 30 + control.topPadding + control.bottomPadding) + + control.destroy() + } + + function test_twoChildren() { + var control = twoChildrenPage.createObject(testCase) + verify(control) + + compare(control.contentWidth, 0) + compare(control.contentHeight, 0) + compare(control.implicitWidth, control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.topPadding + control.bottomPadding) + + control.destroy() + } + + function test_contentItem() { + var control = contentPage.createObject(testCase) + verify(control) + + compare(control.contentWidth, 100) + compare(control.contentHeight, 30) + compare(control.implicitWidth, 100 + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, 30 + control.topPadding + control.bottomPadding) + + control.destroy() + } + function test_layout() { var control = page.createObject(testCase, {width: 100, height: 100}) verify(control) @@ -124,6 +205,25 @@ TestCase { compare(control.contentItem.width, control.availableWidth) compare(control.contentItem.height, control.availableHeight) + control.contentItem.implicitWidth = 50 + control.contentItem.implicitHeight = 60 + compare(control.implicitWidth, control.contentItem.implicitWidth + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentItem.implicitHeight + control.topPadding + control.bottomPadding) + + control.header.visible = true + compare(control.implicitHeight, control.contentItem.implicitHeight + control.topPadding + control.bottomPadding + + control.header.implicitHeight + control.spacing) + + control.footer.visible = true + compare(control.implicitHeight, control.contentItem.implicitHeight + control.topPadding + control.bottomPadding + + control.header.implicitHeight + control.footer.implicitHeight + 2 * control.spacing) + + control.header.implicitWidth = 150 + compare(control.implicitWidth, control.header.implicitWidth + control.leftPadding + control.rightPadding) + + control.footer.implicitWidth = 160 + compare(control.implicitWidth, control.footer.implicitWidth + control.leftPadding + control.rightPadding) + control.destroy() } } diff --git a/tests/auto/controls/data/tst_pageindicator.qml b/tests/auto/controls/data/tst_pageindicator.qml index d1f1223a..a39265c3 100644 --- a/tests/auto/controls/data/tst_pageindicator.qml +++ b/tests/auto/controls/data/tst_pageindicator.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_pane.qml b/tests/auto/controls/data/tst_pane.qml index a0b8a5c8..2f5ddef3 100644 --- a/tests/auto/controls/data/tst_pane.qml +++ b/tests/auto/controls/data/tst_pane.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_popup.qml b/tests/auto/controls/data/tst_popup.qml index 82fcbf8b..c81c6341 100644 --- a/tests/auto/controls/data/tst_popup.qml +++ b/tests/auto/controls/data/tst_popup.qml @@ -40,13 +40,13 @@ import QtQuick 2.4 import QtTest 1.0 -import QtQuick.Controls 2.0 -import QtQuick.Templates 2.0 as T +import QtQuick.Controls 2.1 +import QtQuick.Templates 2.1 as T TestCase { id: testCase - width: 480 - height: 360 + width: 400 + height: 400 visible: true when: windowShown name: "Popup" diff --git a/tests/auto/controls/data/tst_progressbar.qml b/tests/auto/controls/data/tst_progressbar.qml index 5603c280..d7280503 100644 --- a/tests/auto/controls/data/tst_progressbar.qml +++ b/tests/auto/controls/data/tst_progressbar.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_radiobutton.qml b/tests/auto/controls/data/tst_radiobutton.qml index bd3850c8..94e3a2cb 100644 --- a/tests/auto/controls/data/tst_radiobutton.qml +++ b/tests/auto/controls/data/tst_radiobutton.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_radiodelegate.qml b/tests/auto/controls/data/tst_radiodelegate.qml index 1a424a32..66b47b3a 100644 --- a/tests/auto/controls/data/tst_radiodelegate.qml +++ b/tests/auto/controls/data/tst_radiodelegate.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_rangeslider.qml b/tests/auto/controls/data/tst_rangeslider.qml index 3167be0b..eb654bbc 100644 --- a/tests/auto/controls/data/tst_rangeslider.qml +++ b/tests/auto/controls/data/tst_rangeslider.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -675,4 +675,31 @@ TestCase { control.destroy() } + + function test_hover_data() { + return [ + { tag: "first:true", node: "first", hoverEnabled: true }, + { tag: "first:false", node: "first", hoverEnabled: false }, + { tag: "second:true", node: "second", hoverEnabled: true }, + { tag: "second:false", node: "second", hoverEnabled: false } + ] + } + + function test_hover(data) { + var control = sliderComponent.createObject(testCase, {hoverEnabled: data.hoverEnabled}) + verify(control) + + var node = control[data.node] + compare(control.hovered, false) + compare(node.hovered, false) + + mouseMove(control, node.handle.x + node.handle.width / 2, node.handle.y + node.handle.height / 2) + compare(control.hovered, data.hoverEnabled) + compare(node.hovered, data.hoverEnabled && node.handle.enabled) + + mouseMove(control, node.handle.x - 1, node.handle.y - 1) + compare(node.hovered, false) + + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_roundbutton.qml b/tests/auto/controls/data/tst_roundbutton.qml new file mode 100644 index 00000000..aa956776 --- /dev/null +++ b/tests/auto/controls/data/tst_roundbutton.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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: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 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 2.2 +import QtTest 1.0 +import QtQuick.Controls 2.1 + +TestCase { + id: testCase + width: 200 + height: 200 + visible: true + when: windowShown + name: "RoundButton" + + Component { + id: roundButton + RoundButton { } + } + + function test_radius() { + var control = roundButton.createObject(testCase); + verify(control); + + var implicitRadius = control.radius; + compare(implicitRadius, Math.min(control.width, control.height) / 2); + + control.radius = 10; + compare(control.radius, 10); + + control.radius = undefined; + compare(control.radius, implicitRadius); + + control.width = -1; + compare(control.radius, 0); + + control.width = 10; + compare(control.radius, 5); + + control.destroy(); + } +} diff --git a/tests/auto/controls/data/tst_scrollbar.qml b/tests/auto/controls/data/tst_scrollbar.qml index 1684ba51..15b4b3f0 100644 --- a/tests/auto/controls/data/tst_scrollbar.qml +++ b/tests/auto/controls/data/tst_scrollbar.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -97,6 +97,13 @@ TestCase { compare(vertical.y, 0) verify(vertical.width > 0) compare(vertical.height, container.height) + // vertical scroll bar follows flickable's width + container.width += 10 + compare(vertical.x, container.width - vertical.width) + // ...unless explicitly positioned + vertical.x = 123 + container.width += 10 + compare(vertical.x, 123) var horizontal = scrollBar.createObject() verify(!horizontal.parent) @@ -118,6 +125,13 @@ TestCase { compare(horizontal.y, container.height - horizontal.height) compare(horizontal.width, container.width) verify(horizontal.height > 0) + // horizontal scroll bar follows flickable's height + container.height += 10 + compare(horizontal.y, container.height - horizontal.height) + // ...unless explicitly positioned + horizontal.y = 123 + container.height += 10 + compare(horizontal.y, 123) var velocity = container.maximumFlickVelocity @@ -299,4 +313,28 @@ TestCase { container.destroy() } + + function test_hover_data() { + return [ + { tag: "enabled", hoverEnabled: true }, + { tag: "disabled", hoverEnabled: false }, + ] + } + + function test_hover(data) { + var control = scrollBar.createObject(testCase, {hoverEnabled: data.hoverEnabled}) + verify(control) + + compare(control.hovered, false) + + mouseMove(control) + compare(control.hovered, data.hoverEnabled) + compare(control.active, data.hoverEnabled) + + mouseMove(control, -1, -1) + compare(control.hovered, false) + compare(control.active, false) + + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_scrollindicator.qml b/tests/auto/controls/data/tst_scrollindicator.qml index 90d9287a..551247f6 100644 --- a/tests/auto/controls/data/tst_scrollindicator.qml +++ b/tests/auto/controls/data/tst_scrollindicator.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -92,6 +92,13 @@ TestCase { compare(vertical.y, 0) verify(vertical.width > 0) compare(vertical.height, container.height) + // vertical scroll indicator follows flickable's width + container.width += 10 + compare(vertical.x, container.width - vertical.width) + // ...unless explicitly positioned + vertical.x = 123 + container.width += 10 + compare(vertical.x, 123) var horizontal = scrollIndicator.createObject() verify(!horizontal.parent) @@ -113,6 +120,13 @@ TestCase { compare(horizontal.y, container.height - horizontal.height) compare(horizontal.width, container.width) verify(horizontal.height > 0) + // horizontal scroll indicator follows flickable's height + container.height += 10 + compare(horizontal.y, container.height - horizontal.height) + // ...unless explicitly positioned + horizontal.y = 123 + container.height += 10 + compare(horizontal.y, 123) var velocity = container.maximumFlickVelocity diff --git a/tests/auto/controls/data/tst_slider.qml b/tests/auto/controls/data/tst_slider.qml index 4a698076..029aff14 100644 --- a/tests/auto/controls/data/tst_slider.qml +++ b/tests/auto/controls/data/tst_slider.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -520,4 +520,24 @@ TestCase { control.destroy() } + + function test_valueAt_data() { + return [ + { tag: "0.0..1.0", from: 0.0, to: 1.0, values: [0.0, 0.2, 0.5, 1.0] }, + { tag: "0..100", from: 0, to: 100, values: [0, 20, 50, 100] }, + { tag: "100..-100", from: 100, to: -100, values: [100, 60, 0, -100] } + ] + } + + function test_valueAt(data) { + var control = slider.createObject(testCase, {from: data.from, to: data.to}) + verify(control) + + compare(control.valueAt(0.0), data.values[0]) + compare(control.valueAt(0.2), data.values[1]) + compare(control.valueAt(0.5), data.values[2]) + compare(control.valueAt(1.0), data.values[3]) + + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_spinbox.qml b/tests/auto/controls/data/tst_spinbox.qml index a62128d2..30db246f 100644 --- a/tests/auto/controls/data/tst_spinbox.qml +++ b/tests/auto/controls/data/tst_spinbox.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -460,6 +460,35 @@ TestCase { control.destroy() } + function test_hover_data() { + return [ + { tag: "up:true", button: "up", hoverEnabled: true, value: 50 }, + { tag: "up:false", button: "up", hoverEnabled: false, value: 50 }, + { tag: "up:max", button: "up", hoverEnabled: true, value: 99 }, + { tag: "down:true", button: "down", hoverEnabled: true, value: 50 }, + { tag: "down:false", button: "down", hoverEnabled: false, value: 50 }, + { tag: "down:min", button: "down", hoverEnabled: true, value: 0 } + ] + } + + function test_hover(data) { + var control = spinBox.createObject(testCase, {hoverEnabled: data.hoverEnabled, value: data.value}) + verify(control) + + var button = control[data.button] + compare(control.hovered, false) + compare(button.hovered, false) + + mouseMove(control, button.indicator.x + button.indicator.width / 2, button.indicator.y + button.indicator.height / 2) + compare(control.hovered, data.hoverEnabled) + compare(button.hovered, data.hoverEnabled && button.indicator.enabled) + + mouseMove(control, button.indicator.x - 1, button.indicator.y - 1) + compare(button.hovered, false) + + control.destroy() + } + function test_valueFromText_data() { return [ { tag: "editable", editable: true }, diff --git a/tests/auto/controls/data/tst_stackview.qml b/tests/auto/controls/data/tst_stackview.qml index 28a22306..b0e18389 100644 --- a/tests/auto/controls/data/tst_stackview.qml +++ b/tests/auto/controls/data/tst_stackview.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -567,29 +567,60 @@ TestCase { } } - function test_transitions() { + function test_transitions_data() { + return [ + { tag: "undefined", operation: undefined, + pushEnterRuns: [0,1,1,1], pushExitRuns: [0,1,1,1], replaceEnterRuns: [0,0,1,1], replaceExitRuns: [0,0,1,1], popEnterRuns: [0,0,0,1], popExitRuns: [0,0,0,1] }, + { tag: "immediate", operation: StackView.Immediate, + pushEnterRuns: [0,0,0,0], pushExitRuns: [0,0,0,0], replaceEnterRuns: [0,0,0,0], replaceExitRuns: [0,0,0,0], popEnterRuns: [0,0,0,0], popExitRuns: [0,0,0,0] }, + { tag: "push", operation: StackView.PushTransition, + pushEnterRuns: [1,2,3,4], pushExitRuns: [0,1,2,3], replaceEnterRuns: [0,0,0,0], replaceExitRuns: [0,0,0,0], popEnterRuns: [0,0,0,0], popExitRuns: [0,0,0,0] }, + { tag: "pop", operation: StackView.PopTransition, + pushEnterRuns: [0,0,0,0], pushExitRuns: [0,0,0,0], replaceEnterRuns: [0,0,0,0], replaceExitRuns: [0,0,0,0], popEnterRuns: [1,2,3,4], popExitRuns: [0,1,2,3] }, + { tag: "replace", operation: StackView.ReplaceTransition, + pushEnterRuns: [0,0,0,0], pushExitRuns: [0,0,0,0], replaceEnterRuns: [1,2,3,4], replaceExitRuns: [0,1,2,3], popEnterRuns: [0,0,0,0], popExitRuns: [0,0,0,0] }, + ] + } + + function test_transitions(data) { var control = transitionView.createObject(testCase) verify(control) - control.push(component) - verify(!control.busy) - compare(control.pushEnterRuns, 0) - compare(control.pushExitRuns, 0) - - control.push(component) + control.push(component, data.operation) + tryCompare(control, "busy", false) + compare(control.pushEnterRuns, data.pushEnterRuns[0]) + compare(control.pushExitRuns, data.pushExitRuns[0]) + compare(control.replaceEnterRuns, data.replaceEnterRuns[0]) + compare(control.replaceExitRuns, data.replaceExitRuns[0]) + compare(control.popEnterRuns, data.popEnterRuns[0]) + compare(control.popExitRuns, data.popExitRuns[0]) + + control.push(component, data.operation) tryCompare(control, "busy", false) - compare(control.pushEnterRuns, 1) - compare(control.pushExitRuns, 1) + compare(control.pushEnterRuns, data.pushEnterRuns[1]) + compare(control.pushExitRuns, data.pushExitRuns[1]) + compare(control.replaceEnterRuns, data.replaceEnterRuns[1]) + compare(control.replaceExitRuns, data.replaceExitRuns[1]) + compare(control.popEnterRuns, data.popEnterRuns[1]) + compare(control.popExitRuns, data.popExitRuns[1]) - control.replace(component) + control.replace(component, data.operation) tryCompare(control, "busy", false) - compare(control.replaceEnterRuns, 1) - compare(control.replaceExitRuns, 1) + compare(control.pushEnterRuns, data.pushEnterRuns[2]) + compare(control.pushExitRuns, data.pushExitRuns[2]) + compare(control.replaceEnterRuns, data.replaceEnterRuns[2]) + compare(control.replaceExitRuns, data.replaceExitRuns[2]) + compare(control.popEnterRuns, data.popEnterRuns[2]) + compare(control.popExitRuns, data.popExitRuns[2]) - control.pop() + control.pop(data.operation) tryCompare(control, "busy", false) - compare(control.popEnterRuns, 1) - compare(control.popExitRuns, 1) + compare(control.pushEnterRuns, data.pushEnterRuns[3]) + compare(control.pushExitRuns, data.pushExitRuns[3]) + compare(control.replaceEnterRuns, data.replaceEnterRuns[3]) + compare(control.replaceExitRuns, data.replaceExitRuns[3]) + compare(control.popEnterRuns, data.popEnterRuns[3]) + compare(control.popExitRuns, data.popExitRuns[3]) control.destroy() } @@ -644,6 +675,60 @@ TestCase { } Component { + id: removeComponent + + Item { + objectName: "removeItem" + StackView.onRemoved: destroy() + } + } + + function test_destroyOnRemoved() { + var control = stackView.createObject(testCase, { initialItem: component }) + verify(control) + + var item = removeComponent.createObject(control) + verify(item) + + var removedSpy = signalSpy.createObject(control, { target: item.StackView, signalName: "removed" }) + verify(removedSpy) + verify(removedSpy.valid) + + var destructionSpy = signalSpy.createObject(control, { target: item.Component, signalName: "destruction" }) + verify(destructionSpy) + verify(destructionSpy.valid) + + // push-pop + control.push(item, StackView.Immediate) + compare(control.currentItem, item) + control.pop(StackView.Transition) + item = null + tryCompare(removedSpy, "count", 1) + tryCompare(destructionSpy, "count", 1) + compare(control.busy, false) + + item = removeComponent.createObject(control) + verify(item) + + removedSpy.target = item.StackView + verify(removedSpy.valid) + + destructionSpy.target = item.Component + verify(destructionSpy.valid) + + // push-replace + control.push(item, StackView.Immediate) + compare(control.currentItem, item) + control.replace(component, StackView.Transition) + item = null + tryCompare(removedSpy, "count", 2) + tryCompare(destructionSpy, "count", 2) + compare(control.busy, false) + + control.destroy() + } + + Component { id: attachedItem Item { property int index: StackView.index @@ -831,11 +916,11 @@ TestCase { verify(control) ignoreWarning("QQmlComponent: Component is not ready") - ignoreWarning(Qt.resolvedUrl("non-existent.qml") + ":-1 File not found") + ignoreWarning(Qt.resolvedUrl("non-existent.qml") + ":-1 No such file or directory") control.push(Qt.resolvedUrl("non-existent.qml")) ignoreWarning("QQmlComponent: Component is not ready") - ignoreWarning(Qt.resolvedUrl("non-existent.qml") + ":-1 File not found") + ignoreWarning(Qt.resolvedUrl("non-existent.qml") + ":-1 No such file or directory") control.replace(Qt.resolvedUrl("non-existent.qml")) control.pop() @@ -862,6 +947,62 @@ TestCase { control.destroy() } + Component { + id: signalTest + Control { + id: ctrl + property SignalSpy activatedSpy: SignalSpy { target: ctrl.StackView; signalName: "activated" } + property SignalSpy activatingSpy: SignalSpy { target: ctrl.StackView; signalName: "activating" } + property SignalSpy deactivatedSpy: SignalSpy { target: ctrl.StackView; signalName: "deactivated" } + property SignalSpy deactivatingSpy: SignalSpy { target: ctrl.StackView; signalName: "deactivating" } + } + } + + function test_signals() { + var control = stackView.createObject(testCase) + verify(control) + + var item1 = signalTest.createObject(control) + compare(item1.StackView.status, StackView.Inactive) + control.push(item1) + compare(item1.StackView.status, StackView.Active) + compare(item1.activatedSpy.count, 1) + compare(item1.activatingSpy.count, 1) + compare(item1.deactivatedSpy.count, 0) + compare(item1.deactivatingSpy.count, 0) + + var item2 = signalTest.createObject(control) + compare(item2.StackView.status, StackView.Inactive) + control.push(item2) + compare(item2.StackView.status, StackView.Activating) + compare(item2.activatedSpy.count, 0) + compare(item2.activatingSpy.count, 1) + compare(item2.deactivatedSpy.count, 0) + compare(item2.deactivatingSpy.count, 0) + compare(item1.StackView.status, StackView.Deactivating) + compare(item1.activatedSpy.count, 1) + compare(item1.activatingSpy.count, 1) + compare(item1.deactivatedSpy.count, 0) + compare(item1.deactivatingSpy.count, 1) + tryCompare(item2.activatedSpy, "count", 1) + tryCompare(item1.deactivatedSpy, "count", 1) + + control.pop() + compare(item2.StackView.status, StackView.Deactivating) + compare(item2.activatedSpy.count, 1) + compare(item2.activatingSpy.count, 1) + compare(item2.deactivatedSpy.count, 0) + compare(item2.deactivatingSpy.count, 1) + compare(item1.StackView.status, StackView.Activating) + compare(item1.activatedSpy.count, 1) + compare(item1.activatingSpy.count, 2) + compare(item1.deactivatedSpy.count, 1) + compare(item1.deactivatingSpy.count, 1) + tryCompare(item1.activatedSpy, "count", 2) + + control.destroy() + } + // QTBUG-56158 function test_repeatedPop() { var control = stackView.createObject(testCase, {initialItem: component, width: testCase.width, height: testCase.height}) diff --git a/tests/auto/controls/data/tst_swipedelegate.qml b/tests/auto/controls/data/tst_swipedelegate.qml index 21bb1a37..bcf25f28 100644 --- a/tests/auto/controls/data/tst_swipedelegate.qml +++ b/tests/auto/controls/data/tst_swipedelegate.qml @@ -40,7 +40,8 @@ import QtQuick 2.6 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -110,14 +111,14 @@ TestCase { function test_horizontalAnchors_data() { return [ - { tag: "background, fill", component: backgroundFillComponent, itemName: "background", warningLocation: ":58:25" }, - { tag: "background, centerIn", component: backgroundCenterInComponent, itemName: "background", warningLocation: ":65:25" }, - { tag: "background, left", component: backgroundLeftComponent, itemName: "background", warningLocation: ":72:25" }, - { tag: "background, right", component: backgroundRightComponent, itemName: "background", warningLocation: ":79:25" }, - { tag: "contentItem, fill", component: contentItemFillComponent, itemName: "contentItem", warningLocation: ":86:26" }, - { tag: "contentItem, centerIn", component: contentItemCenterInComponent, itemName: "contentItem", warningLocation: ":93:26" }, - { tag: "contentItem, left", component: contentItemLeftComponent, itemName: "contentItem", warningLocation: ":100:26" }, - { tag: "contentItem, right", component: contentItemRightComponent, itemName: "contentItem", warningLocation: ":107:26" } + { tag: "background, fill", component: backgroundFillComponent, itemName: "background", warningLocation: ":59:25" }, + { tag: "background, centerIn", component: backgroundCenterInComponent, itemName: "background", warningLocation: ":66:25" }, + { tag: "background, left", component: backgroundLeftComponent, itemName: "background", warningLocation: ":73:25" }, + { tag: "background, right", component: backgroundRightComponent, itemName: "background", warningLocation: ":80:25" }, + { tag: "contentItem, fill", component: contentItemFillComponent, itemName: "contentItem", warningLocation: ":87:26" }, + { tag: "contentItem, centerIn", component: contentItemCenterInComponent, itemName: "contentItem", warningLocation: ":94:26" }, + { tag: "contentItem, left", component: contentItemLeftComponent, itemName: "contentItem", warningLocation: ":101:26" }, + { tag: "contentItem, right", component: contentItemRightComponent, itemName: "contentItem", warningLocation: ":108:26" } ]; } @@ -166,6 +167,12 @@ TestCase { } Component { + id: signalSpyComponent + + SignalSpy {} + } + + Component { id: itemComponent Item {} @@ -201,7 +208,7 @@ TestCase { verify(control); ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + - ":159:9: QML SwipeDelegate: cannot set both behind and left/right properties") + ":160:9: QML SwipeDelegate: cannot set both behind and left/right properties") control.swipe.behind = itemComponent; // Shouldn't be any warnings when unsetting delegates. @@ -210,7 +217,7 @@ TestCase { // right is still set. ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + - ":159:9: QML SwipeDelegate: cannot set both behind and left/right properties") + ":160:9: QML SwipeDelegate: cannot set both behind and left/right properties") control.swipe.behind = itemComponent; control.swipe.right = null; @@ -219,11 +226,11 @@ TestCase { control.swipe.behind = itemComponent; ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + - ":159:9: QML SwipeDelegate: cannot set both behind and left/right properties") + ":160:9: QML SwipeDelegate: cannot set both behind and left/right properties") control.swipe.left = itemComponent; ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + - ":159:9: QML SwipeDelegate: cannot set both behind and left/right properties") + ":160:9: QML SwipeDelegate: cannot set both behind and left/right properties") control.swipe.right = itemComponent; control.swipe.behind = null; @@ -238,7 +245,7 @@ TestCase { var oldLeft = control.swipe.left; var oldLeftItem = control.swipe.leftItem; ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + - ":159:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0") + ":160:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0") control.swipe.left = null; compare(control.swipe.left, oldLeft); compare(control.swipe.leftItem, oldLeftItem); @@ -249,7 +256,7 @@ TestCase { var oldRight = control.swipe.right; var oldRightItem = control.swipe.rightItem; ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + - ":159:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0") + ":160:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0") control.swipe.right = null; compare(control.swipe.right, oldRight); compare(control.swipe.rightItem, oldRightItem); @@ -275,7 +282,7 @@ TestCase { var oldBehind = control.swipe.behind; var oldBehindItem = control.swipe.behindItem; ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") + - ":159:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0") + ":160:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0") control.swipe.behind = null; compare(control.swipe.behind, oldBehind); compare(control.swipe.behindItem, oldBehindItem); @@ -297,7 +304,7 @@ TestCase { SignalSequenceSpy { id: mouseSignalSequenceSpy - signals: ["pressed", "released", "canceled", "clicked", "doubleClicked", "pressedChanged"] + signals: ["pressed", "released", "canceled", "clicked", "doubleClicked", "pressedChanged", "pressAndHold"] } function test_swipe() { @@ -306,12 +313,17 @@ TestCase { var overDragDistance = Math.round(dragDistance * 1.1); + var completedSpy = signalSpyComponent.createObject(control, { target: control.swipe, signalName: "completed" }); + verify(completedSpy); + verify(completedSpy.valid); + mouseSignalSequenceSpy.target = control; mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], "pressed"]; mousePress(control, control.width / 2, control.height / 2); verify(control.pressed); compare(control.swipe.position, 0.0); verify(!control.swipe.complete); + compare(completedSpy.count, 0); verify(mouseSignalSequenceSpy.success); verify(!control.swipe.leftItem); verify(!control.swipe.rightItem); @@ -321,6 +333,7 @@ TestCase { verify(control.pressed); compare(control.swipe.position, overDragDistance / control.width); verify(!control.swipe.complete); + compare(completedSpy.count, 0); verify(control.swipe.leftItem); verify(control.swipe.leftItem.visible); compare(control.swipe.leftItem.parent, control); @@ -332,6 +345,7 @@ TestCase { verify(control.pressed); compare(control.swipe.position, 0.0); verify(!control.swipe.complete); + compare(completedSpy.count, 0); verify(control.swipe.leftItem); verify(control.swipe.leftItem.visible); compare(control.swipe.leftItem.parent, control); @@ -344,6 +358,7 @@ TestCase { verify(control.pressed); compare(control.swipe.position, -overDragDistance / control.width); verify(!control.swipe.complete); + compare(completedSpy.count, 0); verify(control.swipe.leftItem); verify(!control.swipe.leftItem.visible); verify(control.swipe.rightItem); @@ -356,6 +371,7 @@ TestCase { verify(control.pressed); compare(control.swipe.position, 0.6); verify(!control.swipe.complete); + compare(completedSpy.count, 0); verify(control.swipe.leftItem); verify(control.swipe.leftItem.visible); verify(control.swipe.rightItem); @@ -366,6 +382,7 @@ TestCase { verify(!control.pressed); compare(control.swipe.position, 1.0); verify(control.swipe.complete); + compare(completedSpy.count, 1); verify(mouseSignalSequenceSpy.success); verify(control.swipe.leftItem); verify(control.swipe.leftItem.visible); @@ -381,11 +398,13 @@ TestCase { // complete should still be true, because we haven't moved yet, and hence // haven't started grabbing behind's mouse events. verify(control.swipe.complete); + compare(completedSpy.count, 1); verify(mouseSignalSequenceSpy.success); mouseMove(control, control.width / 2 - overDragDistance, control.height / 2); verify(control.pressed); verify(!control.swipe.complete); + compare(completedSpy.count, 1); compare(control.swipe.position, 1.0 - overDragDistance / control.width); mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "released", "clicked"]; @@ -393,6 +412,7 @@ TestCase { verify(!control.pressed); compare(control.swipe.position, 1.0); verify(control.swipe.complete); + compare(completedSpy.count, 2); verify(mouseSignalSequenceSpy.success); tryCompare(control.contentItem, "x", control.width + control.leftPadding); @@ -402,11 +422,13 @@ TestCase { verify(control.pressed); compare(control.swipe.position, 1.0); verify(control.swipe.complete); + compare(completedSpy.count, 2); verify(mouseSignalSequenceSpy.success); mouseMove(control, control.width * -0.1, control.height / 2); verify(control.pressed); verify(!control.swipe.complete); + compare(completedSpy.count, 2); compare(control.swipe.position, 0.4); mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "released", "clicked"]; @@ -414,6 +436,7 @@ TestCase { verify(!control.pressed); compare(control.swipe.position, 0.0); verify(!control.swipe.complete); + compare(completedSpy.count, 2); verify(mouseSignalSequenceSpy.success); tryCompare(control.contentItem, "x", control.leftPadding); @@ -507,12 +530,6 @@ TestCase { } } - Component { - id: signalSpyComponent - - SignalSpy {} - } - function test_eventsToLeftAndRight() { var control = swipeDelegateWithButtonComponent.createObject(testCase); verify(control); @@ -607,6 +624,26 @@ TestCase { mouseDoubleClickSequence(control, control.width / 2, control.height / 2, Qt.LeftButton); verify(mouseSignalSequenceSpy.success); + // press and hold + var pressAndHoldSpy = signalSpyComponent.createObject(control, { target: control, signalName: "pressAndHold" }); + verify(pressAndHoldSpy); + verify(pressAndHoldSpy.valid); + + mouseSignalSequenceSpy.expectedSequence = [ + ["pressedChanged", { "pressed": true }], + "pressed", + "pressAndHold", + ["pressedChanged", { "pressed": false }], + "released" + ]; + mousePress(control); + compare(control.pressed, true); + tryCompare(pressAndHoldSpy, "count", 1); + + mouseRelease(control); + compare(control.pressed, false); + verify(mouseSignalSequenceSpy.success); + control.destroy(); } @@ -629,8 +666,6 @@ TestCase { text: modelData width: listView.width - onClicked: if (swipe.complete) ListView.view.model.remove(index) - property alias removeAnimation: onRemoveAnimation ListView.onRemove: SequentialAnimation { @@ -655,9 +690,12 @@ TestCase { } swipe.left: Rectangle { - color: rootDelegate.swipe.complete && rootDelegate.pressed ? "#333" : "#444" + objectName: "rectangle" + color: SwipeDelegate.pressed ? "#333" : "#444" anchors.fill: parent + SwipeDelegate.onClicked: listView.model.remove(index) + Label { objectName: "label" text: "Remove" @@ -680,11 +718,14 @@ TestCase { verify(firstItem.pressed); compare(firstItem.swipe.position, 0.0); verify(!firstItem.swipe.complete); + verify(!firstItem.swipe.leftItem); mouseMove(listView, firstItem.width * 1.1, firstItem.height / 2); verify(firstItem.pressed); compare(firstItem.swipe.position, 0.6); verify(!firstItem.swipe.complete); + verify(firstItem.swipe.leftItem); + verify(!firstItem.swipe.leftItem.SwipeDelegate.pressed); mouseRelease(listView, firstItem.width / 2, firstItem.height / 2); verify(!firstItem.pressed); @@ -695,9 +736,23 @@ TestCase { // Wait for it to settle down. tryCompare(firstItem.contentItem, "x", firstItem.leftPadding + firstItem.width); - // Click the button to remove the item. + var leftClickedSpy = signalSpyComponent.createObject(firstItem.swipe.leftItem, + { target: firstItem.swipe.leftItem.SwipeDelegate, signalName: "clicked" }); + verify(leftClickedSpy); + verify(leftClickedSpy.valid); + + // Click the left item to remove the delegate from the list. var contentItemX = firstItem.contentItem.x; - mouseClick(listView, firstItem.width / 2, firstItem.height / 2); + mousePress(listView, firstItem.width / 2, firstItem.height / 2); + verify(firstItem.swipe.leftItem.SwipeDelegate.pressed); + compare(leftClickedSpy.count, 0); + verify(!firstItem.pressed); + + mouseRelease(listView, firstItem.width / 2, firstItem.height / 2); + verify(!firstItem.swipe.leftItem.SwipeDelegate.pressed); + compare(leftClickedSpy.count, 1); + verify(!firstItem.pressed); + leftClickedSpy = null; tryCompare(firstItem.removeAnimation, "running", true); // There was a bug where the resizeContent() would be called because the height // of the control was changing due to the animation. contentItem would then @@ -992,6 +1047,160 @@ TestCase { control.destroy(); } + Component { + id: closeSwipeDelegateComponent + + SwipeDelegate { + text: "SwipeDelegate" + width: 150 + + onClicked: close() + + swipe.right: Item { + width: parent.width + height: parent.height + } + } + } + + function test_close() { + var control = swipeDelegateComponent.createObject(testCase); + verify(control); + + swipe(control, 0.0, -1.0); + compare(control.swipe.rightItem.visible, true); + // Should animate, so it shouldn't change right away. + compare(control.swipe.rightItem.x, 0); + tryCompare(control.swipe.rightItem, "x", control.background.x + control.background.width); + + control.destroy(); + } + + Component { + id: multiActionSwipeDelegateComponent + + SwipeDelegate { + text: "SwipeDelegate" + width: 150 + + swipe.right: Item { + objectName: "rightItemRoot" + width: parent.width + height: parent.height + + property alias firstAction: firstAction + property alias secondAction: secondAction + + property int firstClickCount: 0 + property int secondClickCount: 0 + + RowLayout { + anchors.fill: parent + anchors.margins: 5 + + Rectangle { + id: firstAction + Layout.fillWidth: true + Layout.fillHeight: true + color: "tomato" + + SwipeDelegate.onClicked: ++firstClickCount + } + Rectangle { + id: secondAction + Layout.fillWidth: true + Layout.fillHeight: true + color: "navajowhite" + + SwipeDelegate.onClicked: ++secondClickCount + } + } + } + } + } + + // Tests that it's possible to have multiple non-interactive items in one delegate + // (e.g. left/right/behind) that can each receive clicks. + function test_multipleClickableActions() { + var control = multiActionSwipeDelegateComponent.createObject(testCase); + verify(control); + + swipe(control, 0.0, -1.0); + verify(control.swipe.rightItem); + tryCompare(control.swipe, "complete", true); + + var firstClickedSpy = signalSpyComponent.createObject(control, + { target: control.swipe.rightItem.firstAction.SwipeDelegate, signalName: "clicked" }); + verify(firstClickedSpy); + verify(firstClickedSpy.valid); + + // Clicked within rightItem, but not within an item using the attached properties. + mousePress(control, 2, 2); + compare(control.swipe.rightItem.firstAction.SwipeDelegate.pressed, false); + compare(firstClickedSpy.count, 0); + + mouseRelease(control, 2, 2); + compare(control.swipe.rightItem.firstAction.SwipeDelegate.pressed, false); + compare(firstClickedSpy.count, 0); + + // Click within the first item. + mousePress(control.swipe.rightItem.firstAction, 0, 0); + compare(control.swipe.rightItem.firstAction.SwipeDelegate.pressed, true); + compare(firstClickedSpy.count, 0); + + mouseRelease(control.swipe.rightItem.firstAction, 0, 0); + compare(control.swipe.rightItem.firstAction.SwipeDelegate.pressed, false); + compare(firstClickedSpy.count, 1); + compare(control.swipe.rightItem.firstClickCount, 1); + + var secondClickedSpy = signalSpyComponent.createObject(control, + { target: control.swipe.rightItem.secondAction.SwipeDelegate, signalName: "clicked" }); + verify(secondClickedSpy); + verify(secondClickedSpy.valid); + + // Click within the second item. + mousePress(control.swipe.rightItem.secondAction, 0, 0); + compare(control.swipe.rightItem.secondAction.SwipeDelegate.pressed, true); + compare(secondClickedSpy.count, 0); + + mouseRelease(control.swipe.rightItem.secondAction, 0, 0); + compare(control.swipe.rightItem.secondAction.SwipeDelegate.pressed, false); + compare(secondClickedSpy.count, 1); + compare(control.swipe.rightItem.secondClickCount, 1); + + control.destroy(); + } + + // Pressing on a "side action" and then dragging should eventually + // cause the ListView to grab the mouse and start changing its contentY. + // When this happens, it will grab the mouse and hence we must clear + // that action's pressed state so that it doesn't stay pressed after releasing. + function test_dragSideAction() { + var listView = removableDelegatesComponent.createObject(testCase); + verify(listView); + + var control = listView.itemAt(0, 0); + verify(control); + + // Expose the side action. + swipe(control, 0.0, 1.0); + verify(control.swipe.leftItem); + tryCompare(control.swipe, "complete", true); + + var pressedSpy = signalSpyComponent.createObject(control, + { target: control.swipe.leftItem.SwipeDelegate, signalName: "pressedChanged" }); + verify(pressedSpy); + verify(pressedSpy.valid); + + mouseDrag(listView, 20, 20, 0, listView.height); + compare(pressedSpy.count, 2); + verify(listView.contentY !== 0); + + compare(control.swipe.leftItem.SwipeDelegate.pressed, false); + + listView.destroy(); + } + // When the width of a SwipeDelegate changes (as it does upon portrait => landscape // rotation, for example), the positions of the contentItem and background items // should be updated accordingly. diff --git a/tests/auto/controls/data/tst_swipeview.qml b/tests/auto/controls/data/tst_swipeview.qml index 3afcdf16..2d5f413a 100644 --- a/tests/auto/controls/data/tst_swipeview.qml +++ b/tests/auto/controls/data/tst_swipeview.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -103,6 +103,16 @@ TestCase { compare(control.currentItem.text, "2") compare(currentItemChangedSpy.count, 3); + control.decrementCurrentIndex() + compare(control.currentIndex, 1) + compare(control.currentItem.text, "1") + compare(currentItemChangedSpy.count, 4); + + control.incrementCurrentIndex() + compare(control.currentIndex, 2) + compare(control.currentItem.text, "2") + compare(currentItemChangedSpy.count, 5); + control.destroy() } @@ -404,6 +414,8 @@ TestCase { property int index: SwipeView.index property SwipeView view: SwipeView.view property bool isCurrentItem: SwipeView.isCurrentItem + property bool isNextItem: SwipeView.isNextItem + property bool isPreviousItem: SwipeView.isPreviousItem } } @@ -424,11 +436,15 @@ TestCase { compare(control.itemAt(i).text, titles[i]) compare(control.itemAt(i).SwipeView.index, i) compare(control.itemAt(i).SwipeView.isCurrentItem, i === 0) + compare(control.itemAt(i).SwipeView.isNextItem, i === 1) + compare(control.itemAt(i).SwipeView.isPreviousItem, false) } control.currentIndex = data.currentBefore for (i = 0; i < control.count; ++i) { compare(control.itemAt(i).SwipeView.isCurrentItem, i === data.currentBefore) + compare(control.itemAt(i).SwipeView.isNextItem, i === data.currentBefore + 1) + compare(control.itemAt(i).SwipeView.isPreviousItem, i === data.currentBefore - 1) } control.moveItem(data.from, data.to) @@ -445,6 +461,8 @@ TestCase { compare(control.itemAt(i).text, titles[i]) compare(control.itemAt(i).SwipeView.index, i); compare(control.itemAt(i).SwipeView.isCurrentItem, i === data.currentAfter) + compare(control.itemAt(i).SwipeView.isNextItem, i === data.currentAfter + 1) + compare(control.itemAt(i).SwipeView.isPreviousItem, i === data.currentAfter - 1) } control.destroy() @@ -489,12 +507,16 @@ TestCase { compare(page.view, null); compare(page.index, -1); compare(page.isCurrentItem, false); + compare(page.isNextItem, false); + compare(page.isPreviousItem, false); page.destroy(); page = pageAttached.createObject(null); compare(page.view, null); compare(page.index, -1); compare(page.isCurrentItem, false); + compare(page.isNextItem, false); + compare(page.isPreviousItem, false); control.insertItem(0, page); compare(control.count, 1); @@ -502,6 +524,8 @@ TestCase { compare(page.view, control); compare(page.index, 0); compare(page.isCurrentItem, true); + compare(page.isNextItem, false); + compare(page.isPreviousItem, false); control.removeItem(0); compare(control.count, 0); @@ -509,6 +533,8 @@ TestCase { compare(page.view, null); compare(page.index, -1); compare(page.isCurrentItem, false); + compare(page.isNextItem, false); + compare(page.isPreviousItem, false); control.destroy(); } diff --git a/tests/auto/controls/data/tst_switch.qml b/tests/auto/controls/data/tst_switch.qml index 93773e0d..f3843cf7 100644 --- a/tests/auto/controls/data/tst_switch.qml +++ b/tests/auto/controls/data/tst_switch.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_switchdelegate.qml b/tests/auto/controls/data/tst_switchdelegate.qml index 8bc0e4c3..4a5d711f 100644 --- a/tests/auto/controls/data/tst_switchdelegate.qml +++ b/tests/auto/controls/data/tst_switchdelegate.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_tabbar.qml b/tests/auto/controls/data/tst_tabbar.qml index 9268f765..da0181a1 100644 --- a/tests/auto/controls/data/tst_tabbar.qml +++ b/tests/auto/controls/data/tst_tabbar.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -134,6 +134,16 @@ TestCase { compare(control.currentItem.text, "2") compare(control.currentItem.checked, true) + control.decrementCurrentIndex() + compare(control.currentIndex, 1) + compare(control.currentItem.text, "1") + compare(control.currentItem.checked, true) + + control.incrementCurrentIndex() + compare(control.currentIndex, 2) + compare(control.currentItem.text, "2") + compare(control.currentItem.checked, true) + control.destroy() } diff --git a/tests/auto/controls/data/tst_tabbutton.qml b/tests/auto/controls/data/tst_tabbutton.qml index 4ab9d955..77d22a48 100644 --- a/tests/auto/controls/data/tst_tabbutton.qml +++ b/tests/auto/controls/data/tst_tabbutton.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_textarea.qml b/tests/auto/controls/data/tst_textarea.qml index bda0b3e3..5d3e8d55 100644 --- a/tests/auto/controls/data/tst_textarea.qml +++ b/tests/auto/controls/data/tst_textarea.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -199,6 +199,196 @@ TestCase { testCase.TextArea.flickable = null } + function test_hover_data() { + return [ + { tag: "enabled", hoverEnabled: true }, + { tag: "disabled", hoverEnabled: false }, + ] + } + + function test_hover(data) { + var control = textArea.createObject(testCase, {text: "TextArea", hoverEnabled: data.hoverEnabled}) + verify(control) + + compare(control.hovered, false) + + mouseMove(control) + compare(control.hovered, data.hoverEnabled) + + mouseMove(control, -1, -1) + compare(control.hovered, false) + + control.destroy() + } + + function test_pressedReleased_data() { + return [ + { + tag: "pressed outside", x: -1, y: -1, button: Qt.LeftButton, + controlPressEvent: null, + controlReleaseEvent: null, + parentPressEvent: { + x: 0, y: 0, button: Qt.LeftButton, buttons: Qt.LeftButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + parentReleaseEvent: { + x: 0, y: 0, button: Qt.LeftButton, buttons: Qt.NoButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + }, + { + tag: "left click", x: 0, y: 0, button: Qt.LeftButton, + controlPressEvent: { + x: 0, y: 0, button: Qt.LeftButton, buttons: Qt.LeftButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + controlReleaseEvent: { + x: 0, y: 0, button: Qt.LeftButton, buttons: Qt.NoButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + parentPressEvent: null, + parentReleaseEvent: null, + }, + { + tag: "right click", x: 0, y: 0, button: Qt.RightButton, + controlPressEvent: { + x: 0, y: 0, button: Qt.RightButton, buttons: Qt.RightButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + controlReleaseEvent: { + x: 0, y: 0, button: Qt.RightButton, buttons: Qt.NoButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + parentPressEvent: null, + parentReleaseEvent: null, + }, + ]; + } + + Component { + id: mouseAreaComponent + MouseArea { + anchors.fill: parent + } + } + + function checkMouseEvent(event, expectedEvent) { + compare(event.x, expectedEvent.x) + compare(event.y, expectedEvent.y) + compare(event.button, expectedEvent.button) + compare(event.buttons, expectedEvent.buttons) + } + + function test_pressedReleased(data) { + var mouseArea = mouseAreaComponent.createObject(testCase) + verify(mouseArea) + var control = textArea.createObject(mouseArea, {text: "TextArea"}) + verify(control) + + // Give enough room to check presses outside of the control and on the parent. + control.x = 1; + control.y = 1; + + function checkControlPressEvent(event) { + checkMouseEvent(event, data.controlPressEvent) + } + function checkControlReleaseEvent(event) { + checkMouseEvent(event, data.controlReleaseEvent) + } + function checkParentPressEvent(event) { + checkMouseEvent(event, data.parentPressEvent) + } + function checkParentReleaseEvent(event) { + checkMouseEvent(event, data.parentReleaseEvent) + } + + // Can't use signalArguments, because the event won't live that long. + if (data.controlPressEvent) + control.onPressed.connect(checkControlPressEvent) + if (data.controlReleaseEvent) + control.onReleased.connect(checkControlReleaseEvent) + if (data.parentPressEvent) + control.onPressed.connect(checkParentPressEvent) + if (data.parentReleaseEvent) + control.onReleased.connect(checkParentReleaseEvent) + + var controlPressedSpy = signalSpy.createObject(control, { target: control, signalName: "pressed" }) + verify(controlPressedSpy.valid) + var controlReleasedSpy = signalSpy.createObject(control, { target: control, signalName: "released" }) + verify(controlReleasedSpy.valid) + var parentPressedSpy = signalSpy.createObject(mouseArea, { target: mouseArea, signalName: "pressed" }) + verify(parentPressedSpy.valid) + var parentReleasedSpy = signalSpy.createObject(mouseArea, { target: mouseArea, signalName: "released" }) + verify(parentReleasedSpy.valid) + + mousePress(control, data.x, data.y, data.button) + compare(controlPressedSpy.count, data.controlPressEvent ? 1 : 0) + compare(parentPressedSpy.count, data.parentPressEvent ? 1 : 0) + mouseRelease(control, data.x, data.y, data.button) + compare(controlReleasedSpy.count, data.controlReleaseEvent ? 1 : 0) + compare(parentReleasedSpy.count, data.parentReleaseEvent ? 1 : 0) + + mouseArea.destroy() + } + + Component { + id: ignoreTextArea + + TextArea { + property bool ignorePress: false + property bool ignoreRelease: false + + onPressed: if (ignorePress) event.accepted = false + onReleased: if (ignoreRelease) event.accepted = false + } + } + + function checkEventAccepted(event) { + compare(event.accepted, true) + } + + function checkEventIgnored(event) { + compare(event.accepted, false) + } + + function test_ignorePressRelease() { + var mouseArea = mouseAreaComponent.createObject(testCase) + verify(mouseArea) + var control = ignoreTextArea.createObject(mouseArea) + verify(control) + + var controlPressedSpy = signalSpy.createObject(control, { target: control, signalName: "pressed" }) + verify(controlPressedSpy.valid) + var controlReleasedSpy = signalSpy.createObject(control, { target: control, signalName: "released" }) + verify(controlReleasedSpy.valid) + var parentPressedSpy = signalSpy.createObject(mouseArea, { target: mouseArea, signalName: "pressed" }) + verify(parentPressedSpy.valid) + var parentReleasedSpy = signalSpy.createObject(mouseArea, { target: mouseArea, signalName: "released" }) + verify(parentReleasedSpy.valid) + + // Ignore only press events. + control.onPressed.connect(checkEventIgnored) + control.ignorePress = true + mousePress(control, 0, 0, data.button) + // The control will still get the signal, it just won't accept the event. + compare(controlPressedSpy.count, 1) + compare(parentPressedSpy.count, 1) + mouseRelease(control, 0, 0, data.button) + compare(controlReleasedSpy.count, 0) + compare(parentReleasedSpy.count, 1) + control.onPressed.disconnect(checkEventIgnored) + + // Ignore only release events. + control.onPressed.connect(checkEventAccepted) + control.onReleased.connect(checkEventIgnored) + control.ignorePress = false + control.ignoreRelease = true + mousePress(control, 0, 0, data.button) + compare(controlPressedSpy.count, 2) + compare(parentPressedSpy.count, 1) + mouseRelease(control, 0, 0, data.button) + compare(controlReleasedSpy.count, 1) + compare(parentReleasedSpy.count, 1) + control.onPressed.disconnect(checkEventAccepted) + control.onReleased.disconnect(checkEventIgnored) + + mouseArea.destroy() + } + function test_multiClick() { var control = textArea.createObject(testCase, {text: "Qt Quick Controls 2 TextArea", selectByMouse: true}) verify(control) diff --git a/tests/auto/controls/data/tst_textfield.qml b/tests/auto/controls/data/tst_textfield.qml index 959662ee..5dc93287 100644 --- a/tests/auto/controls/data/tst_textfield.qml +++ b/tests/auto/controls/data/tst_textfield.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -164,6 +164,196 @@ TestCase { control.destroy() } + function test_hover_data() { + return [ + { tag: "enabled", hoverEnabled: true }, + { tag: "disabled", hoverEnabled: false }, + ] + } + + function test_hover(data) { + var control = textField.createObject(testCase, {hoverEnabled: data.hoverEnabled}) + verify(control) + + compare(control.hovered, false) + + mouseMove(control) + compare(control.hovered, data.hoverEnabled) + + mouseMove(control, -1, -1) + compare(control.hovered, false) + + control.destroy() + } + + function test_pressedReleased_data() { + return [ + { + tag: "pressed outside", x: -1, y: -1, button: Qt.LeftButton, + controlPressEvent: null, + controlReleaseEvent: null, + parentPressEvent: { + x: 0, y: 0, button: Qt.LeftButton, buttons: Qt.LeftButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + parentReleaseEvent: { + x: 0, y: 0, button: Qt.LeftButton, buttons: Qt.NoButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + }, + { + tag: "left click", x: 0, y: 0, button: Qt.LeftButton, + controlPressEvent: { + x: 0, y: 0, button: Qt.LeftButton, buttons: Qt.LeftButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + controlReleaseEvent: { + x: 0, y: 0, button: Qt.LeftButton, buttons: Qt.NoButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + parentPressEvent: null, + parentReleaseEvent: null, + }, + { + tag: "right click", x: 0, y: 0, button: Qt.RightButton, + controlPressEvent: { + x: 0, y: 0, button: Qt.RightButton, buttons: Qt.RightButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + controlReleaseEvent: { + x: 0, y: 0, button: Qt.RightButton, buttons: Qt.NoButton, modifiers: Qt.NoModifier, wasHeld: false, isClick: false + }, + parentPressEvent: null, + parentReleaseEvent: null, + }, + ]; + } + + Component { + id: mouseAreaComponent + MouseArea { + anchors.fill: parent + } + } + + function checkMouseEvent(event, expectedEvent) { + compare(event.x, expectedEvent.x) + compare(event.y, expectedEvent.y) + compare(event.button, expectedEvent.button) + compare(event.buttons, expectedEvent.buttons) + } + + function test_pressedReleased(data) { + var mouseArea = mouseAreaComponent.createObject(testCase) + verify(mouseArea) + var control = textField.createObject(mouseArea) + verify(control) + + // Give enough room to check presses outside of the control and on the parent. + control.x = 1; + control.y = 1; + + function checkControlPressEvent(event) { + checkMouseEvent(event, data.controlPressEvent) + } + function checkControlReleaseEvent(event) { + checkMouseEvent(event, data.controlReleaseEvent) + } + function checkParentPressEvent(event) { + checkMouseEvent(event, data.parentPressEvent) + } + function checkParentReleaseEvent(event) { + checkMouseEvent(event, data.parentReleaseEvent) + } + + // Can't use signalArguments, because the event won't live that long. + if (data.controlPressEvent) + control.onPressed.connect(checkControlPressEvent) + if (data.controlReleaseEvent) + control.onReleased.connect(checkControlReleaseEvent) + if (data.parentPressEvent) + control.onPressed.connect(checkParentPressEvent) + if (data.parentReleaseEvent) + control.onReleased.connect(checkParentReleaseEvent) + + var controlPressedSpy = signalSpy.createObject(control, { target: control, signalName: "pressed" }) + verify(controlPressedSpy.valid) + var controlReleasedSpy = signalSpy.createObject(control, { target: control, signalName: "released" }) + verify(controlReleasedSpy.valid) + var parentPressedSpy = signalSpy.createObject(mouseArea, { target: mouseArea, signalName: "pressed" }) + verify(parentPressedSpy.valid) + var parentReleasedSpy = signalSpy.createObject(mouseArea, { target: mouseArea, signalName: "released" }) + verify(parentReleasedSpy.valid) + + mousePress(control, data.x, data.y, data.button) + compare(controlPressedSpy.count, data.controlPressEvent ? 1 : 0) + compare(parentPressedSpy.count, data.parentPressEvent ? 1 : 0) + mouseRelease(control, data.x, data.y, data.button) + compare(controlReleasedSpy.count, data.controlReleaseEvent ? 1 : 0) + compare(parentReleasedSpy.count, data.parentReleaseEvent ? 1 : 0) + + mouseArea.destroy() + } + + Component { + id: ignoreTextField + + TextField { + property bool ignorePress: false + property bool ignoreRelease: false + + onPressed: if (ignorePress) event.accepted = false + onReleased: if (ignoreRelease) event.accepted = false + } + } + + function checkEventAccepted(event) { + compare(event.accepted, true) + } + + function checkEventIgnored(event) { + compare(event.accepted, false) + } + + function test_ignorePressRelease() { + var mouseArea = mouseAreaComponent.createObject(testCase) + verify(mouseArea) + var control = ignoreTextField.createObject(mouseArea) + verify(control) + + var controlPressedSpy = signalSpy.createObject(control, { target: control, signalName: "pressed" }) + verify(controlPressedSpy.valid) + var controlReleasedSpy = signalSpy.createObject(control, { target: control, signalName: "released" }) + verify(controlReleasedSpy.valid) + var parentPressedSpy = signalSpy.createObject(mouseArea, { target: mouseArea, signalName: "pressed" }) + verify(parentPressedSpy.valid) + var parentReleasedSpy = signalSpy.createObject(mouseArea, { target: mouseArea, signalName: "released" }) + verify(parentReleasedSpy.valid) + + // Ignore only press events. + control.onPressed.connect(checkEventIgnored) + control.ignorePress = true + mousePress(control, 0, 0, data.button) + // The control will still get the signal, it just won't accept the event. + compare(controlPressedSpy.count, 1) + compare(parentPressedSpy.count, 1) + mouseRelease(control, 0, 0, data.button) + compare(controlReleasedSpy.count, 0) + compare(parentReleasedSpy.count, 1) + control.onPressed.disconnect(checkEventIgnored) + + // Ignore only release events. + control.onPressed.connect(checkEventAccepted) + control.onReleased.connect(checkEventIgnored) + control.ignorePress = false + control.ignoreRelease = true + mousePress(control, 0, 0, data.button) + compare(controlPressedSpy.count, 2) + compare(parentPressedSpy.count, 1) + mouseRelease(control, 0, 0, data.button) + compare(controlReleasedSpy.count, 1) + compare(parentReleasedSpy.count, 1) + control.onPressed.disconnect(checkEventAccepted) + control.onReleased.disconnect(checkEventIgnored) + + mouseArea.destroy() + } + function test_multiClick() { var control = textField.createObject(testCase, {text: "Qt Quick Controls 2 TextArea", selectByMouse: true}) verify(control) diff --git a/tests/auto/controls/data/tst_toolbar.qml b/tests/auto/controls/data/tst_toolbar.qml index b68f26e6..cc64383e 100644 --- a/tests/auto/controls/data/tst_toolbar.qml +++ b/tests/auto/controls/data/tst_toolbar.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_toolbutton.qml b/tests/auto/controls/data/tst_toolbutton.qml index 73431ca6..a59cff07 100644 --- a/tests/auto/controls/data/tst_toolbutton.qml +++ b/tests/auto/controls/data/tst_toolbutton.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_toolseparator.qml b/tests/auto/controls/data/tst_toolseparator.qml new file mode 100644 index 00000000..47eb933f --- /dev/null +++ b/tests/auto/controls/data/tst_toolseparator.qml @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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: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 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 2.8 +import QtTest 1.0 +import QtQuick.Controls 2.1 + +TestCase { + id: testCase + width: 400 + height: 400 + visible: true + name: "ToolSeparator" + + Component { + id: toolSeparator + ToolSeparator {} + } + + function test_size() { + var control = toolSeparator.createObject(testCase); + verify(control); + verify(control.width > 1); + verify(control.height > 1); + + control.destroy(); + } + + Component { + id: signalSpyComponent + SignalSpy {} + } + + function test_orientation() { + var control = toolSeparator.createObject(testCase); + verify(control); + compare(control.horizontal, false); + compare(control.vertical, true); + + var orientationSpy = signalSpyComponent.createObject(control, { target: control, signalName: "orientationChanged" }); + + var originalWidth = control.width; + var originalHeight = control.height; + control.orientation = Qt.Horizontal; + compare(control.orientation, Qt.Horizontal); + compare(control.width, originalHeight); + compare(control.height, originalWidth); + compare(control.horizontal, true); + compare(control.vertical, false); + compare(orientationSpy.count, 1); + + control.orientation = Qt.Vertical; + compare(control.orientation, Qt.Vertical); + compare(control.width, originalWidth); + compare(control.height, originalHeight); + compare(control.horizontal, false); + compare(control.vertical, true); + compare(orientationSpy.count, 2); + + control.destroy(); + } +} diff --git a/tests/auto/controls/data/tst_tooltip.qml b/tests/auto/controls/data/tst_tooltip.qml index c78a7770..d9c95dbf 100644 --- a/tests/auto/controls/data/tst_tooltip.qml +++ b/tests/auto/controls/data/tst_tooltip.qml @@ -40,7 +40,7 @@ import QtQuick 2.4 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase diff --git a/tests/auto/controls/data/tst_tumbler.qml b/tests/auto/controls/data/tst_tumbler.qml index 2e0e3295..b3230ca4 100644 --- a/tests/auto/controls/data/tst_tumbler.qml +++ b/tests/auto/controls/data/tst_tumbler.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.1 TestCase { id: testCase @@ -58,6 +58,16 @@ TestCase { readonly property real implicitTumblerHeight: 200 readonly property real defaultImplicitDelegateHeight: implicitTumblerHeight / 3 readonly property real defaultListViewTumblerOffset: -defaultImplicitDelegateHeight + readonly property real tumblerDelegateHeight: tumbler ? tumbler.availableHeight / tumbler.visibleItemCount : 0 + property Item tumblerView: null + + Component { + id: tumblerComponent + + Tumbler { + visibleItemCount: 3 + } + } Component { id: itemComponent @@ -85,6 +95,16 @@ TestCase { wait(0) } + function createTumbler(args) { + if (args === undefined) + tumbler = tumblerComponent.createObject(cleanupItem); + else + tumbler = tumblerComponent.createObject(cleanupItem, args); + verify(tumbler, "Tumbler: failed to create an instance"); + tumblerView = findView(tumbler); + verify(tumblerView); + } + function tumblerXCenter() { return tumbler.leftPadding + tumbler.width / 2; } @@ -95,26 +115,46 @@ TestCase { // visualItemIndex is from 0 to the amount of visible items. function itemCenterPos(visualItemIndex) { - var halfDelegateHeight = tumbler.contentItem.delegateHeight / 2; + var halfDelegateHeight = tumblerDelegateHeight / 2; var yCenter = tumbler.y + tumbler.topPadding + halfDelegateHeight - + (tumbler.contentItem.delegateHeight * visualItemIndex); + + (tumblerDelegateHeight * visualItemIndex); return Qt.point(tumblerXCenter(), yCenter); } function checkItemSizes() { - var contentChildren = tumbler.contentItem.hasOwnProperty("contentItem") - ? tumbler.contentItem.contentItem.children : tumbler.contentItem.children; + var contentChildren = tumbler.wrap ? tumblerView.children : tumblerView.contentItem.children; verify(contentChildren.length >= tumbler.count); for (var i = 0; i < contentChildren.length; ++i) { - compare(contentChildren[i].width, tumbler.width); - compare(contentChildren[i].height, tumbler.contentItem.delegateHeight); + compare(contentChildren[i].width, tumbler.availableWidth); + compare(contentChildren[i].height, tumblerDelegateHeight); } } - Component { - id: tumblerComponent + function findView(parent) { + for (var i = 0; i < parent.children.length; ++i) { + var child = parent.children[i]; + if (child.hasOwnProperty("currentIndex")) { + return child; + } + + return findView(child); + } + + return null; + } + + property Component noAttachedPropertiesDelegate: Text { + text: modelData + } + + function test_wrapWithoutAttachedProperties() { + createTumbler(); + verify(tumbler.wrap); - Tumbler {} + tumbler.delegate = noAttachedPropertiesDelegate; + // Shouldn't assert. + tumbler.wrap = false; + verify(findView(tumbler)); } // TODO: test that currentIndex is maintained between contentItem changes... @@ -122,8 +162,7 @@ TestCase { // } function test_currentIndex() { - tumbler = tumblerComponent.createObject(cleanupItem); - verify(tumbler); + createTumbler(); compare(tumbler.contentItem.parent, tumbler); tumbler.model = 5; @@ -133,75 +172,193 @@ TestCase { // Set it through user interaction. var pos = Qt.point(tumblerXCenter(), tumbler.height / 2); - mouseDrag(tumbler, pos.x, pos.y, 0, -tumbler.contentItem.delegateHeight / 2, Qt.LeftButton, Qt.NoModifier, 200); - compare(tumbler.currentIndex, 1); - compare(tumbler.contentItem.currentIndex, 1); + mouseDrag(tumbler, pos.x, pos.y, 0, tumbler.height / 3, Qt.LeftButton, Qt.NoModifier, 200); + tryCompare(tumblerView, "offset", 1); + compare(tumbler.currentIndex, 4); + compare(tumblerView.currentIndex, 4); // Set it manually. tumbler.currentIndex = 2; tryCompare(tumbler, "currentIndex", 2); - compare(tumbler.contentItem.currentIndex, 2); + compare(tumblerView.currentIndex, 2); - // PathView has 0 as its currentIndex in this case for some reason. tumbler.model = null; - tryCompare(tumbler, "currentIndex", 0); + tryCompare(tumbler, "currentIndex", -1); + // PathView will only use 0 as the currentIndex when there are no items. + compare(tumblerView.currentIndex, 0); tumbler.model = ["A", "B", "C"]; tryCompare(tumbler, "currentIndex", 0); + + // Setting a negative current index should have no effect, because the model isn't empty. + tumbler.currentIndex = -1; + compare(tumbler.currentIndex, 0); + + tumbler.model = 1; + compare(tumbler.currentIndex, 0); + + tumbler.model = 5; + compare(tumbler.count, 5); + tumblerView = findView(tumbler); + tryCompare(tumblerView, "count", 5); + tumbler.currentIndex = 4; + compare(tumbler.currentIndex, 4); + compare(tumblerView.currentIndex, 4); + + --tumbler.model; + compare(tumbler.count, 4); + compare(tumblerView.count, 4); + // Removing an item from an integer-based model will cause views to reset their currentIndex to 0. + compare(tumbler.currentIndex, 0); + compare(tumblerView.currentIndex, 0); + + tumbler.model = 0; + compare(tumbler.currentIndex, -1); } - function test_keyboardNavigation() { - tumbler = tumblerComponent.createObject(cleanupItem); + Component { + id: currentIndexTumbler + + Tumbler { + model: 5 + currentIndex: 2 + visibleItemCount: 3 + } + } + + Component { + id: currentIndexTumblerNoWrap + + Tumbler { + model: 5 + currentIndex: 2 + wrap: false + visibleItemCount: 3 + } + } + + Component { + id: currentIndexTumblerNoWrapReversedOrder + + Tumbler { + model: 5 + wrap: false + currentIndex: 2 + visibleItemCount: 3 + } + } + + Component { + id: negativeCurrentIndexTumblerNoWrap + + Tumbler { + model: 5 + wrap: false + currentIndex: -1 + visibleItemCount: 3 + } + } + + Component { + id: currentIndexTooLargeTumbler + + Tumbler { + objectName: "currentIndexTooLargeTumbler" + model: 10 + currentIndex: 10 + } + } + + + function test_currentIndexAtCreation_data() { + return [ + { tag: "wrap: implicit, expected currentIndex: 2", currentIndex: 2, wrap: true, component: currentIndexTumbler }, + { tag: "wrap: false, expected currentIndex: 2", currentIndex: 2, wrap: false, component: currentIndexTumblerNoWrap }, + // Order of property assignments shouldn't matter + { tag: "wrap: false, expected currentIndex: 2, reversed property assignment order", + currentIndex: 2, wrap: false, component: currentIndexTumblerNoWrapReversedOrder }, + { tag: "wrap: false, expected currentIndex: 0", currentIndex: 0, wrap: false, component: negativeCurrentIndexTumblerNoWrap }, + { tag: "wrap: implicit, expected currentIndex: 0", currentIndex: 0, wrap: true, component: currentIndexTooLargeTumbler } + ] + } + + function test_currentIndexAtCreation(data) { + // Test setting currentIndex at creation time + tumbler = data.component.createObject(cleanupItem); verify(tumbler); + // A "statically declared" currentIndex will be pending until the count has changed, + // which happens when the model is set, which happens on the TumblerView's next polish. + tryCompare(tumbler, "currentIndex", data.currentIndex); + + tumblerView = findView(tumbler); + // TODO: replace once QTBUG-19708 is fixed. + for (var delay = 1000; delay >= 0; delay -= 50) { + if (tumblerView.currentItem) + break; + wait(50); + } + verify(tumblerView.currentItem); + compare(tumblerView.currentIndex, data.currentIndex); + compare(tumblerView.currentItem.text, data.currentIndex.toString()); + + var fuzz = 1; + if (data.wrap) { + fuzzyCompare(tumblerView.offset, data.currentIndex > 0 ? tumblerView.count - data.currentIndex : 0, fuzz); + } else { + fuzzyCompare(tumblerView.contentY, tumblerDelegateHeight * data.currentIndex - tumblerView.preferredHighlightBegin, fuzz); + } + } + + function test_keyboardNavigation() { + createTumbler(); tumbler.model = 5; tumbler.forceActiveFocus(); - tumbler.contentItem.highlightMoveDuration = 0; + tumblerView.highlightMoveDuration = 0; // Navigate upwards through entire wheel. for (var j = 0; j < tumbler.count - 1; ++j) { keyClick(Qt.Key_Up, Qt.NoModifier); - tryCompare(tumbler.contentItem, "offset", j + 1); + tryCompare(tumblerView, "offset", j + 1); compare(tumbler.currentIndex, tumbler.count - 1 - j); } keyClick(Qt.Key_Up, Qt.NoModifier); - tryCompare(tumbler.contentItem, "offset", 0); + tryCompare(tumblerView, "offset", 0); compare(tumbler.currentIndex, 0); // Navigate downwards through entire wheel. for (j = 0; j < tumbler.count - 1; ++j) { keyClick(Qt.Key_Down, Qt.NoModifier); - tryCompare(tumbler.contentItem, "offset", tumbler.count - 1 - j); + tryCompare(tumblerView, "offset", tumbler.count - 1 - j); compare(tumbler.currentIndex, j + 1); } keyClick(Qt.Key_Down, Qt.NoModifier); - tryCompare(tumbler.contentItem, "offset", 0); + tryCompare(tumblerView, "offset", 0); compare(tumbler.currentIndex, 0); } function test_itemsCorrectlyPositioned() { - tumbler = tumblerComponent.createObject(cleanupItem); - verify(tumbler); + createTumbler(); tumbler.model = 4; tumbler.height = 120; - compare(tumbler.contentItem.delegateHeight, 40); + compare(tumblerDelegateHeight, 40); checkItemSizes(); - wait(tumbler.contentItem.highlightMoveDuration); + wait(tumblerView.highlightMoveDuration); var firstItemCenterPos = itemCenterPos(1); - var firstItem = tumbler.contentItem.itemAt(firstItemCenterPos.x, firstItemCenterPos.y); + var firstItem = tumblerView.itemAt(firstItemCenterPos.x, firstItemCenterPos.y); var actualPos = cleanupItem.mapFromItem(firstItem, 0, 0); compare(actualPos.x, tumbler.leftPadding); compare(actualPos.y, tumbler.topPadding + 40); tumbler.forceActiveFocus(); keyClick(Qt.Key_Down); - tryCompare(tumbler.contentItem, "offset", 3.0); + tryCompare(tumblerView, "offset", 3.0); firstItemCenterPos = itemCenterPos(0); - firstItem = tumbler.contentItem.itemAt(firstItemCenterPos.x, firstItemCenterPos.y); + firstItem = tumblerView.itemAt(firstItemCenterPos.x, firstItemCenterPos.y); verify(firstItem); // Test QTBUG-40298. actualPos = cleanupItem.mapFromItem(firstItem, 0, 0); @@ -209,12 +366,12 @@ TestCase { compare(actualPos.y, tumbler.topPadding); var secondItemCenterPos = itemCenterPos(1); - var secondItem = tumbler.contentItem.itemAt(secondItemCenterPos.x, secondItemCenterPos.y); + var secondItem = tumblerView.itemAt(secondItemCenterPos.x, secondItemCenterPos.y); verify(secondItem); verify(firstItem.y < secondItem.y); var thirdItemCenterPos = itemCenterPos(2); - var thirdItem = tumbler.contentItem.itemAt(thirdItemCenterPos.x, thirdItemCenterPos.y); + var thirdItem = tumblerView.itemAt(thirdItemCenterPos.x, thirdItemCenterPos.y); verify(thirdItem); verify(firstItem.y < thirdItem.y); verify(secondItem.y < thirdItem.y); @@ -241,18 +398,18 @@ TestCase { tumbler = component.createObject(cleanupItem); // Should not be any warnings. - compare(tumbler.dayTumbler.currentIndex, 0); + tryCompare(tumbler.dayTumbler, "currentIndex", 0); compare(tumbler.dayTumbler.count, 31); compare(tumbler.monthTumbler.currentIndex, 0); compare(tumbler.monthTumbler.count, 12); compare(tumbler.yearTumbler.currentIndex, 0); compare(tumbler.yearTumbler.count, 100); - verify(tumbler.dayTumbler.contentItem.children.length >= tumbler.dayTumbler.visibleItemCount); - verify(tumbler.monthTumbler.contentItem.children.length >= tumbler.monthTumbler.visibleItemCount); + verify(findView(tumbler.dayTumbler).children.length >= tumbler.dayTumbler.visibleItemCount); + verify(findView(tumbler.monthTumbler).children.length >= tumbler.monthTumbler.visibleItemCount); // TODO: do this properly somehow wait(100); - verify(tumbler.yearTumbler.contentItem.children.length >= tumbler.yearTumbler.visibleItemCount); + verify(findView(tumbler.yearTumbler).children.length >= tumbler.yearTumbler.visibleItemCount); // March. tumbler.monthTumbler.currentIndex = 2; @@ -361,27 +518,106 @@ TestCase { } function test_displacement(data) { - tumbler = tumblerComponent.createObject(cleanupItem); - verify(tumbler); + createTumbler(); // TODO: test setting these in the opposite order (delegate after model // doesn't seem to cause a change in delegates in PathView) + tumbler.wrap = true; tumbler.delegate = displacementDelegate; tumbler.model = data.count; compare(tumbler.count, data.count); - var delegate = findChild(tumbler.contentItem, "delegate" + data.index); + var delegate = findChild(tumblerView, "delegate" + data.index); verify(delegate); - tumbler.contentItem.offset = data.offset; + tumblerView.offset = data.offset; compare(delegate.displacement, data.expectedDisplacement); // test displacement after adding and removing items } + function test_wrap() { + createTumbler(); + + tumbler.model = 5; + compare(tumbler.count, 5); + + tumbler.currentIndex = 2; + compare(tumblerView.currentIndex, 2); + + tumbler.wrap = false; + tumblerView = findView(tumbler); + compare(tumbler.count, 5); + compare(tumbler.currentIndex, 2); + // Tumbler's count hasn't changed (the model hasn't changed), + // but the new view needs time to instantiate its items. + tryCompare(tumblerView, "count", 5); + compare(tumblerView.currentIndex, 2); + } + + Component { + id: twoItemTumbler + + Tumbler { + model: 2 + } + } + + Component { + id: tenItemTumbler + + Tumbler { + model: 10 + } + } + + function test_countWrap() { + tumbler = tumblerComponent.createObject(cleanupItem); + verify(tumbler); + + // Check that a count that is less than visibleItemCount results in wrap being set to false. + verify(2 < tumbler.visibleItemCount); + tumbler.model = 2; + compare(tumbler.count, 2); + compare(tumbler.wrap, false); + } + + function test_explicitlyNonwrapping() { + // Check that explicitly setting wrap to false works even when it was implicitly false. + var explicitlyNonWrapping = twoItemTumbler.createObject(cleanupItem); + verify(explicitlyNonWrapping); + tryCompare(explicitlyNonWrapping, "wrap", false); + + explicitlyNonWrapping.wrap = false; + // wrap shouldn't be set to true now that there are more items than there are visible ones. + verify(10 > explicitlyNonWrapping.visibleItemCount); + explicitlyNonWrapping.model = 10; + compare(explicitlyNonWrapping.wrap, false); + + // Test resetting wrap back to the default behavior. + explicitlyNonWrapping.wrap = undefined; + compare(explicitlyNonWrapping.wrap, true); + } + + function test_explicitlyWrapping() { + // Check that explicitly setting wrap to true works even when it was implicitly true. + var explicitlyWrapping = tenItemTumbler.createObject(cleanupItem); + verify(explicitlyWrapping); + compare(explicitlyWrapping.wrap, true); + + explicitlyWrapping.wrap = true; + // wrap shouldn't be set to false now that there are more items than there are visible ones. + explicitlyWrapping.model = 2; + compare(explicitlyWrapping.wrap, true); + + // Test resetting wrap back to the default behavior. + explicitlyWrapping.wrap = undefined; + compare(explicitlyWrapping.wrap, false); + } + Component { - id: listViewTumblerComponent - //! [contentItem] + id: customListViewTumblerComponent + Tumbler { id: listViewTumbler @@ -397,7 +633,95 @@ TestCase { clip: true } } - //! [contentItem] + } + + Component { + id: customPathViewTumblerComponent + + Tumbler { + id: pathViewTumbler + + contentItem: PathView { + id: pathView + model: pathViewTumbler.model + delegate: pathViewTumbler.delegate + clip: true + pathItemCount: pathViewTumbler.visibleItemCount + 1 + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + dragMargin: width / 2 + + path: Path { + startX: pathView.width / 2 + startY: -pathView.delegateHeight / 2 + PathLine { + x: pathView.width / 2 + y: pathView.pathItemCount * pathView.delegateHeight - pathView.delegateHeight / 2 + } + } + + property real delegateHeight: pathViewTumbler.availableHeight / pathViewTumbler.visibleItemCount + } + } + } + + function test_customContentItemAtConstruction_data() { + return [ + { tag: "ListView", component: customListViewTumblerComponent }, + { tag: "PathView", component: customPathViewTumblerComponent } + ]; + } + + function test_customContentItemAtConstruction(data) { + var tumbler = data.component.createObject(cleanupItem); + // Shouldn't assert. + + tumbler.model = 5; + compare(tumbler.count, 5); + + tumbler.currentIndex = 2; + var tumblerView = findView(tumbler); + compare(tumblerView.currentIndex, 2); + + tumblerView.incrementCurrentIndex(); + compare(tumblerView.currentIndex, 3); + compare(tumbler.currentIndex, 3); + + // Shouldn't have any affect. + tumbler.wrap = false; + compare(tumbler.count, 5); + compare(tumblerView.currentIndex, 3); + compare(tumbler.currentIndex, 3); + } + + function test_customContentItemAfterConstruction_data() { + return [ + { tag: "ListView", componentPath: "TumblerListView.qml" }, + { tag: "PathView", componentPath: "TumblerPathView.qml" } + ]; + } + + function test_customContentItemAfterConstruction(data) { + createTumbler(); + + tumbler.model = 5; + compare(tumbler.count, 5); + + tumbler.currentIndex = 2; + compare(tumblerView.currentIndex, 2); + + var contentItemComponent = Qt.createComponent(data.componentPath); + compare(contentItemComponent.status, Component.Ready); + + var customContentItem = contentItemComponent.createObject(tumbler); + tumbler.contentItem = customContentItem; + compare(tumbler.count, 5); + tumblerView = findView(tumbler); + compare(tumblerView.currentIndex, 2); + + tumblerView.incrementCurrentIndex(); + compare(tumblerView.currentIndex, 3); + compare(tumbler.currentIndex, 3); } function test_displacementListView_data() { @@ -438,20 +762,18 @@ TestCase { } function test_displacementListView(data) { - // Sanity check that they're aren't any children at this stage. - tryCompare(cleanupItem.children, "length", 0); - - tumbler = listViewTumblerComponent.createObject(cleanupItem); - verify(tumbler); + createTumbler(); + tumbler.wrap = false; tumbler.delegate = displacementDelegate; tumbler.model = 5; compare(tumbler.count, 5); // Ensure assumptions about the tumbler used in our data() function are correct. - compare(tumbler.contentItem.contentY, -defaultImplicitDelegateHeight); + tumblerView = findView(tumbler); + compare(tumblerView.contentY, -defaultImplicitDelegateHeight); var delegateCount = 0; - var listView = tumbler.contentItem; - var listViewContentItem = tumbler.contentItem.contentItem; + var listView = tumblerView; + var listViewContentItem = tumblerView.contentItem; // We use the mouse instead of setting contentY directly, otherwise the // items snap back into place. This doesn't seem to be an issue for @@ -511,16 +833,17 @@ TestCase { } function test_listViewFlickAboveBounds(data) { - tumbler = listViewTumblerComponent.createObject(cleanupItem); - verify(tumbler); + createTumbler(); + tumbler.wrap = false; tumbler.delegate = displacementDelegate; tumbler.model = data.model; + tumblerView = findView(tumbler); mousePress(tumbler, tumblerXCenter(), tumblerYCenter()); // Ensure it's stationary. - var listView = tumbler.contentItem; + var listView = tumblerView; compare(listView.contentY, defaultListViewTumblerOffset); // We could just move up until the contentY changed, but this is safer. @@ -577,8 +900,7 @@ TestCase { } function test_visibleItemCount(data) { - tumbler = tumblerComponent.createObject(cleanupItem); - verify(tumbler); + createTumbler(); tumbler.delegate = objectNameDelegate; tumbler.visibleItemCount = data.visibleItemCount; @@ -588,9 +910,9 @@ TestCase { for (var delegateIndex = 0; delegateIndex < data.visibleItemCount; ++delegateIndex) { if (data.expectedYPositions.hasOwnProperty(delegateIndex)) { - var delegate = findChild(tumbler.contentItem, "delegate" + delegateIndex); + var delegate = findChild(tumblerView, "delegate" + delegateIndex); verify(delegate, "Delegate found at index " + delegateIndex); - var expectedYPos = data.expectedYPositions[delegateIndex] * tumbler.contentItem.delegateHeight; + var expectedYPos = data.expectedYPositions[delegateIndex] * tumblerDelegateHeight; compare(delegate.mapToItem(tumbler.contentItem, 0, 0).y, expectedYPos); } } @@ -604,12 +926,6 @@ TestCase { property real displacement: Tumbler.displacement } - property Component gridViewComponent: GridView {} - property Component simpleDisplacementDelegate: Text { - property real displacement: Tumbler.displacement - property int index: -1 - } - function test_attachedProperties() { tumbler = tumblerComponent.createObject(cleanupItem); verify(tumbler); @@ -621,19 +937,12 @@ TestCase { // // Cause displacement to be changed. The warning isn't triggered if we don't do this. // tumbler.contentItem.offset += 1; - ignoreWarning("Tumbler: attached properties must be accessed from within a delegate item that has a parent"); + ignoreWarning("Tumbler: attached properties must be accessed through a delegate item that has a parent"); noParentDelegateComponent.createObject(null); ignoreWarning("Tumbler: attempting to access attached property on item without an \"index\" property"); var object = noParentDelegateComponent.createObject(cleanupItem); verify(object); - object.destroy(); - - // Should not be any warnings from this, as ListView, for example, doesn't produce warnings for the same code. - var gridView = gridViewComponent.createObject(cleanupItem); - object = simpleDisplacementDelegate.createObject(gridView); - verify(object); - object.destroy(); } property Component paddingDelegate: Text { @@ -680,8 +989,7 @@ TestCase { } function test_padding(data) { - tumbler = tumblerComponent.createObject(cleanupItem); - verify(tumbler); + createTumbler(); tumbler.delegate = paddingDelegate; tumbler.model = 5; @@ -733,8 +1041,8 @@ TestCase { } // Force new items to be created, as there was a bug where the path was correct until this happened. - compare(tumbler.contentItem.offset, 0); + compare(tumblerView.offset, 0); ++tumbler.currentIndex; - tryCompare(tumbler.contentItem, "offset", 4, tumbler.contentItem.highlightMoveDuration * 2); + tryCompare(tumblerView, "offset", 4, tumblerView.highlightMoveDuration * 2); } } |