diff options
Diffstat (limited to 'tests')
19 files changed, 954 insertions, 95 deletions
diff --git a/tests/auto/controls/data/tst_abstractbutton.qml b/tests/auto/controls/data/tst_abstractbutton.qml index cb12f6f1..27fc4525 100644 --- a/tests/auto/controls/data/tst_abstractbutton.qml +++ b/tests/auto/controls/data/tst_abstractbutton.qml @@ -55,6 +55,11 @@ TestCase { AbstractButton {} } + Component { + id: item + Item { } + } + function test_text() { var control = button.createObject(testCase); verify(control); @@ -67,4 +72,35 @@ TestCase { control.destroy(); } + + function test_baseline() { + var control = button.createObject(testCase, {padding: 6}) + verify(control) + compare(control.baselineOffset, 0) + control.contentItem = item.createObject(control, {baselineOffset: 12}) + compare(control.baselineOffset, 18) + control.destroy() + } + + function test_implicitSize() { + var control = button.createObject(testCase) + verify(control) + + compare(control.implicitWidth, 0) + compare(control.implicitHeight, 0) + + control.contentItem = item.createObject(control, {implicitWidth: 10, implicitHeight: 20}) + compare(control.implicitWidth, 10) + compare(control.implicitHeight, 20) + + control.background = item.createObject(control, {implicitWidth: 20, implicitHeight: 30}) + compare(control.implicitWidth, 20) + compare(control.implicitHeight, 30) + + control.padding = 100 + compare(control.implicitWidth, 210) + compare(control.implicitHeight, 220) + + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_combobox.qml b/tests/auto/controls/data/tst_combobox.qml index 4db8c439..5ae1e0a6 100644 --- a/tests/auto/controls/data/tst_combobox.qml +++ b/tests/auto/controls/data/tst_combobox.qml @@ -62,7 +62,17 @@ TestCase { } Component { + id: signalSpy + SignalSpy { } + } + + Component { id: comboBox + ComboBox { } + } + + Component { + id: emptyBox ComboBox { delegate: ItemDelegate { width: popup.width @@ -131,7 +141,7 @@ TestCase { } function test_objects() { - var control = comboBox.createObject(testCase) + var control = emptyBox.createObject(testCase) verify(control) var items = [ @@ -238,7 +248,7 @@ TestCase { } function test_textRole(data) { - var control = comboBox.createObject(testCase) + var control = emptyBox.createObject(testCase) verify(control) control.model = data.model @@ -443,7 +453,7 @@ TestCase { keyClick(Qt.Key_Space) compare(control.currentIndex, 1) - compare(control.highlightedIndex, -1) + tryCompare(control, "highlightedIndex", -1) control.destroy() } @@ -861,4 +871,51 @@ TestCase { control.destroy() } + + // QTBUG-55030 + function test_highlightRange() { + var control = comboBox.createObject(testCase, {model: 100}) + verify(control) + + control.currentIndex = 50 + compare(control.currentIndex, 50) + compare(control.highlightedIndex, -1) + + var openedSpy = signalSpy.createObject(control, {target: control.popup, signalName: "opened"}) + verify(openedSpy.valid) + + control.popup.open() + compare(control.highlightedIndex, 50) + tryCompare(openedSpy, "count", 1) + + var listview = control.popup.contentItem + verify(listview) + + var first = listview.itemAt(0, listview.contentY) + verify(first) + compare(first.text, "50") + + var closedSpy = signalSpy.createObject(control, {target: control.popup, signalName: "closed"}) + verify(closedSpy.valid) + + control.popup.close() + tryCompare(closedSpy, "count", 1) + compare(control.highlightedIndex, -1) + + control.currentIndex = 99 + compare(control.currentIndex, 99) + compare(control.highlightedIndex, -1) + + control.popup.open() + compare(control.highlightedIndex, 99) + tryCompare(openedSpy, "count", 2) + + var last = listview.itemAt(0, listview.contentY + listview.height - 1) + verify(last) + compare(last.text, "99") + + openedSpy.target = null + closedSpy.target = null + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_spinbox.qml b/tests/auto/controls/data/tst_spinbox.qml index 9e836285..81c67681 100644 --- a/tests/auto/controls/data/tst_spinbox.qml +++ b/tests/auto/controls/data/tst_spinbox.qml @@ -507,4 +507,36 @@ TestCase { control.destroy() } + + function test_valueFromText_data() { + return [ + { tag: "editable", editable: true }, + { tag: "non-editable", editable: false } + ] + } + + function test_valueFromText(data) { + var control = spinBox.createObject(testCase, {editable: data.editable}) + verify(control) + + control.forceActiveFocus() + verify(control.activeFocus) + + var valueFromTextCalls = 0 + control.valueFromText = function(text, locale) { + ++valueFromTextCalls + return Number.fromLocaleString(locale, text); + } + + keyClick(Qt.Key_Enter) + compare(valueFromTextCalls, data.editable ? 1 : 0) + + keyClick(Qt.Key_Return) + compare(valueFromTextCalls, data.editable ? 2 : 0) + + control.focus = false + compare(valueFromTextCalls, data.editable ? 3 : 0) + + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_tabbar.qml b/tests/auto/controls/data/tst_tabbar.qml index 666fc2cb..92e80952 100644 --- a/tests/auto/controls/data/tst_tabbar.qml +++ b/tests/auto/controls/data/tst_tabbar.qml @@ -514,17 +514,37 @@ TestCase { control.destroy() } - function test_layout() { - var control = tabBar.createObject(testCase, {spacing: 0, width: 200}) + function test_layout_data() { + return [ + { tag: "spacing:0", spacing: 0 }, + { tag: "spacing:1", spacing: 1 }, + { tag: "spacing:10", spacing: 10 }, + ] + } + + function test_layout(data) { + var control = tabBar.createObject(testCase, {spacing: data.spacing, width: 200}) - var tab1 = tabButton.createObject(control) + var tab1 = tabButton.createObject(control, {text: "First"}) control.addItem(tab1) tryCompare(tab1, "width", control.width) - var tab2 = tabButton.createObject(control) + var tab2 = tabButton.createObject(control, {text: "Second"}) control.addItem(tab2) - tryCompare(tab1, "width", control.width / 2) - tryCompare(tab2, "width", control.width / 2) + tryCompare(tab1, "width", (control.width - data.spacing) / 2) + compare(tab2.width, (control.width - data.spacing) / 2) + + var tab3 = tabButton.createObject(control, {width: 50, text: "Third"}) + control.addItem(tab3) + tryCompare(tab1, "width", (control.width - 2 * data.spacing - 50) / 2) + compare(tab2.width, (control.width - 2 * data.spacing - 50) / 2) + compare(tab3.width, 50) + + var expectedWidth = tab3.contentItem.implicitWidth + tab3.leftPadding + tab3.rightPadding + tab3.width = tab3.implicitWidth + tryCompare(tab1, "width", (control.width - 2 * data.spacing - expectedWidth) / 2) + tryCompare(tab2, "width", (control.width - 2 * data.spacing - expectedWidth) / 2) + compare(tab3.width, expectedWidth) control.destroy() } diff --git a/tests/auto/controls/data/tst_tooltip.qml b/tests/auto/controls/data/tst_tooltip.qml index 1e6ecf01..d9c95dbf 100644 --- a/tests/auto/controls/data/tst_tooltip.qml +++ b/tests/auto/controls/data/tst_tooltip.qml @@ -156,8 +156,10 @@ TestCase { function test_delay_data() { return [ - {tag: "0", delay: 0}, - {tag: "100", delay: 100}, + {tag: "imperative:0", delay: 0, imperative: true}, + {tag: "imperative:100", delay: 100, imperative: true}, + {tag: "declarative:0", delay: 0, imperative: false}, + {tag: "declarative:100", delay: 100, imperative: false} ] } @@ -165,18 +167,31 @@ TestCase { var control = toolTip.createObject(testCase, {delay: data.delay}) compare(control.visible, false) - control.open() + if (data.imperative) + control.open() + else + control.visible = true compare(control.visible, data.delay <= 0) tryCompare(control, "visible", true) control.destroy() } - function test_timeout() { + function test_timeout_data() { + return [ + {tag: "imperative", imperative: true}, + {tag: "declarative", imperative: false} + ] + } + + function test_timeout(data) { var control = toolTip.createObject(testCase, {timeout: 100}) compare(control.visible, false) - control.open() + if (data.imperative) + control.open() + else + control.visible = true compare(control.visible, true) tryCompare(control, "visible", false) @@ -185,6 +200,55 @@ TestCase { function test_warning() { ignoreWarning(Qt.resolvedUrl("tst_tooltip.qml") + ":68:5: QML QtObject: ToolTip must be attached to an Item") - object.ToolTip.text = "" + ignoreWarning("<Unknown File>:1:30: QML ToolTip: cannot find any window to open popup in.") + object.ToolTip.show("") // don't crash (QTBUG-56243) + } + + Component { + id: toolTipWithExitTransition + + ToolTip { + enter: Transition { + NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; duration: 100 } + } + exit: Transition { + NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; duration: 1000 } + } + } + } + + function test_makeVisibleWhileExitTransitionRunning_data() { + return [ + { tag: "imperative", imperative: true }, + { tag: "declarative", imperative: false } + ] + } + + function test_makeVisibleWhileExitTransitionRunning(data) { + var control = toolTipWithExitTransition.createObject(testCase) + + // Show, hide, and show the tooltip again. Its exit transition should + // start and get cancelled, and then its enter transition should run. + if (data.imperative) + control.open() + else + control.visible = true + tryCompare(control, "opacity", 1) + + if (data.imperative) + control.close() + else + control.visible = false + verify(control.exit.running) + wait(100) // TODO: replace with tryVerify() in 5.8 + verify(control.opacity < 1) + + if (data.imperative) + control.open() + else + control.visible = true + tryCompare(control, "opacity", 1) + + control.destroy() } } diff --git a/tests/auto/controls/data/tst_tumbler.qml b/tests/auto/controls/data/tst_tumbler.qml index 6f1f0200..b3230ca4 100644 --- a/tests/auto/controls/data/tst_tumbler.qml +++ b/tests/auto/controls/data/tst_tumbler.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. @@ -51,6 +51,9 @@ TestCase { name: "Tumbler" property var tumbler: null + // With the help of cleanup(), ensures that all items created during a test function + // are destroyed if that test fails. + property Item cleanupItem readonly property real implicitTumblerWidth: 60 readonly property real implicitTumblerHeight: 200 readonly property real defaultImplicitDelegateHeight: implicitTumblerHeight / 3 @@ -66,20 +69,37 @@ TestCase { } } + Component { + id: itemComponent + + Item { + anchors.fill: parent + } + } + function init() { - createTumbler(); + cleanupItem = itemComponent.createObject(testCase); + verify(cleanupItem); } function cleanup() { - tumbler.destroy(); - tumblerView = null; + var destroyed = false; + cleanupItem.Component.destruction.connect(function() { destroyed = true; }); + + cleanupItem.destroy(); + + // Waiting until it's deleted before continuing makes debugging + // test failures much easier, because there aren't unrelated items hanging around. + // TODO: Replace with tryVerify(!tumbler) in 5.8. + while (!destroyed) + wait(0) } function createTumbler(args) { if (args === undefined) - tumbler = tumblerComponent.createObject(testCase); + tumbler = tumblerComponent.createObject(cleanupItem); else - tumbler = tumblerComponent.createObject(testCase, args); + tumbler = tumblerComponent.createObject(cleanupItem, args); verify(tumbler, "Tumbler: failed to create an instance"); tumblerView = findView(tumbler); verify(tumblerView); @@ -128,6 +148,7 @@ TestCase { } function test_wrapWithoutAttachedProperties() { + createTumbler(); verify(tumbler.wrap); tumbler.delegate = noAttachedPropertiesDelegate; @@ -136,7 +157,14 @@ TestCase { verify(findView(tumbler)); } + // TODO: test that currentIndex is maintained between contentItem changes... +// function tst_dynamicContentItemChange() { +// } + function test_currentIndex() { + createTumbler(); + compare(tumbler.contentItem.parent, tumbler); + tumbler.model = 5; compare(tumbler.currentIndex, 0); @@ -256,7 +284,7 @@ TestCase { function test_currentIndexAtCreation(data) { // Test setting currentIndex at creation time - var tumbler = data.component.createObject(testCase); + 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. @@ -279,11 +307,11 @@ TestCase { } else { fuzzyCompare(tumblerView.contentY, tumblerDelegateHeight * data.currentIndex - tumblerView.preferredHighlightBegin, fuzz); } - - tumbler.destroy(); } function test_keyboardNavigation() { + createTumbler(); + tumbler.model = 5; tumbler.forceActiveFocus(); tumblerView.highlightMoveDuration = 0; @@ -312,6 +340,8 @@ TestCase { } function test_itemsCorrectlyPositioned() { + createTumbler(); + tumbler.model = 4; tumbler.height = 120; compare(tumblerDelegateHeight, 40); @@ -320,7 +350,7 @@ TestCase { wait(tumblerView.highlightMoveDuration); var firstItemCenterPos = itemCenterPos(1); var firstItem = tumblerView.itemAt(firstItemCenterPos.x, firstItemCenterPos.y); - var actualPos = testCase.mapFromItem(firstItem, 0, 0); + var actualPos = cleanupItem.mapFromItem(firstItem, 0, 0); compare(actualPos.x, tumbler.leftPadding); compare(actualPos.y, tumbler.topPadding + 40); @@ -331,7 +361,7 @@ TestCase { firstItem = tumblerView.itemAt(firstItemCenterPos.x, firstItemCenterPos.y); verify(firstItem); // Test QTBUG-40298. - actualPos = testCase.mapFromItem(firstItem, 0, 0); + actualPos = cleanupItem.mapFromItem(firstItem, 0, 0); compare(actualPos.x, tumbler.leftPadding); compare(actualPos.y, tumbler.topPadding); @@ -348,8 +378,11 @@ TestCase { } function test_focusPastTumbler() { + tumbler = tumblerComponent.createObject(cleanupItem); + verify(tumbler); + var mouseArea = Qt.createQmlObject( - "import QtQuick 2.2; TextInput { activeFocusOnTab: true; width: 50; height: 50 }", testCase, ""); + "import QtQuick 2.2; TextInput { activeFocusOnTab: true; width: 50; height: 50 }", cleanupItem, ""); tumbler.forceActiveFocus(); verify(tumbler.activeFocus); @@ -357,16 +390,12 @@ TestCase { keyClick(Qt.Key_Tab); verify(!tumbler.activeFocus); verify(mouseArea.activeFocus); - - mouseArea.destroy(); } function test_datePicker() { - tumbler.destroy(); - var component = Qt.createComponent("TumblerDatePicker.qml"); compare(component.status, Component.Ready, component.errorString()); - tumbler = component.createObject(testCase); + tumbler = component.createObject(cleanupItem); // Should not be any warnings. tryCompare(tumbler.dayTumbler, "currentIndex", 0); @@ -396,6 +425,44 @@ TestCase { tryCompare(tumbler.dayTumbler, "currentIndex", 27); } + Component { + id: timePickerComponent + + Row { + property alias minuteTumbler: minuteTumbler + property alias amPmTumbler: amPmTumbler + + Tumbler { + id: minuteTumbler + currentIndex: 6 + model: 60 + width: 50 + height: 150 + } + + Tumbler { + id: amPmTumbler + model: ["AM", "PM"] + width: 50 + height: 150 + contentItem: ListView { + anchors.fill: parent + model: amPmTumbler.model + delegate: amPmTumbler.delegate + } + } + } + } + + function test_listViewTimePicker() { + var root = timePickerComponent.createObject(cleanupItem); + verify(root); + + mouseDrag(root.minuteTumbler, root.minuteTumbler.width / 2, root.minuteTumbler.height / 2, 0, 50); + // Shouldn't crash. + mouseDrag(root.amPmTumbler, root.amPmTumbler.width / 2, root.amPmTumbler.height / 2, 0, 50); + } + function test_displacement_data() { var data = [ // At 0 offset, the first item is current. @@ -451,6 +518,8 @@ TestCase { } function test_displacement(data) { + 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; @@ -468,6 +537,8 @@ TestCase { } function test_wrap() { + createTumbler(); + tumbler.model = 5; compare(tumbler.count, 5); @@ -501,6 +572,9 @@ TestCase { } 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; @@ -510,7 +584,7 @@ TestCase { function test_explicitlyNonwrapping() { // Check that explicitly setting wrap to false works even when it was implicitly false. - var explicitlyNonWrapping = twoItemTumbler.createObject(testCase); + var explicitlyNonWrapping = twoItemTumbler.createObject(cleanupItem); verify(explicitlyNonWrapping); tryCompare(explicitlyNonWrapping, "wrap", false); @@ -523,13 +597,11 @@ TestCase { // Test resetting wrap back to the default behavior. explicitlyNonWrapping.wrap = undefined; compare(explicitlyNonWrapping.wrap, true); - - explicitlyNonWrapping.destroy(); } function test_explicitlyWrapping() { // Check that explicitly setting wrap to true works even when it was implicitly true. - var explicitlyWrapping = tenItemTumbler.createObject(testCase); + var explicitlyWrapping = tenItemTumbler.createObject(cleanupItem); verify(explicitlyWrapping); compare(explicitlyWrapping.wrap, true); @@ -541,8 +613,6 @@ TestCase { // Test resetting wrap back to the default behavior. explicitlyWrapping.wrap = undefined; compare(explicitlyWrapping.wrap, false); - - explicitlyWrapping.destroy(); } Component { @@ -603,7 +673,7 @@ TestCase { } function test_customContentItemAtConstruction(data) { - var tumbler = data.component.createObject(testCase); + var tumbler = data.component.createObject(cleanupItem); // Shouldn't assert. tumbler.model = 5; @@ -622,8 +692,6 @@ TestCase { compare(tumbler.count, 5); compare(tumblerView.currentIndex, 3); compare(tumbler.currentIndex, 3); - - tumbler.destroy(); } function test_customContentItemAfterConstruction_data() { @@ -634,6 +702,8 @@ TestCase { } function test_customContentItemAfterConstruction(data) { + createTumbler(); + tumbler.model = 5; compare(tumbler.count, 5); @@ -692,6 +762,8 @@ TestCase { } function test_displacementListView(data) { + createTumbler(); + tumbler.wrap = false; tumbler.delegate = displacementDelegate; tumbler.model = 5; @@ -761,6 +833,8 @@ TestCase { } function test_listViewFlickAboveBounds(data) { + createTumbler(); + tumbler.wrap = false; tumbler.delegate = displacementDelegate; tumbler.model = data.model; @@ -826,6 +900,8 @@ TestCase { } function test_visibleItemCount(data) { + createTumbler(); + tumbler.delegate = objectNameDelegate; tumbler.visibleItemCount = data.visibleItemCount; @@ -851,6 +927,9 @@ TestCase { } function test_attachedProperties() { + tumbler = tumblerComponent.createObject(cleanupItem); + verify(tumbler); + // TODO: crashes somewhere in QML's guts // tumbler.model = 5; // tumbler.delegate = wrongDelegateTypeComponent; @@ -862,8 +941,8 @@ TestCase { noParentDelegateComponent.createObject(null); ignoreWarning("Tumbler: attempting to access attached property on item without an \"index\" property"); - var object = noParentDelegateComponent.createObject(testCase); - object.destroy(); + var object = noParentDelegateComponent.createObject(cleanupItem); + verify(object); } property Component paddingDelegate: Text { @@ -910,6 +989,8 @@ TestCase { } function test_padding(data) { + createTumbler(); + tumbler.delegate = paddingDelegate; tumbler.model = 5; compare(tumbler.padding, 0); diff --git a/tests/auto/focus/data/visualFocus.qml b/tests/auto/focus/data/visualFocus.qml new file mode 100644 index 00000000..0af87652 --- /dev/null +++ b/tests/auto/focus/data/visualFocus.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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.5 +import QtQuick.Controls 2.0 + +Column { + width: 400 + height: 400 + Button { + text: "Button" + property bool showFocus: visualFocus + } + TextField { + text: "TextField" + } +} diff --git a/tests/auto/focus/tst_focus.cpp b/tests/auto/focus/tst_focus.cpp index dec4fecd..409f2fc7 100644 --- a/tests/auto/focus/tst_focus.cpp +++ b/tests/auto/focus/tst_focus.cpp @@ -63,6 +63,8 @@ private slots: void reason_data(); void reason(); + + void visualFocus(); }; void tst_focus::initTestCase() @@ -245,6 +247,35 @@ void tst_focus::reason() QCOMPARE(control->property("visualFocus"), QVariant(true)); } +void tst_focus::visualFocus() +{ + QQuickView view; + view.setSource(testFileUrl("visualFocus.qml")); + view.show(); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + QQuickItem *column = view.rootObject(); + QVERIFY(column); + QCOMPARE(column->childItems().count(), 2); + + QQuickControl *button = qobject_cast<QQuickControl *>(column->childItems().first()); + QVERIFY(button); + + QQuickItem *textfield = column->childItems().last(); + QVERIFY(textfield); + + button->forceActiveFocus(Qt::TabFocusReason); + QVERIFY(button->hasActiveFocus()); + QVERIFY(button->hasVisualFocus()); + QVERIFY(button->property("showFocus").toBool()); + + QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, QPoint(textfield->x() + textfield->width() / 2, textfield->y() + textfield->height() / 2)); + QVERIFY(!button->hasActiveFocus()); + QVERIFY(!button->hasVisualFocus()); + QVERIFY(!button->property("showFocus").toBool()); +} + QTEST_MAIN(tst_focus) #include "tst_focus.moc" diff --git a/tests/auto/popup/data/activeFocusOnClose3.qml b/tests/auto/popup/data/activeFocusOnClose3.qml new file mode 100644 index 00000000..5a1c8231 --- /dev/null +++ b/tests/auto/popup/data/activeFocusOnClose3.qml @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias popup1: popup1 + property alias popup2: popup2 + + Button { + focus: true + } + + Popup { + id: popup1 + focus: true + enter: Transition { PauseAnimation { duration: 200 } } + exit: Transition { PauseAnimation { duration: 200 } } + } + + Popup { + id: popup2 + focus: true + enter: Transition { PauseAnimation { duration: 100 } } + exit: Transition { PauseAnimation { duration: 100 } } + } +} diff --git a/tests/auto/popup/tst_popup.cpp b/tests/auto/popup/tst_popup.cpp index 6d1e1e3c..af6ccf34 100644 --- a/tests/auto/popup/tst_popup.cpp +++ b/tests/auto/popup/tst_popup.cpp @@ -64,6 +64,7 @@ private slots: void closePolicy(); void activeFocusOnClose1(); void activeFocusOnClose2(); + void activeFocusOnClose3(); void hover_data(); void hover(); void wheel_data(); @@ -454,6 +455,38 @@ void tst_popup::activeFocusOnClose2() QVERIFY(popup1->hasActiveFocus()); } +void tst_popup::activeFocusOnClose3() +{ + // Test that a closing popup that had focus doesn't steal focus from + // another popup that the focus was transferred to. + QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnClose3.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickPopup *popup1 = helper.appWindow->property("popup1").value<QQuickPopup*>(); + QVERIFY(popup1); + + QQuickPopup *popup2 = helper.appWindow->property("popup2").value<QQuickPopup*>(); + QVERIFY(popup2); + + popup1->open(); + QVERIFY(popup1->isVisible()); + QTRY_VERIFY(popup1->hasActiveFocus()); + + popup2->open(); + popup1->close(); + + QSignalSpy closedSpy(popup1, SIGNAL(closed())); + QVERIFY(closedSpy.isValid()); + QVERIFY(closedSpy.wait()); + + QVERIFY(!popup1->isVisible()); + QVERIFY(popup2->isVisible()); + QTRY_VERIFY(popup2->hasActiveFocus()); +} + void tst_popup::hover_data() { QTest::addColumn<QString>("source"); diff --git a/tests/auto/qquickmaterialstyle/data/tst_material.qml b/tests/auto/qquickmaterialstyle/data/tst_material.qml index 63385a6e..9985997b 100644 --- a/tests/auto/qquickmaterialstyle/data/tst_material.qml +++ b/tests/auto/qquickmaterialstyle/data/tst_material.qml @@ -41,6 +41,7 @@ import QtQuick 2.2 import QtQuick.Window 2.2 import QtTest 1.0 +import QtQuick.Templates 2.1 as T import QtQuick.Controls 2.1 import QtQuick.Controls.Material 2.1 @@ -127,6 +128,7 @@ TestCase { visible: true property alias popup: popupInstance property alias label: labelInstance + property alias label2: labelInstance2 Popup { id: popupInstance Label { @@ -136,6 +138,14 @@ TestCase { } Component.onCompleted: open() } + T.Popup { + contentItem: Label { + id: labelInstance2 + text: "test" + color: Material.textSelectionColor + } + Component.onCompleted: open() + } } } @@ -291,16 +301,19 @@ TestCase { var popupObject = popupComponent.createObject(testCase) compare(popupObject.popup.Material.textSelectionColor.toString(), popupObject.Material.textSelectionColor.toString()) compare(popupObject.label.color.toString(), popupObject.Material.textSelectionColor.toString()) + compare(popupObject.label2.color.toString(), popupObject.Material.textSelectionColor.toString()) popupObject.Material[prop] = data.value1 compare(popupObject.Material[prop], data.value1) compare(popupObject.popup.Material.textSelectionColor.toString(), popupObject.Material.textSelectionColor.toString()) compare(popupObject.label.color.toString(), popupObject.Material.textSelectionColor.toString()) + compare(popupObject.label2.color.toString(), popupObject.Material.textSelectionColor.toString()) popupObject.Material[prop] = data.value2 compare(popupObject.Material[prop], data.value2) compare(popupObject.popup.Material.textSelectionColor.toString(), popupObject.Material.textSelectionColor.toString()) compare(popupObject.label.color.toString(), popupObject.Material.textSelectionColor.toString()) + compare(popupObject.label2.color.toString(), popupObject.Material.textSelectionColor.toString()) popupObject.destroy() } @@ -500,11 +513,11 @@ TestCase { compare(control.Material[prop], "#80808080") // unknown - ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":57:9: QML Button: unknown Material." + prop + " value: 123") + ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":58:9: QML Button: unknown Material." + prop + " value: 123") control.Material[prop] = 123 - ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":57:9: QML Button: unknown Material." + prop + " value: foo") + ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":58:9: QML Button: unknown Material." + prop + " value: foo") control.Material[prop] = "foo" - ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":57:9: QML Button: unknown Material." + prop + " value: #1") + ignoreWarning(Qt.resolvedUrl("tst_material.qml") + ":58:9: QML Button: unknown Material." + prop + " value: #1") control.Material[prop] = "#1" control.destroy() @@ -677,4 +690,19 @@ TestCase { window.destroy() } + + Component { + id: busyIndicator + BusyIndicator { } + } + + function test_shade() { + var control = busyIndicator.createObject(testCase) + + compare(control.contentItem.color.toString(), Material.color(Material.Pink, Material.Shade500)) + control.Material.theme = Material.Dark + compare(control.contentItem.color.toString(), Material.color(Material.Pink, Material.Shade200)) + + control.destroy() + } } diff --git a/tests/auto/sanity/tst_sanity.cpp b/tests/auto/sanity/tst_sanity.cpp index 10348ba4..23b56384 100644 --- a/tests/auto/sanity/tst_sanity.cpp +++ b/tests/auto/sanity/tst_sanity.cpp @@ -139,10 +139,11 @@ private: void tst_Sanity::initTestCase() { QDirIterator it(QQC2_IMPORT_PATH, QStringList() << "*.qml" << "*.js", QDir::Files, QDirIterator::Subdirectories); + const QStringList excludeDirs = QStringList() << QStringLiteral("snippets") << QStringLiteral("screenshots") << QStringLiteral("designer"); while (it.hasNext()) { it.next(); QFileInfo info = it.fileInfo(); - if (info.dir().dirName() != QStringLiteral("snippets") && info.dir().dirName() != QStringLiteral("designer")) + if (!excludeDirs.contains(info.dir().dirName())) files.insert(info.dir().dirName() + "/" + info.fileName(), info.filePath()); } } diff --git a/tests/auto/snippets/tst_snippets.cpp b/tests/auto/snippets/tst_snippets.cpp index 6ca9e72c..7972591b 100644 --- a/tests/auto/snippets/tst_snippets.cpp +++ b/tests/auto/snippets/tst_snippets.cpp @@ -46,75 +46,100 @@ class tst_Snippets : public QObject private slots: void initTestCase(); + void verify(); + void verify_data(); + void screenshots(); void screenshots_data(); private: - QMap<QString, QStringPair> filePaths; - QStringList nonVisualSnippets; + QMap<QString, QStringPair> snippetPaths; + QMap<QString, QStringPair> screenshotSnippetPaths; }; +static QMap<QString, QStringPair> findSnippets(const QDir &inputDir, const QDir &outputDir = QDir()) +{ + QMap<QString, QStringPair> snippetPaths; + QDirIterator it(inputDir.path(), QStringList() << "qtquick*.qml" << "qtlabs*.qml", QDir::Files | QDir::Readable); + while (it.hasNext()) { + QFileInfo fi(it.next()); + const QString outDirPath = !outputDir.path().isEmpty() ? outputDir.filePath(fi.baseName() + ".png") : QString(); + snippetPaths.insert(fi.baseName(), qMakePair(fi.filePath(), outDirPath)); + } + return snippetPaths; +} + void tst_Snippets::initTestCase() { - QDir outdir(QDir::current().filePath("screenshots")); - QVERIFY(outdir.exists() || QDir::current().mkpath("screenshots")); + qInfo() << "Snippets are taken from" << QQC2_SNIPPETS_PATH; - QString datadir(QQC2_SNIPPETS_PATH); - QVERIFY(!datadir.isEmpty()); + QDir snippetsDir(QQC2_SNIPPETS_PATH); + QVERIFY(!snippetsDir.path().isEmpty()); - qInfo() << datadir; + snippetPaths = findSnippets(snippetsDir); + QVERIFY(!snippetPaths.isEmpty()); - QDirIterator it(datadir, QStringList() << "qtquick*.qml" << "qtlabs*.qml", QDir::Files | QDir::Readable, QDirIterator::Subdirectories); - while (it.hasNext()) { - QFileInfo fi(it.next()); - filePaths.insert(fi.baseName(), qMakePair(fi.filePath(), outdir.filePath(fi.baseName() + ".png"))); - } - QVERIFY(!filePaths.isEmpty()); + QDir screenshotOutputDir(QDir::current().filePath("screenshots")); + QVERIFY(screenshotOutputDir.exists() || QDir::current().mkpath("screenshots")); - nonVisualSnippets << "qtquickcontrols2-stackview-custom.qml" - << "qtquickcontrols2-swipeview-custom.qml" - << "qtquickcontrols2-tooltip-custom.qml"; + QDir screenshotSnippetsDir(QQC2_SNIPPETS_PATH "/screenshots"); + QVERIFY(!screenshotSnippetsDir.path().isEmpty()); + + screenshotSnippetPaths = findSnippets(screenshotSnippetsDir, screenshotOutputDir); + QVERIFY(!screenshotSnippetPaths.isEmpty()); } Q_DECLARE_METATYPE(QList<QQmlError>) -void tst_Snippets::screenshots() +static void loadAndShow(QQuickView *view, const QString &source) { - QFETCH(QString, input); - QFETCH(QString, output); - qRegisterMetaType<QList<QQmlError> >(); - - QQuickView view; - QSignalSpy warnings(view.engine(), SIGNAL(warnings(QList<QQmlError>))); + QSignalSpy warnings(view->engine(), SIGNAL(warnings(QList<QQmlError>))); QVERIFY(warnings.isValid()); - view.setSource(QUrl::fromLocalFile(input)); - QCOMPARE(view.status(), QQuickView::Ready); - QVERIFY(view.errors().isEmpty()); - QVERIFY(view.rootObject()); + view->setSource(QUrl::fromLocalFile(source)); + QCOMPARE(view->status(), QQuickView::Ready); + QVERIFY(view->errors().isEmpty()); + QVERIFY(view->rootObject()); QVERIFY(warnings.isEmpty()); - view.show(); - view.requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(&view)); + view->show(); + view->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(view)); +} - bool generateScreenshot = true; - for (const QString &baseName : qAsConst(nonVisualSnippets)) { - if (input.contains(baseName)) { - generateScreenshot = false; - break; - } - } +void tst_Snippets::verify() +{ + QFETCH(QString, input); - if (generateScreenshot) { - QSharedPointer<QQuickItemGrabResult> result = view.contentItem()->grabToImage(); - QSignalSpy spy(result.data(), SIGNAL(ready())); - QVERIFY(spy.isValid()); - QVERIFY(spy.wait()); - QVERIFY(result->saveToFile(output)); - } + QQuickView view; + loadAndShow(&view, input); + QGuiApplication::processEvents(); +} + +void tst_Snippets::verify_data() +{ + QTest::addColumn<QString>("input"); + + QMap<QString, QStringPair>::const_iterator it; + for (it = snippetPaths.constBegin(); it != snippetPaths.constEnd(); ++it) + QTest::newRow(qPrintable(it.key())) << it.value().first; +} + +void tst_Snippets::screenshots() +{ + QFETCH(QString, input); + QFETCH(QString, output); + + QQuickView view; + loadAndShow(&view, input); + + QSharedPointer<QQuickItemGrabResult> result = view.contentItem()->grabToImage(); + QSignalSpy spy(result.data(), SIGNAL(ready())); + QVERIFY(spy.isValid()); + QVERIFY(spy.wait()); + QVERIFY(result->saveToFile(output)); QGuiApplication::processEvents(); } @@ -125,7 +150,7 @@ void tst_Snippets::screenshots_data() QTest::addColumn<QString>("output"); QMap<QString, QStringPair>::const_iterator it; - for (it = filePaths.constBegin(); it != filePaths.constEnd(); ++it) + for (it = screenshotSnippetPaths.constBegin(); it != screenshotSnippetPaths.constEnd(); ++it) QTest::newRow(qPrintable(it.key())) << it.value().first << it.value().second; } diff --git a/tests/manual/gifs/data/qtquickcontrols2-button-flat.qml b/tests/manual/gifs/data/qtquickcontrols2-button-flat.qml new file mode 100644 index 00000000..e20e3bc2 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-button-flat.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: button.width + height: button.height + visible: true + + Button { + id: button + text: pressed ? "Pressed" : "Button" + flat: true + anchors.centerIn: parent + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-button-highlighted.qml b/tests/manual/gifs/data/qtquickcontrols2-button-highlighted.qml new file mode 100644 index 00000000..b031c731 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-button-highlighted.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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 +import QtQuick.Window 2.0 +import QtQuick.Controls 2.0 + +Window { + width: button.width + height: button.height + visible: true + + Button { + id: button + text: pressed ? "Pressed" : "Button" + highlighted: true + anchors.centerIn: parent + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-button.qml b/tests/manual/gifs/data/qtquickcontrols2-button.qml index 6cbcc42a..65262589 100644 --- a/tests/manual/gifs/data/qtquickcontrols2-button.qml +++ b/tests/manual/gifs/data/qtquickcontrols2-button.qml @@ -49,7 +49,7 @@ Window { Button { id: button - text: pressed ? "Pressed" : "Normal" + text: pressed ? "Pressed" : "Button" anchors.centerIn: parent } } diff --git a/tests/manual/gifs/data/qtquickcontrols2-checkbox-tristate.qml b/tests/manual/gifs/data/qtquickcontrols2-checkbox-tristate.qml new file mode 100644 index 00000000..ef7e18d4 --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-checkbox-tristate.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 + +Window { + width: column.implicitWidth + height: column.implicitHeight + visible: true + + property alias english: english + property alias norwegian: norwegian + + ColumnLayout { + id: column + anchors.centerIn: parent + + CheckBox { + text: qsTr("Languages") + checkState: english.checked && norwegian.checked + ? Qt.Checked : (english.checked || norwegian.checked) ? Qt.PartiallyChecked : Qt.Unchecked + tristate: true + } + CheckBox { + id: english + text: qsTr("English") + checked: true + leftPadding: indicator.width + } + CheckBox { + id: norwegian + text: qsTr("Norwegian") + checked: true + leftPadding: indicator.width + } + } +} diff --git a/tests/manual/gifs/data/qtquickcontrols2-checkbox.qml b/tests/manual/gifs/data/qtquickcontrols2-checkbox.qml new file mode 100644 index 00000000..ef53721d --- /dev/null +++ b/tests/manual/gifs/data/qtquickcontrols2-checkbox.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.0 + +Window { + width: column.implicitWidth + height: column.implicitHeight + visible: true + + property alias second: second + property alias third: third + + ColumnLayout { + id: column + anchors.centerIn: parent + + CheckBox { + checked: true + text: qsTr("First") + } + CheckBox { + id: second + text: qsTr("Second") + } + CheckBox { + id: third + checked: true + text: qsTr("Third") + } + } +} diff --git a/tests/manual/gifs/tst_gifs.cpp b/tests/manual/gifs/tst_gifs.cpp index 919ba104..2eebc180 100644 --- a/tests/manual/gifs/tst_gifs.cpp +++ b/tests/manual/gifs/tst_gifs.cpp @@ -54,6 +54,7 @@ private slots: void rangeSlider(); void busyIndicator(); void switchGif(); + void button_data(); void button(); void tabBar(); void menu(); @@ -64,6 +65,8 @@ private slots: void delegates(); void dial_data(); void dial(); + void checkBox(); + void checkBoxTriState(); private: void moveSmoothly(QQuickWindow *window, const QPoint &from, const QPoint &to, int movements, @@ -328,14 +331,23 @@ void tst_Gifs::switchGif() gifRecorder.waitForFinish(); } +void tst_Gifs::button_data() +{ + QTest::addColumn<QString>("qmlFileName"); + QTest::newRow("button") << QString::fromLatin1("qtquickcontrols2-button.qml"); + QTest::newRow("button-flat") << QString::fromLatin1("qtquickcontrols2-button-flat.qml"); + QTest::newRow("button-highlighted") << QString::fromLatin1("qtquickcontrols2-button-highlighted.qml"); +} + void tst_Gifs::button() { + QFETCH(QString, qmlFileName); + GifRecorder gifRecorder; gifRecorder.setDataDirPath(dataDirPath); gifRecorder.setOutputDir(outputDir); gifRecorder.setRecordingDuration(3); - gifRecorder.setQmlFileName("qtquickcontrols2-button.qml"); - gifRecorder.setHighQuality(true); + gifRecorder.setQmlFileName(qmlFileName); gifRecorder.start(); @@ -600,6 +612,62 @@ void tst_Gifs::dial() gifRecorder.waitForFinish(); } +void tst_Gifs::checkBox() +{ + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(5); + gifRecorder.setQmlFileName("qtquickcontrols2-checkbox.qml"); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QQuickItem *second = window->property("second").value<QQuickItem*>(); + QVERIFY(second); + QQuickItem *third = window->property("third").value<QQuickItem*>(); + QVERIFY(third); + + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + second->mapToScene(QPointF(second->width() / 2, second->height() / 2)).toPoint(), 400); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + third->mapToScene(QPointF(third->width() / 2, third->height() / 2)).toPoint(), 800); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + third->mapToScene(QPointF(third->width() / 2, third->height() / 2)).toPoint(), 800); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + second->mapToScene(QPointF(second->width() / 2, second->height() / 2)).toPoint(), 800); + + gifRecorder.waitForFinish(); +} + +void tst_Gifs::checkBoxTriState() +{ + GifRecorder gifRecorder; + gifRecorder.setDataDirPath(dataDirPath); + gifRecorder.setOutputDir(outputDir); + gifRecorder.setRecordingDuration(6); + gifRecorder.setQmlFileName("qtquickcontrols2-checkbox-tristate.qml"); + + gifRecorder.start(); + + QQuickWindow *window = gifRecorder.window(); + QQuickItem *english = window->property("english").value<QQuickItem*>(); + QVERIFY(english); + QQuickItem *norwegian = window->property("norwegian").value<QQuickItem*>(); + QVERIFY(norwegian); + + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + english->mapToScene(QPointF(english->width() / 2, english->height() / 2)).toPoint(), 1000); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + norwegian->mapToScene(QPointF(norwegian->width() / 2, norwegian->height() / 2)).toPoint(), 1000); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + norwegian->mapToScene(QPointF(norwegian->width() / 2, norwegian->height() / 2)).toPoint(), 1000); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, + english->mapToScene(QPointF(english->width() / 2, english->height() / 2)).toPoint(), 1000); + + gifRecorder.waitForFinish(); +} + QTEST_MAIN(tst_Gifs) #include "tst_gifs.moc" |