diff options
Diffstat (limited to 'tests/auto/quick')
48 files changed, 2240 insertions, 212 deletions
diff --git a/tests/auto/quick/examples/tst_examples.cpp b/tests/auto/quick/examples/tst_examples.cpp index eee8dfcf26..ea8830fefa 100644 --- a/tests/auto/quick/examples/tst_examples.cpp +++ b/tests/auto/quick/examples/tst_examples.cpp @@ -74,7 +74,6 @@ tst_examples::tst_examples() { // Add files to exclude here excludedFiles << "snippets/qml/listmodel/listmodel.qml"; //Just a ListModel, no root QQuickItem - excludedFiles << "examples/quick/demos/photosurface/photosurface.qml"; // root item is Window rather than Item // Add directories you want excluded here excludedDirs << "shared"; //Not an example @@ -91,9 +90,6 @@ tst_examples::tst_examples() excludedFiles << "examples/quick/shapes/content/interactive.qml"; // relies on resources #ifdef QT_NO_XMLPATTERNS - excludedDirs << "demos/twitter"; - excludedDirs << "demos/flickr"; - excludedDirs << "demos/photoviewer"; excludedFiles << "snippets/qml/xmlrole.qml"; excludedFiles << "particles/itemparticle/particleview.qml"; excludedFiles << "views/visualdatamodel/slideshow.qml"; diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/GrooveDragSlider.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/GrooveDragSlider.qml new file mode 100644 index 0000000000..485c6ce914 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/GrooveDragSlider.qml @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Qt.labs.handlers 1.0 + +Item { + id: root + property int value: 50 + property int maximumValue: 99 + property alias label: label.text + property alias tapEnabled: tap.enabled + property alias pressed: tap.pressed + signal tapped + + DragHandler { + id: dragHandler + objectName: root.objectName + " DragHandler" + target: knob + xAxis.enabled: false + yAxis.minimum: slot.y + yAxis.maximum: slot.height + slot.y - knob.height + } + + Rectangle { + id: slot + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.margins: 10 + anchors.topMargin: 30 + anchors.bottomMargin: 30 + anchors.horizontalCenter: parent.horizontalCenter + width: 10 + color: "black" + radius: width / 2 + smooth: true + } + + Rectangle { + id: glow + anchors.fill: knob + anchors.margins: -5 + anchors.leftMargin: -2 + anchors.horizontalCenterOffset: 1 + radius: 5 + color: "#4400FFFF" + opacity: tap.pressed || tapFlash.running ? 1 : 0 + FlashAnimation on visible { + id: tapFlash + } + } + Rectangle { + id: knob + objectName: "Slider Knob" + width: parent.width - 2 + height: 20 + radius: 5 + color: "darkgray" + border.color: "black" + property bool programmatic: false + property real multiplier: root.maximumValue / (dragHandler.yAxis.maximum - dragHandler.yAxis.minimum) + onYChanged: if (!programmatic) root.value = root.maximumValue - (knob.y - dragHandler.yAxis.minimum) * multiplier + transformOrigin: Item.Center + function setValue(value) { knob.y = dragHandler.yAxis.maximum - value / knob.multiplier } + TapHandler { + id: tap + objectName: root.objectName + " TapHandler" + gesturePolicy: TapHandler.DragThreshold + onTapped: { + tapFlash.start() + root.tapped + } + } + } + + Text { + color: "red" + anchors.top: slot.bottom + anchors.horizontalCenter: parent.horizontalCenter + text: root.value + } + + Text { + id: label + font.pointSize: 9 + color: "red" + anchors.bottom: slot.top + anchors.bottomMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + verticalAlignment: Text.AlignBottom + } + + Component.onCompleted: { + knob.programmatic = true + knob.setValue(root.value) + knob.programmatic = false + } +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/Slider.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/KnobDragSlider.qml index f6acd53615..7f6535651c 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/data/Slider.qml +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/KnobDragSlider.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -80,14 +80,14 @@ Item { function setValue(value) { knob.y = dragHandler.yAxis.maximum - value / knob.multiplier } DragHandler { id: dragHandler - objectName: label.text + " DragHandler" + objectName: root.objectName + " DragHandler" xAxis.enabled: false yAxis.minimum: slot.y yAxis.maximum: slot.height + slot.y - knob.height } TapHandler { id: tap - objectName: label.text + " TapHandler" + objectName: root.objectName + " TapHandler" gesturePolicy: TapHandler.DragThreshold onTapped: { tapFlash.start() @@ -97,20 +97,20 @@ Item { } Text { - font.pointSize: 16 color: "red" - anchors.bottom: parent.bottom + anchors.top: slot.bottom anchors.horizontalCenter: parent.horizontalCenter text: root.value } Text { id: label - font.pointSize: 12 + font.pointSize: 9 color: "red" - anchors.top: parent.top - anchors.topMargin: 5 + anchors.bottom: slot.top + anchors.bottomMargin: 5 anchors.horizontalCenter: parent.horizontalCenter + verticalAlignment: Text.AlignBottom } Component.onCompleted: { diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml index 7d7f53dd15..8adec58621 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml @@ -46,10 +46,15 @@ Rectangle { Row { spacing: 6 - Slider { - label: "DragHandler" - objectName: "Slider" - value: 49; width: 100; height: 400 + KnobDragSlider { + label: "Slider with\nDH on knob" + objectName: "knobSlider" + value: 49; width: 120; height: 400 + } + GrooveDragSlider { + label: "Slider with\nDH on root" + objectName: "grooveSlider" + value: 49; width: 120; height: 400 } Column { spacing: 6 @@ -80,6 +85,7 @@ Rectangle { objectName: "drag" DragHandler { id: drag1 + objectName: "drag1" } Text { anchors.centerIn: parent @@ -96,6 +102,7 @@ Rectangle { border.width: 3 TapHandler { id: tap1 + objectName: "tap1" gesturePolicy: TapHandler.DragThreshold } Text { @@ -113,9 +120,11 @@ Rectangle { objectName: "dragAndTap" DragHandler { id: drag2 + objectName: "drag2" } TapHandler { id: tap2 + objectName: "tap2" gesturePolicy: TapHandler.DragThreshold } Text { @@ -133,10 +142,12 @@ Rectangle { objectName: "tapAndDrag" TapHandler { id: tap3 + objectName: "tap3" gesturePolicy: TapHandler.DragThreshold } DragHandler { id: drag3 + objectName: "drag3" } Text { anchors.centerIn: parent diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp index f3513881cd..6aa2eaa3cb 100644 --- a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp +++ b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp @@ -69,6 +69,7 @@ private slots: void mouseDragFlickableBehindButton(); void touchDragSlider(); void touchDragFlickableBehindSlider(); + void mouseDragSlider_data(); void mouseDragSlider(); void mouseDragFlickableBehindSlider(); void touchDragFlickableBehindItemWithHandlers_data(); @@ -293,7 +294,7 @@ void tst_FlickableInterop::touchDragSlider() createView(windowPtr, "flickableWithHandlers.qml"); QQuickView * window = windowPtr.data(); - QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("Slider"); + QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("knobSlider"); QVERIFY(slider); QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); QVERIFY(drag); @@ -339,6 +340,26 @@ void tst_FlickableInterop::touchDragSlider() QCOMPARE(translationChangedSpy.count(), 1); } +void tst_FlickableInterop::mouseDragSlider_data() +{ + QTest::addColumn<QString>("nameOfSliderToDrag"); + QTest::addColumn<QPoint>("pressPositionRelativeToKnob"); + QTest::addColumn<QPoint>("dragDirection"); // a unit vector + QTest::addColumn<bool>("expectedTapHandlerPressed"); + QTest::addColumn<bool>("expectedDragHandlerActive"); + QTest::addColumn<bool>("expectedFlickableMoving"); + + QTest::newRow("drag down on knob of knobSlider") << "knobSlider" << QPoint(0, 0) << QPoint(0, 1) << true << true << false; + QTest::newRow("drag sideways on knob of knobSlider") << "knobSlider" << QPoint(0, 0) << QPoint(1, 0) << true << false << true; + QTest::newRow("drag down on groove of knobSlider") << "knobSlider" << QPoint(0, 20) << QPoint(0, 1) << false << false << true; + QTest::newRow("drag sideways on groove of knobSlider") << "knobSlider" << QPoint(0, 20) << QPoint(1, 0) << false << false << true; + + QTest::newRow("drag down on knob of grooveSlider") << "grooveSlider" << QPoint(0, 0) << QPoint(0, 1) << true << true << false; + QTest::newRow("drag sideways on knob of grooveSlider") << "grooveSlider" << QPoint(0, 0) << QPoint(1, 0) << true << false << true; + QTest::newRow("drag down on groove of grooveSlider") << "grooveSlider" << QPoint(0, 20) << QPoint(0, 1) << false << true << false; + QTest::newRow("drag sideways on groove of grooveSlider") << "grooveSlider" << QPoint(0, 20) << QPoint(1, 0) << false << false << true; +} + void tst_FlickableInterop::mouseDragSlider() { const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); @@ -346,7 +367,14 @@ void tst_FlickableInterop::mouseDragSlider() createView(windowPtr, "flickableWithHandlers.qml"); QQuickView * window = windowPtr.data(); - QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("Slider"); + QFETCH(QString, nameOfSliderToDrag); + QFETCH(QPoint, pressPositionRelativeToKnob); + QFETCH(QPoint, dragDirection); // a unit vector + QFETCH(bool, expectedTapHandlerPressed); + QFETCH(bool, expectedDragHandlerActive); + QFETCH(bool, expectedFlickableMoving); + + QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>(nameOfSliderToDrag); QVERIFY(slider); QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); QVERIFY(drag); @@ -357,33 +385,40 @@ void tst_FlickableInterop::mouseDragSlider() QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); - // Drag the slider in the allowed (vertical) direction + // Drag the slider tappedSpy.clear(); - QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint(); + QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint() + pressPositionRelativeToKnob; QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); - QTRY_VERIFY(slider->property("pressed").toBool()); - p1 += QPoint(0, dragThreshold); + QTRY_COMPARE(slider->property("pressed").toBool(), expectedTapHandlerPressed); + p1 += QPoint(dragThreshold * dragDirection.x(), dragThreshold * dragDirection.y()); QTest::mouseMove(window, p1); - QVERIFY(slider->property("pressed").toBool()); + QCOMPARE(drag->active(), false); + QCOMPARE(slider->property("pressed").toBool(), expectedTapHandlerPressed); QCOMPARE(slider->property("value").toInt(), 49); - p1 += QPoint(0, 1); + p1 += dragDirection; // one more pixel QTest::mouseMove(window, p1); - p1 += QPoint(0, 10); + QCOMPARE(drag->active(), expectedDragHandlerActive); + // drag farther, to make sure the knob gets adjusted significantly + p1 += QPoint(10 * dragDirection.x(), 10 * dragDirection.y()); QTest::mouseMove(window, p1); - QVERIFY(slider->property("value").toInt() < 49); - QVERIFY(!flickable->isMoving()); - QVERIFY(!slider->property("pressed").toBool()); + if (expectedDragHandlerActive && dragDirection.y() > 0) + QVERIFY(slider->property("value").toInt() < 49); + // by now, Flickable will have stolen the grab, if it decided that it wanted to during filtering of the last event + QCOMPARE(flickable->isMoving(), expectedFlickableMoving); + QCOMPARE(slider->property("pressed").toBool(), false); - // Now that the DragHandler is active, the Flickable will not steal the grab + // If the DragHandler is active, the Flickable will not steal the grab // even if we move a large distance horizontally - p1 += QPoint(dragThreshold * 2, 0); - QTest::mouseMove(window, p1); - QVERIFY(!flickable->isMoving()); + if (expectedDragHandlerActive) { + p1 += QPoint(dragThreshold * 2, 0); + QTest::mouseMove(window, p1); + QCOMPARE(flickable->isMoving(), false); + } // Release, and do not expect the tapped signal QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(tappedSpy.count(), 0); - QCOMPARE(translationChangedSpy.count(), 1); + QCOMPARE(translationChangedSpy.count(), expectedDragHandlerActive ? 1 : 0); } void tst_FlickableInterop::touchDragFlickableBehindSlider() @@ -393,7 +428,7 @@ void tst_FlickableInterop::touchDragFlickableBehindSlider() createView(windowPtr, "flickableWithHandlers.qml"); QQuickView * window = windowPtr.data(); - QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("Slider"); + QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("knobSlider"); QVERIFY(slider); QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); QVERIFY(drag); @@ -439,7 +474,7 @@ void tst_FlickableInterop::mouseDragFlickableBehindSlider() createView(windowPtr, "flickableWithHandlers.qml"); QQuickView * window = windowPtr.data(); - QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("Slider"); + QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("knobSlider"); QVERIFY(slider); QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); QVERIFY(drag); @@ -568,7 +603,7 @@ void tst_FlickableInterop::touchDragSliderAndFlickable() createView(windowPtr, "flickableWithHandlers.qml"); QQuickView * window = windowPtr.data(); - QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("Slider"); + QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("knobSlider"); QVERIFY(slider); QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); QVERIFY(drag); @@ -576,6 +611,7 @@ void tst_FlickableInterop::touchDragSliderAndFlickable() QVERIFY(knob); QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); QVERIFY(flickable); + QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice, false); // The knob is initially centered over the slider's "groove" qreal initialXOffset = qAbs(knob->mapToScene(knob->clipRect().center()).x() - slider->mapToScene @@ -584,57 +620,36 @@ void tst_FlickableInterop::touchDragSliderAndFlickable() // Drag the slider in the allowed (vertical) direction with one finger QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint(); - QTest::touchEvent(window, touchDevice).press(1, p1, window); + touchSeq.press(1, p1, window).commit(); QQuickTouchUtils::flush(window); p1 += QPoint(0, dragThreshold); - QTest::touchEvent(window, touchDevice).move(1, p1, window); + touchSeq.move(1, p1, window).commit(); QQuickTouchUtils::flush(window); p1 += QPoint(0, dragThreshold); - QTest::touchEvent(window, touchDevice).move(1, p1, window); + touchSeq.move(1, p1, window).commit(); QQuickTouchUtils::flush(window); p1 += QPoint(0, dragThreshold); - QTest::touchEvent(window, touchDevice).move(1, p1, window); + touchSeq.move(1, p1, window).commit(); QQuickTouchUtils::flush(window); QTRY_VERIFY(slider->property("value").toInt() < 49); QVERIFY(!flickable->isMoving()); // Drag the Flickable with a second finger QPoint p2(300,300); - QTest::touchEvent(window, touchDevice).stationary(1).press(2, p2, window); - QQuickTouchUtils::flush(window); - p1 += QPoint(-10, -10); - p2 += QPoint(dragThreshold, 0); - QTest::touchEvent(window, touchDevice).move(1, p1, window).stationary(2); - QQuickTouchUtils::flush(window); - p1 += QPoint(-10, -10); - p2 += QPoint(dragThreshold, 0); - QTest::touchEvent(window, touchDevice).stationary(1).move(2, p2, window); + touchSeq.stationary(1).press(2, p2, window).commit(); QQuickTouchUtils::flush(window); - p1 += QPoint(-10, -10); - p2 += QPoint(dragThreshold, 0); - QTest::touchEvent(window, touchDevice).move(1, p1, window).stationary(2); - QQuickTouchUtils::flush(window); - p1 += QPoint(-10, -10); - p2 += QPoint(dragThreshold, 0); - QTest::touchEvent(window, touchDevice).stationary(1).move(2, p2, window); - QQuickTouchUtils::flush(window); - p1 += QPoint(-10, -10); - p2 += QPoint(dragThreshold, 0); - QTest::touchEvent(window, touchDevice).move(1, p1, window).stationary(2); - QQuickTouchUtils::flush(window); - p1 += QPoint(-10, -10); - p2 += QPoint(dragThreshold, 0); - QTest::touchEvent(window, touchDevice).stationary(1).move(2, p2, window); - QQuickTouchUtils::flush(window); - p1 += QPoint(-10, -10); - p2 += QPoint(dragThreshold, 0); - QTest::touchEvent(window, touchDevice).move(1, p1, window).stationary(2); - QQuickTouchUtils::flush(window); - p1 += QPoint(-10, -10); - p2 += QPoint(dragThreshold, 0); - QTest::touchEvent(window, touchDevice).stationary(1).move(2, p2, window); - QQuickTouchUtils::flush(window); - QTRY_VERIFY(flickable->isMoving()); + for (int i = 0; i < 4; ++i) { + p1 += QPoint(-10, -10); + p2 += QPoint(dragThreshold, 0); + touchSeq.move(1, p1, window).stationary(2).commit(); + QQuickTouchUtils::flush(window); + p1 += QPoint(-10, -10); + p2 += QPoint(dragThreshold, 0); + touchSeq.stationary(1).move(2, p2, window).commit(); + QQuickTouchUtils::flush(window); + qCDebug(lcPointerTests) << "step" << i << ": fingers @" << p1 << p2 << "is Flickable moving yet?" << flickable->isMoving(); + } + QVERIFY(flickable->isMoving()); qreal knobSliderXOffset = qAbs(knob->mapToScene(knob->clipRect().center()).toPoint().x() - slider->mapToScene(slider->clipRect().center()).toPoint().x()) - initialXOffset; if (knobSliderXOffset > 1) @@ -643,7 +658,7 @@ void tst_FlickableInterop::touchDragSliderAndFlickable() QVERIFY(qAbs(knobSliderXOffset) <= 1); // Release - QTest::touchEvent(window, touchDevice).release(1, p1, window).release(2, p2, window); + touchSeq.release(1, p1, window).release(2, p2, window).commit(); } QTEST_MAIN(tst_FlickableInterop) diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp index 4b096f9c3a..0561a9e4f1 100644 --- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp +++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp @@ -210,9 +210,9 @@ void tst_MptaInterop::touchesThenPinch() if (!pinchStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == pinch) pinchStoleGrab = i; } - qCDebug(lcPointerTests) << "pinch started after" << pinchStoleGrab << "moves; ended with scale" << pinch->scale() << "rot" << pinch->rotation(); + qCDebug(lcPointerTests) << "pinch started after" << pinchStoleGrab << "moves; ended with scale" << pinch->activeScale() << "rot" << pinch->rotation(); QTRY_VERIFY(pinch->rotation() > 4); - QVERIFY(pinch->scale() > 1); + QVERIFY(pinch->activeScale() > 1); // Press one more point (pinkie finger) QPoint p4 = mpta->mapToScene(QPointF(300, 200)).toPoint(); diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp index 53bb10b7b8..0271924c9b 100644 --- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp @@ -256,8 +256,9 @@ void tst_DragHandler::touchDragMulti() QPointF ball2Center = ball2->clipRect().center(); QPointF scenePressPos2 = ball2->mapToScene(ball2Center); QPoint p2 = scenePressPos2.toPoint(); + QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice, false); - QTest::touchEvent(window, touchDevice).press(1, p1, window).press(2, p2, window); + touchSeq.press(1, p1, window).press(2, p2, window).commit(); QQuickTouchUtils::flush(window); QVERIFY(!dragHandler1->active()); QCOMPARE(dragHandler1->point().position(), ball1Center); @@ -271,12 +272,12 @@ void tst_DragHandler::touchDragMulti() QCOMPARE(dragHandler2->point().scenePressPosition(), scenePressPos2); p1 += QPoint(dragThreshold, 0); p2 += QPoint(0, dragThreshold); - QTest::touchEvent(window, touchDevice).move(1, p1, window).move(2, p2, window); + touchSeq.move(1, p1, window).move(2, p2, window).commit(); QQuickTouchUtils::flush(window); QVERIFY(!dragHandler1->active()); p1 += QPoint(1, 0); p2 += QPoint(0, 1); - QTest::touchEvent(window, touchDevice).move(1, p1, window).move(2, p2, window); + touchSeq.move(1, p1, window).move(2, p2, window).commit(); QQuickTouchUtils::flush(window); QTRY_VERIFY(dragHandler1->active()); QVERIFY(dragHandler2->active()); @@ -292,7 +293,7 @@ void tst_DragHandler::touchDragMulti() QCOMPARE(translationChangedSpy2.count(), 0); QCOMPARE(dragHandler2->translation().x(), 0.0); QCOMPARE(dragHandler2->point().sceneGrabPosition(), sceneGrabPos2); - QTest::touchEvent(window, touchDevice).move(1, p1, window).move(2, p2, window); + touchSeq.move(1, p1, window).move(2, p2, window).commit(); QQuickTouchUtils::flush(window); QVERIFY(dragHandler1->active()); QVERIFY(dragHandler2->active()); @@ -310,14 +311,14 @@ void tst_DragHandler::touchDragMulti() QCOMPARE(dragHandler2->point().sceneGrabPosition(), sceneGrabPos2); QCOMPARE(dragHandler2->translation().x(), 0.0); QCOMPARE(dragHandler2->translation().y(), dragThreshold + 20.0); - QTest::touchEvent(window, touchDevice).release(1, p1, window).stationary(2); + touchSeq.release(1, p1, window).stationary(2).commit(); QQuickTouchUtils::flush(window); QTRY_VERIFY(!dragHandler1->active()); QVERIFY(dragHandler2->active()); QCOMPARE(dragHandler1->point().pressedButtons(), Qt::NoButton); QCOMPARE(ball1->mapToScene(ball1Center).toPoint(), p1); QCOMPARE(translationChangedSpy1.count(), 1); - QTest::touchEvent(window, touchDevice).release(2, p2, window); + touchSeq.release(2, p2, window).commit(); QQuickTouchUtils::flush(window); QTRY_VERIFY(!dragHandler2->active()); QCOMPARE(ball2->mapToScene(ball2Center).toPoint(), p2); diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp index cf18b5eca1..f9970df9f0 100644 --- a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp @@ -526,23 +526,24 @@ void tst_TapHandler::buttonsMultiTouch() QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild<QQuickItem*>("ReleaseWithinBounds"); QVERIFY(buttonReleaseWithinBounds); QSignalSpy releaseWithinBoundsTappedSpy(buttonReleaseWithinBounds, SIGNAL(tapped())); + QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice, false); // can press multiple buttons at the same time QPoint p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); - QTest::touchEvent(window, touchDevice).press(1, p1, window); + touchSeq.press(1, p1, window).commit(); QQuickTouchUtils::flush(window); QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); QPoint p2 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); - QTest::touchEvent(window, touchDevice).stationary(1).press(2, p2, window); + touchSeq.stationary(1).press(2, p2, window).commit(); QQuickTouchUtils::flush(window); QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); QPoint p3 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); - QTest::touchEvent(window, touchDevice).stationary(1).stationary(2).press(3, p3, window); + touchSeq.stationary(1).stationary(2).press(3, p3, window).commit(); QQuickTouchUtils::flush(window); QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); // can release top button and press again: others stay pressed the whole time - QTest::touchEvent(window, touchDevice).stationary(2).stationary(3).release(1, p1, window); + touchSeq.stationary(2).stationary(3).release(1, p1, window).commit(); QQuickTouchUtils::flush(window); QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); QCOMPARE(dragThresholdTappedSpy.count(), 1); @@ -550,14 +551,14 @@ void tst_TapHandler::buttonsMultiTouch() QCOMPARE(withinBoundsTappedSpy.count(), 0); QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); - QTest::touchEvent(window, touchDevice).stationary(2).stationary(3).press(1, p1, window); + touchSeq.stationary(2).stationary(3).press(1, p1, window).commit(); QQuickTouchUtils::flush(window); QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); QVERIFY(buttonWithinBounds->property("pressed").toBool()); QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); // can release middle button and press again: others stay pressed the whole time - QTest::touchEvent(window, touchDevice).stationary(1).stationary(3).release(2, p2, window); + touchSeq.stationary(1).stationary(3).release(2, p2, window).commit(); QQuickTouchUtils::flush(window); QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); QCOMPARE(withinBoundsTappedSpy.count(), 1); @@ -565,21 +566,21 @@ void tst_TapHandler::buttonsMultiTouch() QCOMPARE(dragThresholdTappedSpy.count(), 1); QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); - QTest::touchEvent(window, touchDevice).stationary(1).stationary(3).press(2, p2, window); + touchSeq.stationary(1).stationary(3).press(2, p2, window).commit(); QQuickTouchUtils::flush(window); QVERIFY(buttonDragThreshold->property("pressed").toBool()); QVERIFY(buttonWithinBounds->property("pressed").toBool()); QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); // can release bottom button and press again: others stay pressed the whole time - QTest::touchEvent(window, touchDevice).stationary(1).stationary(2).release(3, p3, window); + touchSeq.stationary(1).stationary(2).release(3, p3, window).commit(); QQuickTouchUtils::flush(window); QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1); QVERIFY(buttonWithinBounds->property("pressed").toBool()); QCOMPARE(withinBoundsTappedSpy.count(), 1); QVERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); QCOMPARE(dragThresholdTappedSpy.count(), 1); - QTest::touchEvent(window, touchDevice).stationary(1).stationary(2).press(3, p3, window); + touchSeq.stationary(1).stationary(2).press(3, p3, window).commit(); QQuickTouchUtils::flush(window); QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); QVERIFY(buttonWithinBounds->property("pressed").toBool()); @@ -599,8 +600,8 @@ void tst_TapHandler::componentUserBehavioralOverride() QQuickTapHandler *userTapHandler = button->findChild<QQuickTapHandler*>("override"); QVERIFY(userTapHandler); QSignalSpy tappedSpy(button, SIGNAL(tapped())); - QSignalSpy innerGrabChangedSpy(innerTapHandler, SIGNAL(grabChanged(QQuickEventPoint *))); - QSignalSpy userGrabChangedSpy(userTapHandler, SIGNAL(grabChanged(QQuickEventPoint *))); + QSignalSpy innerGrabChangedSpy(innerTapHandler, SIGNAL(grabChanged(QQuickEventPoint::GrabState, QQuickEventPoint *))); + QSignalSpy userGrabChangedSpy(userTapHandler, SIGNAL(grabChanged(QQuickEventPoint::GrabState, QQuickEventPoint *))); QSignalSpy innerPressedChangedSpy(innerTapHandler, SIGNAL(pressedChanged())); QSignalSpy userPressedChangedSpy(userTapHandler, SIGNAL(pressedChanged())); diff --git a/tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml b/tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml new file mode 100644 index 0000000000..551329a457 --- /dev/null +++ b/tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +AnimatedSprite { + loops: AnimatedSprite.Infinite + source: "squarefacesprite.png" + frameCount: 6 + frameDuration: 240 + width: 160 + height: 160 +} diff --git a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp index d24ebd9878..4ca31fd957 100644 --- a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp +++ b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp @@ -53,6 +53,7 @@ private slots: void test_largeAnimation(); void test_reparenting(); void test_changeSourceToSmallerImgKeepingBigFrameSize(); + void test_infiniteLoops(); void test_implicitSize(); }; @@ -79,8 +80,13 @@ void tst_qquickanimatedsprite::test_properties() QVERIFY(sprite->interpolate()); QCOMPARE(sprite->loops(), 30); + QSignalSpy finishedSpy(sprite, SIGNAL(finished())); + QVERIFY(finishedSpy.isValid()); + sprite->setRunning(false); QVERIFY(!sprite->running()); + // The finished() signal shouldn't be emitted when running is manually set to false. + QCOMPARE(finishedSpy.count(), 0); sprite->setInterpolate(false); QVERIFY(!sprite->interpolate()); } @@ -100,10 +106,15 @@ void tst_qquickanimatedsprite::test_runningChangedSignal() QVERIFY(!sprite->running()); QSignalSpy runningChangedSpy(sprite, SIGNAL(runningChanged(bool))); + QSignalSpy finishedSpy(sprite, SIGNAL(finished())); + QVERIFY(finishedSpy.isValid()); + sprite->setRunning(true); QTRY_COMPARE(runningChangedSpy.count(), 1); + QCOMPARE(finishedSpy.count(), 0); QTRY_VERIFY(!sprite->running()); QTRY_COMPARE(runningChangedSpy.count(), 2); + QCOMPARE(finishedSpy.count(), 1); } template <typename T> @@ -357,6 +368,28 @@ void tst_qquickanimatedsprite::test_implicitSize() QCOMPARE(frameImplicitHeightChangedSpy.count(), 1); } +void tst_qquickanimatedsprite::test_infiniteLoops() +{ + QQuickView window; + window.setSource(testFileUrl("infiniteLoops.qml")); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(window.rootObject()); + + QQuickAnimatedSprite* sprite = qobject_cast<QQuickAnimatedSprite*>(window.rootObject()); + QVERIFY(sprite); + + QTRY_VERIFY(sprite->running()); + + QSignalSpy finishedSpy(sprite, SIGNAL(finished())); + QVERIFY(finishedSpy.isValid()); + + // The finished() signal shouldn't be emitted for infinite animations. + const int previousFrame = sprite->currentFrame(); + QTRY_VERIFY(sprite->currentFrame() != previousFrame); + QCOMPARE(finishedSpy.count(), 0); +} + QTEST_MAIN(tst_qquickanimatedsprite) #include "tst_qquickanimatedsprite.moc" diff --git a/tests/auto/quick/qquickanimations/data/finished.qml b/tests/auto/quick/qquickanimations/data/finished.qml new file mode 100644 index 0000000000..a18b321501 --- /dev/null +++ b/tests/auto/quick/qquickanimations/data/finished.qml @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 + +Item { + id: root + width: 400 + height: 400 + + property bool finishedUsableInQml: false + + property alias simpleTopLevelAnimation: simpleTopLevelAnimation + property real foo: 0 + + property alias transitionRect: transitionRect + property alias transition: transition + property alias animationWithinTransition: animationWithinTransition + + property real bar: 0 + property alias animationWithinBehavior: animationWithinBehavior + property alias behavior: behavior + + NumberAnimation { + id: simpleTopLevelAnimation + target: root + property: "foo" + from: 0 + to: 1 + duration: 10 + + onFinished: finishedUsableInQml = true + } + + Rectangle { + id: transitionRect + color: "green" + width: 50 + height: 50 + anchors.centerIn: parent + + states: State { + name: "go" + } + transitions: Transition { + id: transition + to: "go" + SequentialAnimation { + NumberAnimation { + id: animationWithinTransition + duration: 10 + property: "foo" + from: 1 + to: 2 + } + } + } + } + + Behavior on bar { + id: behavior + NumberAnimation { + id: animationWithinBehavior + duration: 10 + property: "bar" + from: 0 + to: 1 + } + } +} diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp index de86bb16db..3cfe03a376 100644 --- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp +++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp @@ -105,6 +105,7 @@ private slots: void pathSvgAnimation(); void pathLineUnspecifiedXYBug(); void unsetAnimatorProxyJobWindow(); + void finished(); }; #define QTIMED_COMPARE(lhs, rhs) do { \ @@ -1612,6 +1613,79 @@ void tst_qquickanimations::unsetAnimatorProxyJobWindow() QCOMPARE(proxy.job().data(), job); } +void tst_qquickanimations::finished() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("finished.qml")); + QScopedPointer<QObject> root(component.create()); + QVERIFY(root); + + // Test that finished() is emitted for a simple top-level animation. + // (Each test is in its own block so that we can reuse the nice signal names :)) + { + QQuickAbstractAnimation *simpleTopLevelAnimation + = root->property("simpleTopLevelAnimation").value<QQuickAbstractAnimation*>(); + QVERIFY(simpleTopLevelAnimation); + + QSignalSpy stoppedSpy(simpleTopLevelAnimation, SIGNAL(stopped())); + QVERIFY(stoppedSpy.isValid()); + + QSignalSpy finishedSpy(simpleTopLevelAnimation, SIGNAL(finished())); + QVERIFY(finishedSpy.isValid()); + + QVERIFY(simpleTopLevelAnimation->setProperty("running", QVariant(true))); + QTRY_COMPARE(stoppedSpy.count(), 1); + QCOMPARE(finishedSpy.count(), 1); + + // Test that the signal is properly revisioned and hence accessible from QML. + QCOMPARE(root->property("finishedUsableInQml").toBool(), true); + } + + // Test that finished() is not emitted for animations within a Transition. + { + QObject *transition = root->property("transition").value<QObject*>(); + QVERIFY(transition); + + QSignalSpy runningChangedSpy(transition, SIGNAL(runningChanged())); + QVERIFY(runningChangedSpy.isValid()); + + QQuickAbstractAnimation *animationWithinTransition + = root->property("animationWithinTransition").value<QQuickAbstractAnimation*>(); + QVERIFY(animationWithinTransition); + + QSignalSpy stoppedSpy(animationWithinTransition, SIGNAL(stopped())); + QVERIFY(stoppedSpy.isValid()); + + QSignalSpy finishedSpy(animationWithinTransition, SIGNAL(finished())); + QVERIFY(finishedSpy.isValid()); + + QObject *transitionRect = root->property("transitionRect").value<QObject*>(); + QVERIFY(transitionRect); + QVERIFY(transitionRect->setProperty("state", QVariant(QLatin1String("go")))); + QTRY_COMPARE(runningChangedSpy.count(), 1); + QCOMPARE(stoppedSpy.count(), 0); + QCOMPARE(finishedSpy.count(), 0); + } + + // Test that finished() is not emitted for animations within a Behavior. + { + QQuickAbstractAnimation *animationWithinBehavior + = root->property("animationWithinBehavior").value<QQuickAbstractAnimation*>(); + QVERIFY(animationWithinBehavior); + + QSignalSpy stoppedSpy(animationWithinBehavior, SIGNAL(stopped())); + QVERIFY(stoppedSpy.isValid()); + + QSignalSpy finishedSpy(animationWithinBehavior, SIGNAL(finished())); + QVERIFY(finishedSpy.isValid()); + + QVERIFY(root->setProperty("bar", QVariant(1.0))); + QTRY_COMPARE(root->property("bar").toReal(), 1.0); + QCOMPARE(stoppedSpy.count(), 0); + QCOMPARE(finishedSpy.count(), 0); + } +} + QTEST_MAIN(tst_qquickanimations) #include "tst_qquickanimations.moc" diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_line.qml b/tests/auto/quick/qquickcanvasitem/data/tst_line.qml index 750f37638d..dc960a24d0 100644 --- a/tests/auto/quick/qquickcanvasitem/data/tst_line.qml +++ b/tests/auto/quick/qquickcanvasitem/data/tst_line.qml @@ -834,5 +834,96 @@ CanvasTestCase { ctx.lineCap = 'square'; compare(ctx.lineCap, 'square'); + } + + function test_lineDash(row) { + var canvas = createCanvasObject(row); + var ctx = canvas.getContext('2d'); + ctx.reset(); + ctx.strokeStyle = "#fff"; + ctx.lineWidth = 2; + var pattern = [2, 3, 5, 1, 6, 3] + ctx.setLineDash(pattern) + + compare(ctx.getLineDash(), pattern); + + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(40, 0); + ctx.stroke(); + + comparePixel(ctx, 0,0, 255,255,255,255); + comparePixel(ctx, 1,0, 255,255,255,255); + comparePixel(ctx, 2,0, 255,255,255,255); + comparePixel(ctx, 3,0, 255,255,255,255); + comparePixel(ctx, 4,0, 0,0,0,0); + comparePixel(ctx, 5,0, 0,0,0,0); + comparePixel(ctx, 6,0, 0,0,0,0); + comparePixel(ctx, 7,0, 0,0,0,0); + comparePixel(ctx, 8,0, 0,0,0,0); + comparePixel(ctx, 9,0, 0,0,0,0); + comparePixel(ctx, 10,0, 255,255,255,255); + comparePixel(ctx, 11,0, 255,255,255,255); + comparePixel(ctx, 12,0, 255,255,255,255); + comparePixel(ctx, 13,0, 255,255,255,255); + comparePixel(ctx, 14,0, 255,255,255,255); + comparePixel(ctx, 15,0, 255,255,255,255); + comparePixel(ctx, 16,0, 255,255,255,255); + comparePixel(ctx, 17,0, 255,255,255,255); + comparePixel(ctx, 18,0, 255,255,255,255); + comparePixel(ctx, 19,0, 255,255,255,255); + comparePixel(ctx, 20,0, 0,0,0,0); + comparePixel(ctx, 21,0, 0,0,0,0); + comparePixel(ctx, 22,0, 255,255,255,255); + comparePixel(ctx, 23,0, 255,255,255,255); + comparePixel(ctx, 24,0, 255,255,255,255); + comparePixel(ctx, 25,0, 255,255,255,255); + comparePixel(ctx, 26,0, 255,255,255,255); + comparePixel(ctx, 27,0, 255,255,255,255); + comparePixel(ctx, 28,0, 255,255,255,255); + comparePixel(ctx, 29,0, 255,255,255,255); + comparePixel(ctx, 30,0, 255,255,255,255); + comparePixel(ctx, 31,0, 255,255,255,255); + comparePixel(ctx, 32,0, 255,255,255,255); + comparePixel(ctx, 33,0, 255,255,255,255); + comparePixel(ctx, 34,0, 0,0,0,0); + comparePixel(ctx, 35,0, 0,0,0,0); + comparePixel(ctx, 36,0, 0,0,0,0); + comparePixel(ctx, 37,0, 0,0,0,0); + comparePixel(ctx, 38,0, 0,0,0,0); + comparePixel(ctx, 39,0, 0,0,0,0); + } + + function test_lineDashOffset(row) { + var canvas = createCanvasObject(row); + var ctx = canvas.getContext('2d'); + ctx.reset(); + ctx.strokeStyle = "#fff"; + ctx.lineWidth = 2; + var pattern = [2,2] + ctx.setLineDash(pattern) + ctx.lineDashOffset = 1 + compare(ctx.getLineDash(), pattern); + + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(40, 0); + ctx.stroke(); + + + comparePixel(ctx, 0,0, 255,255,255,255); + comparePixel(ctx, 1,0, 255,255,255,255); + comparePixel(ctx, 2,0, 0,0,0,0); + comparePixel(ctx, 3,0, 0,0,0,0); + comparePixel(ctx, 4,0, 0,0,0,0); + comparePixel(ctx, 5,0, 0,0,0,0); + comparePixel(ctx, 6,0, 255,255,255,255); + comparePixel(ctx, 7,0, 255,255,255,255); + comparePixel(ctx, 8,0, 255,255,255,255); + comparePixel(ctx, 9,0, 255,255,255,255); + comparePixel(ctx, 10,0, 0,0,0,0); + comparePixel(ctx, 11,0, 0,0,0,0); + comparePixel(ctx, 12,0, 0,0,0,0); + comparePixel(ctx, 13,0, 0,0,0,0); } } diff --git a/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml b/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml index 68f456af99..63d65b435c 100644 --- a/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml +++ b/tests/auto/quick/qquickdesignersupport/data/TestComponent.qml @@ -4,6 +4,8 @@ Item { width: 100 height: 62 - x: Math.max(0, 200) + // Add a dummy dependency to parent.x to ensure that the + // binding stays for the test. + x: parent.x + Math.max(0, 200) - parent.x } diff --git a/tests/auto/quick/qquickdesignersupport/data/test.qml b/tests/auto/quick/qquickdesignersupport/data/test.qml index 1d43cb3b7e..6c89f15257 100644 --- a/tests/auto/quick/qquickdesignersupport/data/test.qml +++ b/tests/auto/quick/qquickdesignersupport/data/test.qml @@ -1,4 +1,4 @@ -import QtQuick 2.0 +import QtQuick 2.11 Rectangle { objectName: "rootItem" @@ -13,7 +13,7 @@ Rectangle { Rectangle { objectName: "rectangleItem" - gradient: Gradient { + containmentMask: Item { } } diff --git a/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp b/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp index 96a11e16e9..3e0765552a 100644 --- a/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp +++ b/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp @@ -209,15 +209,15 @@ void tst_qquickdesignersupport::objectProperties() //Read gradient property as QObject - int propertyIndex = rectangleItem->metaObject()->indexOfProperty("gradient"); + int propertyIndex = rectangleItem->metaObject()->indexOfProperty("containmentMask"); QVERIFY(propertyIndex > 0); QMetaProperty metaProperty = rectangleItem->metaObject()->property(propertyIndex); QVERIFY(metaProperty.isValid()); QVERIFY(QQuickDesignerSupportProperties::isPropertyQObject(metaProperty)); - QObject*gradient = QQuickDesignerSupportProperties::readQObjectProperty(metaProperty, rectangleItem); - QVERIFY(gradient); + QObject *containmentItem = QQuickDesignerSupportProperties::readQObjectProperty(metaProperty, rectangleItem); + QVERIFY(containmentItem); //The width property is not a QObject @@ -450,7 +450,7 @@ void tst_qquickdesignersupport::testNotifyPropertyChangeCallBack() QQuickDesignerSupportMetaInfo::registerNotifyPropertyChangeCallBack(notifyPropertyChangeCallBackPointer); - rectangle->setProperty("gradient", QVariant::fromValue<QQuickGradient *>(gradient)); + rectangle->setProperty("gradient", QVariant::fromValue<QJSValue>(view->engine()->newQObject(gradient))); QVERIFY(s_object); QCOMPARE(s_object, rootItem); diff --git a/tests/auto/quick/qquickflickable/BLACKLIST b/tests/auto/quick/qquickflickable/BLACKLIST index 826c024732..870bb2e1e9 100644 --- a/tests/auto/quick/qquickflickable/BLACKLIST +++ b/tests/auto/quick/qquickflickable/BLACKLIST @@ -20,3 +20,4 @@ osx-10.10 osx-10.10 [nestedSliderUsingTouch:keepNeither] ubuntu-16.04 +ubuntu-18.04 diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 248f8447e0..ba266824e6 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -203,6 +203,8 @@ private slots: void overshoot(); void overshoot_data(); void overshoot_reentrant(); + void synchronousDrag_data(); + void synchronousDrag(); private: void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to); @@ -2458,6 +2460,70 @@ void tst_qquickflickable::overshoot_reentrant() QCOMPARE(flickable->verticalOvershoot(), 25.0); } +void tst_qquickflickable::synchronousDrag_data() +{ + QTest::addColumn<bool>("synchronousDrag"); + + QTest::newRow("default") << false; + QTest::newRow("synch") << true; +} + +void tst_qquickflickable::synchronousDrag() +{ + QFETCH(bool, synchronousDrag); + + QScopedPointer<QQuickView> scopedWindow(new QQuickView); + QQuickView *window = scopedWindow.data(); + window->setSource(testFileUrl("longList.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window); + QQuickViewTestUtil::moveMouseAway(window); + window->show(); + QVERIFY(window->rootObject() != nullptr); + + QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); + QVERIFY(flickable != nullptr); + QCOMPARE(flickable->synchronousDrag(), false); + flickable->setSynchronousDrag(synchronousDrag); + + QPoint p1(100, 100); + QPoint p2(95, 95); + QPoint p3(70, 70); + QPoint p4(50, 50); + QPoint p5(30, 30); + QCOMPARE(flickable->contentY(), 0.0f); + + // Drag via mouse + moveAndPress(window, p1); + QTest::mouseMove(window, p2); + QTest::mouseMove(window, p3); + QTest::mouseMove(window, p4); + QCOMPARE(flickable->contentY(), synchronousDrag ? 50.0f : 0.0f); + QTest::mouseMove(window, p5); + if (!synchronousDrag) + QVERIFY(flickable->contentY() < 50.0f); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p5); + + // Reset to initial condition + flickable->setContentY(0); + + // Drag via touch + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QTest::touchEvent(window, touchDevice).move(0, p2, window); + QQuickTouchUtils::flush(window); + QTest::touchEvent(window, touchDevice).move(0, p3, window); + QQuickTouchUtils::flush(window); + QTest::touchEvent(window, touchDevice).move(0, p4, window); + QQuickTouchUtils::flush(window); + QCOMPARE(flickable->contentY(), synchronousDrag ? 50.0f : 0.0f); + QTest::touchEvent(window, touchDevice).move(0, p5, window); + QQuickTouchUtils::flush(window); + if (!synchronousDrag) + QVERIFY(flickable->contentY() < 50.0f); + QTest::touchEvent(window, touchDevice).release(0, p5, window); +} + QTEST_MAIN(tst_qquickflickable) #include "tst_qquickflickable.moc" diff --git a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp index 805baebc7a..6aff66d61e 100644 --- a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp +++ b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp @@ -193,7 +193,7 @@ void tst_QQuickFramebufferObject::testThatStuffWorks() view.show(); view.requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(&view)); + QVERIFY(QTest::qWaitForWindowExposed(&view)); QImage result = view.grabWindow(); @@ -233,7 +233,7 @@ void tst_QQuickFramebufferObject::testInvalidate() view.show(); view.requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(&view)); + QVERIFY(QTest::qWaitForWindowExposed(&view)); QCOMPARE(frameInfo.fboSize, QSize(200, 200)); diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp index 915b9b43ea..7deed8c5a8 100644 --- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp @@ -4387,24 +4387,34 @@ void tst_QQuickGridView::snapOneRow_data() QTest::addColumn<qreal>("snapAlignment"); QTest::addColumn<qreal>("endExtent"); QTest::addColumn<qreal>("startExtent"); + QTest::addColumn<qreal>("flickSlowdown"); QTest::newRow("vertical, left to right") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) - << QPoint(20, 160) << QPoint(20, 20) << 100.0 << 240.0 << 0.0; + << QPoint(20, 160) << QPoint(20, 20) << 100.0 << 240.0 << 0.0 << 1.0; QTest::newRow("horizontal, left to right") << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) - << QPoint(160, 20) << QPoint(20, 20) << 100.0 << 240.0 << 0.0; + << QPoint(160, 20) << QPoint(20, 20) << 100.0 << 240.0 << 0.0 << 1.0; QTest::newRow("horizontal, right to left") << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange) - << QPoint(20, 20) << QPoint(160, 20) << -340.0 << -240.0 - 240.0 << -240.0; + << QPoint(20, 20) << QPoint(160, 20) << -340.0 << -240.0 - 240.0 << -240.0 << 1.0; QTest::newRow("vertical, left to right, enforce range") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) - << QPoint(20, 160) << QPoint(20, 20) << 100.0 << 340.0 << -20.0; + << QPoint(20, 160) << QPoint(20, 20) << 100.0 << 340.0 << -20.0 << 1.0; QTest::newRow("horizontal, left to right, enforce range") << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) - << QPoint(160, 20) << QPoint(20, 20) << 100.0 << 340.0 << -20.0; + << QPoint(160, 20) << QPoint(20, 20) << 100.0 << 340.0 << -20.0 << 1.0; QTest::newRow("horizontal, right to left, enforce range") << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange) - << QPoint(20, 20) << QPoint(160, 20) << -340.0 << -240.0 - 240.0 - 100.0 << -220.0; + << QPoint(20, 20) << QPoint(160, 20) << -340.0 << -240.0 - 240.0 - 100.0 << -220.0 << 1.0; + + // Using e.g. 120 rather than 95 always went to the next row. + // Ensure this further movement has the same behavior + QTest::newRow("vertical, left to right, no more blindspot") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) + << QPoint(20, 160) << QPoint(20, 95) << 100.0 << 240.0 << 0.0 << 4.0; + + // StrictlyEnforceRange should not override valid SnapOneItem decisions + QTest::newRow("vertical, left to right, no more blindspot, enforce range") << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) + << QPoint(20, 160) << QPoint(20, 95) << 100.0 << 340.0 << -20.0 << 4.0; } void tst_QQuickGridView::snapOneRow() @@ -4417,6 +4427,9 @@ void tst_QQuickGridView::snapOneRow() QFETCH(qreal, snapAlignment); QFETCH(qreal, endExtent); QFETCH(qreal, startExtent); + QFETCH(qreal, flickSlowdown); + + qreal flickDuration = 180 * flickSlowdown; QQuickView *window = getView(); QQuickViewTestUtil::moveMouseAway(window); @@ -4439,7 +4452,7 @@ void tst_QQuickGridView::snapOneRow() QSignalSpy currentIndexSpy(gridview, SIGNAL(currentIndexChanged())); // confirm that a flick hits next row boundary - flick(window, flickStart, flickEnd, 180); + flick(window, flickStart, flickEnd, flickDuration); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(gridview->contentY(), snapAlignment); @@ -4453,7 +4466,7 @@ void tst_QQuickGridView::snapOneRow() // flick to end do { - flick(window, flickStart, flickEnd, 180); + flick(window, flickStart, flickEnd, flickDuration); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops } while (flow == QQuickGridView::FlowLeftToRight ? !gridview->isAtYEnd() @@ -4471,7 +4484,7 @@ void tst_QQuickGridView::snapOneRow() // flick to start do { - flick(window, flickEnd, flickStart, 180); + flick(window, flickEnd, flickStart, flickDuration); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops } while (flow == QQuickGridView::FlowLeftToRight ? !gridview->isAtYBeginning() diff --git a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp index d8464ebc74..4b75a7e008 100644 --- a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp +++ b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp @@ -65,6 +65,7 @@ private slots: void threadTest(); void asyncTextureTest(); + void instantAsyncTextureTest(); private: QString newImageFileName() const; @@ -550,6 +551,70 @@ void tst_qquickimageprovider::asyncTextureTest() } } +class InstantAsyncImageResponse : public QQuickImageResponse +{ + public: + InstantAsyncImageResponse(const QString &id, const QSize &requestedSize) + { + QImage image(50, 50, QImage::Format_RGB32); + image.fill(QColor(id).rgb()); + if (requestedSize.isValid()) + image = image.scaled(requestedSize); + m_texture = QQuickTextureFactory::textureFactoryForImage(image); + emit finished(); + } + + QQuickTextureFactory *textureFactory() const + { + return m_texture; + } + + QQuickTextureFactory *m_texture; +}; + +class InstancAsyncProvider : public QQuickAsyncImageProvider +{ + public: + InstancAsyncProvider() + { + } + + ~InstancAsyncProvider() {} + + QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) + { + return new InstantAsyncImageResponse(id, requestedSize); + } +}; + +void tst_qquickimageprovider::instantAsyncTextureTest() +{ + QQmlEngine engine; + + InstancAsyncProvider *provider = new InstancAsyncProvider; + + engine.addImageProvider("test_instantasync", provider); + QVERIFY(engine.imageProvider("test_instantasync") != nullptr); + + QString componentStr = "import QtQuick 2.0\nItem { \n" + "Image { source: \"image://test_instantasync/blue\"; }\n" + "Image { source: \"image://test_instantasync/red\"; }\n" + "Image { source: \"image://test_instantasync/green\"; }\n" + "Image { source: \"image://test_instantasync/yellow\"; }\n" + " }"; + QQmlComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QScopedPointer<QObject> obj(component.create()); + + QVERIFY(!obj.isNull()); + const QList<QQuickImage *> images = obj->findChildren<QQuickImage *>(); + QCOMPARE(images.count(), 4); + + for (QQuickImage *img: images) { + QTRY_COMPARE(img->status(), QQuickImage::Ready); + } +} + QTEST_MAIN(tst_qquickimageprovider) diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index c1daddb561..64a186eade 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -118,6 +118,7 @@ private slots: void noCurrentIndex(); void keyNavigation(); void keyNavigation_data(); + void checkCountForMultiColumnModels(); void enforceRange(); void enforceRange_withoutHighlight(); void spacing(); @@ -1855,6 +1856,38 @@ void tst_QQuickListView::swapWithFirstItem() delete testObject; } +void tst_QQuickListView::checkCountForMultiColumnModels() +{ + // Check that a list view will only load items for the first + // column, even if the model reports that it got several columns. + // We test this since QQmlDelegateModel has been changed to + // also understand multi-column models, but this should not affect ListView. + QScopedPointer<QQuickView> window(createView()); + + const int rowCount = 10; + const int columnCount = 10; + + QaimModel model; + model.columns = columnCount; + for (int i = 0; i < rowCount; i++) + model.addItem("Item" + QString::number(i), ""); + + QQmlContext *ctxt = window->rootContext(); + ctxt->setContextProperty("testModel", &model); + + QScopedPointer<TestObject> testObject(new TestObject); + ctxt->setContextProperty("testObject", testObject.data()); + + window->setSource(testFileUrl("listviewtest.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); + QTRY_VERIFY(listview != nullptr); + + QCOMPARE(listview->count(), rowCount); +} + void tst_QQuickListView::enforceRange() { QScopedPointer<QQuickView> window(createView()); @@ -5481,38 +5514,50 @@ void tst_QQuickListView::snapOneItem_data() QTest::addColumn<qreal>("snapAlignment"); QTest::addColumn<qreal>("endExtent"); QTest::addColumn<qreal>("startExtent"); + QTest::addColumn<qreal>("flickSlowdown"); QTest::newRow("vertical, top to bottom") << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::NoHighlightRange) - << QPoint(20, 200) << QPoint(20, 20) << 180.0 << 560.0 << 0.0; + << QPoint(20, 200) << QPoint(20, 20) << 180.0 << 560.0 << 0.0 << 1.0; QTest::newRow("vertical, bottom to top") << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop << int(QQuickItemView::NoHighlightRange) - << QPoint(20, 20) << QPoint(20, 200) << -420.0 << -560.0 - 240.0 << -240.0; + << QPoint(20, 20) << QPoint(20, 200) << -420.0 << -560.0 - 240.0 << -240.0 << 1.0; QTest::newRow("horizontal, left to right") << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::NoHighlightRange) - << QPoint(200, 20) << QPoint(20, 20) << 180.0 << 560.0 << 0.0; + << QPoint(200, 20) << QPoint(20, 20) << 180.0 << 560.0 << 0.0 << 1.0; QTest::newRow("horizontal, right to left") << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom << int(QQuickItemView::NoHighlightRange) - << QPoint(20, 20) << QPoint(200, 20) << -420.0 << -560.0 - 240.0 << -240.0; + << QPoint(20, 20) << QPoint(200, 20) << -420.0 << -560.0 - 240.0 << -240.0 << 1.0; QTest::newRow("vertical, top to bottom, enforce range") << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::StrictlyEnforceRange) - << QPoint(20, 200) << QPoint(20, 20) << 180.0 << 580.0 << -20.0; + << QPoint(20, 200) << QPoint(20, 20) << 180.0 << 580.0 << -20.0 << 1.0; QTest::newRow("vertical, bottom to top, enforce range") << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop << int(QQuickItemView::StrictlyEnforceRange) - << QPoint(20, 20) << QPoint(20, 200) << -420.0 << -580.0 - 240.0 << -220.0; + << QPoint(20, 20) << QPoint(20, 200) << -420.0 << -580.0 - 240.0 << -220.0 << 1.0; QTest::newRow("horizontal, left to right, enforce range") << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::StrictlyEnforceRange) - << QPoint(200, 20) << QPoint(20, 20) << 180.0 << 580.0 << -20.0; + << QPoint(200, 20) << QPoint(20, 20) << 180.0 << 580.0 << -20.0 << 1.0; QTest::newRow("horizontal, right to left, enforce range") << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom << int(QQuickItemView::StrictlyEnforceRange) - << QPoint(20, 20) << QPoint(200, 20) << -420.0 << -580.0 - 240.0 << -220.0; + << QPoint(20, 20) << QPoint(200, 20) << -420.0 << -580.0 - 240.0 << -220.0 << 1.0; + + // Using e.g. 120 rather than 95 always went to the next item. + // Ensure this further movement has the same behavior + QTest::newRow("vertical, top to bottom, no more blindspot") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::NoHighlightRange) + << QPoint(20, 200) << QPoint(20, 95) << 180.0 << 560.0 << 0.0 << 6.0; + + // StrictlyEnforceRange should not override valid SnapOneItem decisions + QTest::newRow("vertical, top to bottom, no more blindspot, enforce range") + << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom << int(QQuickItemView::StrictlyEnforceRange) + << QPoint(20, 200) << QPoint(20, 95) << 180.0 << 580.0 << -20.0 << 6.0; } void tst_QQuickListView::snapOneItem() @@ -5526,6 +5571,9 @@ void tst_QQuickListView::snapOneItem() QFETCH(qreal, snapAlignment); QFETCH(qreal, endExtent); QFETCH(qreal, startExtent); + QFETCH(qreal, flickSlowdown); + + qreal flickDuration = 180 * flickSlowdown; QQuickView *window = getView(); QQuickViewTestUtil::moveMouseAway(window); @@ -5550,7 +5598,7 @@ void tst_QQuickListView::snapOneItem() QSignalSpy currentIndexSpy(listview, SIGNAL(currentIndexChanged())); // confirm that a flick hits the next item boundary - flick(window, flickStart, flickEnd, 180); + flick(window, flickStart, flickEnd, flickDuration); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops if (orientation == QQuickListView::Vertical) QCOMPARE(listview->contentY(), snapAlignment); @@ -5564,7 +5612,7 @@ void tst_QQuickListView::snapOneItem() // flick to end do { - flick(window, flickStart, flickEnd, 180); + flick(window, flickStart, flickEnd, flickDuration); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops } while (orientation == QQuickListView::Vertical ? verticalLayoutDirection == QQuickItemView::TopToBottom ? !listview->isAtYEnd() : !listview->isAtYBeginning() @@ -5582,7 +5630,7 @@ void tst_QQuickListView::snapOneItem() // flick to start do { - flick(window, flickEnd, flickStart, 180); + flick(window, flickEnd, flickStart, flickDuration); QTRY_VERIFY(listview->isMoving() == false); // wait until it stops } while (orientation == QQuickListView::Vertical ? verticalLayoutDirection == QQuickItemView::TopToBottom ? !listview->isAtYBeginning() : !listview->isAtYEnd() diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index 5c3729a8cd..fbdd87905b 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -739,7 +739,7 @@ void tst_QQuickLoader::initialPropertyValuesError_data() << (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": No such file or directory")); QTest::newRow("invalid source url") << testFileUrl("initialPropertyValues.error.3.qml") - << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error")); + << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Expected token `:'")); QTest::newRow("invalid initial property values object with invalid property access") << testFileUrl("initialPropertyValues.error.4.qml") << (QStringList() << QString(testFileUrl("initialPropertyValues.error.4.qml").toString() + ":7:5: QML Loader: setSource: value is not an object") @@ -885,7 +885,7 @@ void tst_QQuickLoader::asynchronous_data() << (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": No such file or directory")); QTest::newRow("Invalid component") << testFileUrl("InvalidSourceComponent.qml") - << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error")); + << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Expected token `:'")); } void tst_QQuickLoader::asynchronous() diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST index cab6e2f7bf..cdb3e7733b 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST +++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST @@ -1,4 +1,6 @@ [nonOverlapping] ubuntu-16.04 +ubuntu-18.04 [nested] ubuntu-16.04 +ubuntu-18.04 diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index e6c03d052c..7d297d3fa2 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -367,6 +367,10 @@ void tst_QQuickPathView::insertModel_data() void tst_QQuickPathView::insertModel() { +#ifdef Q_OS_MACOS + QSKIP("this test currently crashes on MacOS. See QTBUG-68048"); +#endif + QFETCH(int, mode); QFETCH(int, idx); QFETCH(int, count); @@ -773,6 +777,10 @@ void tst_QQuickPathView::path() void tst_QQuickPathView::dataModel() { +#ifdef Q_OS_MACOS + QSKIP("this test currently crashes on MacOS. See QTBUG-68047"); +#endif + QScopedPointer<QQuickView> window(createView()); window->show(); diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp index 0395b08f10..ec31acf035 100644 --- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp +++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp @@ -40,6 +40,8 @@ using namespace QQuickViewTestUtil; using namespace QQuickVisualTestUtil; +Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") + class tst_qquickpositioners : public QQmlDataTest { Q_OBJECT @@ -3772,6 +3774,10 @@ void tst_qquickpositioners::test_mirroring() QList<QString> objectNames; objectNames << "one" << "two" << "three" << "four" << "five"; +#ifdef Q_OS_MACOS + qputenv("QSG_RENDER_LOOP","basic"); // QTBUG-69040 +#endif + foreach (const QString qmlFile, qmlFiles) { QScopedPointer<QQuickView> windowA(createView(testFile(qmlFile))); QQuickItem *rootA = qobject_cast<QQuickItem*>(windowA->rootObject()); @@ -4007,15 +4013,19 @@ void tst_qquickpositioners::test_attachedproperties_dynamic() QQuickView *tst_qquickpositioners::createView(const QString &filename, bool wait) { QQuickView *window = new QQuickView(nullptr); - qDebug() << "1"; + qCDebug(lcTests) << "created window"; window->setSource(QUrl::fromLocalFile(filename)); - qDebug() << "2"; + qCDebug(lcTests) << "loaded content from" << filename; window->show(); - qDebug() << "3"; + qCDebug(lcTests) << "window shown"; + bool exposed = true; if (wait) - QTest::qWaitForWindowExposed(window); //It may not relayout until the next frame, so it needs to be drawn - qDebug() << "4"; + exposed = QTest::qWaitForWindowExposed(window); //It may not relayout until the next frame, so it needs to be drawn + if (exposed) + qCDebug(lcTests) << "window exposed"; + else + qCWarning(lcTests) << "window NOT exposed"; return window; } diff --git a/tests/auto/quick/qquickrectangle/data/gradient-preset.qml b/tests/auto/quick/qquickrectangle/data/gradient-preset.qml new file mode 100644 index 0000000000..b740bdd610 --- /dev/null +++ b/tests/auto/quick/qquickrectangle/data/gradient-preset.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 + +Item { + Rectangle { + objectName: "enum" + gradient: Gradient.NightFade + } + Rectangle { + objectName: "string" + gradient: "NightFade" + } + Rectangle { + objectName: "invalid" + gradient: -1 + } +} diff --git a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp index 2aaad867bf..f6ca999cf5 100644 --- a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp +++ b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp @@ -49,6 +49,7 @@ private slots: void gradient_border(); void gradient_separate(); void gradient_multiple(); + void gradient_preset(); void antialiasing(); private: @@ -84,7 +85,7 @@ void tst_qquickrectangle::gradient() QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(component.create()); QVERIFY(rect); - QQuickGradient *grad = rect->gradient(); + QQuickGradient *grad = qobject_cast<QQuickGradient *>(rect->gradient().toQObject()); QVERIFY(grad); QQmlListProperty<QQuickGradientStop> stops = grad->stops(); @@ -103,7 +104,7 @@ void tst_qquickrectangle::gradient() QMetaObject::invokeMethod(rect, "resetGradient"); - grad = rect->gradient(); + grad = qobject_cast<QQuickGradient *>(rect->gradient().toQObject()); QVERIFY(!grad); delete rect; @@ -174,6 +175,29 @@ void tst_qquickrectangle::gradient_multiple() QVERIFY(secondIsDirty); } +void tst_qquickrectangle::gradient_preset() +{ + QQuickView view; + view.setSource(testFileUrl("gradient-preset.qml")); + view.show(); + + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QQuickRectangle *enumRect = view.rootObject()->findChild<QQuickRectangle *>("enum"); + QVERIFY(enumRect); + QVERIFY(enumRect->gradient().isNumber()); + QCOMPARE(enumRect->gradient().toUInt(), QGradient::NightFade); + + QQuickRectangle *stringRect = view.rootObject()->findChild<QQuickRectangle *>("string"); + QVERIFY(stringRect); + QVERIFY(stringRect->gradient().isString()); + QCOMPARE(stringRect->gradient().toString(), QLatin1String("NightFade")); + + QQuickRectangle *invalidRect = view.rootObject()->findChild<QQuickRectangle *>("invalid"); + QVERIFY(invalidRect); + QVERIFY(invalidRect->gradient().isUndefined()); +} + void tst_qquickrectangle::antialiasing() { QQmlComponent component(&engine); diff --git a/tests/auto/quick/qquickrepeater/data/ownership.qml b/tests/auto/quick/qquickrepeater/data/ownership.qml new file mode 100644 index 0000000000..e13df3ab3a --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/ownership.qml @@ -0,0 +1,4 @@ +import QtQuick 2.0 + +Repeater { +} diff --git a/tests/auto/quick/qquickrepeater/data/package.qml b/tests/auto/quick/qquickrepeater/data/package.qml new file mode 100644 index 0000000000..1f9eb0d970 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/package.qml @@ -0,0 +1,35 @@ +import QtQuick 2.0 +import QtQml.Models 2.2 +import QtQuick.Window 2.0 + +Window { + width: 300 + height: 300 + visible: true + DelegateModel { + id: mdl + + model: 1 + delegate: Package { + Item { + id: first + Package.name: "first" + objectName: "firstItem" + } + Item{ + id: second + Package.name: "second" + objectName: "secondItem" + } + } + } + + Repeater { + id: repeater1 + model: mdl.parts.first + } + Repeater { + id: repeater2 + model: mdl.parts.second + } +} diff --git a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp index 0499e2f9a6..0860956224 100644 --- a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp +++ b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp @@ -37,6 +37,7 @@ #include <QtQuick/private/qquicktext_p.h> #include <QtQml/private/qqmllistmodel_p.h> #include <QtQml/private/qqmlobjectmodel_p.h> +#include <QtGui/qstandarditemmodel.h> #include "../../shared/util.h" #include "../shared/viewtestutil.h" @@ -76,6 +77,8 @@ private slots: void stackingOrder(); void objectModel(); void QTBUG54859_asynchronousMove(); + void package(); + void ownership(); }; class TestObject : public QObject @@ -1014,6 +1017,91 @@ void tst_QQuickRepeater::QTBUG54859_asynchronousMove() QTRY_COMPARE(item->property("finished"), QVariant(true)); } +void tst_QQuickRepeater::package() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("package.qml")); + + QScopedPointer<QObject>o(component.create()); // don't crash! + QVERIFY(o != nullptr); + + { + QQuickRepeater *repeater1 = qobject_cast<QQuickRepeater*>(qmlContext(o.data())->contextProperty("repeater1").value<QObject*>()); + QVERIFY(repeater1); + QCOMPARE(repeater1->count(), 1); + QCOMPARE(repeater1->itemAt(0)->objectName(), "firstItem"); + } + + { + QQuickRepeater *repeater2 = qobject_cast<QQuickRepeater*>(qmlContext(o.data())->contextProperty("repeater2").value<QObject*>()); + QVERIFY(repeater2); + QCOMPARE(repeater2->count(), 1); + QCOMPARE(repeater2->itemAt(0)->objectName(), "secondItem"); + } +} + +void tst_QQuickRepeater::ownership() +{ + QQmlEngine engine; + + QQmlComponent component(&engine, testFileUrl("ownership.qml")); + + QScopedPointer<QAbstractItemModel> aim(new QStandardItemModel); + QPointer<QAbstractItemModel> modelGuard(aim.data()); + QQmlEngine::setObjectOwnership(aim.data(), QQmlEngine::JavaScriptOwnership); + { + QJSValue wrapper = engine.newQObject(aim.data()); + } + + QScopedPointer<QObject> repeater(component.create()); + QVERIFY(!repeater.isNull()); + + QVERIFY(!QQmlData::keepAliveDuringGarbageCollection(aim.data())); + + repeater->setProperty("model", QVariant::fromValue<QObject*>(aim.data())); + + QVERIFY(!QQmlData::keepAliveDuringGarbageCollection(aim.data())); + + engine.collectGarbage(); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); + + QVERIFY(modelGuard); + + QScopedPointer<QQmlComponent> delegate(new QQmlComponent(&engine)); + delegate->setData(QByteArrayLiteral("import QtQuick 2.0\nItem{}"), dataDirectoryUrl().resolved(QUrl("inline.qml"))); + QPointer<QQmlComponent> delegateGuard(delegate.data()); + QQmlEngine::setObjectOwnership(delegate.data(), QQmlEngine::JavaScriptOwnership); + { + QJSValue wrapper = engine.newQObject(delegate.data()); + } + + QVERIFY(!QQmlData::keepAliveDuringGarbageCollection(delegate.data())); + + repeater->setProperty("delegate", QVariant::fromValue<QObject*>(delegate.data())); + + QVERIFY(!QQmlData::keepAliveDuringGarbageCollection(delegate.data())); + + engine.collectGarbage(); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); + + QVERIFY(delegateGuard); + + repeater->setProperty("model", QVariant()); + repeater->setProperty("delegate", QVariant()); + + QVERIFY(delegateGuard); + QVERIFY(modelGuard); + + delegate.take(); + aim.take(); + + engine.collectGarbage(); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); + + QVERIFY(!delegateGuard); + QVERIFY(!modelGuard); +} + QTEST_MAIN(tst_QQuickRepeater) #include "tst_qquickrepeater.moc" diff --git a/tests/auto/quick/qquickshape/qquickshape.pro b/tests/auto/quick/qquickshape/qquickshape.pro index 29c3502b86..a0e5c002e0 100644 --- a/tests/auto/quick/qquickshape/qquickshape.pro +++ b/tests/auto/quick/qquickshape/qquickshape.pro @@ -9,27 +9,5 @@ include (../shared/util.pri) TESTDATA = data/* -HEADERS += \ - ../../../../src/imports/shapes/qquickshape_p.h \ - ../../../../src/imports/shapes/qquickshape_p_p.h \ - ../../../../src/imports/shapes/qquickshapegenericrenderer_p.h \ - ../../../../src/imports/shapes/qquickshapesoftwarerenderer_p.h - -SOURCES += \ - ../../../../src/imports/shapes/qquickshape.cpp \ - ../../../../src/imports/shapes/qquickshapegenericrenderer.cpp \ - ../../../../src/imports/shapes/qquickshapesoftwarerenderer.cpp - -qtConfig(opengl) { - HEADERS += \ - ../../../../src/imports/shapes/qquicknvprfunctions_p.h \ - ../../../../src/imports/shapes/qquicknvprfunctions_p_p.h \ - ../../../../src/imports/shapes/qquickshapenvprrenderer_p.h - - SOURCES += \ - ../../../../src/imports/shapes/qquicknvprfunctions.cpp \ - ../../../../src/imports/shapes/qquickshapenvprrenderer.cpp -} - -QT += core-private gui-private qml-private quick-private testlib +QT += core-private gui-private qml-private quick-private testlib quickshapes-private qtHaveModule(widgets): QT += widgets diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp index 2a349d2013..72f987ce4a 100644 --- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp +++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp @@ -33,7 +33,7 @@ #include <QtQml/qqmlcontext.h> #include <QtQml/qqmlexpression.h> #include <QtQml/qqmlincubator.h> -#include "../../../../src/imports/shapes/qquickshape_p.h" +#include <QtQuickShapes/private/qquickshape_p.h> #include "../../shared/util.h" #include "../shared/viewtestutil.h" diff --git a/tests/auto/quick/qquicktableview/data/countingtableview.qml b/tests/auto/quick/qquicktableview/data/countingtableview.qml new file mode 100644 index 0000000000..d8315be54f --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/countingtableview.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Window 2.3 +import Qt.labs.tableview 1.0 + +Item { + id: root + width: 640 + height: 450 + + property alias tableView: tableView + property int currentDelegateCount: 0 + property int maxDelegateCount: 0 + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + cacheBuffer: 0 + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + TableView.cellWidth: 100 + TableView.cellHeight: 50 + color: "lightgray" + border.width: 1 + Text { + anchors.centerIn: parent + text: modelData + } + Component.onCompleted: { + currentDelegateCount++; + maxDelegateCount = Math.max(maxDelegateCount, currentDelegateCount); + } + Component.onDestruction: { + currentDelegateCount--; + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/plaintableview.qml b/tests/auto/quick/qquicktableview/data/plaintableview.qml new file mode 100644 index 0000000000..7668f0ca01 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/plaintableview.qml @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Window 2.3 +import Qt.labs.tableview 1.0 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + property real delegateWidth: 100 + property real delegateHeight: 50 + property Component delegate: tableViewDelegate + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + cacheBuffer: 0 + columnSpacing: 1 + rowSpacing: 1 + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + TableView.cellWidth: delegateWidth + TableView.cellHeight: delegateHeight + color: "lightgray" + border.width: 1 + Text { + anchors.centerIn: parent + text: modelData + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml b/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml new file mode 100644 index 0000000000..65e4d0861c --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Window 2.3 +import Qt.labs.tableview 1.0 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + cacheBuffer: 0 + columnSpacing: 1 + rowSpacing: 1 + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + color: "lightgray" + border.width: 1 + implicitWidth: 90 + implicitHeight: 60 + Text { + anchors.centerIn: parent + text: modelData + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/qquicktableview.pro b/tests/auto/quick/qquicktableview/qquicktableview.pro new file mode 100644 index 0000000000..f4d0265dd3 --- /dev/null +++ b/tests/auto/quick/qquicktableview/qquicktableview.pro @@ -0,0 +1,14 @@ +CONFIG += testcase +TARGET = tst_qquicktableview +macos:CONFIG -= app_bundle + +HEADERS += testmodel.h +SOURCES += tst_qquicktableview.cpp + +include (../../shared/util.pri) +include (../shared/util.pri) + +TESTDATA = data/* + +QT += core-private gui-private qml-private quick-private testlib + diff --git a/tests/auto/quick/qquicktableview/testmodel.h b/tests/auto/quick/qquicktableview/testmodel.h new file mode 100644 index 0000000000..06384f7a5e --- /dev/null +++ b/tests/auto/quick/qquicktableview/testmodel.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QtCore> +#include <QtGui/QStandardItemModel> + +class TestModel : public QAbstractTableModel +{ + Q_OBJECT + Q_PROPERTY(int rowCount READ rowCount WRITE setRowCount NOTIFY rowCountChanged) + Q_PROPERTY(int columnCount READ columnCount WRITE setColumnCount NOTIFY columnCountChanged) + +public: + TestModel(QObject *parent = nullptr) + : QAbstractTableModel(parent) + {} + + TestModel(int rows, int columns, QObject *parent = nullptr) + : QAbstractTableModel(parent) + , m_rows(rows) + , m_columns(columns) + {} + + int rowCount(const QModelIndex & = QModelIndex()) const override { return m_rows; } + void setRowCount(int count) { beginResetModel(); m_rows = count; emit rowCountChanged(); endResetModel(); } + + int columnCount(const QModelIndex & = QModelIndex()) const override { return m_columns; } + void setColumnCount(int count) { beginResetModel(); m_columns = count; emit columnCountChanged(); endResetModel(); } + + QVariant data(const QModelIndex &index, int role) const override + { + if (!index.isValid() || role != Qt::DisplayRole) + return QVariant(); + + int cell = index.row() + (index.column() * m_columns); + if (selectedCells.contains(cell)) + return QStringLiteral("selected"); + return QString("%1").arg(index.row()); + } + + QHash<int, QByteArray> roleNames() const override + { + return { {Qt::DisplayRole, "display"} }; + } + + Q_INVOKABLE void selectCell(int row, int column) + { + int cell = row + (column * m_columns); + selectedCells.insert(cell); + auto index = createIndex(row, column, nullptr); + emit dataChanged(index, index); + } + +signals: + void rowCountChanged(); + void columnCountChanged(); + +private: + int m_rows = 0; + int m_columns = 0; + QSet<int> selectedCells; +}; + +#define TestModelAsVariant(...) QVariant::fromValue(QSharedPointer<TestModel>(new TestModel(__VA_ARGS__))) diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp new file mode 100644 index 0000000000..8caced4396 --- /dev/null +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -0,0 +1,791 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <QtQuick/qquickview.h> +#include <QtQuick/private/qquicktableview_p.h> +#include <QtQuick/private/qquicktableview_p_p.h> + +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlexpression.h> +#include <QtQml/qqmlincubator.h> +#include <QtQml/private/qqmlobjectmodel_p.h> +#include <QtQml/private/qqmllistmodel_p.h> +#include <QtQml/private/qqmldelegatemodel_p.h> + +#include "testmodel.h" + +#include "../../shared/util.h" +#include "../shared/viewtestutil.h" +#include "../shared/visualtestutil.h" + +using namespace QQuickViewTestUtil; +using namespace QQuickVisualTestUtil; + +static const char* kTableViewPropName = "tableView"; +static const char* kDelegateObjectName = "tableViewDelegate"; + +Q_DECLARE_METATYPE(QMarginsF); + +#define LOAD_TABLEVIEW(fileName) \ + QScopedPointer<QQuickView> view(createView()); \ + view->setSource(testFileUrl(fileName)); \ + view->show(); \ + QVERIFY(QTest::qWaitForWindowActive(view.data())); \ + auto tableView = view->rootObject()->property(kTableViewPropName).value<QQuickTableView *>(); \ + QVERIFY(tableView); \ + auto tableViewPrivate = QQuickTableViewPrivate::get(tableView); \ + Q_UNUSED(tableViewPrivate) + +#define WAIT_UNTIL_POLISHED \ + QVERIFY(tableViewPrivate->polishScheduled); \ + QTRY_VERIFY(!tableViewPrivate->polishScheduled) + +class tst_QQuickTableView : public QQmlDataTest +{ + Q_OBJECT +public: + tst_QQuickTableView(); + + QQuickTableViewAttached *getAttachedObject(const QObject *object) const; + QPoint getContextRowAndColumn(const QQuickItem *item) const; + +private slots: + void initTestCase() override; + + void setAndGetModel_data(); + void setAndGetModel(); + void emptyModel_data(); + void emptyModel(); + void checkZeroSizedDelegate(); + void checkImplicitSizeDelegate(); + void noDelegate(); + void countDelegateItems_data(); + void countDelegateItems(); + void checkLayoutOfEqualSizedDelegateItems_data(); + void checkLayoutOfEqualSizedDelegateItems(); + void checkTableMargins_data(); + void checkTableMargins(); + void fillTableViewButNothingMore_data(); + void fillTableViewButNothingMore(); + void checkInitialAttachedProperties_data(); + void checkInitialAttachedProperties(); + void flick_data(); + void flick(); + void flickOvershoot_data(); + void flickOvershoot(); + void checkRowColumnCount(); +}; + +tst_QQuickTableView::tst_QQuickTableView() +{ +} + +void tst_QQuickTableView::initTestCase() +{ + QQmlDataTest::initTestCase(); + qmlRegisterType<TestModel>("TestModel", 0, 1, "TestModel"); +} + +QQuickTableViewAttached *tst_QQuickTableView::getAttachedObject(const QObject *object) const +{ + QObject *attachedObject = qmlAttachedPropertiesObject<QQuickTableView>(object); + return static_cast<QQuickTableViewAttached *>(attachedObject); +} + +QPoint tst_QQuickTableView::getContextRowAndColumn(const QQuickItem *item) const +{ + const auto context = qmlContext(item); + const int row = context->contextProperty("row").toInt(); + const int column = context->contextProperty("column").toInt(); + return QPoint(column, row); +} + +void tst_QQuickTableView::setAndGetModel_data() +{ + QTest::addColumn<QVariant>("model"); + + QTest::newRow("QAIM 1x1") << TestModelAsVariant(1, 1); + QTest::newRow("Number model 1") << QVariant::fromValue(1); + QTest::newRow("QStringList 1") << QVariant::fromValue(QStringList() << "one"); +} + +void tst_QQuickTableView::setAndGetModel() +{ + // Test that we can set and get different kind of models + QFETCH(QVariant, model); + LOAD_TABLEVIEW("plaintableview.qml"); + + tableView->setModel(model); + QCOMPARE(model, tableView->model()); +} + +void tst_QQuickTableView::emptyModel_data() +{ + QTest::addColumn<QVariant>("model"); + + QTest::newRow("QAIM") << TestModelAsVariant(0, 0); + QTest::newRow("Number model") << QVariant::fromValue(0); + QTest::newRow("QStringList") << QVariant::fromValue(QStringList()); +} + +void tst_QQuickTableView::emptyModel() +{ + // Check that if we assign an empty model to + // TableView, no delegate items will be created. + QFETCH(QVariant, model); + LOAD_TABLEVIEW("plaintableview.qml"); + + tableView->setModel(model); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableViewPrivate->loadedItems.count(), 0); +} + +void tst_QQuickTableView::checkZeroSizedDelegate() +{ + // Check that if we assign a delegate with empty width and height, we + // fall back to use kDefaultColumnWidth and kDefaultRowHeight as + // column/row sizes. + LOAD_TABLEVIEW("plaintableview.qml"); + + auto model = TestModelAsVariant(100, 100); + tableView->setModel(model); + + view->rootObject()->setProperty("delegateWidth", 0); + view->rootObject()->setProperty("delegateHeight", 0); + + WAIT_UNTIL_POLISHED; + + auto items = tableViewPrivate->loadedItems; + QVERIFY(!items.isEmpty()); + + for (auto fxItem : tableViewPrivate->loadedItems) { + auto item = fxItem->item; + QCOMPARE(item->width(), kDefaultColumnWidth); + QCOMPARE(item->height(), kDefaultRowHeight); + } +} + +void tst_QQuickTableView::checkImplicitSizeDelegate() +{ + // Check that we can set the size of delegate items using + // implicit width/height, instead of forcing the user to + // create an attached object by using TableView.cellWidth/Height. + LOAD_TABLEVIEW("tableviewimplicitsize.qml"); + + auto model = TestModelAsVariant(100, 100); + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + auto items = tableViewPrivate->loadedItems; + QVERIFY(!items.isEmpty()); + + for (auto fxItem : tableViewPrivate->loadedItems) { + auto item = fxItem->item; + QCOMPARE(item->width(), 90); + QCOMPARE(item->height(), 60); + } +} + +void tst_QQuickTableView::noDelegate() +{ + // Check that you can skip setting a delegate without + // it causing any problems (like crashing or asserting). + // And then set a delegate, and do a quick check that the + // view gets populated as expected. + LOAD_TABLEVIEW("plaintableview.qml"); + + const int rows = 5; + const int columns = 5; + auto model = TestModelAsVariant(columns, rows); + tableView->setModel(model); + + // Start with no delegate, and check + // that we end up with no items in the table. + tableView->setDelegate(nullptr); + + WAIT_UNTIL_POLISHED; + + auto items = tableViewPrivate->loadedItems; + QVERIFY(items.isEmpty()); + + // Set a delegate, and check that we end + // up with the expected number of items. + auto delegate = view->rootObject()->property("delegate").value<QQmlComponent *>(); + QVERIFY(delegate); + tableView->setDelegate(delegate); + + WAIT_UNTIL_POLISHED; + + items = tableViewPrivate->loadedItems; + QCOMPARE(items.count(), rows * columns); + + // And then unset the delegate again, and check + // that we end up with no items. + tableView->setDelegate(nullptr); + + WAIT_UNTIL_POLISHED; + + items = tableViewPrivate->loadedItems; + QVERIFY(items.isEmpty()); +} + +void tst_QQuickTableView::countDelegateItems_data() +{ + QTest::addColumn<QVariant>("model"); + QTest::addColumn<int>("count"); + + QTest::newRow("QAIM 1x1") << TestModelAsVariant(1, 1) << 1; + QTest::newRow("QAIM 2x1") << TestModelAsVariant(2, 1) << 2; + QTest::newRow("QAIM 1x2") << TestModelAsVariant(1, 2) << 2; + QTest::newRow("QAIM 2x2") << TestModelAsVariant(2, 2) << 4; + QTest::newRow("QAIM 4x4") << TestModelAsVariant(4, 4) << 16; + + QTest::newRow("Number model 1") << QVariant::fromValue(1) << 1; + QTest::newRow("Number model 4") << QVariant::fromValue(4) << 4; + + QTest::newRow("QStringList 1") << QVariant::fromValue(QStringList() << "one") << 1; + QTest::newRow("QStringList 4") << QVariant::fromValue(QStringList() << "one" << "two" << "three" << "four") << 4; +} + +void tst_QQuickTableView::countDelegateItems() +{ + // Assign different models of various sizes, and check that the number of + // delegate items in the view matches the size of the model. Note that for + // this test to be valid, all items must be within the visible area of the view. + QFETCH(QVariant, model); + QFETCH(int, count); + LOAD_TABLEVIEW("plaintableview.qml"); + + tableView->setModel(model); + WAIT_UNTIL_POLISHED; + + // Check that tableview internals contain the expected number of items + auto const items = tableViewPrivate->loadedItems; + QCOMPARE(items.count(), count); + + // Check that this also matches the items found in the view + auto foundItems = findItems<QQuickItem>(tableView, kDelegateObjectName); + QCOMPARE(foundItems.count(), count); +} + +void tst_QQuickTableView::checkLayoutOfEqualSizedDelegateItems_data() +{ + QTest::addColumn<QVariant>("model"); + QTest::addColumn<QSize>("tableSize"); + QTest::addColumn<QSizeF>("spacing"); + QTest::addColumn<QMarginsF>("margins"); + + // Check spacing together with different table setups + QTest::newRow("QAIM 1x1 1,1") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0); + QTest::newRow("QAIM 5x5 0,0") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0); + QTest::newRow("QAIM 5x5 1,0") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(1, 0) << QMarginsF(0, 0, 0, 0); + QTest::newRow("QAIM 5x5 0,1") << TestModelAsVariant(5, 5) << QSize(5, 5) << QSizeF(0, 1) << QMarginsF(0, 0, 0, 0); + + // Check spacing together with margins + QTest::newRow("QAIM 1x1 1,1 5555") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(5, 5, 5, 5); + QTest::newRow("QAIM 4x4 0,0 3333") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(0, 0) << QMarginsF(3, 3, 3, 3); + QTest::newRow("QAIM 4x4 2,2 1234") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(2, 2) << QMarginsF(1, 2, 3, 4); + + // Check "list" models + QTest::newRow("NumberModel 1x4, 0000") << QVariant::fromValue(4) << QSize(1, 4) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0); + QTest::newRow("QStringList 1x4, 0,0 1111") << QVariant::fromValue(QStringList() << "one" << "two" << "three" << "four") + << QSize(1, 4) << QSizeF(0, 0) << QMarginsF(1, 1, 1, 1); +} + +void tst_QQuickTableView::checkLayoutOfEqualSizedDelegateItems() +{ + // Check that the geometry of the delegate items are correct + QFETCH(QVariant, model); + QFETCH(QSize, tableSize); + QFETCH(QSizeF, spacing); + QFETCH(QMarginsF, margins); + LOAD_TABLEVIEW("plaintableview.qml"); + + const qreal expectedItemWidth = 100; + const qreal expectedItemHeight = 50; + const int expectedItemCount = tableSize.width() * tableSize.height(); + + tableView->setModel(model); + tableView->setRowSpacing(spacing.height()); + tableView->setColumnSpacing(spacing.width()); + tableView->setLeftMargin(margins.left()); + tableView->setTopMargin(margins.top()); + tableView->setRightMargin(margins.right()); + tableView->setBottomMargin(margins.bottom()); + + WAIT_UNTIL_POLISHED; + + auto const items = tableViewPrivate->loadedItems; + QVERIFY(!items.isEmpty()); + + for (int i = 0; i < expectedItemCount; ++i) { + const QQuickItem *item = items[i]->item; + QVERIFY(item); + QCOMPARE(item->parentItem(), tableView->contentItem()); + + const QPoint cell = getContextRowAndColumn(item); + qreal expectedX = margins.left() + (cell.x() * (expectedItemWidth + spacing.width())); + qreal expectedY = margins.top() + (cell.y() * (expectedItemHeight + spacing.height())); + QCOMPARE(item->x(), expectedX); + QCOMPARE(item->y(), expectedY); + QCOMPARE(item->width(), expectedItemWidth); + QCOMPARE(item->height(), expectedItemHeight); + } +} + +void tst_QQuickTableView::checkTableMargins_data() +{ + QTest::addColumn<QVariant>("model"); + QTest::addColumn<QSize>("tableSize"); + QTest::addColumn<QSizeF>("spacing"); + QTest::addColumn<QMarginsF>("margins"); + + QTest::newRow("QAIM 1x1 1,1 0000") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0); + QTest::newRow("QAIM 4x4 1,1 0000") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(1, 1) << QMarginsF(0, 0, 0, 0); + QTest::newRow("QAIM 1x1 1,1 5555") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(1, 1) << QMarginsF(5, 5, 5, 5); + QTest::newRow("QAIM 4x4 0,0 3333") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(0, 0) << QMarginsF(3, 3, 3, 3); + QTest::newRow("QAIM 4x4 2,2 1234") << TestModelAsVariant(4, 4) << QSize(4, 4) << QSizeF(2, 2) << QMarginsF(1, 2, 3, 4); + QTest::newRow("QAIM 1x1 0,0 3210") << TestModelAsVariant(1, 1) << QSize(1, 1) << QSizeF(0, 0) << QMarginsF(3, 2, 1, 0); +} + +void tst_QQuickTableView::checkTableMargins() +{ + // Check that the space between the content view and + // the items matches the margins we set on the tableview. + QFETCH(QVariant, model); + QFETCH(QSize, tableSize); + QFETCH(QSizeF, spacing); + QFETCH(QMarginsF, margins); + LOAD_TABLEVIEW("plaintableview.qml"); + + tableView->setModel(model); + tableView->setRowSpacing(spacing.height()); + tableView->setColumnSpacing(spacing.width()); + tableView->setLeftMargin(margins.left()); + tableView->setTopMargin(margins.top()); + tableView->setRightMargin(margins.right()); + tableView->setBottomMargin(margins.bottom()); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->loadedTable.size(), tableSize); + + auto const topLeftFxItem = tableViewPrivate->loadedTableItem(QPoint(0, 0)); + auto const bottomRightFxItem = tableViewPrivate->loadedTableItem(tableViewPrivate->loadedTable.bottomRight()); + auto const topLeftItem = topLeftFxItem->item; + auto const bottomRightItem = bottomRightFxItem->item; + + qreal leftSpace = topLeftItem->x(); + qreal topSpace = topLeftItem->y(); + qreal rightSpace = tableView->contentWidth() - (bottomRightItem->x() + bottomRightItem->width()); + qreal bottomSpace = tableView->contentHeight() - (bottomRightItem->y() + bottomRightItem->height()); + QCOMPARE(leftSpace, margins.left()); + QCOMPARE(topSpace, margins.top()); + QCOMPARE(rightSpace, margins.right()); + QCOMPARE(bottomSpace, margins.bottom()); +} + +void tst_QQuickTableView::fillTableViewButNothingMore_data() +{ + QTest::addColumn<QSizeF>("spacing"); + QTest::addColumn<QMarginsF>("margins"); + + QTest::newRow("0 0,0 0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0); + QTest::newRow("0 10,10 0") << QSizeF(10, 10) << QMarginsF(0, 0, 0, 0); + QTest::newRow("100 10,10 0") << QSizeF(10, 10) << QMarginsF(0, 0, 0, 0); + QTest::newRow("0 0,0 100") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0); + QTest::newRow("0 10,10 100") << QSizeF(10, 10) << QMarginsF(100, 100, 100, 100); + QTest::newRow("100 10,10 100") << QSizeF(10, 10) << QMarginsF(100, 100, 100, 100); +} + +void tst_QQuickTableView::fillTableViewButNothingMore() +{ + // Check that we end up filling the whole visible part of + // the tableview with cells, but nothing more. + QFETCH(QSizeF, spacing); + QFETCH(QMarginsF, margins); + LOAD_TABLEVIEW("plaintableview.qml"); + + const int rows = 100; + const int columns = 100; + auto model = TestModelAsVariant(rows, columns); + + tableView->setModel(model); + tableView->setRowSpacing(spacing.height()); + tableView->setColumnSpacing(spacing.width()); + tableView->setLeftMargin(margins.left()); + tableView->setTopMargin(margins.top()); + tableView->setRightMargin(margins.right()); + tableView->setBottomMargin(margins.bottom()); + tableView->setCacheBuffer(0); + + WAIT_UNTIL_POLISHED; + + auto const topLeftFxItem = tableViewPrivate->loadedTableItem(QPoint(0, 0)); + auto const topLeftItem = topLeftFxItem->item; + + // Check that the top-left item are at the corner of the view + QCOMPARE(topLeftItem->x(), margins.left()); + QCOMPARE(topLeftItem->y(), margins.top()); + + auto const bottomRightFxItem = tableViewPrivate->loadedTableItem(tableViewPrivate->loadedTable.bottomRight()); + auto const bottomRightItem = bottomRightFxItem->item; + const QPoint bottomRightCell = getContextRowAndColumn(bottomRightItem.data()); + + // Check that the right-most item is overlapping the right edge of the view + QVERIFY(bottomRightItem->x() < tableView->width()); + QVERIFY(bottomRightItem->x() + bottomRightItem->width() >= tableView->width() - spacing.width()); + + // Check that the actual number of columns matches what we expect + qreal cellWidth = bottomRightItem->width() + spacing.width(); + qreal availableWidth = tableView->width() - margins.left(); + int expectedColumns = qCeil(availableWidth / cellWidth); + int actualColumns = bottomRightCell.x() + 1; + QCOMPARE(actualColumns, expectedColumns); + + // Check that the bottom-most item is overlapping the bottom edge of the view + QVERIFY(bottomRightItem->y() < tableView->height()); + QVERIFY(bottomRightItem->y() + bottomRightItem->height() >= tableView->height() - spacing.height()); + + // Check that the actual number of rows matches what we expect + qreal cellHeight = bottomRightItem->height() + spacing.height(); + qreal availableHeight = tableView->height() - margins.top(); + int expectedRows = qCeil(availableHeight / cellHeight); + int actualRows = bottomRightCell.y() + 1; + QCOMPARE(actualRows, expectedRows); +} + +void tst_QQuickTableView::checkInitialAttachedProperties_data() +{ + QTest::addColumn<QVariant>("model"); + + QTest::newRow("QAIM") << TestModelAsVariant(4, 4); + QTest::newRow("Number model") << QVariant::fromValue(4); + QTest::newRow("QStringList") << QVariant::fromValue(QStringList() << "0" << "1" << "2" << "3"); +} + +void tst_QQuickTableView::checkInitialAttachedProperties() +{ + // Check that the context and attached properties inside + // the delegate items are what we expect at start-up. + QFETCH(QVariant, model); + LOAD_TABLEVIEW("plaintableview.qml"); + + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + for (auto fxItem : tableViewPrivate->loadedItems) { + const int index = fxItem->index; + const auto item = fxItem->item; + const auto context = qmlContext(item.data()); + const QPoint cell = tableViewPrivate->cellAtModelIndex(index); + const int contextIndex = context->contextProperty("index").toInt(); + const QPoint contextCell = getContextRowAndColumn(item.data()); + const QString contextModelData = context->contextProperty("modelData").toString(); + const QQmlDelegateModelAttached *delegateModelAttached = + static_cast<QQmlDelegateModelAttached *>( + qmlAttachedPropertiesObject<QQmlDelegateModel>(item)); + const int contextItemsIndex = delegateModelAttached->property("itemsIndex").toInt(); + + QCOMPARE(contextCell.y(), cell.y()); + QCOMPARE(contextCell.x(), cell.x()); + QCOMPARE(contextIndex, index); + QCOMPARE(contextModelData, QStringLiteral("%1").arg(cell.y())); + QCOMPARE(contextItemsIndex, index); + } +} + +void tst_QQuickTableView::flick_data() +{ + QTest::addColumn<QSizeF>("spacing"); + QTest::addColumn<QMarginsF>("margins"); + + QTest::newRow("s:0 m:0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0); + QTest::newRow("s:5 m:0") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0); + QTest::newRow("s:0 m:20") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20); + QTest::newRow("s:5 m:20") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20); +} + +void tst_QQuickTableView::flick() +{ + // Check that if we end up with the correct start and end column/row as we flick around + // with different table configurations. + QFETCH(QSizeF, spacing); + QFETCH(QMarginsF, margins); + LOAD_TABLEVIEW("plaintableview.qml"); + + const qreal delegateWidth = 100; + const qreal delegateHeight = 50; + const int visualColumnCount = 4; + const int visualRowCount = 4; + const qreal cellWidth = delegateWidth + spacing.width(); + const qreal cellHeight = delegateHeight + spacing.height(); + auto model = TestModelAsVariant(100, 100); + + tableView->setModel(model); + tableView->setRowSpacing(spacing.height()); + tableView->setColumnSpacing(spacing.width()); + tableView->setLeftMargin(margins.left()); + tableView->setTopMargin(margins.top()); + tableView->setRightMargin(margins.right()); + tableView->setBottomMargin(margins.bottom()); + tableView->setCacheBuffer(0); + tableView->setWidth(margins.left() + (visualColumnCount * cellWidth) - spacing.width()); + tableView->setHeight(margins.top() + (visualRowCount * cellHeight) - spacing.height()); + + WAIT_UNTIL_POLISHED; + + // Check the "simple" case if the cells never lands egde-to-edge with the viewport. For + // that case we only accept that visible row/columns are loaded. + qreal flickValues[] = {0.5, 1.5, 4.5, 20.5, 10.5, 3.5, 1.5, 0.5}; + + for (qreal cellsToFlick : flickValues) { + // Flick to the beginning of the cell + tableView->setContentX(cellsToFlick * cellWidth); + tableView->setContentY(cellsToFlick * cellHeight); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + const QRect loadedTable = tableViewPrivate->loadedTable; + + const int expectedTableLeft = cellsToFlick - int((margins.left() + spacing.width()) / cellWidth); + const int expectedTableTop = cellsToFlick - int((margins.top() + spacing.height()) / cellHeight); + + QCOMPARE(loadedTable.left(), expectedTableLeft); + QCOMPARE(loadedTable.right(), expectedTableLeft + visualColumnCount); + QCOMPARE(loadedTable.top(), expectedTableTop); + QCOMPARE(loadedTable.bottom(), expectedTableTop + visualRowCount); + } +} + +void tst_QQuickTableView::flickOvershoot_data() +{ + QTest::addColumn<QSizeF>("spacing"); + QTest::addColumn<QMarginsF>("margins"); + + QTest::newRow("s:0 m:0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0); + QTest::newRow("s:5 m:0") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0); + QTest::newRow("s:0 m:20") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20); + QTest::newRow("s:5 m:20") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20); +} + +void tst_QQuickTableView::flickOvershoot() +{ + // Flick the table completely out and then in again, and see + // that we still contains the expected rows/columns + // Note that TableView always keeps top-left item loaded, even + // when everything is flicked out of view. + QFETCH(QSizeF, spacing); + QFETCH(QMarginsF, margins); + LOAD_TABLEVIEW("plaintableview.qml"); + + const int rowCount = 5; + const int columnCount = 5; + const qreal delegateWidth = 100; + const qreal delegateHeight = 50; + const qreal cellWidth = delegateWidth + spacing.width(); + const qreal cellHeight = delegateHeight + spacing.height(); + const qreal tableWidth = margins.left() + margins.right() + (cellWidth * columnCount) - spacing.width(); + const qreal tableHeight = margins.top() + margins.bottom() + (cellHeight * rowCount) - spacing.height(); + const int outsideMargin = 10; + auto model = TestModelAsVariant(rowCount, columnCount); + + tableView->setModel(model); + tableView->setRowSpacing(spacing.height()); + tableView->setColumnSpacing(spacing.width()); + tableView->setLeftMargin(margins.left()); + tableView->setTopMargin(margins.top()); + tableView->setRightMargin(margins.right()); + tableView->setBottomMargin(margins.bottom()); + tableView->setCacheBuffer(0); + tableView->setWidth(tableWidth - margins.right() - cellWidth / 2); + tableView->setHeight(tableHeight - margins.bottom() - cellHeight / 2); + + WAIT_UNTIL_POLISHED; + + // Flick table out of view left + tableView->setContentX(-tableView->width() - outsideMargin); + tableView->setContentY(0); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->loadedTable.left(), 0); + QCOMPARE(tableViewPrivate->loadedTable.right(), 0); + QCOMPARE(tableViewPrivate->loadedTable.top(), 0); + QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1); + + // Flick table out of view right + tableView->setContentX(tableWidth + outsideMargin); + tableView->setContentY(0); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->loadedTable.left(), columnCount - 1); + QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1); + QCOMPARE(tableViewPrivate->loadedTable.top(), 0); + QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1); + + // Flick table out of view on top + tableView->setContentX(0); + tableView->setContentY(-tableView->height() - outsideMargin); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->loadedTable.left(), 0); + QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1); + QCOMPARE(tableViewPrivate->loadedTable.top(), 0); + QCOMPARE(tableViewPrivate->loadedTable.bottom(), 0); + + // Flick table out of view at the bottom + tableView->setContentX(0); + tableView->setContentY(tableHeight + outsideMargin); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->loadedTable.left(), 0); + QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1); + QCOMPARE(tableViewPrivate->loadedTable.top(), rowCount - 1); + QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1); + + // Flick table out of view left and top at the same time + tableView->setContentX(-tableView->width() - outsideMargin); + tableView->setContentY(-tableView->height() - outsideMargin); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->loadedTable.left(), 0); + QCOMPARE(tableViewPrivate->loadedTable.right(), 0); + QCOMPARE(tableViewPrivate->loadedTable.top(), 0); + QCOMPARE(tableViewPrivate->loadedTable.bottom(), 0); + + // Flick table back to origo + tableView->setContentX(0); + tableView->setContentY(0); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->loadedTable.left(), 0); + QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1); + QCOMPARE(tableViewPrivate->loadedTable.top(), 0); + QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1); + + // Flick table out of view right and bottom at the same time + tableView->setContentX(tableWidth + outsideMargin); + tableView->setContentY(tableHeight + outsideMargin); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->loadedTable.left(), columnCount - 1); + QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1); + QCOMPARE(tableViewPrivate->loadedTable.top(), rowCount - 1); + QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1); + + // Flick table back to origo + tableView->setContentX(0); + tableView->setContentY(0); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->loadedTable.left(), 0); + QCOMPARE(tableViewPrivate->loadedTable.right(), columnCount - 1); + QCOMPARE(tableViewPrivate->loadedTable.top(), 0); + QCOMPARE(tableViewPrivate->loadedTable.bottom(), rowCount - 1); +} + +void tst_QQuickTableView::checkRowColumnCount() +{ + // If we flick several columns (rows) at the same time, check that we don't + // end up with loading more delegate items into memory than necessary. We + // should free up columns as we go before loading new ones. + LOAD_TABLEVIEW("countingtableview.qml"); + + const char *maxDelegateCountProp = "maxDelegateCount"; + auto model = TestModelAsVariant(100, 100); + + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + const int tableViewCount = tableViewPrivate->loadedItems.count(); + const int qmlCountAfterInit = view->rootObject()->property(maxDelegateCountProp).toInt(); + QCOMPARE(tableViewCount, qmlCountAfterInit); + + // Flick a long distance right + tableView->setContentX(tableView->width() * 2); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + const int qmlCountAfterRightFlick = view->rootObject()->property(maxDelegateCountProp).toInt(); + QCOMPARE(qmlCountAfterRightFlick, qmlCountAfterInit); + + // Flick a long distance down + tableView->setContentX(tableView->height() * 2); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + const int qmlCountAfterDownFlick = view->rootObject()->property(maxDelegateCountProp).toInt(); + QCOMPARE(qmlCountAfterDownFlick, qmlCountAfterInit); + + // Flick a long distance left + tableView->setContentX(0); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + const int qmlCountAfterLeftFlick = view->rootObject()->property(maxDelegateCountProp).toInt(); + QCOMPARE(qmlCountAfterLeftFlick, qmlCountAfterInit); + + // Flick a long distance up + tableView->setContentY(0); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + const int qmlCountAfterUpFlick = view->rootObject()->property(maxDelegateCountProp).toInt(); + QCOMPARE(qmlCountAfterUpFlick, qmlCountAfterInit); +} + +QTEST_MAIN(tst_QQuickTableView) + +#include "tst_qquicktableview.moc" diff --git a/tests/auto/quick/qquicktext/data/implicitSizeChangeRewrap.qml b/tests/auto/quick/qquicktext/data/implicitSizeChangeRewrap.qml new file mode 100644 index 0000000000..fb8626a75a --- /dev/null +++ b/tests/auto/quick/qquicktext/data/implicitSizeChangeRewrap.qml @@ -0,0 +1,27 @@ +import QtQuick 2.0 +import QtQuick.Layouts 1.0 + +Item +{ + id : _rootItem + width : 200 + height : 1000 + ColumnLayout + { + id : _textContainer + anchors.centerIn: parent + Layout.maximumWidth: (_rootItem.width - 40) // to have some space left / right + Text + { + id : text + objectName: "text" + font.italic: true + textFormat: Text.RichText + horizontalAlignment : Text.AlignHCenter + verticalAlignment : Text.AlignVCenter + wrapMode: Text.Wrap + Layout.maximumWidth: (_rootItem.width - 60) + Component.onCompleted: text.text = "This is a too long text for the interface with a stupid path also too long -> /home/long/long/long/to/force/it/to/need/to/wrap This is a too long text for the interface with a stupid path also too long -> /home/long/long/long/to/force/it/to/need/to/wrap This is a too long text for the interface with a stupid path also too long -> /home/long/long/long/to/force/it/to/need/to/wrap This is a too long text for the interface with a stupid path also too long -> /home/long/long/long/to/force/it/to/need/to/wrap" + } + } +} diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index 89d2590c03..48069ab8c5 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -105,6 +105,7 @@ private slots: void implicitSize_data(); void implicitSize(); + void implicitSizeChangeRewrap(); void dependentImplicitSizes(); void contentSize(); void implicitSizeBinding_data(); @@ -999,11 +1000,14 @@ static inline QByteArray msgNotLessThan(int n1, int n2) void tst_qquicktext::hAlignImplicitWidth() { +#ifdef Q_OS_MACOS + QSKIP("this test currently crashes on MacOS. See QTBUG-68047"); +#endif QQuickView view(testFileUrl("hAlignImplicitWidth.qml")); view.setFlags(view.flags() | Qt::WindowStaysOnTopHint); // Prevent being obscured by other windows. view.show(); view.requestActivate(); - QVERIFY(QTest::qWaitForWindowActive(&view)); + QVERIFY(QTest::qWaitForWindowExposed(&view)); QQuickText *text = view.rootObject()->findChild<QQuickText*>("textItem"); QVERIFY(text != nullptr); @@ -4369,6 +4373,23 @@ void tst_qquicktext::fontInfo() QVERIFY(copy->font().pixelSize() < 1000); } +void tst_qquicktext::implicitSizeChangeRewrap() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("implicitSizeChangeRewrap.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QObject *root = window->rootObject(); + + QQuickText *text = root->findChild<QQuickText *>("text"); + QVERIFY(text != nullptr); + + QVERIFY(text->contentWidth() < window->width()); +} + QTEST_MAIN(tst_qquicktext) #include "tst_qquicktext.moc" diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index 65c9c9e8ad..ed2d535fda 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -1990,9 +1990,6 @@ void tst_qquicktextinput::validators() QCOMPARE(intInput->hasAcceptableInput(), false); QCOMPARE(intInput->property("acceptable").toBool(), false); QCOMPARE(intSpy.count(), 0); - QTest::keyPress(&window, Qt::Key_2); - QTest::keyRelease(&window, Qt::Key_2, Qt::NoModifier); - QTRY_COMPARE(intInput->text(), QLatin1String("1")); QCOMPARE(intInput->hasAcceptableInput(), false); QCOMPARE(intInput->property("acceptable").toBool(), false); QCOMPARE(intSpy.count(), 0); @@ -5989,7 +5986,7 @@ void tst_qquicktextinput::QTBUG_19956_regexp() { QUrl url = testFileUrl("qtbug-19956regexp.qml"); - QString warning = url.toString() + ":11:17: Unable to assign [undefined] to QRegExp"; + QString warning = url.toString() + ":11:9: Unable to assign [undefined] to QRegExp"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); QQuickView window(url); diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 44cd1dd656..381da76fa3 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -631,9 +631,10 @@ void tst_qquickwindow::touchEvent_basic() topItem->setSize(QSizeF(150, 150)); QPointF pos(10, 10); + QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice, false); // press single point - QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window); + touchSeq.press(0, topItem->mapToScene(pos).toPoint(),window).commit(); QQuickTouchUtils::flush(window); QTRY_COMPARE(topItem->lastEvent.touchPoints.count(), 1); @@ -643,11 +644,11 @@ void tst_qquickwindow::touchEvent_basic() // would put the decorated window at that position rather than the window itself. COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(topItem, pos))); topItem->reset(); - QTest::touchEvent(window, touchDevice).release(0, topItem->mapToScene(pos).toPoint(), window); + touchSeq.release(0, topItem->mapToScene(pos).toPoint(), window).commit(); // press multiple points - QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window) - .press(1, bottomItem->mapToScene(pos).toPoint(), window); + touchSeq.press(0, topItem->mapToScene(pos).toPoint(), window) + .press(1, bottomItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); @@ -656,35 +657,35 @@ void tst_qquickwindow::touchEvent_basic() COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos))); topItem->reset(); bottomItem->reset(); - QTest::touchEvent(window, touchDevice).release(0, topItem->mapToScene(pos).toPoint(), window).release(1, bottomItem->mapToScene(pos).toPoint(), window); + touchSeq.release(0, topItem->mapToScene(pos).toPoint(), window).release(1, bottomItem->mapToScene(pos).toPoint(), window).commit(); // touch point on top item moves to bottom item, but top item should still receive the event - QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window); + touchSeq.press(0, topItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); - QTest::touchEvent(window, touchDevice).move(0, bottomItem->mapToScene(pos).toPoint(), window); + touchSeq.move(0, bottomItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, Qt::TouchPointMoved, makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos))); topItem->reset(); - QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(), window); + touchSeq.release(0, bottomItem->mapToScene(pos).toPoint(), window).commit(); // touch point on bottom item moves to top item, but bottom item should still receive the event - QTest::touchEvent(window, touchDevice).press(0, bottomItem->mapToScene(pos).toPoint(), window); + touchSeq.press(0, bottomItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); - QTest::touchEvent(window, touchDevice).move(0, topItem->mapToScene(pos).toPoint(), window); + touchSeq.move(0, topItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1); COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, Qt::TouchPointMoved, makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos))); bottomItem->reset(); - QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(), window); + touchSeq.release(0, bottomItem->mapToScene(pos).toPoint(), window).commit(); // a single stationary press on an item shouldn't cause an event - QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window); + touchSeq.press(0, topItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); - QTest::touchEvent(window, touchDevice).stationary(0) - .press(1, bottomItem->mapToScene(pos).toPoint(), window); + touchSeq.stationary(0) + .press(1, bottomItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); // received press only, not stationary QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); @@ -696,13 +697,13 @@ void tst_qquickwindow::touchEvent_basic() // cleanup: what is pressed must be released // Otherwise you will get an assertion failure: // ASSERT: "itemForTouchPointId.isEmpty()" in file items/qquickwindow.cpp - QTest::touchEvent(window, touchDevice).release(0, pos.toPoint(), window).release(1, pos.toPoint(), window); + touchSeq.release(0, pos.toPoint(), window).release(1, pos.toPoint(), window).commit(); QQuickTouchUtils::flush(window); // move touch point from top item to bottom, and release - QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window); + touchSeq.press(0, topItem->mapToScene(pos).toPoint(),window).commit(); QQuickTouchUtils::flush(window); - QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(),window); + touchSeq.release(0, bottomItem->mapToScene(pos).toPoint(),window).commit(); QQuickTouchUtils::flush(window); QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, window, Qt::TouchPointReleased, @@ -710,13 +711,13 @@ void tst_qquickwindow::touchEvent_basic() topItem->reset(); // release while another point is pressed - QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window) - .press(1, bottomItem->mapToScene(pos).toPoint(), window); + touchSeq.press(0, topItem->mapToScene(pos).toPoint(),window) + .press(1, bottomItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); - QTest::touchEvent(window, touchDevice).move(0, bottomItem->mapToScene(pos).toPoint(), window); + touchSeq.move(0, bottomItem->mapToScene(pos).toPoint(), window).commit(); QQuickTouchUtils::flush(window); - QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(), window) - .stationary(1); + touchSeq.release(0, bottomItem->mapToScene(pos).toPoint(), window) + .stationary(1).commit(); QQuickTouchUtils::flush(window); QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); diff --git a/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp b/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp index 757cb8f513..bcff0c46fb 100644 --- a/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp +++ b/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp @@ -354,7 +354,7 @@ void tst_qquickxmllistmodel::xml() QSignalSpy spy(model, SIGNAL(statusChanged(QQuickXmlListModel::Status))); QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->property("progress").toDouble(), qreal(0.0)); + QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), QQuickXmlListModel::Loading); QTRY_COMPARE(spy.count(), 1); spy.clear(); @@ -410,6 +410,13 @@ void tst_qquickxmllistmodel::headers() QTRY_COMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), QQuickXmlListModel::Ready); + // It doesn't do a network request for a local file + QCOMPARE(factory.lastSentHeaders.count(), 0); + + model->setProperty("source", QUrl("http://localhost/filethatdoesnotexist.xml")); + QTRY_COMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), + QQuickXmlListModel::Error); + QVariantMap expectedHeaders; expectedHeaders["Accept"] = "application/xml,*/*"; @@ -433,7 +440,7 @@ void tst_qquickxmllistmodel::source() QSignalSpy spy(model, SIGNAL(statusChanged(QQuickXmlListModel::Status))); QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->property("progress").toDouble(), qreal(0.0)); + QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), QQuickXmlListModel::Loading); QTRY_COMPARE(spy.count(), 1); spy.clear(); @@ -447,7 +454,7 @@ void tst_qquickxmllistmodel::source() if (model->property("source").toString().isEmpty()) QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), QQuickXmlListModel::Null); - QCOMPARE(model->property("progress").toDouble(), qreal(0.0)); + QCOMPARE(model->property("progress").toDouble(), qreal(source.isLocalFile() ? 1.0 : 0.0)); QTRY_COMPARE(spy.count(), 1); spy.clear(); QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), QQuickXmlListModel::Loading); diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index a54a707f4a..a4b6076a34 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -66,6 +66,7 @@ QUICKTESTS += \ qquickitem2 \ qquickitemlayer \ qquicklistview \ + qquicktableview \ qquickloader \ qquickmousearea \ qquickmultipointtoucharea \ @@ -93,7 +94,7 @@ QUICKTESTS += \ SUBDIRS += $$PUBLICTESTS # Following tests are too slow on qemu + software backend -boot2qt: QUICKTESTS -= qquickgridview qquicklistview qquickpositioners +boot2qt: QUICKTESTS -= qquickgridview qquicklistview qquicktableview qquickpositioners !qtConfig(accessibility):QUICKTESTS -= qquickaccessible diff --git a/tests/auto/quick/shared/viewtestutil.cpp b/tests/auto/quick/shared/viewtestutil.cpp index dc813b9d59..3bfa23173e 100644 --- a/tests/auto/quick/shared/viewtestutil.cpp +++ b/tests/auto/quick/shared/viewtestutil.cpp @@ -153,6 +153,12 @@ int QQuickViewTestUtil::QaimModel::rowCount(const QModelIndex &parent) const return list.count(); } +int QQuickViewTestUtil::QaimModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return columns; +} + QHash<int,QByteArray> QQuickViewTestUtil::QaimModel::roleNames() const { QHash<int,QByteArray> roles = QAbstractListModel::roleNames(); @@ -174,7 +180,7 @@ QVariant QQuickViewTestUtil::QaimModel::data(const QModelIndex &index, int role) int QQuickViewTestUtil::QaimModel::count() const { - return rowCount(); + return rowCount() * columnCount(); } QString QQuickViewTestUtil::QaimModel::name(int index) const diff --git a/tests/auto/quick/shared/viewtestutil.h b/tests/auto/quick/shared/viewtestutil.h index b11d5e4859..04e1771ef8 100644 --- a/tests/auto/quick/shared/viewtestutil.h +++ b/tests/auto/quick/shared/viewtestutil.h @@ -76,6 +76,7 @@ namespace QQuickViewTestUtil QaimModel(QObject *parent=0); int rowCount(const QModelIndex &parent=QModelIndex()) const; + int columnCount(const QModelIndex &parent=QModelIndex()) const; QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const; QHash<int,QByteArray> roleNames() const; @@ -104,6 +105,8 @@ namespace QQuickViewTestUtil using QAbstractListModel::dataChanged; + int columns = 1; + private: QList<QPair<QString,QString> > list; }; diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index a69cd5bc34..2fc56c2ad8 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -824,6 +824,7 @@ void tst_TouchMouse::buttonOnTouch() EventItem *eventItem4 = window->rootObject()->findChild<EventItem*>("eventItem4"); QVERIFY(eventItem4); + QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window.data(), device, false); // Test the common case of a mouse area on top of pinch eventItem1->setAcceptedMouseButtons(Qt::LeftButton); @@ -835,9 +836,9 @@ void tst_TouchMouse::buttonOnTouch() // Normal touch click QPoint p1 = QPoint(10, 110); - QTest::touchEvent(window.data(), device).press(0, p1, window.data()); + touchSeq.press(0, p1, window.data()).commit(); QQuickTouchUtils::flush(window.data()); - QTest::touchEvent(window.data(), device).release(0, p1, window.data()); + touchSeq.release(0, p1, window.data()).commit(); QQuickTouchUtils::flush(window.data()); QCOMPARE(eventItem1->eventList.size(), 5); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); @@ -860,9 +861,9 @@ void tst_TouchMouse::buttonOnTouch() QPoint p2 = QPoint(60, 10); // Start the events after each other - QTest::touchEvent(window.data(), device).press(0, p1, window.data()); + touchSeq.press(0, p1, window.data()).commit(); QQuickTouchUtils::flush(window.data()); - QTest::touchEvent(window.data(), device).stationary(0).press(1, p2, window.data()); + touchSeq.stationary(0).press(1, p2, window.data()).commit(); QQuickTouchUtils::flush(window.data()); QCOMPARE(button1->scale(), 1.0); @@ -870,24 +871,24 @@ void tst_TouchMouse::buttonOnTouch() // This event seems to be discarded, let's ignore it for now until someone digs into pincharea p1 -= QPoint(10, 0); p2 += QPoint(10, 0); - QTest::touchEvent(window.data(), device).move(0, p1, window.data()).move(1, p2, window.data()); + touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); QQuickTouchUtils::flush(window.data()); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); - QTest::touchEvent(window.data(), device).move(0, p1, window.data()).move(1, p2, window.data()); + touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); QQuickTouchUtils::flush(window.data()); // QCOMPARE(button1->scale(), 1.5); qDebug() << "Button scale: " << button1->scale(); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); - QTest::touchEvent(window.data(), device).move(0, p1, window.data()).move(1, p2, window.data()); + touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); QQuickTouchUtils::flush(window.data()); // QCOMPARE(button1->scale(), 2.0); qDebug() << "Button scale: " << button1->scale(); - QTest::touchEvent(window.data(), device).release(0, p1, window.data()).release(1, p2, window.data()); + touchSeq.release(0, p1, window.data()).release(1, p2, window.data()).commit(); QQuickTouchUtils::flush(window.data()); // QVERIFY(eventItem1->eventList.isEmpty()); // QCOMPARE(button1->scale(), 2.0); @@ -901,7 +902,7 @@ void tst_TouchMouse::buttonOnTouch() button1->setScale(1.0); p1 = QPoint(40, 110); p2 = QPoint(60, 110); - QTest::touchEvent(window.data(), device).press(0, p1, window.data()).press(1, p2, window.data()); + touchSeq.press(0, p1, window.data()).press(1, p2, window.data()).commit(); QQuickTouchUtils::flush(window.data()); QCOMPARE(button1->scale(), 1.0); QCOMPARE(eventItem1->eventList.count(), 2); @@ -911,24 +912,24 @@ void tst_TouchMouse::buttonOnTouch() // This event seems to be discarded, let's ignore it for now until someone digs into pincharea p1 -= QPoint(10, 0); p2 += QPoint(10, 0); - QTest::touchEvent(window.data(), device).move(0, p1, window.data()).move(1, p2, window.data()); + touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); QQuickTouchUtils::flush(window.data()); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); - QTest::touchEvent(window.data(), device).move(0, p1, window.data()).move(1, p2, window.data()); + touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); QQuickTouchUtils::flush(window.data()); //QCOMPARE(button1->scale(), 1.5); qDebug() << button1->scale(); p1 -= QPoint(10, 0); p2 += QPoint(10, 0); - QTest::touchEvent(window.data(), device).move(0, p1, window.data()).move(1, p2, window.data()); + touchSeq.move(0, p1, window.data()).move(1, p2, window.data()).commit(); QQuickTouchUtils::flush(window.data()); qDebug() << button1->scale(); //QCOMPARE(button1->scale(), 2.0); - QTest::touchEvent(window.data(), device).release(0, p1, window.data()).release(1, p2, window.data()); + touchSeq.release(0, p1, window.data()).release(1, p2, window.data()).commit(); QQuickTouchUtils::flush(window.data()); // QCOMPARE(eventItem1->eventList.size(), 99); qDebug() << button1->scale(); @@ -1334,6 +1335,7 @@ void tst_TouchMouse::touchPointDeliveryOrder() QPoint pLeftMiddle = QPoint(200, 100); QPoint pRightMiddle = QPoint(350, 100); + QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window.data(), device, false); QVector<QQuickItem*> events; EventItem *background = window->rootObject()->findChild<EventItem*>("background"); @@ -1349,7 +1351,7 @@ void tst_TouchMouse::touchPointDeliveryOrder() connect(middle, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); }); connect(right, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); }); - QTest::touchEvent(window.data(), device).press(0, pLeft, window.data()); + touchSeq.press(0, pLeft, window.data()).commit(); QQuickTouchUtils::flush(window.data()); // Touch on left, then background @@ -1359,7 +1361,7 @@ void tst_TouchMouse::touchPointDeliveryOrder() events.clear(); // New press events are deliverd first, the stationary point was not accepted, thus it doesn't get delivered - QTest::touchEvent(window.data(), device).stationary(0).press(1, pRightMiddle, window.data()); + touchSeq.stationary(0).press(1, pRightMiddle, window.data()).commit(); QQuickTouchUtils::flush(window.data()); QCOMPARE(events.size(), 3); QCOMPARE(events.at(0), middle); @@ -1367,49 +1369,49 @@ void tst_TouchMouse::touchPointDeliveryOrder() QCOMPARE(events.at(2), background); events.clear(); - QTest::touchEvent(window.data(), device).release(0, pLeft, window.data()).release(1, pRightMiddle, window.data()); + touchSeq.release(0, pLeft, window.data()).release(1, pRightMiddle, window.data()).commit(); QQuickTouchUtils::flush(window.data()); QCOMPARE(events.size(), 0); // no accepted events // Two presses, the first point should come first - QTest::touchEvent(window.data(), device).press(0, pLeft, window.data()).press(1, pRight, window.data()); + touchSeq.press(0, pLeft, window.data()).press(1, pRight, window.data()).commit(); QQuickTouchUtils::flush(window.data()); QCOMPARE(events.size(), 3); QCOMPARE(events.at(0), left); QCOMPARE(events.at(1), right); QCOMPARE(events.at(2), background); - QTest::touchEvent(window.data(), device).release(0, pLeft, window.data()).release(1, pRight, window.data()); + touchSeq.release(0, pLeft, window.data()).release(1, pRight, window.data()).commit(); events.clear(); // Again, pressing right first - QTest::touchEvent(window.data(), device).press(0, pRight, window.data()).press(1, pLeft, window.data()); + touchSeq.press(0, pRight, window.data()).press(1, pLeft, window.data()).commit(); QQuickTouchUtils::flush(window.data()); QCOMPARE(events.size(), 3); QCOMPARE(events.at(0), right); QCOMPARE(events.at(1), left); QCOMPARE(events.at(2), background); - QTest::touchEvent(window.data(), device).release(0, pRight, window.data()).release(1, pLeft, window.data()); + touchSeq.release(0, pRight, window.data()).release(1, pLeft, window.data()).commit(); events.clear(); // Two presses, both hitting the middle item on top, then branching left and right, then bottom // Each target should be offered the events exactly once, middle first, left must come before right (id 0) - QTest::touchEvent(window.data(), device).press(0, pLeftMiddle, window.data()).press(1, pRightMiddle, window.data()); + touchSeq.press(0, pLeftMiddle, window.data()).press(1, pRightMiddle, window.data()).commit(); QCOMPARE(events.size(), 4); QCOMPARE(events.at(0), middle); QCOMPARE(events.at(1), left); QCOMPARE(events.at(2), right); QCOMPARE(events.at(3), background); - QTest::touchEvent(window.data(), device).release(0, pLeftMiddle, window.data()).release(1, pRightMiddle, window.data()); + touchSeq.release(0, pLeftMiddle, window.data()).release(1, pRightMiddle, window.data()).commit(); events.clear(); - QTest::touchEvent(window.data(), device).press(0, pRightMiddle, window.data()).press(1, pLeftMiddle, window.data()); + touchSeq.press(0, pRightMiddle, window.data()).press(1, pLeftMiddle, window.data()).commit(); qDebug() << events; QCOMPARE(events.size(), 4); QCOMPARE(events.at(0), middle); QCOMPARE(events.at(1), right); QCOMPARE(events.at(2), left); QCOMPARE(events.at(3), background); - QTest::touchEvent(window.data(), device).release(0, pRightMiddle, window.data()).release(1, pLeftMiddle, window.data()); + touchSeq.release(0, pRightMiddle, window.data()).release(1, pLeftMiddle, window.data()).commit(); } void tst_TouchMouse::hoverEnabled() |