diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-03-21 20:42:38 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2019-03-21 20:42:47 +0100 |
commit | 6767114285db9d0e16dc278d08f231e8561546b4 (patch) | |
tree | 0945902a2242fd7ec0a1f7fd3e6acbb769e723bd /tests/auto/quick | |
parent | ee076afedccbe1d37306a7972051f84eb036d655 (diff) | |
parent | c32b109e9dea44c6775c2dbf8f164870c1dc8971 (diff) |
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Change-Id: Ib5662d80d5b2f58cf4634c54c054545ba9df807e
Diffstat (limited to 'tests/auto/quick')
331 files changed, 22129 insertions, 5238 deletions
diff --git a/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp b/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp index d4065e3d38..afc66948b0 100644 --- a/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp +++ b/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp @@ -51,8 +51,8 @@ public: view.setResizeMode(QQuickView::SizeViewToRootObject); view.setSource(testFileUrl(fileName)); view.setVisible(true); - QTest::qWaitForWindowExposed(&view); - return view.grabWindow(); + bool exposed = QTest::qWaitForWindowExposed(&view); + return exposed ? view.grabWindow() : QImage(); } //It is important for platforms that only are able to show fullscreen windows @@ -149,6 +149,10 @@ void tst_drawingmodes::points() if (QGuiApplication::primaryScreen()->depth() < 24) QSKIP("This test does not work at display depths < 24"); + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + #ifdef Q_OS_WIN if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) QSKIP("ANGLE cannot draw GL_POINTS."); @@ -187,6 +191,11 @@ void tst_drawingmodes::lines() DrawingModeItem::drawingMode = GL_LINES; if (QGuiApplication::primaryScreen()->depth() < 24) QSKIP("This test does not work at display depths < 24"); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("DrawingModes.qml"); QCOMPARE(fb.width(), 200); @@ -213,6 +222,11 @@ void tst_drawingmodes::lineStrip() DrawingModeItem::drawingMode = GL_LINE_STRIP; if (QGuiApplication::primaryScreen()->depth() < 24) QSKIP("This test does not work at display depths < 24"); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("DrawingModes.qml"); QCOMPARE(fb.width(), 200); @@ -241,6 +255,11 @@ void tst_drawingmodes::lineLoop() DrawingModeItem::drawingMode = GL_LINE_LOOP; if (QGuiApplication::primaryScreen()->depth() < 24) QSKIP("This test does not work at display depths < 24"); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("DrawingModes.qml"); QCOMPARE(fb.width(), 200); @@ -269,6 +288,11 @@ void tst_drawingmodes::triangles() DrawingModeItem::drawingMode = GL_TRIANGLES; if (QGuiApplication::primaryScreen()->depth() < 24) QSKIP("This test does not work at display depths < 24"); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("DrawingModes.qml"); QCOMPARE(fb.width(), 200); @@ -293,6 +317,11 @@ void tst_drawingmodes::triangleStrip() DrawingModeItem::drawingMode = GL_TRIANGLE_STRIP; if (QGuiApplication::primaryScreen()->depth() < 24) QSKIP("This test does not work at display depths < 24"); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("DrawingModes.qml"); QCOMPARE(fb.width(), 200); @@ -316,6 +345,11 @@ void tst_drawingmodes::triangleFan() DrawingModeItem::drawingMode = GL_TRIANGLE_FAN; if (QGuiApplication::primaryScreen()->depth() < 24) QSKIP("This test does not work at display depths < 24"); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("DrawingModes.qml"); QCOMPARE(fb.width(), 200); diff --git a/tests/auto/quick/examples/examples.pro b/tests/auto/quick/examples/examples.pro index fd8cfd83c8..c047f993ea 100644 --- a/tests/auto/quick/examples/examples.pro +++ b/tests/auto/quick/examples/examples.pro @@ -8,5 +8,4 @@ DEFINES += SRCDIR=\\\"$$PWD\\\" #temporary QT += core-private gui-private qml-private quick-private testlib -!qtHaveModule(xmlpatterns): DEFINES += QT_NO_XMLPATTERNS diff --git a/tests/auto/quick/examples/tst_examples.cpp b/tests/auto/quick/examples/tst_examples.cpp index d35a2e971a..fdefa855e4 100644 --- a/tests/auto/quick/examples/tst_examples.cpp +++ b/tests/auto/quick/examples/tst_examples.cpp @@ -36,7 +36,7 @@ #include <QQmlEngine> #include <QQmlError> -static QtMessageHandler testlibMsgHandler = 0; +static QtMessageHandler testlibMsgHandler = nullptr; void msgHandlerFilter(QtMsgType type, const QMessageLogContext &ctxt, const QString &msg) { if (type == QtCriticalMsg || type == QtFatalMsg) @@ -74,29 +74,20 @@ 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 + excludedFiles << "snippets/qml/tablemodel/fruit-example-delegatechooser.qml"; // Requires QtQuick.Controls import. // Add directories you want excluded here excludedDirs << "shared"; //Not an example excludedDirs << "snippets/qml/path"; //No root QQuickItem excludedDirs << "examples/qml/qmlextensionplugins"; //Requires special import search path - excludedDirs << "examples/quick/tutorials/gettingStartedQml"; //C++ example, but no cpp files in root dir // These snippets are not expected to run on their own. excludedDirs << "snippets/qml/visualdatamodel_rootindex"; excludedDirs << "snippets/qml/qtbinding"; excludedDirs << "snippets/qml/imports"; - excludedFiles << "examples/quick/shapes/content/pathitem.qml"; // relies on resources - excludedFiles << "examples/quick/shapes/content/pathiteminteract.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"; -#endif + excludedFiles << "snippets/qml/image-ext.qml"; + excludedFiles << "examples/quick/shapes/content/main.qml"; // relies on resources + excludedFiles << "examples/quick/shapes/content/interactive.qml"; // relies on resources #if !QT_CONFIG(opengl) //No support for Particles diff --git a/tests/auto/quick/geometry/tst_geometry.cpp b/tests/auto/quick/geometry/tst_geometry.cpp index 904f85c4c6..54de46276c 100644 --- a/tests/auto/quick/geometry/tst_geometry.cpp +++ b/tests/auto/quick/geometry/tst_geometry.cpp @@ -58,7 +58,7 @@ void GeometryTest::testPoint2D() QSGGeometry::updateRectGeometry(&geometry, QRectF(1, 2, 3, 4)); QSGGeometry::Point2D *pts = geometry.vertexDataAsPoint2D(); - QVERIFY(pts != 0); + QVERIFY(pts != nullptr); QCOMPARE(pts[0].x, (float) 1); QCOMPARE(pts[0].y, (float) 2); @@ -91,7 +91,7 @@ void GeometryTest::testTexturedPoint2D() QSGGeometry::updateTexturedRectGeometry(&geometry, QRectF(1, 2, 3, 4), QRectF(5, 6, 7, 8)); QSGGeometry::TexturedPoint2D *pts = geometry.vertexDataAsTexturedPoint2D(); - QVERIFY(pts != 0); + QVERIFY(pts != nullptr); QCOMPARE(pts[0].x, (float) 1); QCOMPARE(pts[0].y, (float) 2); diff --git a/tests/auto/quick/nodes/tst_nodestest.cpp b/tests/auto/quick/nodes/tst_nodestest.cpp index 63e0aeb324..79a9e5f757 100644 --- a/tests/auto/quick/nodes/tst_nodestest.cpp +++ b/tests/auto/quick/nodes/tst_nodestest.cpp @@ -41,6 +41,9 @@ #include <QtQuick/qsgsimpletexturenode.h> #include <QtQuick/private/qsgtexture_p.h> +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qpa/qplatformintegration.h> + QT_BEGIN_NAMESPACE inline bool operator==(const QSGGeometry::TexturedPoint2D& l, const QSGGeometry::TexturedPoint2D& r) { @@ -73,13 +76,16 @@ private Q_SLOTS: void textureNodeRect(); private: - QOffscreenSurface *surface; - QOpenGLContext *context; - QSGDefaultRenderContext *renderContext; + QOffscreenSurface *surface = nullptr; + QOpenGLContext *context = nullptr; + QSGDefaultRenderContext *renderContext = nullptr; }; void NodesTest::initTestCase() { + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) + QSKIP("OpenGL not supported by the platform"); + QSGRenderLoop *renderLoop = QSGRenderLoop::instance(); surface = new QOffscreenSurface; @@ -112,8 +118,8 @@ class DummyRenderer : public QSGBatchRenderer::Renderer public: DummyRenderer(QSGRootNode *root, QSGDefaultRenderContext *renderContext) : QSGBatchRenderer::Renderer(renderContext) - , changedNode(0) - , changedState(0) + , changedNode(nullptr) + , changedState(nullptr) , renderCount(0) { setRootNode(root); @@ -141,9 +147,6 @@ public: int DummyRenderer::globalRendereringOrder; NodesTest::NodesTest() - : surface(Q_NULLPTR) - , context(Q_NULLPTR) - , renderContext(Q_NULLPTR) { } diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST new file mode 100644 index 0000000000..62aa19a9ae --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST @@ -0,0 +1,4 @@ +[touchAndDragHandlerOnFlickable] +windows gcc +[touchDragFlickableBehindSlider] +windows gcc diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml new file mode 100644 index 0000000000..4b2935b52e --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests 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 + +SequentialAnimation { + id: tapFlash + running: false + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } +} 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..7a32170bed --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/GrooveDragSlider.qml @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** 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 + 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/KnobDragSlider.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/KnobDragSlider.qml new file mode 100644 index 0000000000..b3d621c447 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/KnobDragSlider.qml @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** 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 + 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 + + 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 } + DragHandler { + id: dragHandler + objectName: root.objectName + " DragHandler" + xAxis.enabled: false + yAxis.minimum: slot.y + yAxis.maximum: slot.height + slot.y - knob.height + } + 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/TapHandlerButton.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml new file mode 100644 index 0000000000..2c9fa30a70 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 + +Rectangle { + id: root + property alias label: label.text + property alias pressed: tap.pressed + property bool checked: false + property alias gesturePolicy: tap.gesturePolicy + property alias enabled: tap.enabled + signal tapped + + width: label.implicitWidth * 1.5; height: label.implicitHeight * 2.0 + border.color: "#9f9d9a"; border.width: 1; radius: height / 4; antialiasing: true + + gradient: Gradient { + GradientStop { position: 0.0; color: tap.pressed ? "#b8b5b2" : "#efebe7" } + GradientStop { position: 1.0; color: "#b8b5b2" } + } + + TapHandler { + id: tap + objectName: label.text + longPressThreshold: 100 // CI can be insanely slow, so don't demand a timely release to generate onTapped + onTapped: { + tapFlash.start() + root.tapped() + } + } + + Text { + id: label + font.pointSize: 14 + text: "Button" + anchors.centerIn: parent + } + + Rectangle { + anchors.fill: parent; anchors.margins: -5 + color: "transparent"; border.color: "#4400FFFF" + border.width: 5; radius: root.radius; antialiasing: true + opacity: tapFlash.running ? 1 : 0 + FlashAnimation on visible { id: tapFlash } + } + + Rectangle { + objectName: "expandingCircle" + radius: tap.timeHeld * 100 + visible: radius > 0 && tap.pressed + border.width: 3 + border.color: "cyan" + color: "transparent" + width: radius * 2 + height: radius * 2 + x: tap.point.scenePressPosition.x - radius + y: tap.point.scenePressPosition.y - radius + opacity: 0.25 + Component.onCompleted: { + // get on top of all the buttons + var par = root.parent; + while (par.parent) + par = par.parent; + parent = par; + } + } +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnFlickable.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnFlickable.qml new file mode 100644 index 0000000000..fd32baad10 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnFlickable.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 + +Flickable { + id: root + objectName: "root" + width: 800 + height: 480 + contentWidth: 1000 + contentHeight: 600 + + Rectangle { + anchors.fill: parent + color: "transparent" + border.color: "black" + } + + Rectangle { + objectName: "button" + anchors.centerIn: parent + border.color: "tomato" + border.width: 10 + color: buttonDrag.active ? "goldenrod" : "beige" + width: 100 + height: 100 + DragHandler { + id: buttonDrag + objectName: "buttonDrag" + } + } + + DragHandler { + id: contentItemDrag + objectName: "contentItemDrag" + } + Text { + x: 100; y: 100 + text: "dragging contentItem" + visible: contentItemDrag.active + } + + Component.onCompleted: contentItem.objectName = "Flickable's contentItem" +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnList.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnList.qml new file mode 100644 index 0000000000..bb39c2267c --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnList.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 + +ListView { + id: root + objectName: "root" + property Item buttonUnderTest: null + property Item delegateUnderTest: null + width: 800 + height: 480 + model: 10 + spacing: 2 + + delegate: Rectangle { + objectName: "itemview delegate" + color: delegateDrag.active ? "wheat" : "beige" + border.color: "black" + width: parent.width; height: 140 + Rectangle { + objectName: "button" + x: 350; y: 20 + border.color: "tomato" + border.width: 10 + color: buttonDrag.active ? "goldenrod" : "beige" + width: 100 + height: 100 + DragHandler { + id: buttonDrag + objectName: "buttonDrag" + } + Component.onCompleted: if (!root.buttonUnderTest) { + root.buttonUnderTest = this + root.delegateUnderTest = parent + } + } + DragHandler { + id: delegateDrag + objectName: "delegateDrag" + } + } + + DragHandler { + objectName: "contentItemDrag" + } + + Component.onCompleted: contentItem.objectName = "ListView's contentItem" +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnTable.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnTable.qml new file mode 100644 index 0000000000..43cc44f62e --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnTable.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 + +TableView { + id: root + objectName: "root" + property Item buttonUnderTest: null + property Item delegateUnderTest: null + width: 800 + height: 480 + columnSpacing: 2 + rowSpacing: 2 + // TODO use TableModel when it's ready, to test with multiple columns + model: 10 + + delegate: Rectangle { + id: tableDelegate + objectName: "itemview delegate" + color: delegateDrag.active ? "wheat" : "beige" + implicitWidth: 200 + implicitHeight: 140 + + Rectangle { + objectName: "button" + x: 50; y: 20 + border.color: "tomato" + border.width: 10 + color: buttonDrag.active ? "goldenrod" : "beige" + width: 100 + height: 100 + DragHandler { + id: buttonDrag + objectName: "buttonDrag" + } + Component.onCompleted: if (!root.buttonUnderTest) { + root.buttonUnderTest = this + root.delegateUnderTest = parent + } + } + + DragHandler { + id: delegateDrag + objectName: "delegateDrag" + } + } + + DragHandler { + objectName: "contentItemDrag" + } + + Component.onCompleted: contentItem.objectName = "TableView's contentItem" +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml new file mode 100644 index 0000000000..5693a6acd2 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 + +Rectangle { + id: root + width: 800 + height: 480 + objectName: "root" + color: "#222222" + + Flickable { + anchors.fill: parent + anchors.margins: 10 + anchors.topMargin: 40 + contentHeight: 600 + contentWidth: 1000 +// pressDelay: TODO + + Row { + spacing: 6 + 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 + TapHandlerButton { + objectName: "DragThreshold" + label: "DragThreshold" + gesturePolicy: TapHandler.DragThreshold + } + TapHandlerButton { + objectName: "WithinBounds" + label: "WithinBounds" + gesturePolicy: TapHandler.WithinBounds + } + TapHandlerButton { + objectName: "ReleaseWithinBounds" + label: "ReleaseWithinBounds" + gesturePolicy: TapHandler.ReleaseWithinBounds // the default + } + } + Column { + spacing: 6 + Rectangle { + width: 50 + height: 50 + color: "aqua" + border.color: drag1.active ? "darkgreen" : "transparent" + border.width: 3 + objectName: "drag" + DragHandler { + id: drag1 + objectName: "drag1" + } + Text { + anchors.centerIn: parent + enabled: false + text: "drag" + } + } + Rectangle { + width: 50 + height: 50 + color: "aqua" + objectName: "tap" + border.color: tap1.isPressed ? "red" : "transparent" + border.width: 3 + TapHandler { + id: tap1 + objectName: "tap1" + gesturePolicy: TapHandler.DragThreshold + } + Text { + anchors.centerIn: parent + enabled: false + text: "tap" + } + } + Rectangle { + width: 50 + height: 50 + color: "aqua" + border.color: tap2.isPressed ? "red" : drag2.active ? "darkgreen" : "transparent" + border.width: 3 + objectName: "dragAndTap" + DragHandler { + id: drag2 + objectName: "drag2" + } + TapHandler { + id: tap2 + objectName: "tap2" + gesturePolicy: TapHandler.DragThreshold + } + Text { + anchors.centerIn: parent + enabled: false + text: "drag\nand\ntap" + } + } + Rectangle { + width: 50 + height: 50 + color: "aqua" + border.color: tap3.isPressed ? "red" : drag3.active ? "darkgreen" : "transparent" + border.width: 3 + objectName: "tapAndDrag" + TapHandler { + id: tap3 + objectName: "tap3" + gesturePolicy: TapHandler.DragThreshold + } + DragHandler { + id: drag3 + objectName: "drag3" + } + Text { + anchors.centerIn: parent + enabled: false + text: "tap\nand\ndrag" + } + } + } + } + } +} + diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnFlickable.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnFlickable.qml new file mode 100644 index 0000000000..a71db0b4c2 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnFlickable.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 + +Flickable { + id: root + objectName: "root" + width: 800 + height: 480 + contentWidth: 1000 + contentHeight: 600 + + Rectangle { + objectName: "button" + anchors.centerIn: parent + border.color: "tomato" + border.width: 10 + color: innerTap.pressed ? "wheat" : "transparent" + width: 100 + height: 100 + TapHandler { + id: innerTap + objectName: "buttonTap" + } + } + + TapHandler { + objectName: "contentItemTap" + } + Component.onCompleted: contentItem.objectName = "Flickable's contentItem" +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnList.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnList.qml new file mode 100644 index 0000000000..ef27955043 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnList.qml @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 + +ListView { + id: root + objectName: "root" + property Item buttonUnderTest: null + property Item delegateUnderTest: null + width: 800 + height: 480 + model: 10 + spacing: 2 + + delegate: Rectangle { + objectName: "itemview delegate" + color: delegateTap.pressed ? "wheat" : "beige" + width: parent.width; height: 140 + Rectangle { + objectName: "button" + anchors.centerIn: parent + border.color: "tomato" + border.width: 10 + color: innerTap.pressed ? "goldenrod" : "beige" + width: 100 + height: 100 + TapHandler { + id: innerTap + objectName: "buttonTap" + } + Component.onCompleted: if (!root.buttonUnderTest) { + root.buttonUnderTest = this + root.delegateUnderTest = parent + } + } + TapHandler { + id: delegateTap + objectName: "delegateTap" + } + } + + TapHandler { + objectName: "contentItemTap" + } + + Component.onCompleted: contentItem.objectName = "ListView's contentItem" +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnTable.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnTable.qml new file mode 100644 index 0000000000..6bf1054d7a --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnTable.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 + +TableView { + id: root + objectName: "root" + property Item buttonUnderTest: null + property Item delegateUnderTest: null + width: 800 + height: 480 + columnSpacing: 2 + rowSpacing: 2 + // TODO use TableModel when it's ready, to test with multiple columns + model: 10 + + delegate: Rectangle { + id: tableDelegate + objectName: "itemview delegate" + color: delegateTap.pressed ? "wheat" : "beige" + implicitWidth: 200 + implicitHeight: 140 + + Rectangle { + objectName: "button" + anchors.centerIn: parent + border.color: "tomato" + border.width: 10 + color: innerTap.pressed ? "goldenrod" : "beige" + width: 100 + height: 100 + TapHandler { + id: innerTap + objectName: "buttonTap" + } + Component.onCompleted: if (!root.buttonUnderTest) { + root.buttonUnderTest = this + root.delegateUnderTest = parent + } + } + + TapHandler { + id: delegateTap + objectName: "delegateTap" + } + } + + TapHandler { + objectName: "contentItemTap" + } + + Component.onCompleted: contentItem.objectName = "TableView's contentItem" +} diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/flickableinterop.pro b/tests/auto/quick/pointerhandlers/flickableinterop/flickableinterop.pro new file mode 100644 index 0000000000..9075044bd3 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/flickableinterop.pro @@ -0,0 +1,15 @@ +CONFIG += testcase + +TARGET = tst_flickableinterop +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_flickableinterop.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +OTHER_FILES += data/flickableWithHandlers.qml data/Slider.qml diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp new file mode 100644 index 0000000000..f4ed051e1f --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp @@ -0,0 +1,799 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module 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 <QtGui/qstylehints.h> +#include <QtQuick/qquickview.h> +#include <QtQuick/qquickitem.h> +#include <QtQuick/private/qquickflickable_p.h> +#include <QtQuick/private/qquickitemview_p.h> +#include <QtQuick/private/qquickpointerhandler_p.h> +#include <QtQuick/private/qquickdraghandler_p.h> +#include <QtQuick/private/qquicktaphandler_p.h> +#include <QtQuick/private/qquicktableview_p.h> +#include <qpa/qwindowsysteminterface.h> + +#include <private/qquickwindow_p.h> + +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlproperty.h> + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_FlickableInterop : public QQmlDataTest +{ + Q_OBJECT +public: + tst_FlickableInterop() + :touchDevice(QTest::createTouchDevice()) + {} + +private slots: + void touchTapButton_data(); + void touchTapButton(); + void touchDragFlickableBehindButton_data(); + void touchDragFlickableBehindButton(); + void mouseClickButton_data(); + void mouseClickButton(); + void mouseDragFlickableBehindButton_data(); + void mouseDragFlickableBehindButton(); + void touchDragSlider(); + void touchDragFlickableBehindSlider(); + void mouseDragSlider_data(); + void mouseDragSlider(); + void mouseDragFlickableBehindSlider(); + void touchDragFlickableBehindItemWithHandlers_data(); + void touchDragFlickableBehindItemWithHandlers(); + void mouseDragFlickableBehindItemWithHandlers_data(); + void mouseDragFlickableBehindItemWithHandlers(); + void touchDragSliderAndFlickable(); + void touchAndDragHandlerOnFlickable_data(); + void touchAndDragHandlerOnFlickable(); + +private: + void createView(QScopedPointer<QQuickView> &window, const char *fileName); + QTouchDevice *touchDevice; +}; + +void tst_FlickableInterop::createView(QScopedPointer<QQuickView> &window, const char *fileName) +{ + window.reset(new QQuickView); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != nullptr); +} + +void tst_FlickableInterop::touchTapButton_data() +{ + QTest::addColumn<QString>("buttonName"); + QTest::newRow("DragThreshold") << QStringLiteral("DragThreshold"); + QTest::newRow("WithinBounds") << QStringLiteral("WithinBounds"); + QTest::newRow("ReleaseWithinBounds") << QStringLiteral("ReleaseWithinBounds"); +} + +void tst_FlickableInterop::touchTapButton() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QFETCH(QString, buttonName); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>(buttonName); + QVERIFY(button); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Button changes pressed state and emits tapped on release + QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 1); + + // We can drag <= dragThreshold and the button still acts normal, Flickable doesn't grab + p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 2); +} + +void tst_FlickableInterop::touchDragFlickableBehindButton_data() +{ + QTest::addColumn<QString>("buttonName"); + QTest::newRow("DragThreshold") << QStringLiteral("DragThreshold"); + QTest::newRow("WithinBounds") << QStringLiteral("WithinBounds"); + QTest::newRow("ReleaseWithinBounds") << QStringLiteral("ReleaseWithinBounds"); +} + +void tst_FlickableInterop::touchDragFlickableBehindButton() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QFETCH(QString, buttonName); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>(buttonName); + QVERIFY(button); + QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + tappedSpy.clear(); + QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(button->property("pressed").toBool()); + int i = 0; + // Start dragging; eventually when the touchpoint goes beyond dragThreshold, + // Button is no longer pressed because Flickable steals the grab + for (; i < 100 && !flickable->isMoving(); ++i) { + p1 += QPoint(1, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + } + qCDebug(lcPointerTests) << "flickable started moving after" << i << "moves, when we got to" << p1; + QVERIFY(flickable->isMoving()); + QCOMPARE(i, 2); + QVERIFY(!button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); +} + +void tst_FlickableInterop::mouseClickButton_data() +{ + QTest::addColumn<QString>("buttonName"); + QTest::newRow("DragThreshold") << QStringLiteral("DragThreshold"); + QTest::newRow("WithinBounds") << QStringLiteral("WithinBounds"); + QTest::newRow("ReleaseWithinBounds") << QStringLiteral("ReleaseWithinBounds"); +} + +void tst_FlickableInterop::mouseClickButton() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QFETCH(QString, buttonName); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>(buttonName); + QVERIFY(button); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Button changes pressed state and emits tapped on release + QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 1); + + // We can drag <= dragThreshold and the button still acts normal, Flickable doesn't grab + p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1, qApp->styleHints()->mouseDoubleClickInterval() + 10); + QTRY_VERIFY(button->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QVERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 2); +} + +void tst_FlickableInterop::mouseDragFlickableBehindButton_data() +{ + QTest::addColumn<QString>("buttonName"); + QTest::newRow("DragThreshold") << QStringLiteral("DragThreshold"); + QTest::newRow("WithinBounds") << QStringLiteral("WithinBounds"); + QTest::newRow("ReleaseWithinBounds") << QStringLiteral("ReleaseWithinBounds"); +} + +void tst_FlickableInterop::mouseDragFlickableBehindButton() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QFETCH(QString, buttonName); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>(buttonName); + QVERIFY(button); + QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Button is no longer pressed if touchpoint goes beyond dragThreshold, + // because Flickable steals the grab + tappedSpy.clear(); + QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QVERIFY(button->property("pressed").toBool()); + int i = 0; + for (; i < 100 && !flickable->isMoving(); ++i) { + p1 += QPoint(1, 0); + QTest::mouseMove(window, p1); + } + qCDebug(lcPointerTests) << "flickable started moving after" << i << "moves, when we got to" << p1; + QVERIFY(flickable->isMoving()); + QCOMPARE(i, 2); + QVERIFY(!button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); +} + +void tst_FlickableInterop::touchDragSlider() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("knobSlider"); + QVERIFY(slider); + QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); + QVERIFY(drag); + QQuickItem *knob = slider->findChild<QQuickItem*>("Slider Knob"); + QVERIFY(knob); + QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); + QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); + + // Drag the slider in the allowed (vertical) direction + tappedSpy.clear(); + QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint() - QPoint(0, 8); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(slider->property("pressed").toBool()); + p1 += QPoint(0, dragThreshold); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(slider->property("pressed").toBool()); + QCOMPARE(slider->property("value").toInt(), 49); + p1 += QPoint(0, 1); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + p1 += QPoint(0, 10); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(slider->property("value").toInt() < 49); + QVERIFY(!flickable->isMoving()); + QVERIFY(!slider->property("pressed").toBool()); + + // Now that 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::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!flickable->isMoving()); + + // Release, and do not expect the tapped signal + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(tappedSpy.count(), 0); + 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, -8) << 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, -8) << 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(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + 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); + QQuickItem *knob = slider->findChild<QQuickItem*>("Slider Knob"); + QVERIFY(knob); + QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); + QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); + + // Drag the slider + tappedSpy.clear(); + QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint() + pressPositionRelativeToKnob; + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(slider->property("pressed").toBool(), expectedTapHandlerPressed); + p1 += QPoint(dragThreshold * dragDirection.x(), dragThreshold * dragDirection.y()); + QTest::mouseMove(window, p1); + QCOMPARE(drag->active(), false); + QCOMPARE(slider->property("pressed").toBool(), expectedTapHandlerPressed); + QCOMPARE(slider->property("value").toInt(), 49); + p1 += dragDirection; // one more pixel + QTest::mouseMove(window, p1); + // After moving by the drag threshold, the point should still be inside the knob. + // However, QQuickTapHandler::wantsEventPoint() returns false because the drag threshold is exceeded. + // Therefore QQuickTapHandler::setPressed(false, true, point) is called: the active state is canceled. + QCOMPARE(slider->property("pressed").toBool(), false); + 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); + 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); + + // If the DragHandler is active, the Flickable will not steal the grab + // even if we move a large distance horizontally + 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(), expectedDragHandlerActive ? 1 : 0); +} + +void tst_FlickableInterop::touchDragFlickableBehindSlider() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("knobSlider"); + QVERIFY(slider); + QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); + QVERIFY(drag); + QQuickItem *knob = slider->findChild<QQuickItem*>("Slider Knob"); + QVERIFY(knob); + QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); + QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); + + // Button is no longer pressed if touchpoint goes beyond dragThreshold, + // because Flickable steals the grab + tappedSpy.clear(); + QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(slider->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(slider->property("pressed").toBool()); + int i = 0; + for (; i < 100 && !flickable->isMoving(); ++i) { + p1 += QPoint(1, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + } + qCDebug(lcPointerTests) << "flickable started moving after" << i << "moves, when we got to" << p1; + QVERIFY(flickable->isMoving()); + QCOMPARE(i, 2); + QVERIFY(!slider->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!slider->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); + QCOMPARE(translationChangedSpy.count(), 0); +} + +void tst_FlickableInterop::mouseDragFlickableBehindSlider() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("knobSlider"); + QVERIFY(slider); + QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); + QVERIFY(drag); + QQuickItem *knob = slider->findChild<QQuickItem*>("Slider Knob"); + QVERIFY(knob); + QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped())); + QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged())); + + // Button is no longer pressed if touchpoint goes beyond dragThreshold, + // because Flickable steals the grab + tappedSpy.clear(); + QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(slider->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QQuickTouchUtils::flush(window); + QVERIFY(slider->property("pressed").toBool()); + int i = 0; + for (; i < 100 && !flickable->isMoving(); ++i) { + p1 += QPoint(1, 0); + QTest::mouseMove(window, p1); + } + qCDebug(lcPointerTests) << "flickable started moving after" << i << "moves, when we got to" << p1; + QVERIFY(flickable->isMoving()); + QCOMPARE(i, 2); + QVERIFY(!slider->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(tappedSpy.count(), 0); + QCOMPARE(translationChangedSpy.count(), 0); +} + +void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers_data() +{ + QTest::addColumn<QByteArray>("nameOfRectangleToDrag"); + QTest::addColumn<bool>("expectedFlickableMoving"); + QTest::newRow("drag") << QByteArray("drag") << false; + QTest::newRow("tap") << QByteArray("tap") << true; + QTest::newRow("dragAndTap") << QByteArray("dragAndTap") << false; + QTest::newRow("tapAndDrag") << QByteArray("tapAndDrag") << false; +} + +void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers() +{ + QFETCH(bool, expectedFlickableMoving); + QFETCH(QByteArray, nameOfRectangleToDrag); + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>(nameOfRectangleToDrag); + QVERIFY(rect); + QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + QPoint p1 = rect->mapToScene(rect->clipRect().center()).toPoint(); + QPoint originP1 = p1; + + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + for (int i = 0; i < dragThreshold * 3; ++i) { + p1 = originP1; + p1.rx() += i; + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + } + QCOMPARE(flickable->isMoving(), expectedFlickableMoving); + if (!expectedFlickableMoving) { + QVERIFY(rect->mapToScene(rect->clipRect().center()).toPoint().x() > originP1.x()); + } + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); +} + +void tst_FlickableInterop::mouseDragFlickableBehindItemWithHandlers_data() +{ + touchDragFlickableBehindItemWithHandlers_data(); +} + +void tst_FlickableInterop::mouseDragFlickableBehindItemWithHandlers() +{ + QFETCH(bool, expectedFlickableMoving); + QFETCH(QByteArray, nameOfRectangleToDrag); + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>(nameOfRectangleToDrag); + QVERIFY(rect); + QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>(); + QVERIFY(flickable); + QPoint p1 = rect->mapToScene(rect->clipRect().center()).toPoint(); + QPoint originP1 = p1; + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + for (int i = 0; i < 3; ++i) { + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QQuickTouchUtils::flush(window); + } + QCOMPARE(flickable->isMoving(), expectedFlickableMoving); + if (!expectedFlickableMoving) { + QCOMPARE(originP1 + QPoint(3*dragThreshold, 0), p1); + } + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + // wait until flickable stops + QTRY_COMPARE(flickable->isMoving(), false); + + // After the mouse button has been released, move the mouse and ensure that nothing is moving + // because of that (this tests if all grabs are released when the mouse button is released). + p1 = rect->mapToScene(rect->clipRect().center()).toPoint(); + originP1 = p1; + for (int i = 0; i < 3; ++i) { + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QQuickTouchUtils::flush(window); + } + QCOMPARE(flickable->isMoving(), false); + QCOMPARE(originP1, rect->mapToScene(rect->clipRect().center()).toPoint()); +} + +void tst_FlickableInterop::touchDragSliderAndFlickable() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "flickableWithHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *slider = window->rootObject()->findChild<QQuickItem*>("knobSlider"); + QVERIFY(slider); + QQuickDragHandler *drag = slider->findChild<QQuickDragHandler*>(); + QVERIFY(drag); + QQuickItem *knob = slider->findChild<QQuickItem*>("Slider Knob"); + 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 + (slider->clipRect().center()).x()); + QVERIFY(initialXOffset <= 1); + + // Drag the slider in the allowed (vertical) direction with one finger + QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint(); + touchSeq.press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + p1 += QPoint(0, dragThreshold); + touchSeq.move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + p1 += QPoint(0, dragThreshold); + touchSeq.move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + p1 += QPoint(0, dragThreshold); + 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); + touchSeq.stationary(1).press(2, p2, window).commit(); + QQuickTouchUtils::flush(window); + 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) + qCDebug(lcPointerTests) << "knob has slipped out of groove by" << knobSliderXOffset << "pixels"; + // See if the knob is still centered over the slider's "groove" + QVERIFY(qAbs(knobSliderXOffset) <= 1); + + // Release + touchSeq.release(1, p1, window).release(2, p2, window).commit(); +} + +void tst_FlickableInterop::touchAndDragHandlerOnFlickable_data() +{ + QTest::addColumn<QByteArray>("qmlFile"); + QTest::addColumn<bool>("pressDelay"); + QTest::addColumn<bool>("targetNull"); + QTest::newRow("tapOnFlickable") << QByteArray("tapOnFlickable.qml") << false << false; + QTest::newRow("tapOnList") << QByteArray("tapOnList.qml") << false << false; + QTest::newRow("tapOnTable") << QByteArray("tapOnTable.qml") << false << false; + QTest::newRow("dragOnFlickable") << QByteArray("dragOnFlickable.qml") << false << false; + QTest::newRow("dragOnList") << QByteArray("dragOnList.qml") << false << false; + QTest::newRow("dragOnTable") << QByteArray("dragOnTable.qml") << false << false; + QTest::newRow("tapDelayOnFlickable") << QByteArray("tapOnFlickable.qml") << true << false; + QTest::newRow("tapDelayOnList") << QByteArray("tapOnList.qml") << true << false; + QTest::newRow("tapDelayOnTable") << QByteArray("tapOnTable.qml") << true << false; + QTest::newRow("dragDelayOnFlickable") << QByteArray("dragOnFlickable.qml") << true << false; + QTest::newRow("dragDelayOnList") << QByteArray("dragOnList.qml") << true << false; + QTest::newRow("dragDelayOnTable") << QByteArray("dragOnTable.qml") << true << false; + QTest::newRow("tapOnFlickableWithNullTargets") << QByteArray("tapOnFlickable.qml") << false << true; + QTest::newRow("tapOnListWithNullTargets") << QByteArray("tapOnList.qml") << false << true; + QTest::newRow("tapOnTableWithNullTargets") << QByteArray("tapOnTable.qml") << false << true; + QTest::newRow("dragOnFlickableWithNullTargets") << QByteArray("dragOnFlickable.qml") << false << true; + QTest::newRow("dragOnListWithNullTargets") << QByteArray("dragOnList.qml") << false << true; + QTest::newRow("dragOnTableWithNullTargets") << QByteArray("dragOnTable.qml") << false << true; + QTest::newRow("tapDelayOnFlickableWithNullTargets") << QByteArray("tapOnFlickable.qml") << true << true; + QTest::newRow("tapDelayOnListWithNullTargets") << QByteArray("tapOnList.qml") << true << true; + QTest::newRow("tapDelayOnTableWithNullTargets") << QByteArray("tapOnTable.qml") << true << true; + QTest::newRow("dragDelayOnFlickableWithNullTargets") << QByteArray("dragOnFlickable.qml") << true << true; + QTest::newRow("dragDelayOnListWithNullTargets") << QByteArray("dragOnList.qml") << true << true; + QTest::newRow("dragDelayOnTableWithNullTargets") << QByteArray("dragOnTable.qml") << true << true; +} + +void tst_FlickableInterop::touchAndDragHandlerOnFlickable() +{ + QFETCH(QByteArray, qmlFile); + QFETCH(bool, pressDelay); + QFETCH(bool, targetNull); + + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, qmlFile.constData()); + QQuickView * window = windowPtr.data(); + QQuickFlickable *flickable = qmlobject_cast<QQuickFlickable*>(window->rootObject()); + QVERIFY(flickable); + flickable->setPressDelay(pressDelay ? 5000 : 0); + QQuickItem *delegate = nullptr; + if (QQuickItemView *itemView = qmlobject_cast<QQuickItemView *>(flickable)) + delegate = itemView->currentItem(); + if (!delegate) + delegate = flickable->property("delegateUnderTest").value<QQuickItem*>(); + QQuickItem *button = delegate ? delegate->findChild<QQuickItem*>("button") + : flickable->findChild<QQuickItem*>("button"); + if (!button) + button = flickable->property("buttonUnderTest").value<QQuickItem*>(); + QVERIFY(button); + QQuickPointerHandler *buttonHandler = button->findChild<QQuickPointerHandler*>(); + QVERIFY(buttonHandler); + QQuickTapHandler *buttonTapHandler = qmlobject_cast<QQuickTapHandler *>(buttonHandler); + QQuickDragHandler *buttonDragHandler = qmlobject_cast<QQuickDragHandler *>(buttonHandler); + QQuickPointerHandler *delegateHandler = delegate ? delegate->findChild<QQuickPointerHandler*>() : nullptr; + QQuickPointerHandler *contentItemHandler = flickable->findChild<QQuickPointerHandler*>(); + QVERIFY(contentItemHandler); + // a handler declared directly in a Flickable (or item view) must actually be a child of the contentItem, + // just as Items declared inside are (QTBUG-71918 and QTBUG-73035) + QCOMPARE(contentItemHandler->parentItem(), flickable->contentItem()); + if (targetNull) { + buttonHandler->setTarget(nullptr); + if (delegateHandler) + delegateHandler->setTarget(nullptr); + contentItemHandler->setTarget(nullptr); + } + + // Drag one finger on the Flickable and make sure it flicks + QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice, false); + QPoint p1(780, 460); + touchSeq.press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + for (int i = 0; i < 4; ++i) { + p1 -= QPoint(dragThreshold, dragThreshold); + touchSeq.move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + } + if (!(buttonDragHandler && !pressDelay)) + QTRY_VERIFY(flickable->contentY() >= dragThreshold); + if (buttonTapHandler) + QCOMPARE(buttonTapHandler->isPressed(), false); + touchSeq.release(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + + // Drag one finger on the delegate and make sure Flickable flicks + if (delegate) { + flickable->setContentY(0); + QTRY_COMPARE(flickable->isMoving(), false); + QVERIFY(delegateHandler); + QQuickTapHandler *delegateTapHandler = qmlobject_cast<QQuickTapHandler *>(delegateHandler); + p1 = button->mapToScene(button->clipRect().bottomRight()).toPoint() + QPoint(10, 0); + touchSeq.press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + if (delegateTapHandler && !pressDelay) + QCOMPARE(delegateTapHandler->isPressed(), true); + for (int i = 0; i < 4; ++i) { + p1 -= QPoint(dragThreshold, dragThreshold); + touchSeq.move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + if (i > 1) + QTRY_VERIFY(delegateHandler->active() || flickable->isMoving()); + } + if (!(buttonDragHandler && !pressDelay)) + QVERIFY(flickable->contentY() > 0); + if (delegateTapHandler) + QCOMPARE(delegateTapHandler->isPressed(), false); + touchSeq.release(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + } + + // Drag one finger on the button and make sure Flickable flicks + flickable->setContentY(0); + QTRY_COMPARE(flickable->isMoving(), false); + p1 = button->mapToScene(button->clipRect().center()).toPoint(); + touchSeq.press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + if (buttonTapHandler && !pressDelay) + QTRY_COMPARE(buttonTapHandler->isPressed(), true); + for (int i = 0; i < 4; ++i) { + p1 -= QPoint(dragThreshold, dragThreshold); + touchSeq.move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + } + if (!(buttonDragHandler && !pressDelay)) + QVERIFY(flickable->contentY() > 0); + if (buttonTapHandler) + QCOMPARE(buttonTapHandler->isPressed(), false); + touchSeq.release(1, p1, window).commit(); +} + +QTEST_MAIN(tst_FlickableInterop) + +#include "tst_flickableinterop.moc" + diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml new file mode 100644 index 0000000000..f1591a412e --- /dev/null +++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 + +Rectangle { + width: 1024; height: 600 + color: "beige" + objectName: "beige root" + + Rectangle { + id: container + objectName: "container rect" + width: 600 + height: 500 + color: "black" + border.color: pinch3.active ? "red" : "black" + border.width: 3 + antialiasing: true + + MultiPointTouchArea { + id: mpta + anchors.fill: parent + //onGestureStarted: gesture.grab() // in case this is embedded in something that might steal + touchPoints: [ + TouchPoint { property color color: "red" }, + TouchPoint { property color color: "orange" }, + TouchPoint { property color color: "lightsteelblue" }, + TouchPoint { property color color: "green" } + ] } + + Repeater { + model: 4 + + Item { + id: crosshairs + property TouchPoint touchPoint + x: touchPoint.x - width / 2 + y: touchPoint.y - height / 2 + width: 300; height: 300 + visible: touchPoint.pressed + rotation: touchPoint.rotation + + Rectangle { + color: touchPoint.color + anchors.centerIn: parent + width: 2; height: parent.height + antialiasing: true + } + Rectangle { + color: touchPoint.color + anchors.centerIn: parent + width: parent.width; height: 2 + antialiasing: true + } + Component.onCompleted: touchPoint = mpta.touchPoints[index] + } + } + + Item { + objectName: "pinch and drag" + anchors.fill: parent + // In order for PinchHandler to get a chance to take a passive grab, it has to get the touchpoints first. + // In order to get the touchpoints first, it has to be on top of the Z order: i.e. come last in paintOrderChildItems(). + // This is the opposite situation as with filtersChildMouseEvents: e.g. PinchArea would have wanted to be the parent, + // if it even knew that trick (which it doesn't). + DragHandler { + id: dragHandler + objectName: "DragHandler" + target: container + grabPermissions: PointerHandler.CanTakeOverFromItems + } + PinchHandler { + id: pinch3 + objectName: "3-finger pinch" + target: container + minimumPointCount: 3 + minimumScale: 0.1 + maximumScale: 10 + grabPermissions: PointerHandler.CanTakeOverFromItems + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml new file mode 100644 index 0000000000..1bd20c6bcb --- /dev/null +++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 { + width: 640 + height: 480 + + Loader { + id: loader + + width: 480 + height: 480 + + sourceComponent: Rectangle { + id: item2 + anchors.fill: parent + color: "blue" + + DragHandler{} + } + } + + Rectangle { + color: "yellow" + width: 180 + height: 180 + + MultiPointTouchArea { + anchors.fill: parent + touchPoints: [ + TouchPoint { onPressedChanged: loader.sourceComponent = undefined } + ] + } + } +} + + diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/multipointtoucharea_interop.pro b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/multipointtoucharea_interop.pro new file mode 100644 index 0000000000..10d0ff8018 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/multipointtoucharea_interop.pro @@ -0,0 +1,15 @@ +CONFIG += testcase + +TARGET = tst_multipointtoucharea_interop +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_multipointtoucharea_interop.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +OTHER_FILES += data/pinchDragMPTA.qml diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp new file mode 100644 index 0000000000..bf582b820b --- /dev/null +++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp @@ -0,0 +1,306 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module 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 <QtQml/qqmlengine.h> +#include <QtQml/qqmlproperty.h> +#include <QtQuick/private/qquickdraghandler_p.h> +#include <QtQuick/private/qquickmultipointtoucharea_p.h> +#include <QtQuick/private/qquickpinchhandler_p.h> +#include <QtQuick/qquickitem.h> +#include <QtQuick/qquickview.h> + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_MptaInterop : public QQmlDataTest +{ + Q_OBJECT +public: + tst_MptaInterop() + : touchDevice(QTest::createTouchDevice()) + , touchPointerDevice(QQuickPointerDevice::touchDevice(touchDevice)) + {} + +private slots: + void initTestCase(); + + void touchDrag(); + void touchesThenPinch(); + void unloadHandlerWithPassiveGrab(); + +private: + void createView(QScopedPointer<QQuickView> &window, const char *fileName); + QTouchDevice *touchDevice; + QQuickPointerDevice *touchPointerDevice; +}; + +void tst_MptaInterop::createView(QScopedPointer<QQuickView> &window, const char *fileName) +{ + window.reset(new QQuickView); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != nullptr); +} + +void tst_MptaInterop::initTestCase() +{ + // This test assumes that we don't get synthesized mouse events from QGuiApplication + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + + QQmlDataTest::initTestCase(); +} + +void tst_MptaInterop::touchDrag() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "pinchDragMPTA.qml"); + QQuickView * window = windowPtr.data(); + + QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>(); + QVERIFY(mpta); + QQuickPinchHandler *pinch = window->rootObject()->findChild<QQuickPinchHandler*>(); + QVERIFY(pinch); + QQuickDragHandler *drag = window->rootObject()->findChild<QQuickDragHandler*>(); + QVERIFY(drag); + QQmlListReference tp(mpta, "touchPoints"); + QVERIFY(tp.at(3)); // the QML declares four touchpoints + QSignalSpy mptaPressedSpy(mpta, SIGNAL(pressed(QList<QObject*>))); + QSignalSpy mptaReleasedSpy(mpta, SIGNAL(released(QList<QObject*>))); + QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice); + + // Press one touchpoint: + // DragHandler gets a passive grab + // PinchHandler declines, because it wants 3 touchpoints + // MPTA grabs because DragHandler doesn't accept the single EventPoint + QPoint p1 = mpta->mapToScene(QPointF(20, 20)).toPoint(); + touch.press(1, p1).commit(); + QQuickTouchUtils::flush(window); + auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(touchPointerDevice); + QCOMPARE(tp.at(0)->property("pressed").toBool(), true); + QTRY_VERIFY(pointerEvent->point(0)->passiveGrabbers().contains(drag)); + + // Start moving + // DragHandler keeps monitoring, due to its passive grab, + // and eventually steals the exclusive grab from MPTA + int dragStoleGrab = 0; + for (int i = 0; i < 4; ++i) { + p1 += QPoint(dragThreshold / 2, 0); + touch.move(1, p1).commit(); + QQuickTouchUtils::flush(window); + if (!dragStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == drag) + dragStoleGrab = i; + } + if (dragStoleGrab) + qCDebug(lcPointerTests, "DragHandler stole the grab after %d events", dragStoleGrab); + QVERIFY(dragStoleGrab > 1); + + touch.release(1, p1).commit(); + QQuickTouchUtils::flush(window); +} + +// TODO touchesThenPinch_data with press/release sequences somehow: vectors of touchpoint IDs? or a string representation? +void tst_MptaInterop::touchesThenPinch() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "pinchDragMPTA.qml"); + QQuickView * window = windowPtr.data(); + + QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>(); + QVERIFY(mpta); + QQuickPinchHandler *pinch = window->rootObject()->findChild<QQuickPinchHandler*>(); + QVERIFY(pinch); + QQuickDragHandler *drag = window->rootObject()->findChild<QQuickDragHandler*>(); + QVERIFY(drag); + QQmlListReference tp(mpta, "touchPoints"); + QVERIFY(tp.at(3)); // the QML declares four touchpoints + QSignalSpy mptaPressedSpy(mpta, SIGNAL(pressed(QList<QObject*>))); + QSignalSpy mptaReleasedSpy(mpta, SIGNAL(released(QList<QObject*>))); + QSignalSpy mptaCanceledSpy(mpta, SIGNAL(canceled(QList<QObject*>))); + QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice); + auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(touchPointerDevice); + + // Press one touchpoint: + // DragHandler gets a passive grab + // PinchHandler declines, because it wants 3 touchpoints + // MPTA doesn't get a chance, because DragHandler accepted the single EventPoint + QPoint p1 = mpta->mapToScene(QPointF(20, 20)).toPoint(); + touch.press(1, p1).commit(); + QQuickTouchUtils::flush(window); + QTRY_COMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); + QTRY_COMPARE(pointerEvent->point(0)->passiveGrabbers().first(), drag); + + // Press a second touchpoint: MPTA grabs it + QPoint p2 = mpta->mapToScene(QPointF(200, 30)).toPoint(); + touch.stationary(1).press(2, p2).commit(); + QQuickTouchUtils::flush(window); + QVERIFY(tp.at(0)->property("pressed").toBool()); + QTRY_VERIFY(tp.at(1)->property("pressed").toBool()); + QCOMPARE(mptaPressedSpy.count(), 2); + + // Press a third touchpoint: MPTA grabs it too + QPoint p3 = mpta->mapToScene(QPointF(110, 200)).toPoint(); + touch.stationary(1).stationary(2).press(3, p3).commit(); + QQuickTouchUtils::flush(window); + QCOMPARE(tp.at(0)->property("pressed").toBool(), true); + QCOMPARE(tp.at(1)->property("pressed").toBool(), true); + QCOMPARE(tp.at(2)->property("pressed").toBool(), true); + QCOMPARE(mptaPressedSpy.count(), 3); + QCOMPARE(mptaCanceledSpy.count(), 0); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); + QCOMPARE(pointerEvent->point(1)->exclusiveGrabber(), mpta); + QCOMPARE(pointerEvent->point(2)->exclusiveGrabber(), mpta); + QVERIFY(!pinch->active()); + + // Start moving: PinchHandler steals the exclusive grab from MPTA as soon as dragThreshold is exceeded + int pinchStoleGrab = 0; + + const QPointF c = (p1 + p2 + p3)/3; // centroid of p1,p2,p3 + QTransform xform; // transform to rotate around the centroid + xform.translate(c.x(), c.y()).rotate(1).translate(-c.x(), -c.y()); + + for (int i = 0; i < 16; ++i) { + p1 = xform.map(p1); + p2 = xform.map(p2); + p3 = xform.map(p3); + touch.move(1, p1).move(2, p2).move(3, p3).commit(); + QQuickTouchUtils::flush(window); + if (!pinchStoleGrab && pointerEvent->point(0)->exclusiveGrabber() == pinch) { + pinchStoleGrab = i; + QCOMPARE(tp.at(0)->property("pressed").toBool(), false); + QCOMPARE(tp.at(1)->property("pressed").toBool(), false); + QCOMPARE(tp.at(2)->property("pressed").toBool(), false); + } + } + qCDebug(lcPointerTests) << "pinch started after" << pinchStoleGrab << "moves; ended with scale" << pinch->activeScale() << "rot" << pinch->rotation(); + QTRY_VERIFY(pinch->rotation() > 4); + QVERIFY(pinch->activeScale() > 1); + + // Press one more point (pinkie finger) + QPoint p4 = mpta->mapToScene(QPointF(300, 200)).toPoint(); + touch.move(1, p1).move(2, p2).move(3, p3).press(4, p4).commit(); + // PinchHandler deactivates, which lets MPTA grab all the points + QTRY_COMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); + QCOMPARE(pointerEvent->point(1)->exclusiveGrabber(), mpta); + QCOMPARE(pointerEvent->point(2)->exclusiveGrabber(), mpta); + QCOMPARE(pointerEvent->point(3)->exclusiveGrabber(), mpta); + // Move some more... MPTA keeps reacting + for (int i = 0; i < 8; ++i) { + p1 += QPoint(4, 4); + p2 += QPoint(4, 4); + p3 += QPoint(-4, 4); + p4 += QPoint(-4, -4); + touch.move(1, p1).move(2, p2).move(3, p3).move(4, p4).commit(); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), mpta); + QCOMPARE(pointerEvent->point(1)->exclusiveGrabber(), mpta); + QCOMPARE(pointerEvent->point(2)->exclusiveGrabber(), mpta); + QCOMPARE(pointerEvent->point(3)->exclusiveGrabber(), mpta); + QCOMPARE(tp.at(0)->property("pressed").toBool(), true); + QCOMPARE(tp.at(1)->property("pressed").toBool(), true); + QCOMPARE(tp.at(2)->property("pressed").toBool(), true); + QCOMPARE(tp.at(3)->property("pressed").toBool(), true); + } + + // Release the pinkie: PinchHandler acquires passive grabs on the 3 remaining points + touch.move(1, p1).move(2, p2).move(3, p3).release(4, p4).commit(); + // Move some more: PinchHander grabs again, and reacts + for (int i = 0; i < 8; ++i) { + p1 -= QPoint(4, 4); + p2 += QPoint(4, 4); + p3 -= QPoint(-4, 4); + touch.move(1, p1).move(2, p2).move(3, p3).commit(); + QTRY_COMPARE(pointerEvent->point(0)->exclusiveGrabber(), pinch); + QCOMPARE(pointerEvent->point(1)->exclusiveGrabber(), pinch); + QCOMPARE(pointerEvent->point(2)->exclusiveGrabber(), pinch); + } + + // Release the first finger + touch.stationary(2).stationary(3).release(1, p1).commit(); + // Move some more: PinchHander isn't interested in a mere 2 points. + // MPTA could maybe react; but QQuickWindowPrivate::deliverTouchEvent() calls + // deliverPressOrReleaseEvent() in a way which "starts over" with event delivery + // only for handlers, not for Items; therefore MPTA is not visited at this time. + for (int i = 0; i < 8; ++i) { + p2 -= QPoint(4, 4); + p3 += QPoint(4, 4); + touch.move(2, p2).move(3, p3).commit(); + QQuickTouchUtils::flush(window); + } + + // Release another finger + touch.stationary(2).release(3, p3).commit(); + // Move some more: DragHandler eventually reacts. + int dragTookGrab = 0; + for (int i = 0; i < 8; ++i) { + p2 += QPoint(8, -8); + touch.move(2, p2).commit(); + QQuickTouchUtils::flush(window); + QVERIFY(pointerEvent->point(0)->passiveGrabbers().contains(drag)); + if (!dragTookGrab && pointerEvent->point(0)->exclusiveGrabber() == drag) + dragTookGrab = i; + } + qCDebug(lcPointerTests) << "drag started after" << dragTookGrab << "moves; ended with translation" << drag->translation(); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), drag); + QTRY_VERIFY(drag->translation().x() > 0); + + touch.release(2, p2).commit(); + QQuickTouchUtils::flush(window); + QTRY_COMPARE(mptaReleasedSpy.count(), 1); +} + +void tst_MptaInterop::unloadHandlerWithPassiveGrab() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "unloadHandlerOnPress.qml"); + QQuickView * window = windowPtr.data(); + + QPointer<QQuickPointerHandler> handler = window->rootObject()->findChild<QQuickPointerHandler*>(); + QVERIFY(handler); + QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>(); + QVERIFY(mpta); + + QPoint point(90, 90); + QTest::mousePress(window, Qt::LeftButton, 0, point); + QCOMPARE(window->mouseGrabberItem(), mpta); + QTRY_VERIFY(handler.isNull()); // it got unloaded + QTest::mouseRelease(window, Qt::LeftButton, 0, point); // QTBUG-73819: don't crash +} + +QTEST_MAIN(tst_MptaInterop) + +#include "tst_multipointtoucharea_interop.moc" diff --git a/tests/auto/quick/pointerhandlers/pointerhandlers.pro b/tests/auto/quick/pointerhandlers/pointerhandlers.pro new file mode 100644 index 0000000000..950d6835eb --- /dev/null +++ b/tests/auto/quick/pointerhandlers/pointerhandlers.pro @@ -0,0 +1,13 @@ +TEMPLATE = subdirs + +qtConfig(private_tests) { + SUBDIRS += \ + flickableinterop \ + multipointtoucharea_interop \ + qquickdraghandler \ + qquickhoverhandler \ + qquickpinchhandler \ + qquickpointerhandler \ + qquickpointhandler \ + qquicktaphandler \ +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml new file mode 100644 index 0000000000..778a799d70 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 + objectName: label + 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 + width: 140 + height: 400 + + DragHandler { + id: dragHandler + objectName: label.text + " 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: 30 + 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: label.text + " TapHandler" + gesturePolicy: TapHandler.DragThreshold + onTapped: { + tapFlash.start() + root.tapped + } + } + } + + Text { + font.pointSize: 16 + color: "red" + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + text: root.value + } + + Text { + id: label + font.pointSize: 12 + color: "red" + anchors.top: parent.top + anchors.topMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + } + + Component.onCompleted: { + knob.programmatic = true + knob.setValue(root.value) + knob.programmatic = false + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml new file mode 100644 index 0000000000..158a02b7a6 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 + +SequentialAnimation { + id: tapFlash + running: false + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml new file mode 100644 index 0000000000..782750b783 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 + objectName: label + 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 + width: 140 + height: 400 + + 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: root.label + " Knob" + width: parent.width - 2 + height: 30 + 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 } + function flash() { tapFlash.start() } + DragHandler { + id: dragHandler + objectName: label.text + " DragHandler" + xAxis.enabled: false + yAxis.minimum: slot.y + yAxis.maximum: slot.height + slot.y - knob.height + } + TapHandler { + id: tap + objectName: label.text + " TapHandler" + gesturePolicy: TapHandler.DragThreshold + onTapped: { + tapFlash.start() + root.tapped + } + } + } + + Text { + font.pointSize: 16 + color: "red" + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + text: root.value + } + + Text { + id: label + font.pointSize: 12 + color: "red" + anchors.top: parent.top + anchors.topMargin: 5 + anchors.horizontalCenter: parent.horizontalCenter + } + + Component.onCompleted: { + knob.programmatic = true + knob.setValue(root.value) + knob.programmatic = false + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml new file mode 100644 index 0000000000..7b3601bea0 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests 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 + objectName: "Draggables" + width: 640 + height: 480 + + Repeater { + model: 2 + + Rectangle { + id: ball + objectName: "Ball " + (index + 1) + color: dragHandler.active ? "blue" : "lightsteelblue" + width: 80; height: 80; x: 200 + index * 200; y: 200; radius: width / 2 + onParentChanged: console.log(this + " parent " + parent) + + DragHandler { + id: dragHandler + objectName: "DragHandler " + (index + 1) + } + + Text { + color: "white" + anchors.centerIn: parent + horizontalAlignment: Text.AlignHCenter + text: ball.objectName + "\n" + dragHandler.centroid.position.x.toFixed(1) + "," + dragHandler.centroid.position.y.toFixed(1) + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draghandler_and_pinchhandler.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draghandler_and_pinchhandler.qml new file mode 100644 index 0000000000..08b85aef50 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draghandler_and_pinchhandler.qml @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests 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 + objectName: "DragHandler_and_PinchHandler" + width: 640 + height: 480 + + Rectangle { + id: rect + objectName: "Rect" + color: dragHandler.active ? "blue" : (pinchHandler.active ? "magenta" : "grey") + width: 200; height: 200; x: 100; y: 100 + + PinchHandler { + id: pinchHandler + objectName: "PinchHandler" + } + DragHandler { + id: dragHandler + objectName: "DragHandler" + } + + Text { + color: "white" + anchors.centerIn: parent + horizontalAlignment: Text.AlignHCenter + text: rect.objectName + "\n" + + "rotation:" + rect.rotation + "\n" + + dragHandler.centroid.position.x.toFixed(1) + "," + dragHandler.centroid.position.y.toFixed(1) + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml new file mode 100644 index 0000000000..f6042f4461 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 + +Rectangle { + id: root + width: 900 + height: 850 + objectName: "root" + color: "#222222" + + Grid { + objectName: "grid" + anchors.fill: parent + spacing: 10 + columns: 6 + Repeater { + id: top + objectName: "top" + model: 6 + + delegate: Slider { + objectName: label + label: "Drag Knob " + index + width: 140 + } + } + Repeater { + id: bottom + objectName: "bottom" + model: 6 + + delegate: DragAnywhereSlider { + objectName: label + label: "Drag Anywhere " + index + width: 140 + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/reparenting.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/reparenting.qml new file mode 100644 index 0000000000..e23cddf7a6 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/reparenting.qml @@ -0,0 +1,59 @@ +import QtQuick 2.12 + +Grid { + id: root + objectName: "root" + property bool reparentOnDrag: true + width: 200; height: 200 + columns: 3 + spacing: 10 + Repeater { + model: 9 + anchors.fill: parent + Item { + id: gridPlaceholder + objectName: "gridPlaceholder" + index + width: 60 + height: 60 + Rectangle { + id: icon + border.color: "black" + color: "beige" + radius: 3 + width: 60 + height: 60 + onParentChanged :console.log("parent " + parent) + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + DragHandler { + id: dragArea + } + Text { + anchors.centerIn: parent + text: index + "@" + Math.round(icon.x) + "," + Math.round(icon.y) + font.pointSize: 8 + } + states: [ + State { + when: dragArea.dragging + AnchorChanges { + target: icon + anchors.horizontalCenter: undefined + anchors.verticalCenter: undefined + } + ParentChange { + target: root.reparentOnDrag ? icon : null + parent: root + } + PropertyChanges { + target: icon + color: "yellow" + } + } + ] + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml new file mode 100644 index 0000000000..6e5574787c --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests 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 + +Rectangle { + id: root + width: 900 + height: 850 + objectName: "root" + color: "#222222" + + Row { + objectName: "row" + anchors.fill: parent + spacing: 10 + Rectangle { + width: 50 + height: 50 + color: "aqua" + objectName: "dragAndTap" + DragHandler { + objectName: "drag" + } + TapHandler { + objectName: "tap" + gesturePolicy: TapHandler.DragThreshold + } + } + Rectangle { + width: 50 + height: 50 + color: "aqua" + objectName: "tapAndDrag" + TapHandler { + objectName: "tap" + gesturePolicy: TapHandler.DragThreshold + } + DragHandler { + objectName: "drag" + } + } + + Rectangle { + color: "aqua" + width: 50 + height: 50 + objectName: "dragAndTapNotSiblings" + DragHandler { + objectName: "drag" + } + Rectangle { + color: "blue" + width: 30 + height: 30 + anchors.centerIn: parent + TapHandler { + objectName: "tap" + gesturePolicy: TapHandler.DragThreshold + } + } + } + Rectangle { + color: "aqua" + width: 50 + height: 50 + objectName: "tapAndDragNotSiblings" + TapHandler { + objectName: "tap" + gesturePolicy: TapHandler.DragThreshold + } + Rectangle { + color: "blue" + x: 10 + y: 10 + width: 30 + height: 30 + DragHandler { + objectName: "drag" + } + } + } + + + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro b/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro new file mode 100644 index 0000000000..42c4e46c4f --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/qquickdraghandler.pro @@ -0,0 +1,21 @@ +CONFIG += testcase + +TARGET = tst_qquickdraghandler +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_qquickdraghandler.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +OTHER_FILES += data/DragAnywhereSlider.qml \ + data/FlashAnimation.qml \ + data/Slider.qml \ + data/draggables.qml \ + data/grabberstate.qml \ + data/multipleSliders.qml \ + data/reparenting.qml \ diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp new file mode 100644 index 0000000000..eb210c2112 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp @@ -0,0 +1,573 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module 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 <QtQml/qqmlengine.h> +#include <QtQml/qqmlproperty.h> +#include <QtQuick/private/qquickdraghandler_p.h> +#include <QtQuick/private/qquickrepeater_p.h> +#include <QtQuick/private/qquicktaphandler_p.h> +#include <QtQuick/qquickitem.h> +#include <QtQuick/qquickview.h> + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_DragHandler : public QQmlDataTest +{ + Q_OBJECT +public: + tst_DragHandler() + :touchDevice(QTest::createTouchDevice()) + {} + +private slots: + void initTestCase(); + + void defaultPropertyValues(); + void touchDrag(); + void mouseDrag(); + void touchDragMulti(); + void touchDragMultiSliders_data(); + void touchDragMultiSliders(); + void touchPassiveGrabbers_data(); + void touchPassiveGrabbers(); + void touchPinchAndMouseMove(); + +private: + void createView(QScopedPointer<QQuickView> &window, const char *fileName); + QSet<QQuickPointerHandler *> passiveGrabbers(QQuickWindow *window, int pointId = 0); + QTouchDevice *touchDevice; +}; + +void tst_DragHandler::createView(QScopedPointer<QQuickView> &window, const char *fileName) +{ + window.reset(new QQuickView); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != nullptr); +} + +QSet<QQuickPointerHandler*> tst_DragHandler::passiveGrabbers(QQuickWindow *window, int pointId /*= 0*/) +{ + QSet<QQuickPointerHandler*> result; + QQuickWindowPrivate *winp = QQuickWindowPrivate::get(window); + if (QQuickPointerDevice* device = QQuickPointerDevice::touchDevice(touchDevice)) { + QQuickPointerEvent *pointerEvent = winp->pointerEventInstance(device); + for (int i = 0; i < pointerEvent->pointCount(); ++i) { + QQuickEventPoint *eventPoint = pointerEvent->point(i); + QVector<QPointer <QQuickPointerHandler> > passives = eventPoint->passiveGrabbers(); + if (!pointId || eventPoint->pointId() == pointId) { + for (auto it = passives.constBegin(); it != passives.constEnd(); ++it) + result << it->data(); + } + } + } + return result; +} + +void tst_DragHandler::initTestCase() +{ + // This test assumes that we don't get synthesized mouse events from QGuiApplication + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + + QQmlDataTest::initTestCase(); +} + +void tst_DragHandler::defaultPropertyValues() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "draggables.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *ball = window->rootObject()->childItems().first(); + QVERIFY(ball); + QQuickDragHandler *dragHandler = ball->findChild<QQuickDragHandler*>(); + QVERIFY(dragHandler); + + QCOMPARE(dragHandler->acceptedButtons(), Qt::LeftButton); + QCOMPARE(dragHandler->translation(), QVector2D()); + QCOMPARE(dragHandler->centroid().position(), QPointF()); + QCOMPARE(dragHandler->centroid().scenePosition(), QPointF()); + QCOMPARE(dragHandler->centroid().pressPosition(), QPointF()); + QCOMPARE(dragHandler->centroid().scenePressPosition(), QPointF()); + QCOMPARE(dragHandler->centroid().sceneGrabPosition(), QPointF()); +} + +void tst_DragHandler::touchDrag() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "draggables.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *ball = window->rootObject()->childItems().first(); + QVERIFY(ball); + QQuickDragHandler *dragHandler = ball->findChild<QQuickDragHandler*>(); + QVERIFY(dragHandler); + + QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged())); + QSignalSpy centroidChangedSpy(dragHandler, SIGNAL(centroidChanged())); + + QPointF ballCenter = ball->clipRect().center(); + QPointF scenePressPos = ball->mapToScene(ballCenter); + QPoint p1 = scenePressPos.toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->centroid().position(), ballCenter); + QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter); + QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().velocity(), QVector2D()); + QCOMPARE(centroidChangedSpy.count(), 1); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0); + QCOMPARE(centroidChangedSpy.count(), 2); + QVERIFY(!dragHandler->active()); + p1 += QPoint(1, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(translationChangedSpy.count(), 0); + QCOMPARE(centroidChangedSpy.count(), 3); + QCOMPARE(dragHandler->translation().x(), 0.0); + QPointF sceneGrabPos = p1; + QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos); + p1 += QPoint(19, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(dragHandler->centroid().position(), ballCenter); + QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter); + QCOMPARE(dragHandler->centroid().scenePosition(), ball->mapToScene(ballCenter)); + QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos); + QCOMPARE(dragHandler->translation().x(), dragThreshold + 20.0); + QCOMPARE(dragHandler->translation().y(), 0.0); + QVERIFY(dragHandler->centroid().velocity().x() > 0); + QCOMPARE(centroidChangedSpy.count(), 4); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton); + QCOMPARE(dragHandler->centroid().velocity(), QVector2D()); + QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1); + QCOMPARE(translationChangedSpy.count(), 1); + QCOMPARE(centroidChangedSpy.count(), 5); +} + +void tst_DragHandler::mouseDrag() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "draggables.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *ball = window->rootObject()->childItems().first(); + QVERIFY(ball); + QQuickDragHandler *dragHandler = ball->findChild<QQuickDragHandler*>(); + QVERIFY(dragHandler); + + QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged())); + QSignalSpy centroidChangedSpy(dragHandler, SIGNAL(centroidChanged())); + + QPointF ballCenter = ball->clipRect().center(); + QPointF scenePressPos = ball->mapToScene(ballCenter); + QPoint p1 = scenePressPos.toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->centroid().position(), ballCenter); + QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter); + QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().velocity(), QVector2D()); + QCOMPARE(centroidChangedSpy.count(), 1); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0); + QCOMPARE(centroidChangedSpy.count(), 2); + QVERIFY(!dragHandler->active()); + p1 += QPoint(1, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(translationChangedSpy.count(), 0); + QCOMPARE(centroidChangedSpy.count(), 3); + QCOMPARE(dragHandler->translation().x(), 0.0); + QPointF sceneGrabPos = p1; + QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos); + p1 += QPoint(19, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(dragHandler->active()); + QCOMPARE(dragHandler->centroid().position(), ballCenter); + QCOMPARE(dragHandler->centroid().pressPosition(), ballCenter); + QCOMPARE(dragHandler->centroid().scenePosition(), ball->mapToScene(ballCenter)); + QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos); + QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos); + QCOMPARE(dragHandler->translation().x(), dragThreshold + 20.0); + QCOMPARE(dragHandler->translation().y(), 0.0); + QVERIFY(dragHandler->centroid().velocity().x() > 0); + QCOMPARE(centroidChangedSpy.count(), 4); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!dragHandler->active()); + QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton); + QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1); + QCOMPARE(translationChangedSpy.count(), 1); + QCOMPARE(centroidChangedSpy.count(), 5); +} + +void tst_DragHandler::touchDragMulti() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "draggables.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *ball1 = window->rootObject()->childItems().first(); + QVERIFY(ball1); + QQuickDragHandler *dragHandler1 = ball1->findChild<QQuickDragHandler*>(); + QVERIFY(dragHandler1); + QSignalSpy translationChangedSpy1(dragHandler1, SIGNAL(translationChanged())); + QSignalSpy centroidChangedSpy1(dragHandler1, SIGNAL(centroidChanged())); + + QQuickItem *ball2 = window->rootObject()->childItems().at(1); + QVERIFY(ball2); + QQuickDragHandler *dragHandler2 = ball2->findChild<QQuickDragHandler*>(); + QVERIFY(dragHandler2); + QSignalSpy translationChangedSpy2(dragHandler2, SIGNAL(translationChanged())); + QSignalSpy centroidChangedSpy2(dragHandler1, SIGNAL(centroidChanged())); + + QPointF ball1Center = ball1->clipRect().center(); + QPointF scenePressPos1 = ball1->mapToScene(ball1Center); + QPoint p1 = scenePressPos1.toPoint(); + QPointF ball2Center = ball2->clipRect().center(); + QPointF scenePressPos2 = ball2->mapToScene(ball2Center); + QPoint p2 = scenePressPos2.toPoint(); + QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice, false); + + touchSeq.press(1, p1, window).press(2, p2, window).commit(); + QQuickTouchUtils::flush(window); + QVERIFY(!dragHandler1->active()); + QCOMPARE(centroidChangedSpy1.count(), 1); + QCOMPARE(dragHandler1->centroid().position(), ball1Center); + QCOMPARE(dragHandler1->centroid().pressPosition(), ball1Center); + QCOMPARE(dragHandler1->centroid().scenePosition(), scenePressPos1); + QCOMPARE(dragHandler1->centroid().scenePressPosition(), scenePressPos1); + QVERIFY(!dragHandler2->active()); + QCOMPARE(centroidChangedSpy2.count(), 1); + QCOMPARE(dragHandler2->centroid().position(), ball2Center); + QCOMPARE(dragHandler2->centroid().pressPosition(), ball2Center); + QCOMPARE(dragHandler2->centroid().scenePosition(), scenePressPos2); + QCOMPARE(dragHandler2->centroid().scenePressPosition(), scenePressPos2); + p1 += QPoint(dragThreshold, 0); + p2 += QPoint(0, dragThreshold); + touchSeq.move(1, p1, window).move(2, p2, window).commit(); + QQuickTouchUtils::flush(window); + QVERIFY(!dragHandler1->active()); + QCOMPARE(centroidChangedSpy1.count(), 2); + QCOMPARE(dragHandler1->centroid().position(), ball1Center + QPointF(dragThreshold, 0)); + QCOMPARE(dragHandler1->centroid().pressPosition(), ball1Center); + QCOMPARE(dragHandler1->centroid().scenePosition().toPoint(), p1); + QCOMPARE(dragHandler1->centroid().scenePressPosition(), scenePressPos1); + QVERIFY(!dragHandler2->active()); + QCOMPARE(centroidChangedSpy2.count(), 2); + QCOMPARE(dragHandler2->centroid().position(), ball2Center + QPointF(0, dragThreshold)); + QCOMPARE(dragHandler2->centroid().pressPosition(), ball2Center); + QCOMPARE(dragHandler2->centroid().scenePosition().toPoint(), p2); + QCOMPARE(dragHandler2->centroid().scenePressPosition(), scenePressPos2); + p1 += QPoint(1, 0); + p2 += QPoint(0, 1); + touchSeq.move(1, p1, window).move(2, p2, window).commit(); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(dragHandler1->active()); + QVERIFY(dragHandler2->active()); + QCOMPARE(translationChangedSpy1.count(), 0); + QCOMPARE(dragHandler1->translation().x(), 0.0); + QPointF sceneGrabPos1 = p1; + QPointF sceneGrabPos2 = p2; + QCOMPARE(dragHandler1->centroid().sceneGrabPosition(), sceneGrabPos1); + QCOMPARE(dragHandler2->centroid().sceneGrabPosition(), sceneGrabPos2); + p1 += QPoint(19, 0); + p2 += QPoint(0, 19); + QVERIFY(dragHandler2->active()); + QCOMPARE(translationChangedSpy2.count(), 0); + QCOMPARE(dragHandler2->translation().x(), 0.0); + QCOMPARE(dragHandler2->centroid().sceneGrabPosition(), sceneGrabPos2); + touchSeq.move(1, p1, window).move(2, p2, window).commit(); + QQuickTouchUtils::flush(window); + QVERIFY(dragHandler1->active()); + QVERIFY(dragHandler2->active()); + QCOMPARE(dragHandler1->centroid().position(), ball1Center); + QCOMPARE(dragHandler1->centroid().pressPosition(), ball1Center); + QCOMPARE(dragHandler1->centroid().scenePosition(), ball1->mapToScene(ball1Center)); + QCOMPARE(dragHandler1->centroid().scenePressPosition(), scenePressPos1); + QCOMPARE(dragHandler1->centroid().sceneGrabPosition(), sceneGrabPos1); + QCOMPARE(dragHandler1->translation().x(), dragThreshold + 20.0); + QCOMPARE(dragHandler1->translation().y(), 0.0); + QCOMPARE(dragHandler2->centroid().position(), ball2Center); + QCOMPARE(dragHandler2->centroid().pressPosition(), ball2Center); + QCOMPARE(dragHandler2->centroid().scenePosition(), ball2->mapToScene(ball2Center)); + QCOMPARE(dragHandler2->centroid().scenePressPosition(), scenePressPos2); + QCOMPARE(dragHandler2->centroid().sceneGrabPosition(), sceneGrabPos2); + QCOMPARE(dragHandler2->translation().x(), 0.0); + QCOMPARE(dragHandler2->translation().y(), dragThreshold + 20.0); + touchSeq.release(1, p1, window).stationary(2).commit(); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!dragHandler1->active()); + QVERIFY(dragHandler2->active()); + QCOMPARE(dragHandler1->centroid().pressedButtons(), Qt::NoButton); + QCOMPARE(ball1->mapToScene(ball1Center).toPoint(), p1); + QCOMPARE(translationChangedSpy1.count(), 1); + touchSeq.release(2, p2, window).commit(); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!dragHandler2->active()); + QCOMPARE(ball2->mapToScene(ball2Center).toPoint(), p2); + QCOMPARE(translationChangedSpy2.count(), 1); +} + +void tst_DragHandler::touchDragMultiSliders_data() +{ + QTest::addColumn<int>("sliderRow"); + QTest::addColumn<QVector<int> >("whichSliders"); + QTest::addColumn<QVector<int> >("startingCenterOffsets"); + QTest::addColumn<QVector<QVector2D> >("movements"); + + QTest::newRow("Drag Knob: start on the knobs, drag down") << + 0 << QVector<int> { 0, 1, 2 } << QVector<int> { 0, 0, 0 } << QVector<QVector2D> { {0, 60}, {0, 60}, {0, 60} }; + QTest::newRow("Drag Knob: start on the knobs, drag diagonally downward") << + 0 << QVector<int> { 0, 1, 2 } << QVector<int> { 0, 0, 0 } << QVector<QVector2D> { {20, 40}, {20, 60}, {20, 80} }; + QTest::newRow("Drag Anywhere: start on the knobs, drag down") << + 1 << QVector<int> { 0, 1, 2 } << QVector<int> { 0, 0, 0 } << QVector<QVector2D> { {0, 60}, {0, 60}, {0, 60} }; + QTest::newRow("Drag Anywhere: start on the knobs, drag diagonally downward") << + 1 << QVector<int> { 0, 1, 2 } << QVector<int> { 0, 0, 0 } << QVector<QVector2D> { {20, 40}, {20, 60}, {20, 80} }; + // TODO these next two fail because the DragHandler grabs when a finger + // drags across it from outside, but should rather start only if it is pressed inside +// QTest::newRow("Drag Knob: start above the knobs, drag down") << +// 0 << QVector<int> { 0, 1, 2 } << QVector<int> { -30, -30, -30 } << QVector<QVector2D> { {0, 40}, {0, 60}, {0, 80} }; +// QTest::newRow("Drag Knob: start above the knobs, drag diagonally downward") << +// 0 << QVector<int> { 0, 1, 2 } << QVector<int> { -30, -30, -30 } << QVector<QVector2D> { {20, 40}, {20, 60}, {20, 80} }; + QTest::newRow("Drag Anywhere: start above the knobs, drag down") << + 1 << QVector<int> { 0, 1, 2 } << QVector<int> { -20, -30, -40 } << QVector<QVector2D> { {0, 60}, {0, 60}, {0, 60} }; + QTest::newRow("Drag Anywhere: start above the knobs, drag diagonally downward") << + 1 << QVector<int> { 0, 1, 2 } << QVector<int> { -20, -30, -40 } << QVector<QVector2D> { {20, 40}, {20, 60}, {20, 80} }; +} + +void tst_DragHandler::touchDragMultiSliders() +{ + QFETCH(int, sliderRow); + QFETCH(QVector<int>, whichSliders); + QFETCH(QVector<int>, startingCenterOffsets); + QFETCH(QVector<QVector2D>, movements); + const int moveCount = 8; + + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "multipleSliders.qml"); + QQuickView * window = windowPtr.data(); + QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice); + + QQuickRepeater *rowRepeater = window->rootObject()->findChildren<QQuickRepeater *>()[sliderRow]; + QVector<QQuickItem *> knobs; + QVector<QQuickDragHandler *> dragHandlers; + QVector<QQuickTapHandler *> tapHandlers; + QVector<QPointF> startPoints; + for (int sli : whichSliders) { + QQuickItem *slider = rowRepeater->itemAt(sli); + QVERIFY(slider); + dragHandlers << slider->findChild<QQuickDragHandler*>(); + QVERIFY(dragHandlers[sli]); + tapHandlers << slider->findChild<QQuickTapHandler*>(); + QVERIFY(tapHandlers[sli]); + knobs << tapHandlers[sli]->parentItem(); + QPointF startPoint = knobs[sli]->mapToScene(knobs[sli]->clipRect().center()); + startPoint.setY(startPoint.y() + startingCenterOffsets[sli]); + startPoints << startPoint; + qCDebug(lcPointerTests) << "row" << sliderRow << "slider" << sli << slider->objectName() << + "start" << startingCenterOffsets[sli] << startPoints[sli]; + } + QVector<QPointF> touchPoints = startPoints; + + // Press + for (int sli : whichSliders) + touch.press(sli, touchPoints[sli].toPoint()); + touch.commit(); + + // Moves + for (int m = 0; m < moveCount; ++m) { + for (int sli : whichSliders) { + QVector2D incr = movements[sli] / moveCount; + touchPoints[sli] += incr.toPointF(); + touch.move(sli, touchPoints[sli].toPoint()); + } + touch.commit(); + QQuickTouchUtils::flush(window); + } + + // Check that they moved to where they should: since the slider is constrained, + // only the y component should have an effect; knobs should not come out of their "grooves" + for (int sli : whichSliders) { + QPoint endPosition = knobs[sli]->mapToScene(knobs[sli]->clipRect().center()).toPoint(); + QPoint expectedEndPosition(startPoints[sli].x(), startPoints[sli].y() + movements[sli].y()); + if (sliderRow == 0 && qAbs(startingCenterOffsets[sli]) > knobs[sli]->height() / 2) + expectedEndPosition = startPoints[sli].toPoint(); + qCDebug(lcPointerTests) << "slider " << knobs[sli]->objectName() << "started @" << startPoints[sli] + << "tried to move by" << movements[sli] << "ended up @" << endPosition << "expected" << expectedEndPosition; + QTRY_COMPARE(endPosition, expectedEndPosition); + } + + // Release + for (int sli : whichSliders) + touch.release(sli, touchPoints[sli].toPoint()); + touch.commit(); +} + +void tst_DragHandler::touchPassiveGrabbers_data() +{ + QTest::addColumn<QString>("itemName"); + QTest::addColumn<QStringList>("expectedPassiveGrabberNames"); + + QTest::newRow("Drag And Tap") << "dragAndTap" << QStringList({"drag", "tap"}); + QTest::newRow("Tap And Drag") << "tapAndDrag" << QStringList({"tap", "drag"}); + QTest::newRow("Drag And Tap (not siblings)") << "dragAndTapNotSiblings" << QStringList({"drag", "tap"}); + QTest::newRow("Tap And Drag (not siblings)") << "tapAndDragNotSiblings" << QStringList({"tap", "drag"}); +} + +void tst_DragHandler::touchPassiveGrabbers() +{ + QFETCH(QString, itemName); + QFETCH(QStringList, expectedPassiveGrabberNames); + + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "simpleTapAndDragHandlers.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *row2 = window->rootObject()->findChild<QQuickItem*>(itemName); + QSet<QQuickPointerHandler *> expectedPassiveGrabbers; + for (QString objectName : expectedPassiveGrabberNames) + expectedPassiveGrabbers << row2->findChild<QQuickPointerHandler*>(objectName); + + QPointF p1 = row2->mapToScene(row2->clipRect().center()); + QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice); + touch.press(1, p1.toPoint()).commit(); + QQuickTouchUtils::flush(window); + + QCOMPARE(passiveGrabbers(window), expectedPassiveGrabbers); + + QQuickDragHandler *dragHandler = nullptr; + for (QQuickPointerHandler *handler: expectedPassiveGrabbers) { + QPointF scenePressPos; + if (QQuickMultiPointHandler *mph = qmlobject_cast<QQuickMultiPointHandler *>(handler)) + scenePressPos = mph->centroid().scenePressPosition(); + else + scenePressPos = static_cast<QQuickSinglePointHandler *>(handler)->point().scenePressPosition(); + QCOMPARE(scenePressPos, p1); + QQuickDragHandler *dh = qmlobject_cast<QQuickDragHandler *>(handler); + if (dh) + dragHandler = dh; + } + QVERIFY(dragHandler); + QPointF initialPos = dragHandler->target()->position(); + + p1 += QPointF(50, 50); + touch.move(1, p1.toPoint()).commit(); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(dragHandler->active()); + + p1 += QPointF(50, 50); + touch.move(1, p1.toPoint()).commit(); + QQuickTouchUtils::flush(window); + QPointF movementDelta = dragHandler->target()->position() - initialPos; + qCDebug(lcPointerTests) << "DragHandler moved the target by" << movementDelta; + QVERIFY(movementDelta.x() >= 100); + QVERIFY(movementDelta.y() >= 100); + + QTest::qWait(500); + + touch.release(1, p1.toPoint()); + touch.commit(); + QQuickTouchUtils::flush(window); +} + +void tst_DragHandler::touchPinchAndMouseMove() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "draghandler_and_pinchhandler.qml"); + QQuickView *window = windowPtr.data(); + QQuickItem *rect = window->rootObject()->findChild<QQuickItem*>(QLatin1String("Rect")); + QQuickPointerHandler *pinchHandler = window->rootObject()->findChild<QQuickPointerHandler*>(QLatin1String("PinchHandler")); + + QPoint p1(150,200); + QPoint p2(250,200); + + // Trigger a scale pinch, PinchHandler should activate + QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice); + touch.press(1, p1).press(2, p2).commit(); + QQuickTouchUtils::flush(window); + QPoint delta(10,0); + for (int i = 0; i < 10 && !pinchHandler->active(); ++i) { + p1-=delta; + p2+=delta; + touch.move(1, p1).move(2, p2).commit(); + QQuickTouchUtils::flush(window); + } + QCOMPARE(pinchHandler->active(), true); + + // While having the touch points pressed, send wrong mouse event as MS Windows did: + // * A MoveMove with LeftButton down + // (in order to synthesize that, qtestMouseButtons needs to be modified) + // (This will make the DragHandler do a passive grab) + QTestPrivate::qtestMouseButtons = Qt::LeftButton; + QTest::mouseMove(window, p1 + delta); + + touch.release(1, p1).release(2, p2).commit(); + QQuickTouchUtils::flush(window); + + // Now move the mouse with no buttons down and check if the rect did not move + // At this point, no touch points are pressed and no mouse buttons are pressed. + QTestPrivate::qtestMouseButtons = Qt::NoButton; + QSignalSpy rectMovedSpy(rect, SIGNAL(xChanged())); + for (int i = 0; i < 10; ++i) { + p1 += delta; + QTest::mouseMove(window, p1); + QCOMPARE(rectMovedSpy.count(), 0); + } +} + +QTEST_MAIN(tst_DragHandler) + +#include "tst_qquickdraghandler.moc" + diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml new file mode 100644 index 0000000000..011dc4e75f --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** 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 + +Rectangle { + id: root + width: 640 + height: 480 + color: "#444" + + Component { + id: buttonsAndStuff + Column { + anchors.fill: parent + anchors.margins: 8 + spacing: 8 + + Rectangle { + objectName: "buttonWithMA" + width: parent.width + height: 30 + color: buttonMA.pressed ? "lightsteelblue" : "#999" + border.color: buttonMA.containsMouse ? "cyan" : "transparent" + + MouseArea { + id: buttonMA + objectName: "buttonMA" + hoverEnabled: true + anchors.fill: parent + onClicked: console.log("clicked MA") + } + + Text { + anchors.centerIn: parent + text: "MouseArea" + } + } + + Rectangle { + objectName: "buttonWithHH" + width: parent.width + height: 30 + color: flash ? "#999" : "white" + border.color: buttonHH.hovered ? "cyan" : "transparent" + property bool flash: true + + HoverHandler { + id: buttonHH + objectName: "buttonHH" + acceptedDevices: PointerDevice.AllDevices + } + + TapHandler { } + + Text { + anchors.centerIn: parent + text: "HoverHandler" + } + } + } + } + + Rectangle { + id: paddle + objectName: "paddle" + width: 100 + height: 100 + color: paddleHH.hovered ? "indianred" : "#888" + x: (parent.width - width) / 2 + y: parent.height - 100 + radius: 10 + + HoverHandler { + id: paddleHH + objectName: "paddleHH" + } + } + + Rectangle { + objectName: "topSidebar" + radius: 5 + antialiasing: true + x: -radius + y: -radius + width: 120 + height: 200 + border.color: topSidebarHH.hovered ? "cyan" : "black" + color: "#777" + + Rectangle { + color: "cyan" + width: 10 + height: width + radius: width / 2 + visible: topSidebarHH.hovered + x: topSidebarHH.point.position.x - width / 2 + y: topSidebarHH.point.position.y - height / 2 + z: 100 + } + + HoverHandler { + id: topSidebarHH + objectName: "topSidebarHH" + } + + Loader { + objectName: "topSidebarLoader" + sourceComponent: buttonsAndStuff + anchors.fill: parent + } + } + + Rectangle { + objectName: "bottomSidebar" + radius: 5 + antialiasing: true + x: -radius + anchors.bottom: parent.bottom + anchors.bottomMargin: -radius + width: 120 + height: 200 + border.color: bottomSidebarMA.containsMouse ? "cyan" : "black" + color: "#777" + + MouseArea { + id: bottomSidebarMA + objectName: "bottomSidebarMA" + hoverEnabled: true + anchors.fill: parent + } + + Loader { + objectName: "bottomSidebarLoader" + sourceComponent: buttonsAndStuff + anchors.fill: parent + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/qquickhoverhandler.pro b/tests/auto/quick/pointerhandlers/qquickhoverhandler/qquickhoverhandler.pro new file mode 100644 index 0000000000..34633e2532 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/qquickhoverhandler.pro @@ -0,0 +1,15 @@ +CONFIG += testcase + +TARGET = tst_qquickhoverhandler +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_qquickhoverhandler.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +OTHER_FILES += data/lesHoverables.qml \ diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp new file mode 100644 index 0000000000..f141a2546c --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** 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/qquickitem.h> +#include <QtQuick/private/qquickhoverhandler_p.h> +#include <QtQuick/private/qquickmousearea_p.h> +#include <qpa/qwindowsysteminterface.h> + +#include <private/qquickwindow_p.h> + +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlproperty.h> + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +static bool isPlatformWayland() +{ + return !QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive); +} + +class tst_HoverHandler : public QQmlDataTest +{ + Q_OBJECT +public: + tst_HoverHandler() + {} + +private slots: + void hoverHandlerAndUnderlyingHoverHandler(); + void mouseAreaAndUnderlyingHoverHandler(); + void hoverHandlerAndUnderlyingMouseArea(); + void movingItemWithHoverHandler(); + +private: + void createView(QScopedPointer<QQuickView> &window, const char *fileName); +}; + +void tst_HoverHandler::createView(QScopedPointer<QQuickView> &window, const char *fileName) +{ + window.reset(new QQuickView); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != nullptr); +} + +void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "lesHoverables.qml"); + QQuickView * window = windowPtr.data(); + QQuickItem * topSidebar = window->rootObject()->findChild<QQuickItem *>("topSidebar"); + QVERIFY(topSidebar); + QQuickItem * button = topSidebar->findChild<QQuickItem *>("buttonWithHH"); + QVERIFY(button); + QQuickHoverHandler *topSidebarHH = topSidebar->findChild<QQuickHoverHandler *>("topSidebarHH"); + QVERIFY(topSidebarHH); + QQuickHoverHandler *buttonHH = button->findChild<QQuickHoverHandler *>("buttonHH"); + QVERIFY(buttonHH); + + QPoint buttonCenter(button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint()); + QPoint rightOfButton(button->mapToScene(QPointF(button->width() + 2, button->height() / 2)).toPoint()); + QPoint outOfSidebar(topSidebar->mapToScene(QPointF(topSidebar->width() + 2, topSidebar->height() / 2)).toPoint()); + QSignalSpy sidebarHoveredSpy(topSidebarHH, SIGNAL(hoveredChanged())); + QSignalSpy buttonHoveredSpy(buttonHH, SIGNAL(hoveredChanged())); + + QTest::mouseMove(window, outOfSidebar); + QCOMPARE(topSidebarHH->isHovered(), false); + QCOMPARE(sidebarHoveredSpy.count(), 0); + QCOMPARE(buttonHH->isHovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 0); + + QTest::mouseMove(window, rightOfButton); + QCOMPARE(topSidebarHH->isHovered(), true); + QCOMPARE(sidebarHoveredSpy.count(), 1); + QCOMPARE(buttonHH->isHovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 0); + + QTest::mouseMove(window, buttonCenter); + QCOMPARE(topSidebarHH->isHovered(), true); + QCOMPARE(sidebarHoveredSpy.count(), 1); + QCOMPARE(buttonHH->isHovered(), true); + QCOMPARE(buttonHoveredSpy.count(), 1); + + QTest::mouseMove(window, rightOfButton); + QCOMPARE(topSidebarHH->isHovered(), true); + QCOMPARE(sidebarHoveredSpy.count(), 1); + QCOMPARE(buttonHH->isHovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 2); + + QTest::mouseMove(window, outOfSidebar); + QCOMPARE(topSidebarHH->isHovered(), false); + QCOMPARE(sidebarHoveredSpy.count(), 2); + QCOMPARE(buttonHH->isHovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 2); +} + +void tst_HoverHandler::mouseAreaAndUnderlyingHoverHandler() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "lesHoverables.qml"); + QQuickView * window = windowPtr.data(); + QQuickItem * topSidebar = window->rootObject()->findChild<QQuickItem *>("topSidebar"); + QVERIFY(topSidebar); + QQuickMouseArea * buttonMA = topSidebar->findChild<QQuickMouseArea *>("buttonMA"); + QVERIFY(buttonMA); + QQuickHoverHandler *topSidebarHH = topSidebar->findChild<QQuickHoverHandler *>("topSidebarHH"); + QVERIFY(topSidebarHH); + + QPoint buttonCenter(buttonMA->mapToScene(QPointF(buttonMA->width() / 2, buttonMA->height() / 2)).toPoint()); + QPoint rightOfButton(buttonMA->mapToScene(QPointF(buttonMA->width() + 2, buttonMA->height() / 2)).toPoint()); + QPoint outOfSidebar(topSidebar->mapToScene(QPointF(topSidebar->width() + 2, topSidebar->height() / 2)).toPoint()); + QSignalSpy sidebarHoveredSpy(topSidebarHH, SIGNAL(hoveredChanged())); + QSignalSpy buttonHoveredSpy(buttonMA, SIGNAL(hoveredChanged())); + + QTest::mouseMove(window, outOfSidebar); + QCOMPARE(topSidebarHH->isHovered(), false); + QCOMPARE(sidebarHoveredSpy.count(), 0); + QCOMPARE(buttonMA->hovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 0); + + QTest::mouseMove(window, rightOfButton); + QCOMPARE(topSidebarHH->isHovered(), true); + QCOMPARE(sidebarHoveredSpy.count(), 1); + QCOMPARE(buttonMA->hovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 0); + + QTest::mouseMove(window, buttonCenter); + QCOMPARE(topSidebarHH->isHovered(), true); + QCOMPARE(sidebarHoveredSpy.count(), 1); + QCOMPARE(buttonMA->hovered(), true); + QCOMPARE(buttonHoveredSpy.count(), 1); + + QTest::mouseMove(window, rightOfButton); + QCOMPARE(topSidebarHH->isHovered(), true); + QCOMPARE(sidebarHoveredSpy.count(), 1); + QCOMPARE(buttonMA->hovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 2); + + QTest::mouseMove(window, outOfSidebar); + QCOMPARE(topSidebarHH->isHovered(), false); + QCOMPARE(sidebarHoveredSpy.count(), 2); + QCOMPARE(buttonMA->hovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 2); +} + +void tst_HoverHandler::hoverHandlerAndUnderlyingMouseArea() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "lesHoverables.qml"); + QQuickView * window = windowPtr.data(); + QQuickItem * bottomSidebar = window->rootObject()->findChild<QQuickItem *>("bottomSidebar"); + QVERIFY(bottomSidebar); + QQuickMouseArea *bottomSidebarMA = bottomSidebar->findChild<QQuickMouseArea *>("bottomSidebarMA"); + QVERIFY(bottomSidebarMA); + QQuickItem * button = bottomSidebar->findChild<QQuickItem *>("buttonWithHH"); + QVERIFY(button); + QQuickHoverHandler *buttonHH = button->findChild<QQuickHoverHandler *>("buttonHH"); + QVERIFY(buttonHH); + + QPoint buttonCenter(button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint()); + QPoint rightOfButton(button->mapToScene(QPointF(button->width() + 2, button->height() / 2)).toPoint()); + QPoint outOfSidebar(bottomSidebar->mapToScene(QPointF(bottomSidebar->width() + 2, bottomSidebar->height() / 2)).toPoint()); + QSignalSpy sidebarHoveredSpy(bottomSidebarMA, SIGNAL(hoveredChanged())); + QSignalSpy buttonHoveredSpy(buttonHH, SIGNAL(hoveredChanged())); + + QTest::mouseMove(window, outOfSidebar); + QCOMPARE(bottomSidebarMA->hovered(), false); + QCOMPARE(sidebarHoveredSpy.count(), 0); + QCOMPARE(buttonHH->isHovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 0); + + QTest::mouseMove(window, rightOfButton); + QCOMPARE(bottomSidebarMA->hovered(), true); + QCOMPARE(sidebarHoveredSpy.count(), 1); + QCOMPARE(buttonHH->isHovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 0); + + QTest::mouseMove(window, buttonCenter); + QCOMPARE(bottomSidebarMA->hovered(), false); + QCOMPARE(sidebarHoveredSpy.count(), 2); + QCOMPARE(buttonHH->isHovered(), true); + QCOMPARE(buttonHoveredSpy.count(), 1); + + QTest::mouseMove(window, rightOfButton); + QCOMPARE(bottomSidebarMA->hovered(), true); + QCOMPARE(sidebarHoveredSpy.count(), 3); + QCOMPARE(buttonHH->isHovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 2); + + QTest::mouseMove(window, outOfSidebar); + QCOMPARE(bottomSidebarMA->hovered(), false); + QCOMPARE(sidebarHoveredSpy.count(), 4); + QCOMPARE(buttonHH->isHovered(), false); + QCOMPARE(buttonHoveredSpy.count(), 2); +} + +void tst_HoverHandler::movingItemWithHoverHandler() +{ + if (isPlatformWayland()) + QSKIP("Wayland: QCursor::setPos() doesn't work."); + + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "lesHoverables.qml"); + QQuickView * window = windowPtr.data(); + QQuickItem * paddle = window->rootObject()->findChild<QQuickItem *>("paddle"); + QVERIFY(paddle); + QQuickHoverHandler *paddleHH = paddle->findChild<QQuickHoverHandler *>("paddleHH"); + QVERIFY(paddleHH); + + // Find the global coordinate of the paddle + const QPoint p(paddle->mapToScene(paddle->clipRect().center()).toPoint()); + const QPoint paddlePos = window->mapToGlobal(p); + + // Now hide the window, put the cursor where the paddle was and show it again + window->hide(); + QTRY_COMPARE(window->isVisible(), false); + QCursor::setPos(paddlePos); + window->show(); + QTest::qWaitForWindowExposed(window); + + QTRY_COMPARE(paddleHH->isHovered(), true); + + paddle->setX(100); + QTRY_COMPARE(paddleHH->isHovered(), false); + + paddle->setX(p.x()); + QTRY_COMPARE(paddleHH->isHovered(), true); + + paddle->setX(540); + QTRY_COMPARE(paddleHH->isHovered(), false); +} + +QTEST_MAIN(tst_HoverHandler) + +#include "tst_qquickhoverhandler.moc" diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml new file mode 100644 index 0000000000..3cabde5f59 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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 + +Rectangle { + id: whiteRect + property real scale: -1.0 + property int activeCount : 0 + property int deactiveCount : 0 + width: 320; height: 320 + color: "white" + Rectangle { + id: blackRect + objectName: "blackrect" + color: "black" + y: 50 + x: 50 + width: 100 + height: 100 + opacity: (whiteRect.width-blackRect.x+whiteRect.height-blackRect.y-199)/200 + Text { color: "white"; text: "opacity: " + blackRect.opacity + "\nscale: " + blackRect.scale} + Rectangle { + color: "red" + width: 6; height: 6; radius: 3 + visible: pincharea.active + x: pincharea.centroid.position.x - radius + y: pincharea.centroid.position.y - radius + } + + PinchHandler { + id: pincharea + objectName: "pinchHandler" + minimumScale: 1.0 + maximumScale: 4.0 + minimumRotation: 0.0 + maximumRotation: 90.0 + xAxis.maximum: 140 + yAxis.maximum: 170 + onActiveChanged: { + whiteRect.scale = pincharea.scale + if (active) ++activeCount + else ++deactiveCount; + } + + onUpdated: { + whiteRect.scale = pincharea.scale + //whiteRect.pointCount = pincharea.pointCount + } + } + } + } diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml new file mode 100644 index 0000000000..4d1a520c01 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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 + +Rectangle { + id: root + property variant centroid : pinchHandler.centroid + property real scale: pinchHandler.scale + property int pointCount: 0 + property bool pinchActive: pinchHandler.active + width: 240; height: 320 + + Rectangle { + id: blackRect + objectName: "blackrect" + color: "black" + y: 50 + x: 50 + width: 200 + height: 200 + + PinchHandler { + id: pinchHandler + objectName: "pinchHandler" + minimumScale: 0.5 + maximumScale: 2.0 + minimumRotation: 0.0 + maximumRotation: 0.0 + minimumPointCount: 3 + maximumPointCount: 3 + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml new file mode 100644 index 0000000000..46e9ccca87 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** 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 + +Rectangle { + width: 400 + height: 400 + + Rectangle { + x: 100 + y: 100 + width: 200 + height: 200 + rotation: 45 + + Rectangle { + id: rect + scale: 0.5 + color: "black" + anchors.fill: parent + + PinchHandler { + objectName: "pinchHandler" + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/qquickpinchhandler.pro b/tests/auto/quick/pointerhandlers/qquickpinchhandler/qquickpinchhandler.pro new file mode 100644 index 0000000000..7e177d9786 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/qquickpinchhandler.pro @@ -0,0 +1,16 @@ +CONFIG += testcase +TARGET = tst_qquickpinchhandler +macos:CONFIG -= app_bundle + +SOURCES += tst_qquickpinchhandler.cpp +OTHER_FILES = \ + data/pinchproperties.qml \ + data/threeFingers.qml \ + data/transformedPinchArea.qml + +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/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp new file mode 100644 index 0000000000..19fdae3b44 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp @@ -0,0 +1,772 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 <QtTest/QSignalSpy> +#include <QtGui/QStyleHints> +#include <qpa/qwindowsysteminterface.h> +#include <private/qquickpinchhandler_p.h> +#include <QtQuick/private/qquickrectangle_p.h> +#include <QtQuick/qquickview.h> +#include <QtQml/qqmlcontext.h> +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_QQuickPinchHandler: public QQmlDataTest +{ + Q_OBJECT +public: + tst_QQuickPinchHandler() : device(0) { } +private slots: + void initTestCase(); + void cleanupTestCase(); + void pinchProperties(); + void scale(); + void scaleThreeFingers(); + void pan(); + void dragAxesEnabled_data(); + void dragAxesEnabled(); + void retouch(); + void cancel(); + void transformedpinchHandler_data(); + void transformedpinchHandler(); + +private: + QQuickView *createView(); + QTouchDevice *device; +}; +void tst_QQuickPinchHandler::initTestCase() +{ + QQmlDataTest::initTestCase(); + if (!device) { + device = new QTouchDevice; + device->setType(QTouchDevice::TouchScreen); + QWindowSystemInterface::registerTouchDevice(device); + } +} + +void tst_QQuickPinchHandler::cleanupTestCase() +{ + +} + +static bool withinBounds(qreal lower, qreal num, qreal upper) +{ + return num >= lower && num <= upper; +} + +void tst_QQuickPinchHandler::pinchProperties() +{ + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("pinchproperties.qml")); + window->show(); + QVERIFY(window->rootObject() != nullptr); + + QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler"); + QVERIFY(pinchHandler != nullptr); + + // target + QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); + QVERIFY(blackRect != nullptr); + QCOMPARE(blackRect, pinchHandler->target()); + QQuickItem *rootItem = qobject_cast<QQuickItem*>(window->rootObject()); + QVERIFY(rootItem != nullptr); + QSignalSpy targetSpy(pinchHandler, SIGNAL(targetChanged())); + pinchHandler->setTarget(rootItem); + QCOMPARE(targetSpy.count(),1); + pinchHandler->setTarget(rootItem); + QCOMPARE(targetSpy.count(),1); + + // axis + /* + QCOMPARE(pinchHandler->axis(), QQuickPinch::XAndYAxis); + QSignalSpy axisSpy(pinchHandler, SIGNAL(dragAxisChanged())); + pinchHandler->setAxis(QQuickPinch::XAxis); + QCOMPARE(pinchHandler->axis(), QQuickPinch::XAxis); + QCOMPARE(axisSpy.count(),1); + pinchHandler->setAxis(QQuickPinch::XAxis); + QCOMPARE(axisSpy.count(),1); + + // minimum and maximum drag properties + QSignalSpy xminSpy(pinchHandler, SIGNAL(minimumXChanged())); + QSignalSpy xmaxSpy(pinchHandler, SIGNAL(maximumXChanged())); + QSignalSpy yminSpy(pinchHandler, SIGNAL(minimumYChanged())); + QSignalSpy ymaxSpy(pinchHandler, SIGNAL(maximumYChanged())); + + QCOMPARE(pinchHandler->xmin(), 0.0); + QCOMPARE(pinchHandler->xmax(), rootItem->width()-blackRect->width()); + QCOMPARE(pinchHandler->ymin(), 0.0); + QCOMPARE(pinchHandler->ymax(), rootItem->height()-blackRect->height()); + + pinchHandler->setXmin(10); + pinchHandler->setXmax(10); + pinchHandler->setYmin(10); + pinchHandler->setYmax(10); + + QCOMPARE(pinchHandler->xmin(), 10.0); + QCOMPARE(pinchHandler->xmax(), 10.0); + QCOMPARE(pinchHandler->ymin(), 10.0); + QCOMPARE(pinchHandler->ymax(), 10.0); + + QCOMPARE(xminSpy.count(),1); + QCOMPARE(xmaxSpy.count(),1); + QCOMPARE(yminSpy.count(),1); + QCOMPARE(ymaxSpy.count(),1); + + pinchHandler->setXmin(10); + pinchHandler->setXmax(10); + pinchHandler->setYmin(10); + pinchHandler->setYmax(10); + + QCOMPARE(xminSpy.count(),1); + QCOMPARE(xmaxSpy.count(),1); + QCOMPARE(yminSpy.count(),1); + QCOMPARE(ymaxSpy.count(),1); + */ + + // minimum and maximum scale properties + QSignalSpy scaleMinSpy(pinchHandler, SIGNAL(minimumScaleChanged())); + QSignalSpy scaleMaxSpy(pinchHandler, SIGNAL(maximumScaleChanged())); + + QCOMPARE(pinchHandler->minimumScale(), 1.0); + QCOMPARE(pinchHandler->maximumScale(), 4.0); + + pinchHandler->setMinimumScale(0.5); + pinchHandler->setMaximumScale(1.5); + + QCOMPARE(pinchHandler->minimumScale(), 0.5); + QCOMPARE(pinchHandler->maximumScale(), 1.5); + + QCOMPARE(scaleMinSpy.count(),1); + QCOMPARE(scaleMaxSpy.count(),1); + + pinchHandler->setMinimumScale(0.5); + pinchHandler->setMaximumScale(1.5); + + QCOMPARE(scaleMinSpy.count(),1); + QCOMPARE(scaleMaxSpy.count(),1); + + // minimum and maximum rotation properties + QSignalSpy rotMinSpy(pinchHandler, SIGNAL(minimumRotationChanged())); + QSignalSpy rotMaxSpy(pinchHandler, SIGNAL(maximumRotationChanged())); + + QCOMPARE(pinchHandler->minimumRotation(), 0.0); + QCOMPARE(pinchHandler->maximumRotation(), 90.0); + + pinchHandler->setMinimumRotation(-90.0); + pinchHandler->setMaximumRotation(45.0); + + QCOMPARE(pinchHandler->minimumRotation(), -90.0); + QCOMPARE(pinchHandler->maximumRotation(), 45.0); + + QCOMPARE(rotMinSpy.count(),1); + QCOMPARE(rotMaxSpy.count(),1); + + pinchHandler->setMinimumRotation(-90.0); + pinchHandler->setMaximumRotation(45.0); + + QCOMPARE(rotMinSpy.count(),1); + QCOMPARE(rotMaxSpy.count(),1); +} + +QTouchEvent::TouchPoint makeTouchPoint(int id, QPoint p, QQuickView *v, QQuickItem *i) +{ + QTouchEvent::TouchPoint touchPoint(id); + touchPoint.setPos(i->mapFromScene(p)); + touchPoint.setScreenPos(v->mapToGlobal(p)); + touchPoint.setScenePos(p); + return touchPoint; +} + +void tst_QQuickPinchHandler::scale() +{ + QQuickView *window = createView(); + QScopedPointer<QQuickView> scope(window); + window->setSource(testFileUrl("pinchproperties.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(window->rootObject() != nullptr); + qApp->processEvents(); + + QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler"); + QVERIFY(pinchHandler != nullptr); + + QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); + QVERIFY(root != nullptr); + + // target + QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); + QVERIFY(blackRect != nullptr); + + QPoint p0(80, 80); + QPoint p1(100, 100); + { + QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); + pinchSequence.press(0, p0, window).commit(); + QQuickTouchUtils::flush(window); + // In order for the stationary point to remember its previous position, + // we have to reuse the same pinchSequence object. Otherwise if we let it + // be destroyed and then start a new sequence, point 0 will default to being + // stationary at 0, 0, and pinchHandler will filter out that touchpoint because + // it is outside its bounds. + pinchSequence.stationary(0).press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + + QPoint pd(10, 10); + // move one point until PinchHandler activates + for (int pi = 0; pi < 10 && !pinchHandler->active(); ++pi) { + p1 += pd; + pinchSequence.stationary(0).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + } + QCOMPARE(pinchHandler->active(), true); + QLineF line(p0, p1); + const qreal startLength = line.length(); + + p1+=pd; + pinchSequence.stationary(0).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + line.setP2(p1); + qreal scale = line.length() / startLength; + QVERIFY(qFloatDistance(root->property("scale").toReal(), scale) < 10); + QVERIFY(qFloatDistance(blackRect->scale(), scale) < 10); + + p1+=pd; + pinchSequence.stationary(0).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + line.setP2(p1); + scale = line.length() / startLength; + + QVERIFY(qFloatDistance(root->property("scale").toReal(), scale) < 10); + QVERIFY(qFloatDistance(blackRect->scale(), scale) < 10); + + QPointF expectedCentroid = p0 + (p1 - p0)/2; + QCOMPARE(pinchHandler->centroid().scenePosition(), expectedCentroid); + } + + // scale beyond bound + p1 += QPoint(20, 20); + { + QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); + pinchSequence.stationary(0).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + QCOMPARE(blackRect->scale(), qreal(4)); // qquickpinchhandler does not manipulate scale property + pinchSequence.release(0, p0, window).release(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + } + QCOMPARE(pinchHandler->active(), false); +} + +void tst_QQuickPinchHandler::scaleThreeFingers() +{ + QQuickView *window = createView(); + QScopedPointer<QQuickView> scope(window); + window->setSource(testFileUrl("threeFingers.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(window->rootObject() != nullptr); + qApp->processEvents(); + + QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler"); + QVERIFY(pinchHandler != nullptr); + + QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); + QVERIFY(root != nullptr); + + // target + QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); + QVERIFY(blackRect != nullptr); + + // center of blackrect is at 150,150 + QPoint p0(80, 80); + QPoint p1(220, 80); + QPoint p2(150, 220); + { + QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); + pinchSequence.press(0, p0, window).commit(); + QQuickTouchUtils::flush(window); + // In order for the stationary point to remember its previous position, + // we have to reuse the same pinchSequence object. Otherwise if we let it + // be destroyed and then start a new sequence, point 0 will default to being + // stationary at 0, 0, and pinchHandler will filter out that touchpoint because + // it is outside its bounds. + pinchSequence.stationary(0).press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + pinchSequence.stationary(0).stationary(1).press(2, p2, window).commit(); + QQuickTouchUtils::flush(window); + for (int i = 0; i < 5;++i) { + p0 += QPoint(-4, -4); + p1 += QPoint(+4, -4); + p2 += QPoint( 0, +6); + pinchSequence.move(0, p0,window).move(1, p1,window).move(2, p2,window).commit(); + QQuickTouchUtils::flush(window); + } + + QCOMPARE(pinchHandler->active(), true); + // scale we got was 1.1729088738267854364, but keep some slack + QVERIFY(withinBounds(1.163, root->property("scale").toReal(), 1.183)); + // should not rotate + QCOMPARE(root->property("rotation").toReal(), 0.); + + for (int i = 0; i < 5;++i) { + p0 += QPoint(-4, -4); + p1 += QPoint(+4, -4); + p2 += QPoint( 0, +6); + pinchSequence.move(0, p0,window).move(1, p1,window).move(2, p2,window).commit(); + QQuickTouchUtils::flush(window); + } + // scale we got was 1.4613, but keep some slack + QVERIFY(withinBounds(1.361, root->property("scale").toReal(), 1.561)); + + // since points were moved symetrically around the y axis, centroid should remain at x:150 + QCOMPARE(root->property("centroid").value<QQuickHandlerPoint>().scenePosition().x(), 150); // blackrect is at 50,50 + + // scale beyond bound, we should reach the maximumScale + p0 += QPoint(-40, -40); + p1 += QPoint(+40, -40); + p2 += QPoint( 0, +60); + pinchSequence.move(0, p0,window).move(1, p1,window).move(2, p2,window).commit(); + QQuickTouchUtils::flush(window); + + QCOMPARE(root->property("scale").toReal(), 2.); + pinchSequence.release(0, p0, window).release(1, p1, window).release(2, p2, window).commit(); + QQuickTouchUtils::flush(window); + } + QCOMPARE(pinchHandler->active(), false); +} + +void tst_QQuickPinchHandler::pan() +{ + QQuickView *window = createView(); + QScopedPointer<QQuickView> scope(window); + window->setSource(testFileUrl("pinchproperties.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(window->rootObject() != nullptr); + qApp->processEvents(); + + QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler"); + QVERIFY(pinchHandler != nullptr); + + QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); + QVERIFY(root != nullptr); + + // target + QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); + QVERIFY(blackRect != nullptr); + + QPoint p0(80, 80); + QPoint p1(100, 100); + { + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); + pinchSequence.press(0, p0, window).commit(); + QQuickTouchUtils::flush(window); + // In order for the stationary point to remember its previous position, + // we have to reuse the same pinchSequence object. + pinchSequence.stationary(0).press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + QVERIFY(!root->property("pinchActive").toBool()); + QCOMPARE(root->property("scale").toReal(), -1.0); + + p0 += QPoint(dragThreshold, 0); + p1 += QPoint(dragThreshold, 0); + pinchSequence.move(0, p0, window).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + // movement < dragThreshold: pinchHandler not yet active + QVERIFY(!root->property("pinchActive").toBool()); + QCOMPARE(root->property("scale").toReal(), -1.0); + + // just above the dragThreshold: pinchHandler starts + p0 += QPoint(1, 0); + p1 += QPoint(1, 0); + pinchSequence.move(0, p0, window).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + QCOMPARE(pinchHandler->active(), true); + QCOMPARE(root->property("scale").toReal(), 1.0); + + // Calculation of the center point is tricky at first: + // center point of the two touch points in item coordinates: + // scene coordinates: (80, 80) + (dragThreshold, 0), (100, 100) + (dragThreshold, 0) + // = ((180+dT)/2, 180/2) = (90+dT, 90) + // item coordinates: (scene) - (50, 50) = (40+dT, 40) + QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 1, 90)); + // pan started, but no actual movement registered yet: + // blackrect starts at 50,50 + QCOMPARE(blackRect->x(), 50.0); + QCOMPARE(blackRect->y(), 50.0); + + p0 += QPoint(10, 0); + p1 += QPoint(10, 0); + pinchSequence.move(0, p0, window).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 11, 90)); + QCOMPARE(blackRect->x(), 60.0); + QCOMPARE(blackRect->y(), 50.0); + + p0 += QPoint(0, 10); + p1 += QPoint(0, 10); + pinchSequence.move(0, p0, window).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 11, 90 + 10)); + QCOMPARE(blackRect->x(), 60.0); + QCOMPARE(blackRect->y(), 60.0); + + p0 += QPoint(10, 10); + p1 += QPoint(10, 10); + pinchSequence.move(0, p0, window).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + // now the item moved again, thus the center point of the touch is moved in total by (10, 10) + QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 21, 90 + 20)); + QCOMPARE(blackRect->x(), 70.0); + QCOMPARE(blackRect->y(), 70.0); + } + + // pan x beyond bound + p0 += QPoint(100,100); + p1 += QPoint(100,100); + QTest::touchEvent(window, device).move(0, p0, window).move(1, p1, window); + QQuickTouchUtils::flush(window); + + QCOMPARE(blackRect->x(), 140.0); + QCOMPARE(blackRect->y(), 170.0); + + QTest::touchEvent(window, device).release(0, p0, window).release(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!root->property("pinchActive").toBool()); +} + +void tst_QQuickPinchHandler::dragAxesEnabled_data() +{ + QTest::addColumn<bool>("xEnabled"); + QTest::addColumn<bool>("yEnabled"); + + QTest::newRow("both enabled") << true << true; + QTest::newRow("x enabled") << true << false; + QTest::newRow("y enabled") << false << true; + QTest::newRow("both disabled") << false << false; +} + +void tst_QQuickPinchHandler::dragAxesEnabled() +{ + QQuickView *window = createView(); + QScopedPointer<QQuickView> scope(window); + window->setSource(testFileUrl("pinchproperties.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(window->rootObject() != nullptr); + QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); + QVERIFY(blackRect != nullptr); + QQuickPinchHandler *pinchHandler = blackRect->findChild<QQuickPinchHandler*>(); + QVERIFY(pinchHandler != nullptr); + + QFETCH(bool, xEnabled); + QFETCH(bool, yEnabled); + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + pinchHandler->xAxis()->setEnabled(xEnabled); + pinchHandler->yAxis()->setEnabled(yEnabled); + QPoint c = blackRect->mapToScene(blackRect->clipRect().center()).toPoint(); + QPoint p0 = c - QPoint(0, dragThreshold); + QPoint p1 = c + QPoint(0, dragThreshold); + QPoint blackRectPos = blackRect->position().toPoint(); + + // press two points, one above the rectangle's center and one below + QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); + pinchSequence.press(0, p0, window).press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + + // expand the pinch vertically + p0 -= QPoint(0, dragThreshold); + p1 += QPoint(0, dragThreshold); + pinchSequence.move(0, p0, window).move(1, p1, window).commit(); + for (int pi = 0; pi < 4; ++pi) { + p0 -= QPoint(0, dragThreshold); + p1 += QPoint(0, dragThreshold); + pinchSequence.move(0, p0, window).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + qCDebug(lcPointerTests) << pi << "active" << pinchHandler->active() << "pts" << p0 << p1 + << "centroid" << pinchHandler->centroid().scenePosition() + << "rect pos" << blackRect->position() << "scale" << blackRect->scale(); + } + QCOMPARE(pinchHandler->active(), true); + QVERIFY(blackRect->scale() >= 2.0); + // drag started, but we only did scaling without any translation + QCOMPARE(pinchHandler->centroid().scenePosition().toPoint(), c); + QCOMPARE(blackRect->position().toPoint().x(), blackRectPos.x()); + QCOMPARE(blackRect->position().toPoint().y(), blackRectPos.y()); + + // drag diagonally + p0 += QPoint(150, 150); + p1 += QPoint(150, 150); + pinchSequence.move(0, p0, window).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + // the target should move if the xAxis is enabled, or stay in place if not + qCDebug(lcPointerTests) << "after diagonal drag: pts" << p0 << p1 + << "centroid" << pinchHandler->centroid().scenePosition() + << "rect pos" << blackRect->position() << "scale" << blackRect->scale(); + QCOMPARE(pinchHandler->centroid().scenePosition().toPoint(), QPoint(250, 250)); + QCOMPARE(blackRect->position().toPoint().x(), xEnabled ? 140 : blackRectPos.x()); // because of xAxis.maximum + QCOMPARE(blackRect->position().toPoint().y(), yEnabled ? 170 : blackRectPos.y()); // because of yAxis.maximum + + QTest::touchEvent(window, device).release(0, p0, window).release(1, p1, window); + QQuickTouchUtils::flush(window); +} + +// test pinchHandler, release one point, touch again to continue pinchHandler +void tst_QQuickPinchHandler::retouch() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QQuickView *window = createView(); + QScopedPointer<QQuickView> scope(window); + window->setSource(testFileUrl("pinchproperties.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(window->rootObject() != nullptr); + qApp->processEvents(); + + QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler"); + QVERIFY(pinchHandler != nullptr); + + QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); + QVERIFY(root != nullptr); + + // target + QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); + QVERIFY(blackRect != nullptr); + + QPoint p0(80, 80); + QPoint p1(100, 100); + { + QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); + pinchSequence.press(0, p0, window).commit(); + QQuickTouchUtils::flush(window); + // In order for the stationary point to remember its previous position, + // we have to reuse the same pinchSequence object. + pinchSequence.stationary(0).press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + const QPoint delta(dragThreshold + 1, dragThreshold + 1); + p0 -= delta; + p1 += delta; + pinchSequence.move(0, p0,window).move(1, p1,window).commit(); + QQuickTouchUtils::flush(window); + + QCOMPARE(root->property("scale").toReal(), 1.0); + QCOMPARE(pinchHandler->active(), true); + + p0 -= delta; + p1 += delta; + pinchSequence.move(0, p0,window).move(1, p1,window).commit(); + QQuickTouchUtils::flush(window); + + QCOMPARE(pinchHandler->active(), true); + + // accept some slack + QVERIFY(withinBounds(1.4, root->property("scale").toReal(), 1.6)); + QCOMPARE(pinchHandler->centroid().position(), QPointF(40, 40)); // blackrect is at 50,50 + QVERIFY(withinBounds(1.4, blackRect->scale(), 1.6)); + + QCOMPARE(root->property("activeCount").toInt(), 1); + QCOMPARE(root->property("deactiveCount").toInt(), 0); + + // Hold down the first finger but release the second one + pinchSequence.stationary(0).release(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + + QCOMPARE(root->property("activeCount").toInt(), 1); + QCOMPARE(root->property("deactiveCount").toInt(), 1); + + // Keep holding down the first finger and re-touch the second one, then move them both + pinchSequence.stationary(0).press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + p0 -= QPoint(10,10); + p1 += QPoint(10,10); + pinchSequence.move(0, p0, window).move(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + + // Lifting and retouching results in onPinchStarted being called again + QCOMPARE(root->property("activeCount").toInt(), 2); + QCOMPARE(root->property("deactiveCount").toInt(), 1); + + pinchSequence.release(0, p0, window).release(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + + QCOMPARE(pinchHandler->active(), false); + QCOMPARE(root->property("activeCount").toInt(), 2); + QCOMPARE(root->property("deactiveCount").toInt(), 2); + } +} + +void tst_QQuickPinchHandler::cancel() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QQuickView *window = createView(); + QScopedPointer<QQuickView> scope(window); + window->setSource(testFileUrl("pinchproperties.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(window->rootObject() != nullptr); + qApp->processEvents(); + + QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler"); + QVERIFY(pinchHandler != nullptr); + + QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); + QVERIFY(root != nullptr); + + // target + QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); + QVERIFY(blackRect != nullptr); + + QPoint p0(80, 80); + QPoint p1(100, 100); + { + QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); + pinchSequence.press(0, p0, window).commit(); + QQuickTouchUtils::flush(window); + // In order for the stationary point to remember its previous position, + // we have to reuse the same pinchSequence object. Otherwise if we let it + // be destroyed and then start a new sequence, point 0 will default to being + // stationary at 0, 0, and pinchHandler will filter out that touchpoint because + // it is outside its bounds. + pinchSequence.stationary(0).press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + const QPoint delta(dragThreshold + 1, dragThreshold + 1); + p0 -= delta; + p1 += delta; + pinchSequence.move(0, p0,window).move(1, p1,window).commit(); + QQuickTouchUtils::flush(window); + + QCOMPARE(root->property("scale").toReal(), 1.0); + QCOMPARE(pinchHandler->active(), true); + + p0 -= delta; + p1 += delta; + pinchSequence.move(0, p0,window).move(1, p1,window).commit(); + QQuickTouchUtils::flush(window); + + QVERIFY(withinBounds(1.4, root->property("scale").toReal(), 1.6)); + QCOMPARE(pinchHandler->centroid().position(), QPointF(40, 40)); // blackrect is at 50,50 + QVERIFY(withinBounds(1.4, blackRect->scale(), 1.6)); + + QSKIP("cancel is not supported atm"); + + QTouchEvent cancelEvent(QEvent::TouchCancel); + cancelEvent.setDevice(device); + QCoreApplication::sendEvent(window, &cancelEvent); + QQuickTouchUtils::flush(window); + + QCOMPARE(root->property("scale").toReal(), 1.0); + QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50 + QCOMPARE(blackRect->scale(), 1.0); + QVERIFY(!root->property("pinchActive").toBool()); + } +} + +void tst_QQuickPinchHandler::transformedpinchHandler_data() +{ + QTest::addColumn<QPoint>("p0"); + QTest::addColumn<QPoint>("p1"); + QTest::addColumn<bool>("shouldPinch"); + + QTest::newRow("checking inner pinchHandler 1") + << QPoint(200, 140) << QPoint(200, 260) << true; + + QTest::newRow("checking inner pinchHandler 2") + << QPoint(140, 200) << QPoint(200, 140) << true; + + QTest::newRow("checking inner pinchHandler 3") + << QPoint(140, 200) << QPoint(260, 200) << true; + + QTest::newRow("checking outer pinchHandler 1") + << QPoint(140, 140) << QPoint(260, 260) << false; + + QTest::newRow("checking outer pinchHandler 2") + << QPoint(140, 140) << QPoint(200, 200) << false; + + QTest::newRow("checking outer pinchHandler 3") + << QPoint(140, 260) << QPoint(260, 260) << false; +} + +void tst_QQuickPinchHandler::transformedpinchHandler() +{ + QFETCH(QPoint, p0); + QFETCH(QPoint, p1); + QFETCH(bool, shouldPinch); + + QQuickView *view = createView(); + QScopedPointer<QQuickView> scope(view); + view->setSource(testFileUrl("transformedPinchHandler.qml")); + view->show(); + QVERIFY(QTest::qWaitForWindowExposed(view)); + QVERIFY(view->rootObject() != nullptr); + qApp->processEvents(); + + QQuickPinchHandler *pinchHandler = view->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler"); + QVERIFY(pinchHandler != nullptr); + + const int threshold = qApp->styleHints()->startDragDistance(); + + { + QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(view, device); + // start pinchHandler + pinchSequence.press(0, p0, view).commit(); + QQuickTouchUtils::flush(view); + // In order for the stationary point to remember its previous position, + // we have to reuse the same pinchSequence object. + pinchSequence.stationary(0).press(1, p1, view).commit(); + QQuickTouchUtils::flush(view); + + // we move along the line that the two points form. + // The distance we move should be above the threshold (threshold * 2 to be safe) + QVector2D delta(p1 - p0); + delta.normalize(); + QVector2D movement = delta * (threshold * 2); + pinchSequence.stationary(0).move(1, p1 + movement.toPoint(), view).commit(); + QQuickTouchUtils::flush(view); + QCOMPARE(pinchHandler->active(), shouldPinch); + + // release pinchHandler + pinchSequence.release(0, p0, view).release(1, p1, view).commit(); + QQuickTouchUtils::flush(view); + QCOMPARE(pinchHandler->active(), false); + } +} + +QQuickView *tst_QQuickPinchHandler::createView() +{ + QQuickView *window = new QQuickView(0); + window->setGeometry(0,0,240,320); + + return window; +} + +QTEST_MAIN(tst_QQuickPinchHandler) + +#include "tst_qquickpinchhandler.moc" diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/dynamicallyCreated.qml b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/dynamicallyCreated.qml new file mode 100644 index 0000000000..8f774a7ec3 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/dynamicallyCreated.qml @@ -0,0 +1,34 @@ +import QtQuick 2.12 +import Qt.test 1.0 + +Item { + id: root + objectName: "root Item" + width: 320 + height: 480 + + Rectangle { + objectName: "eventItem's bounds" + anchors.fill: eventItem + color: "lightsteelblue" + } + + EventItem { + id: eventItem + objectName: "eventItem1" + x: 5 + y: 5 + height: 30 + width: 30 + + Component.onCompleted: handlerComponent.createObject(eventItem) + + Component { + id: handlerComponent + + EventHandler { + objectName: "eventHandler" + } + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/dynamicallyCreatedInWindow.qml b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/dynamicallyCreatedInWindow.qml new file mode 100644 index 0000000000..058726b267 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/dynamicallyCreatedInWindow.qml @@ -0,0 +1,20 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import Qt.test 1.0 + +Window { + id: root + objectName: "root Window" + width: 320 + height: 480 + + Component.onCompleted: handlerComponent.createObject(root) + + Component { + id: handlerComponent + + EventHandler { + objectName: "eventHandler" + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/handlerInWindow.qml b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/handlerInWindow.qml new file mode 100644 index 0000000000..49ec9be4a7 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/handlerInWindow.qml @@ -0,0 +1,14 @@ +import QtQuick 2.12 +import QtQuick.Window 2.12 +import Qt.test 1.0 + +Window { + id: root + objectName: "root Window" + width: 320 + height: 480 + + EventHandler { + objectName: "eventHandler" + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/singleitem.qml b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/singleitem.qml new file mode 100644 index 0000000000..126cf3ff2b --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/singleitem.qml @@ -0,0 +1,28 @@ +import QtQuick 2.8 +import Qt.test 1.0 + +Item { + id: root + objectName: "root Item" + width: 320 + height: 480 + + Rectangle { + objectName: "eventItem's bounds" + anchors.fill: eventItem + color: "lightsteelblue" + } + + EventItem { + id: eventItem + objectName: "eventItem1" + x: 5 + y: 5 + height: 30 + width: 30 + + EventHandler { + objectName: "eventHandler" + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/qquickpointerhandler.pro b/tests/auto/quick/pointerhandlers/qquickpointerhandler/qquickpointerhandler.pro new file mode 100644 index 0000000000..c386969206 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/qquickpointerhandler.pro @@ -0,0 +1,16 @@ +CONFIG += testcase + +TARGET = tst_qquickpointerhandler +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_qquickpointerhandler.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +# OTHER_FILES += data/foo.qml + diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp new file mode 100644 index 0000000000..2b6482465c --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp @@ -0,0 +1,685 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module 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 <private/qdebug_p.h> +#include <QtGui/qstylehints.h> +#include <QtQuick/private/qquickpointerhandler_p.h> +#include <QtQuick/qquickitem.h> +#include <QtQuick/qquickview.h> + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class Event +{ + Q_GADGET +public: + enum Destination { + FilterDestination, + MouseDestination, + TouchDestination, + HandlerDestination + }; + Q_ENUM(Destination) + + Event(Destination d, QEvent::Type t, Qt::TouchPointState s, int grabTransition, QPointF item, QPointF scene) + : destination(d), type(t), state(s), grabTransition(grabTransition), posWrtItem(item), posWrtScene(scene) + {} + + Destination destination; + QEvent::Type type; // if this represents a QEvent that was received + Qt::TouchPointState state; // if this represents an event (pointer, touch or mouse) + int grabTransition; // if this represents an onGrabChanged() notification (QQuickEventPoint::GrabTransition) + QPointF posWrtItem; + QPointF posWrtScene; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const class Event &event) { + QDebugStateSaver saver(dbg); + dbg.nospace(); + dbg << "Event("; + QtDebugUtils::formatQEnum(dbg, event.destination); + dbg << ' '; + QtDebugUtils::formatQEnum(dbg, event.type); + dbg << ' '; + QtDebugUtils::formatQEnum(dbg, event.state); + if (event.grabTransition) { + dbg << ' '; + QtDebugUtils::formatQEnum(dbg, QQuickEventPoint::GrabTransition(event.grabTransition)); + } + dbg << " @ "; + QtDebugUtils::formatQPoint(dbg, event.posWrtItem); + dbg << " S "; + QtDebugUtils::formatQPoint(dbg, event.posWrtScene); + dbg << ')'; + return dbg; +} +#endif + +enum { + NoGrab = 0, +}; + +class EventItem : public QQuickItem +{ + Q_OBJECT +public: + EventItem(QQuickItem *parent = nullptr) + : QQuickItem(parent), acceptPointer(false), grabPointer(false), acceptMouse(false), acceptTouch(false), filterTouch(false) + {} + + inline int grabTransition(bool accept, Qt::TouchPointState state) { + return (accept && (state != Qt::TouchPointReleased)) ? (int)QQuickEventPoint::GrabExclusive : (int)NoGrab; + } + + void touchEvent(QTouchEvent *event) + { + qCDebug(lcPointerTests) << event << "will accept?" << acceptTouch; + for (const QTouchEvent::TouchPoint &tp : event->touchPoints()) + eventList.append(Event(Event::TouchDestination, event->type(), tp.state(), grabTransition(acceptTouch, tp.state()), tp.pos(), tp.scenePos())); + event->setAccepted(acceptTouch); + } + void mousePressEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointPressed, grabTransition(acceptMouse, Qt::TouchPointPressed), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + void mouseMoveEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointMoved, grabTransition(acceptMouse, Qt::TouchPointMoved), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + void mouseReleaseEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointReleased, grabTransition(acceptMouse, Qt::TouchPointReleased), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + void mouseDoubleClickEvent(QMouseEvent *event) + { + qCDebug(lcPointerTests) << event; + eventList.append(Event(Event::MouseDestination, event->type(), Qt::TouchPointPressed, grabTransition(acceptMouse, Qt::TouchPointPressed), event->pos(), event->windowPos())); + event->setAccepted(acceptMouse); + } + + void mouseUngrabEvent() + { + qCDebug(lcPointerTests); + eventList.append(Event(Event::MouseDestination, QEvent::UngrabMouse, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive, QPoint(0,0), QPoint(0,0))); + } + + bool event(QEvent *event) + { + qCDebug(lcPointerTests) << event; + return QQuickItem::event(event); + } + + QList<Event> eventList; + bool acceptPointer; + bool grabPointer; + bool acceptMouse; + bool acceptTouch; + bool filterTouch; // when used as event filter + + bool eventFilter(QObject *o, QEvent *event) + { + qCDebug(lcPointerTests) << event << o; + if (event->type() == QEvent::TouchBegin || + event->type() == QEvent::TouchUpdate || + event->type() == QEvent::TouchCancel || + event->type() == QEvent::TouchEnd) { + QTouchEvent *touch = static_cast<QTouchEvent*>(event); + for (const QTouchEvent::TouchPoint &tp : touch->touchPoints()) + eventList.append(Event(Event::FilterDestination, event->type(), tp.state(), QQuickEventPoint::GrabExclusive, tp.pos(), tp.scenePos())); + if (filterTouch) + event->accept(); + return true; + } + return false; + } +}; + +#define QCOMPARE_EVENT(i, d, t, s, g) \ + {\ + const Event &event = eventItem1->eventList.at(i);\ + QCOMPARE(event.destination, d);\ + QCOMPARE(event.type, t);\ + QCOMPARE(event.state, s);\ + QCOMPARE(event.grabTransition, g);\ + }\ + +class EventHandler : public QQuickPointerHandler +{ +public: + void handlePointerEventImpl(QQuickPointerEvent *event) override + { + QQuickPointerHandler::handlePointerEventImpl(event); + if (!enabled()) + return; + if (event->isPressEvent()) + ++pressEventCount; + if (event->isReleaseEvent()) + ++releaseEventCount; + EventItem *item = qmlobject_cast<EventItem *>(target()); + if (!item) { + event->point(0)->setGrabberPointerHandler(this); + return; + } + qCDebug(lcPointerTests) << item->objectName() << event; + int c = event->pointCount(); + for (int i = 0; i < c; ++i) { + QQuickEventPoint *point = event->point(i); + if (item->acceptPointer) + point->setAccepted(item->acceptPointer); // does NOT imply a grab + if (item->grabPointer) + setExclusiveGrab(point, true); + qCDebug(lcPointerTests) << " " << i << ":" << point << "accepted?" << item->acceptPointer << "grabbed?" << (point->exclusiveGrabber() == this); + item->eventList.append(Event(Event::HandlerDestination, QEvent::Pointer, + static_cast<Qt::TouchPointState>(point->state()), + item->grabPointer ? (int)QQuickEventPoint::GrabExclusive : (int)NoGrab, + eventPos(point), point->scenePosition())); + } + } + + void onGrabChanged(QQuickPointerHandler *, QQuickEventPoint::GrabTransition stateChange, QQuickEventPoint *point) override + { + EventItem *item = qmlobject_cast<EventItem *>(target()); + if (item) + item->eventList.append(Event(Event::HandlerDestination, QEvent::None, + static_cast<Qt::TouchPointState>(point->state()), stateChange, eventPos(point), point->scenePosition())); + } + + int pressEventCount = 0; + int releaseEventCount = 0; +}; + +class tst_PointerHandlers : public QQmlDataTest +{ + Q_OBJECT +public: + tst_PointerHandlers() + :touchDevice(QTest::createTouchDevice()) + {} + +private slots: + void initTestCase(); + + void touchEventDelivery_data(); + void touchEventDelivery(); + void mouseEventDelivery(); + void touchReleaseOutside_data(); + void touchReleaseOutside(); + void dynamicCreation(); + void handlerInWindow(); + void dynamicCreationInWindow(); + +protected: + bool eventFilter(QObject *, QEvent *event) + { + Qt::TouchPointState tpState; + switch (event->type()) { + case QEvent::MouseButtonPress: + tpState = Qt::TouchPointPressed; + break; + case QEvent::MouseMove: + tpState = Qt::TouchPointMoved; + break; + case QEvent::MouseButtonRelease: + tpState = Qt::TouchPointReleased; + break; + default: + // So far we aren't recording filtered touch events here - they would be quite numerous in some cases + return false; + } + QMouseEvent *me = static_cast<QMouseEvent*>(event); + filteredEventList.append(Event(Event::FilterDestination, event->type(), tpState, + 0, me->pos(), me->globalPos())); + return false; + } + +private: + void createView(QScopedPointer<QQuickView> &window, const char *fileName); + QTouchDevice *touchDevice; + QList<Event> filteredEventList; +}; + +void tst_PointerHandlers::createView(QScopedPointer<QQuickView> &window, const char *fileName) +{ + window.reset(new QQuickView); +// window->setGeometry(0,0,240,320); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != nullptr); +} + +void tst_PointerHandlers::initTestCase() +{ + QQmlDataTest::initTestCase(); + qmlRegisterType<EventItem>("Qt.test", 1, 0, "EventItem"); + qmlRegisterType<EventHandler>("Qt.test", 1, 0, "EventHandler"); +} + +void tst_PointerHandlers::touchEventDelivery_data() +{ + QTest::addColumn<bool>("synthMouse"); // AA_SynthesizeMouseForUnhandledTouchEvents + QTest::newRow("no synth") << false; + QTest::newRow("synth") << true; +} + +void tst_PointerHandlers::touchEventDelivery() +{ + QFETCH(bool, synthMouse); + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, synthMouse); + + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "singleitem.qml"); + QQuickView * window = windowPtr.data(); + + EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); + QVERIFY(eventItem1); + + // Do not accept anything + QPoint p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QTRY_COMPARE(eventItem1->eventList.size(), synthMouse ? 3 : 2); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, Qt::TouchPointPressed, NoGrab); + if (synthMouse) + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, Qt::TouchPointPressed, NoGrab); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 4 : 3); + QCOMPARE_EVENT(eventItem1->eventList.size() - 1, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, NoGrab); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 5 : 4); + QCOMPARE_EVENT(eventItem1->eventList.size() - 1, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, NoGrab); + eventItem1->eventList.clear(); + + // Accept touch + eventItem1->acceptTouch = true; + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); + auto pointerEvent = QQuickWindowPrivate::get(window)->pointerEventInstance(QQuickPointerDevice::touchDevices().at(0)); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), eventItem1); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, NoGrab); + QCOMPARE_EVENT(3, Event::TouchDestination, QEvent::TouchUpdate, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(5, Event::TouchDestination, QEvent::TouchEnd, Qt::TouchPointReleased, NoGrab); + eventItem1->eventList.clear(); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // Accept mouse + eventItem1->acceptTouch = false; + eventItem1->acceptMouse = true; + eventItem1->setAcceptedMouseButtons(Qt::LeftButton); + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 3 : 2); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, Qt::TouchPointPressed, NoGrab); + if (synthMouse) + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); + QCOMPARE(window->mouseGrabberItem(), synthMouse ? eventItem1 : nullptr); + + QPointF localPos = eventItem1->mapFromScene(p1); + QPointF scenePos = p1; // item is at 0,0 + QCOMPARE(eventItem1->eventList.at(1).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(1).posWrtScene, scenePos); + if (synthMouse) { + QCOMPARE(eventItem1->eventList.at(2).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(2).posWrtScene, scenePos); + } + + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 6 : 3); + if (synthMouse) { + QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, NoGrab); + QCOMPARE_EVENT(4, Event::TouchDestination, QEvent::TouchUpdate, Qt::TouchPointMoved, NoGrab); + QCOMPARE_EVENT(5, Event::MouseDestination, QEvent::MouseMove, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); + } + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 10 : 4); + if (synthMouse) { + QCOMPARE_EVENT(6, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(7, Event::TouchDestination, QEvent::TouchEnd, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(8, Event::MouseDestination, QEvent::MouseButtonRelease, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(9, Event::MouseDestination, QEvent::UngrabMouse, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive); + } else { + QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, NoGrab); + } + eventItem1->eventList.clear(); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // Accept mouse buttons but not the touch event + eventItem1->acceptTouch = false; + eventItem1->acceptMouse = false; + eventItem1->setAcceptedMouseButtons(Qt::LeftButton); + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 3 : 2); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, Qt::TouchPointPressed, NoGrab); + if (synthMouse) + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, Qt::TouchPointPressed, NoGrab); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), nullptr); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 4 : 3); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 5 : 4); + eventItem1->eventList.clear(); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // Accept touch + eventItem1->acceptTouch = true; + eventItem1->setAcceptedMouseButtons(Qt::LeftButton); + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::TouchDestination, QEvent::TouchBegin, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, NoGrab); + QCOMPARE_EVENT(3, Event::TouchDestination, QEvent::TouchUpdate, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(5, Event::TouchDestination, QEvent::TouchEnd, Qt::TouchPointReleased, NoGrab); + eventItem1->eventList.clear(); + + // Accept pointer events + eventItem1->acceptPointer = true; + eventItem1->grabPointer = true; + p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::None, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); + p1 += QPoint(10, 0); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + QCOMPARE(eventItem1->eventList.size(), 5); + qCDebug(lcPointerTests) << eventItem1->eventList; + QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::None, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive); + eventItem1->eventList.clear(); +} + +void tst_PointerHandlers::mouseEventDelivery() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "singleitem.qml"); + QQuickView * window = windowPtr.data(); + + EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); + QVERIFY(eventItem1); + + // Do not accept anything + QPoint p1 = QPoint(20, 20); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 2); + p1 += QPoint(10, 0); + QTest::mouseMove(window, p1); + QCOMPARE(eventItem1->eventList.size(), 3); + QTest::mouseRelease(window, Qt::LeftButton); + QCOMPARE(eventItem1->eventList.size(), 3); + eventItem1->eventList.clear(); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // Accept mouse + eventItem1->acceptTouch = false; + eventItem1->acceptMouse = true; + eventItem1->setAcceptedMouseButtons(Qt::LeftButton); + p1 = QPoint(20, 20); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::MouseDestination, QEvent::MouseButtonPress, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); + QCOMPARE(window->mouseGrabberItem(), eventItem1); + + QPointF localPos = eventItem1->mapFromScene(p1); + QPointF scenePos = p1; // item is at 0,0 + QCOMPARE(eventItem1->eventList.at(0).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(0).posWrtScene, scenePos); + QCOMPARE(eventItem1->eventList.at(1).posWrtItem, localPos); + QCOMPARE(eventItem1->eventList.at(1).posWrtScene, scenePos); + + p1 += QPoint(10, 0); + QTest::mouseMove(window, p1); + QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseMove, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 5); + QCOMPARE_EVENT(3, Event::MouseDestination, QEvent::MouseButtonRelease, Qt::TouchPointReleased, NoGrab); + QCOMPARE_EVENT(4, Event::MouseDestination, QEvent::UngrabMouse, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive); + eventItem1->eventList.clear(); + + // wait to avoid getting a double click event + QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + + // Grab pointer events + eventItem1->acceptMouse = false; + eventItem1->acceptPointer = true; + eventItem1->grabPointer = true; + p1 = QPoint(20, 20); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(eventItem1->eventList.size(), 3); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::None, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, Qt::TouchPointPressed, 0); + p1 += QPoint(10, 0); + QTest::mouseMove(window, p1); + QCOMPARE(eventItem1->eventList.size(), 4); + QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointMoved, QQuickEventPoint::GrabExclusive); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(eventItem1->eventList.size(), 6); + QCOMPARE_EVENT(4, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointReleased, QQuickEventPoint::GrabExclusive); + QCOMPARE_EVENT(5, Event::HandlerDestination, QEvent::None, Qt::TouchPointReleased, QQuickEventPoint::UngrabExclusive); + eventItem1->eventList.clear(); +} + +void tst_PointerHandlers::touchReleaseOutside_data() +{ + QTest::addColumn<bool>("acceptPointer"); + QTest::addColumn<bool>("grabPointer"); + QTest::addColumn<int>("eventCount"); + QTest::addColumn<int>("endIndexToTest"); + QTest::addColumn<int>("endDestination"); // Event::Destination + QTest::addColumn<int>("endType"); // QEvent::Type + QTest::addColumn<int>("endState"); // Qt::TouchPointState + QTest::addColumn<int>("endGrabState"); // Qt::TouchPointState + + QTest::newRow("reject and ignore") << false << false << 6 << 5 << (int)Event::TouchDestination + << (int)QEvent::TouchEnd << (int)Qt::TouchPointReleased << (int)NoGrab; + QTest::newRow("reject and grab") << false << true << 5 << 4 << (int)Event::HandlerDestination + << (int)QEvent::None << (int)Qt::TouchPointReleased << (int)QQuickEventPoint::UngrabExclusive; + QTest::newRow("accept and ignore") << true << false << 1 << 0 << (int)Event::HandlerDestination + << (int)QEvent::Pointer << (int)Qt::TouchPointPressed << (int)NoGrab; + QTest::newRow("accept and grab") << true << true << 5 << 4 << (int)Event::HandlerDestination + << (int)QEvent::None << (int)Qt::TouchPointReleased << (int)QQuickEventPoint::UngrabExclusive; +} + +void tst_PointerHandlers::touchReleaseOutside() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "singleitem.qml"); + QQuickView * window = windowPtr.data(); + + QFETCH(bool, acceptPointer); + QFETCH(bool, grabPointer); + QFETCH(int, eventCount); + QFETCH(int, endIndexToTest); + QFETCH(int, endDestination); + QFETCH(int, endType); + QFETCH(int, endState); + QFETCH(int, endGrabState); + + EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); + QVERIFY(eventItem1); + + eventItem1->acceptTouch = true; + eventItem1->acceptPointer = acceptPointer; + eventItem1->grabPointer = grabPointer; + + QPoint p1 = QPoint(20, 20); + QTest::touchEvent(window, touchDevice).press(0, p1, window); + QQuickTouchUtils::flush(window); + p1.setX(eventItem1->mapToScene(eventItem1->clipRect().bottomRight()).x() + 10); + QTest::touchEvent(window, touchDevice).move(0, p1, window); + QTest::touchEvent(window, touchDevice).release(0, p1, window); + QQuickTouchUtils::flush(window); + qCDebug(lcPointerTests) << eventItem1->eventList; + QCOMPARE(eventItem1->eventList.size(), eventCount); + QCOMPARE_EVENT(endIndexToTest, endDestination, endType, endState, endGrabState); +} + +void tst_PointerHandlers::dynamicCreation() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "dynamicallyCreated.qml"); + QQuickView * window = windowPtr.data(); + + EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); + QVERIFY(eventItem1); + EventHandler *handler = window->rootObject()->findChild<EventHandler*>("eventHandler"); + QVERIFY(handler); + + QCOMPARE(handler->parentItem(), eventItem1); + QCOMPARE(handler->target(), eventItem1); + + QPoint p1(20, 20); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(eventItem1->eventList.size(), 2); + QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, Qt::TouchPointPressed, NoGrab); + QCOMPARE_EVENT(1, Event::MouseDestination, QEvent::MouseButtonPress, Qt::TouchPointPressed, NoGrab); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); +} + +void tst_PointerHandlers::handlerInWindow() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("handlerInWindow.qml")); + QQuickWindow *window = qobject_cast<QQuickWindow*>(component.create()); + QScopedPointer<QQuickWindow> cleanup(window); + QVERIFY(window); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + EventHandler *handler = window->contentItem()->findChild<EventHandler*>("eventHandler"); + QVERIFY(handler); + + QCOMPARE(handler->parentItem(), window->contentItem()); + QCOMPARE(handler->target(), window->contentItem()); + + QPoint p1(20, 20); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(handler->pressEventCount, 1); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(handler->releaseEventCount, 1); +} + +void tst_PointerHandlers::dynamicCreationInWindow() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("dynamicallyCreatedInWindow.qml")); + QQuickWindow *window = qobject_cast<QQuickWindow*>(component.create()); + QScopedPointer<QQuickWindow> cleanup(window); + QVERIFY(window); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + EventHandler *handler = window->contentItem()->findChild<EventHandler*>("eventHandler"); + QVERIFY(handler); + + QCOMPARE(handler->parentItem(), window->contentItem()); + QCOMPARE(handler->target(), window->contentItem()); + + QPoint p1(20, 20); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(handler->pressEventCount, 1); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(handler->releaseEventCount, 1); +} + +QTEST_MAIN(tst_PointerHandlers) + +#include "tst_qquickpointerhandler.moc" + diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/data/multiPointTracker.qml b/tests/auto/quick/pointerhandlers/qquickpointhandler/data/multiPointTracker.qml new file mode 100644 index 0000000000..3f50d7c761 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/data/multiPointTracker.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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 + + PointHandler { + id: ph1 + objectName: "ph1" + + target: Rectangle { + parent: root + visible: ph1.active + x: ph1.point.position.x - width / 2 + y: ph1.point.position.y - height / 2 + width: 140 + height: width + radius: width / 2 + color: "orange" + opacity: 0.3 + } + } + + PointHandler { + id: ph2 + objectName: "ph2" + + target: Rectangle { + parent: root + visible: ph2.active + x: ph2.point.position.x - width / 2 + y: ph2.point.position.y - height / 2 + width: 140 + height: width + radius: width / 2 + color: "orange" + opacity: 0.3 + } + } + + PointHandler { + id: ph3 + objectName: "ph3" + + target: Rectangle { + parent: root + visible: ph3.active + x: ph3.point.position.x - width / 2 + y: ph3.point.position.y - height / 2 + width: 140 + height: width + radius: width / 2 + color: "orange" + opacity: 0.3 + } + } +} + diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/data/pointTracker.qml b/tests/auto/quick/pointerhandlers/qquickpointhandler/data/pointTracker.qml new file mode 100644 index 0000000000..674bbda850 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/data/pointTracker.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** 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 { + width: 200 + height: 200 + Rectangle { + id: rect + objectName: "pointTracker" + width: 20 + height: 20 + radius: 10 + color: "green" + x: handler.point.position.x + y: handler.point.position.y + } + + Text { + id: text + anchors.top: rect.bottom + anchors.left: rect.right + text: "<" + handler.point.position.x + ", " + handler.point.position.y + "> " + handler.point.pressedButtons + " [" + handler.point.pressure + "]" + } + + PointHandler { + id: handler + objectName: "pointHandler" + acceptedButtons: Qt.LeftButton | Qt.RightButton + } +} diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/qquickpointhandler.pro b/tests/auto/quick/pointerhandlers/qquickpointhandler/qquickpointhandler.pro new file mode 100644 index 0000000000..d64fc96d74 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/qquickpointhandler.pro @@ -0,0 +1,15 @@ +CONFIG += testcase + +TARGET = tst_qquickpointhandler +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_qquickpointhandler.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +OTHER_FILES += data/pointTracker.qml \ diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp new file mode 100644 index 0000000000..d0b3bc3d36 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp @@ -0,0 +1,346 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module 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/qquickitem.h> +#include <QtQuick/private/qquickpointhandler_p.h> +#include <qpa/qwindowsysteminterface.h> + +#include <private/qquickwindow_p.h> + +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlproperty.h> + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_PointHandler : public QQmlDataTest +{ + Q_OBJECT +public: + tst_PointHandler() + : touchDevice(QTest::createTouchDevice()) + {} + +private slots: + void initTestCase(); + + void singleTouch(); + void simultaneousMultiTouch(); + void pressedMultipleButtons_data(); + void pressedMultipleButtons(); + +private: + void createView(QScopedPointer<QQuickView> &window, const char *fileName); + QTouchDevice *touchDevice; +}; + +void tst_PointHandler::createView(QScopedPointer<QQuickView> &window, const char *fileName) +{ + window.reset(new QQuickView); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != nullptr); +} + +void tst_PointHandler::initTestCase() +{ + // This test assumes that we don't get synthesized mouse events from QGuiApplication + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + + QQmlDataTest::initTestCase(); +} + +void tst_PointHandler::singleTouch() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "pointTracker.qml"); + QQuickView * window = windowPtr.data(); + QQuickItem *tracker = window->rootObject()->findChild<QQuickItem *>("pointTracker"); + QVERIFY(tracker); + QQuickPointHandler *handler = window->rootObject()->findChild<QQuickPointHandler *>("pointHandler"); + QVERIFY(handler); + + QSignalSpy activeSpy(handler, SIGNAL(activeChanged())); + QSignalSpy pointSpy(handler, SIGNAL(pointChanged())); + QSignalSpy translationSpy(handler, SIGNAL(translationChanged())); + + QPoint point(100,100); + QTest::touchEvent(window, touchDevice).press(1, point, window); + QQuickTouchUtils::flush(window); + QTRY_COMPARE(handler->active(), true); + QCOMPARE(activeSpy.count(), 1); + QCOMPARE(pointSpy.count(), 1); + QCOMPARE(handler->point().position().toPoint(), point); + QCOMPARE(handler->point().scenePosition().toPoint(), point); + QCOMPARE(handler->point().pressedButtons(), Qt::NoButton); + QCOMPARE(handler->translation(), QVector2D()); + QCOMPARE(translationSpy.count(), 1); + + point += QPoint(10, 10); + QTest::touchEvent(window, touchDevice).move(1, point, window); + QQuickTouchUtils::flush(window); + QCOMPARE(handler->active(), true); + QCOMPARE(activeSpy.count(), 1); + QCOMPARE(pointSpy.count(), 2); + QCOMPARE(handler->point().position().toPoint(), point); + QCOMPARE(handler->point().scenePosition().toPoint(), point); + QCOMPARE(handler->point().pressPosition().toPoint(), QPoint(100, 100)); + QCOMPARE(handler->point().scenePressPosition().toPoint(), QPoint(100, 100)); + QCOMPARE(handler->point().pressedButtons(), Qt::NoButton); + QVERIFY(handler->point().velocity().x() > 0); + QVERIFY(handler->point().velocity().y() > 0); + QCOMPARE(handler->translation(), QVector2D(10, 10)); + QCOMPARE(translationSpy.count(), 2); + + QTest::touchEvent(window, touchDevice).release(1, point, window); + QQuickTouchUtils::flush(window); + QTRY_COMPARE(handler->active(), false); + QCOMPARE(activeSpy.count(), 2); + QCOMPARE(pointSpy.count(), 3); + QCOMPARE(handler->translation(), QVector2D()); + QCOMPARE(translationSpy.count(), 3); +} + +void tst_PointHandler::simultaneousMultiTouch() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "multiPointTracker.qml"); + QQuickView * window = windowPtr.data(); + QList<QQuickPointHandler *> handlers = window->rootObject()->findChildren<QQuickPointHandler *>(); + QCOMPARE(handlers.count(), 3); + + QVector<QSignalSpy*> activeSpies; + QVector<QSignalSpy*> pointSpies; + QVector<QSignalSpy*> translationSpies; + QVector<QPoint> points{{100,100}, {200, 200}, {100, 300}}; + QVector<QPoint> pressPoints = points; + for (auto h : handlers) { + activeSpies << new QSignalSpy(h, SIGNAL(activeChanged())); + pointSpies << new QSignalSpy(h, SIGNAL(pointChanged())); + translationSpies << new QSignalSpy(h, SIGNAL(translationChanged())); + } + + QTest::touchEvent(window, touchDevice).press(1, points[0], window).press(2, points[1], window).press(3, points[2], window); + QQuickTouchUtils::flush(window); + QVector<int> pointIndexPerHandler; + int i = 0; + for (auto h : handlers) { + QTRY_COMPARE(h->active(), true); + QCOMPARE(activeSpies[i]->count(), 1); + QCOMPARE(pointSpies[i]->count(), 1); + int chosenPointIndex = points.indexOf(h->point().position().toPoint()); + QVERIFY(chosenPointIndex != -1); + // Verify that each handler chose a unique point + QVERIFY(!pointIndexPerHandler.contains(chosenPointIndex)); + pointIndexPerHandler.append(chosenPointIndex); + QPoint point = points[chosenPointIndex]; + QCOMPARE(h->point().scenePosition().toPoint(), point); + QCOMPARE(h->point().pressedButtons(), Qt::NoButton); + QCOMPARE(h->translation(), QVector2D()); + QCOMPARE(translationSpies[i]->count(), 1); + ++i; + } + + for (int i = 0; i < 3; ++i) + points[i] += QPoint(10 + 10 * i, 10 + 10 * i % 2); + QTest::touchEvent(window, touchDevice).move(1, points[0], window).move(2, points[1], window).move(3, points[2], window); + QQuickTouchUtils::flush(window); + i = 0; + for (auto h : handlers) { + QCOMPARE(h->active(), true); + QCOMPARE(activeSpies[i]->count(), 1); + QCOMPARE(pointSpies[i]->count(), 2); + QCOMPARE(h->point().position().toPoint(), points[pointIndexPerHandler[i]]); + QCOMPARE(h->point().scenePosition().toPoint(), points[pointIndexPerHandler[i]]); + QCOMPARE(h->point().pressPosition().toPoint(), pressPoints[pointIndexPerHandler[i]]); + QCOMPARE(h->point().scenePressPosition().toPoint(), pressPoints[pointIndexPerHandler[i]]); + QCOMPARE(h->point().pressedButtons(), Qt::NoButton); + QVERIFY(h->point().velocity().x() > 0); + QVERIFY(h->point().velocity().y() > 0); + QCOMPARE(h->translation(), QVector2D(10 + 10 * pointIndexPerHandler[i], 10 + 10 * pointIndexPerHandler[i] % 2)); + QCOMPARE(translationSpies[i]->count(), 2); + ++i; + } + + QTest::touchEvent(window, touchDevice).release(1, points[0], window).release(2, points[1], window).release(3, points[2], window); + QQuickTouchUtils::flush(window); + i = 0; + for (auto h : handlers) { + QTRY_COMPARE(h->active(), false); + QCOMPARE(activeSpies[i]->count(), 2); + QCOMPARE(pointSpies[i]->count(), 3); + QCOMPARE(h->translation(), QVector2D()); + QCOMPARE(translationSpies[i]->count(), 3); + ++i; + } + + qDeleteAll(activeSpies); + qDeleteAll(pointSpies); + qDeleteAll(translationSpies); +} + +void tst_PointHandler::pressedMultipleButtons_data() +{ + QTest::addColumn<Qt::MouseButtons>("accepted"); + QTest::addColumn<QList<Qt::MouseButtons> >("buttons"); + QTest::addColumn<QList<bool> >("active"); + QTest::addColumn<QList<Qt::MouseButtons> >("pressedButtons"); + QTest::addColumn<int>("changeCount"); + + QList<Qt::MouseButtons> buttons; + QList<bool> active; + QList<Qt::MouseButtons> pressedButtons; + buttons << Qt::LeftButton + << (Qt::LeftButton | Qt::RightButton) + << Qt::LeftButton + << Qt::NoButton; + active << true + << true + << true + << false; + pressedButtons << Qt::LeftButton + << (Qt::LeftButton | Qt::RightButton) + << Qt::LeftButton + << Qt::NoButton; + QTest::newRow("Accept Left - Press left, Press Right, Release Right") + << Qt::MouseButtons(Qt::LeftButton) << buttons << active << pressedButtons << 4; + + buttons.clear(); + active.clear(); + pressedButtons.clear(); + buttons << Qt::LeftButton + << (Qt::LeftButton | Qt::RightButton) + << Qt::RightButton + << Qt::NoButton; + active << true + << true + << false + << false; + pressedButtons << Qt::LeftButton + << (Qt::LeftButton | Qt::RightButton) + << Qt::NoButton // Not the "truth" but filtered according to this handler's acceptedButtons + << Qt::NoButton; + QTest::newRow("Accept Left - Press left, Press Right, Release Left") + << Qt::MouseButtons(Qt::LeftButton) << buttons << active << pressedButtons << 3; + + buttons.clear(); + active.clear(); + pressedButtons.clear(); + buttons << Qt::LeftButton + << (Qt::LeftButton | Qt::RightButton) + << Qt::LeftButton + << Qt::NoButton; + active << true + << true + << true + << false; + pressedButtons << Qt::LeftButton + << (Qt::LeftButton | Qt::RightButton) + << Qt::LeftButton + << Qt::NoButton; + QTest::newRow("Accept Left|Right - Press left, Press Right, Release Right") + << (Qt::LeftButton | Qt::RightButton) << buttons << active << pressedButtons << 4; + + buttons.clear(); + active.clear(); + pressedButtons.clear(); + buttons << Qt::RightButton + << (Qt::LeftButton | Qt::RightButton) + << Qt::LeftButton + << Qt::NoButton; + active << true + << true + << false + << false; + pressedButtons << Qt::RightButton + << (Qt::LeftButton | Qt::RightButton) + << Qt::NoButton // Not the "truth" but filtered according to this handler's acceptedButtons + << Qt::NoButton; + QTest::newRow("Accept Right - Press Right, Press Left, Release Right") + << Qt::MouseButtons(Qt::RightButton) << buttons << active << pressedButtons << 3; +} + +void tst_PointHandler::pressedMultipleButtons() +{ + QFETCH(Qt::MouseButtons, accepted); + QFETCH(QList<Qt::MouseButtons>, buttons); + QFETCH(QList<bool>, active); + QFETCH(QList<Qt::MouseButtons>, pressedButtons); + QFETCH(int, changeCount); + + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "pointTracker.qml"); + QQuickView * window = windowPtr.data(); + QQuickItem *tracker = window->rootObject()->findChild<QQuickItem *>("pointTracker"); + QVERIFY(tracker); + QQuickPointHandler *handler = window->rootObject()->findChild<QQuickPointHandler *>("pointHandler"); + QVERIFY(handler); + + QSignalSpy activeSpy(handler, SIGNAL(activeChanged())); + QSignalSpy pointSpy(handler, SIGNAL(pointChanged())); + handler->setAcceptedButtons(accepted); + + QPoint point(100,100); + + for (int i = 0; i < buttons.count(); ++i) { + int btns = int(buttons.at(i)); + int release = 0; + if (i > 0) { + int lastBtns = int(buttons.at(i - 1)); + release = lastBtns & ~btns; + } + if (release) + QTest::mouseRelease(windowPtr.data(), Qt::MouseButton(release), Qt::NoModifier, point); + else + QTest::mousePress(windowPtr.data(), Qt::MouseButton(btns), Qt::NoModifier, point); + + qCDebug(lcPointerTests) << i << ": acceptedButtons" << handler->acceptedButtons() + << "; comparing" << handler->point().pressedButtons() << pressedButtons.at(i); + QCOMPARE(handler->point().pressedButtons(), pressedButtons.at(i)); + QCOMPARE(handler->active(), active.at(i)); + } + + QTest::mousePress(windowPtr.data(), Qt::NoButton, Qt::NoModifier, point); + QCOMPARE(handler->active(), false); + QCOMPARE(activeSpy.count(), 2); + QCOMPARE(pointSpy.count(), changeCount); +} + +QTEST_MAIN(tst_PointHandler) + +#include "tst_qquickpointhandler.moc" diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml new file mode 100644 index 0000000000..221e7df139 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 + +Rectangle { + id: root + property alias label: label.text + property alias pressed: tap.pressed + property bool checked: false + property alias gesturePolicy: tap.gesturePolicy + signal tapped + signal canceled + + width: label.implicitWidth * 1.5; height: label.implicitHeight * 2.0 + border.color: "#9f9d9a"; border.width: 1; radius: height / 4; antialiasing: true + + gradient: Gradient { + GradientStop { position: 0.0; color: tap.pressed ? "#b8b5b2" : "#efebe7" } + GradientStop { position: 1.0; color: "#b8b5b2" } + } + + TapHandler { + id: tap + objectName: label.text + longPressThreshold: 100 // CI can be insanely slow, so don't demand a timely release to generate onTapped + onTapped: { + tapFlash.start() + root.tapped() + } + onCanceled: root.canceled() + } + + Text { + id: label + font.pointSize: 14 + text: "Button" + anchors.centerIn: parent + } + + Rectangle { + anchors.fill: parent + color: "transparent" + border.width: 2; radius: root.radius; antialiasing: true + opacity: tapFlash.running ? 1 : 0 + FlashAnimation on visible { id: tapFlash } + } + + Rectangle { + objectName: "expandingCircle" + radius: tap.timeHeld * 100 + visible: radius > 0 && tap.pressed + border.width: 3 + border.color: "blue" + color: "transparent" + width: radius * 2 + height: radius * 2 + x: tap.point.scenePressPosition.x - radius + y: tap.point.scenePressPosition.y - radius + opacity: 0.25 + Component.onCompleted: parent = root.parent + } +} diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml new file mode 100644 index 0000000000..158a02b7a6 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 + +SequentialAnimation { + id: tapFlash + running: false + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } + PauseAnimation { duration: 100 } + PropertyAction { value: false } + PauseAnimation { duration: 100 } + PropertyAction { value: true } +} diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml new file mode 100644 index 0000000000..4a8b8e1375 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 { + width: 320 + height: 240 + Button { + id: button + objectName: "Overridden" + label: "Overridden" + x: 10; y: 10; width: parent.width - 20; height: 40 + TapHandler { + gesturePolicy: TapHandler.ReleaseWithinBounds + objectName: "override" + onTapped: button.tapped() + } + } +} diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml new file mode 100644 index 0000000000..821b8073e9 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 { + width: 320 + height: 240 + Button { + objectName: "DragThreshold" + label: "DragThreshold" + x: 10; y: 10; width: parent.width - 20; height: 40 + gesturePolicy: TapHandler.DragThreshold + } + Button { + objectName: "WithinBounds" + label: "WithinBounds" + x: 10; y: 60; width: parent.width - 20; height: 40 + gesturePolicy: TapHandler.WithinBounds + } + Button { + objectName: "ReleaseWithinBounds" + label: "ReleaseWithinBounds" + x: 10; y: 110; width: parent.width - 20; height: 40 + gesturePolicy: TapHandler.ReleaseWithinBounds + } +} diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/rightTapHandler.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/rightTapHandler.qml new file mode 100644 index 0000000000..aea01c154c --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/rightTapHandler.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** 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 + +Rectangle { + width: 320 + height: 240 + color: rightTap.pressed ? "tomato" : "beige" + TapHandler { + id: rightTap + objectName: "right button TapHandler" + longPressThreshold: 0.5 + acceptedButtons: Qt.RightButton + } +} diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/qquicktaphandler.pro b/tests/auto/quick/pointerhandlers/qquicktaphandler/qquicktaphandler.pro new file mode 100644 index 0000000000..b41a94b55e --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/qquicktaphandler.pro @@ -0,0 +1,16 @@ +CONFIG += testcase + +TARGET = tst_qquicktaphandler +QT += core-private gui-private qml-private quick-private testlib + +macos:CONFIG -= app_bundle + +SOURCES += tst_qquicktaphandler.cpp + +include (../../../shared/util.pri) +include (../../shared/util.pri) + +TESTDATA = data/* + +# OTHER_FILES += data/foo.qml + diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp new file mode 100644 index 0000000000..33cea69147 --- /dev/null +++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp @@ -0,0 +1,721 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module 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 <QtGui/qstylehints.h> +#include <QtQuick/qquickview.h> +#include <QtQuick/qquickitem.h> +#include <QtQuick/private/qquickpointerhandler_p.h> +#include <QtQuick/private/qquicktaphandler_p.h> +#include <qpa/qwindowsysteminterface.h> + +#include <private/qquickwindow_p.h> + +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlproperty.h> + +#include "../../../shared/util.h" +#include "../../shared/viewtestutil.h" + +Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests") + +class tst_TapHandler : public QQmlDataTest +{ + Q_OBJECT +public: + tst_TapHandler() + :touchDevice(QTest::createTouchDevice()) + {} + +private slots: + void initTestCase(); + + void touchGesturePolicyDragThreshold(); + void mouseGesturePolicyDragThreshold(); + void touchMouseGesturePolicyDragThreshold(); + void touchGesturePolicyWithinBounds(); + void mouseGesturePolicyWithinBounds(); + void touchGesturePolicyReleaseWithinBounds(); + void mouseGesturePolicyReleaseWithinBounds(); + void touchMultiTap(); + void mouseMultiTap(); + void touchLongPress(); + void mouseLongPress(); + void buttonsMultiTouch(); + void componentUserBehavioralOverride(); + void rightLongPressIgnoreWheel(); + +private: + void createView(QScopedPointer<QQuickView> &window, const char *fileName); + QTouchDevice *touchDevice; +}; + +void tst_TapHandler::createView(QScopedPointer<QQuickView> &window, const char *fileName) +{ + window.reset(new QQuickView); + window->setSource(testFileUrl(fileName)); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != nullptr); +} + +void tst_TapHandler::initTestCase() +{ + // This test assumes that we don't get synthesized mouse events from QGuiApplication + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + + QQmlDataTest::initTestCase(); +} + +void tst_TapHandler::touchGesturePolicyDragThreshold() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(buttonDragThreshold); + QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped())); + + // DragThreshold button stays pressed while touchpoint stays within dragThreshold, emits tapped on release + QPoint p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 1); + + // DragThreshold button is no longer pressed if touchpoint goes beyond dragThreshold + dragThresholdTappedSpy.clear(); + p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(1, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 0); +} + +void tst_TapHandler::mouseGesturePolicyDragThreshold() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(buttonDragThreshold); + QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped())); + + // DragThreshold button stays pressed while mouse stays within dragThreshold, emits tapped on release + QPoint p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QTRY_COMPARE(dragThresholdTappedSpy.count(), 1); + + // DragThreshold button is no longer pressed if mouse goes beyond dragThreshold + dragThresholdTappedSpy.clear(); + p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(dragThreshold, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + p1 += QPoint(1, 0); + QTest::mouseMove(window, p1); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 0); +} + +void tst_TapHandler::touchMouseGesturePolicyDragThreshold() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(buttonDragThreshold); + QSignalSpy tappedSpy(buttonDragThreshold, SIGNAL(tapped())); + QSignalSpy canceledSpy(buttonDragThreshold, SIGNAL(canceled())); + + // Press mouse, drag it outside the button, release + QPoint p1 = buttonDragThreshold->mapToScene(QPointF(20, 20)).toPoint(); + QPoint p2 = p1 + QPoint(int(buttonDragThreshold->height()), 0); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QTest::mouseMove(window, p2); + QTRY_COMPARE(canceledSpy.count(), 1); + QCOMPARE(tappedSpy.count(), 0); + QCOMPARE(buttonDragThreshold->property("pressed").toBool(), false); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p2); + + // Press and release touch, verify that it still works (QTBUG-71466) + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 1); + + // Press touch, drag it outside the button, release + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).move(1, p2, window); + QQuickTouchUtils::flush(window); + QTRY_COMPARE(buttonDragThreshold->property("pressed").toBool(), false); + QTest::touchEvent(window, touchDevice).release(1, p2, window); + QQuickTouchUtils::flush(window); + QTRY_COMPARE(canceledSpy.count(), 2); + QCOMPARE(tappedSpy.count(), 1); // didn't increase + QCOMPARE(buttonDragThreshold->property("pressed").toBool(), false); + + // Press and release mouse, verify that it still works + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(tappedSpy.count(), 2); + QCOMPARE(canceledSpy.count(), 2); // didn't increase + QCOMPARE(buttonDragThreshold->property("pressed").toBool(), false); +} + +void tst_TapHandler::touchGesturePolicyWithinBounds() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonWithinBounds = window->rootObject()->findChild<QQuickItem*>("WithinBounds"); + QVERIFY(buttonWithinBounds); + QSignalSpy withinBoundsTappedSpy(buttonWithinBounds, SIGNAL(tapped())); + + // WithinBounds button stays pressed while touchpoint stays within bounds, emits tapped on release + QPoint p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 1); + + // WithinBounds button is no longer pressed if touchpoint leaves bounds + withinBoundsTappedSpy.clear(); + p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::mouseGesturePolicyWithinBounds() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonWithinBounds = window->rootObject()->findChild<QQuickItem*>("WithinBounds"); + QVERIFY(buttonWithinBounds); + QSignalSpy withinBoundsTappedSpy(buttonWithinBounds, SIGNAL(tapped())); + + // WithinBounds button stays pressed while touchpoint stays within bounds, emits tapped on release + QPoint p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 1); + + // WithinBounds button is no longer pressed if touchpoint leaves bounds + withinBoundsTappedSpy.clear(); + p1 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::mouseMove(window, p1); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QVERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::touchGesturePolicyReleaseWithinBounds() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild<QQuickItem*>("ReleaseWithinBounds"); + QVERIFY(buttonReleaseWithinBounds); + QSignalSpy releaseWithinBoundsTappedSpy(buttonReleaseWithinBounds, SIGNAL(tapped())); + + // ReleaseWithinBounds button stays pressed while touchpoint wanders anywhere, + // then if it comes back within bounds, emits tapped on release + QPoint p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(250, 100); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(25, 15)).toPoint(); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1); + + // ReleaseWithinBounds button does not emit tapped if released out of bounds + releaseWithinBoundsTappedSpy.clear(); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::touchEvent(window, touchDevice).move(1, p1, window); + QQuickTouchUtils::flush(window); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::mouseGesturePolicyReleaseWithinBounds() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonReleaseWithinBounds = window->rootObject()->findChild<QQuickItem*>("ReleaseWithinBounds"); + QVERIFY(buttonReleaseWithinBounds); + QSignalSpy releaseWithinBoundsTappedSpy(buttonReleaseWithinBounds, SIGNAL(tapped())); + + // ReleaseWithinBounds button stays pressed while touchpoint wanders anywhere, + // then if it comes back within bounds, emits tapped on release + QPoint p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(50, 0); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(250, 100); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(25, 15)).toPoint(); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1); + + // ReleaseWithinBounds button does not emit tapped if released out of bounds + releaseWithinBoundsTappedSpy.clear(); + p1 = buttonReleaseWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + p1 += QPoint(0, 100); + QTest::mouseMove(window, p1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); +} + +void tst_TapHandler::touchMultiTap() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(button); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Tap once + QPoint p1 = button->mapToScene(QPointF(2, 2)).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 1); + + // Tap again in exactly the same place (not likely with touch in the real world) + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 2); + + // Tap a third time, nearby + p1 += QPoint(dragThreshold, dragThreshold); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 3); + + // Tap a fourth time, drifting farther away + p1 += QPoint(dragThreshold, dragThreshold); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 4); +} + +void tst_TapHandler::mouseMultiTap() +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(button); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + + // Tap once + QPoint p1 = button->mapToScene(QPointF(2, 2)).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 1); + + // Tap again in exactly the same place (not likely with touch in the real world) + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 2); + + // Tap a third time, nearby + p1 += QPoint(dragThreshold, dragThreshold); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 3); + + // Tap a fourth time, drifting farther away + p1 += QPoint(dragThreshold, dragThreshold); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 4); +} + +void tst_TapHandler::touchLongPress() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(button); + QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>("DragThreshold"); + QVERIFY(tapHandler); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + QSignalSpy longPressThresholdChangedSpy(tapHandler, SIGNAL(longPressThresholdChanged())); + QSignalSpy timeHeldSpy(tapHandler, SIGNAL(timeHeldChanged())); + QSignalSpy longPressedSpy(tapHandler, SIGNAL(longPressed())); + + // Reduce the threshold so that we can get a long press quickly + tapHandler->setLongPressThreshold(0.5); + QCOMPARE(longPressThresholdChangedSpy.count(), 1); + + // Press and hold + QPoint p1 = button->mapToScene(button->clipRect().center()).toPoint(); + QTest::touchEvent(window, touchDevice).press(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(button->property("pressed").toBool()); + QTRY_COMPARE(longPressedSpy.count(), 1); + timeHeldSpy.wait(); // the longer we hold it, the more this will occur + qDebug() << "held" << tapHandler->timeHeld() << "secs; timeHeld updated" << timeHeldSpy.count() << "times"; + QVERIFY(timeHeldSpy.count() > 0); + QVERIFY(tapHandler->timeHeld() > 0.4); // Should be > 0.5 but slow CI and timer granularity can interfere + + // Release and verify that tapped was not emitted + QTest::touchEvent(window, touchDevice).release(1, p1, window); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); +} + +void tst_TapHandler::mouseLongPress() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(button); + QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>("DragThreshold"); + QVERIFY(tapHandler); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + QSignalSpy longPressThresholdChangedSpy(tapHandler, SIGNAL(longPressThresholdChanged())); + QSignalSpy timeHeldSpy(tapHandler, SIGNAL(timeHeldChanged())); + QSignalSpy longPressedSpy(tapHandler, SIGNAL(longPressed())); + + // Reduce the threshold so that we can get a long press quickly + tapHandler->setLongPressThreshold(0.5); + QCOMPARE(longPressThresholdChangedSpy.count(), 1); + + // Press and hold + QPoint p1 = button->mapToScene(button->clipRect().center()).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_VERIFY(button->property("pressed").toBool()); + QTRY_COMPARE(longPressedSpy.count(), 1); + timeHeldSpy.wait(); // the longer we hold it, the more this will occur + qDebug() << "held" << tapHandler->timeHeld() << "secs; timeHeld updated" << timeHeldSpy.count() << "times"; + QVERIFY(timeHeldSpy.count() > 0); + QVERIFY(tapHandler->timeHeld() > 0.4); // Should be > 0.5 but slow CI and timer granularity can interfere + + // Release and verify that tapped was not emitted + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1, 500); + QTRY_VERIFY(!button->property("pressed").toBool()); + QCOMPARE(tappedSpy.count(), 0); +} + +void tst_TapHandler::buttonsMultiTouch() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttons.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *buttonDragThreshold = window->rootObject()->findChild<QQuickItem*>("DragThreshold"); + QVERIFY(buttonDragThreshold); + QSignalSpy dragThresholdTappedSpy(buttonDragThreshold, SIGNAL(tapped())); + + QQuickItem *buttonWithinBounds = window->rootObject()->findChild<QQuickItem*>("WithinBounds"); + QVERIFY(buttonWithinBounds); + QSignalSpy withinBoundsTappedSpy(buttonWithinBounds, SIGNAL(tapped())); + + 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(); + touchSeq.press(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QPoint p2 = buttonWithinBounds->mapToScene(QPointF(20, 20)).toPoint(); + 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(); + 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 + touchSeq.stationary(2).stationary(3).release(1, p1, window).commit(); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 1); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 0); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); + 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 + touchSeq.stationary(1).stationary(3).release(2, p2, window).commit(); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool()); + QCOMPARE(withinBoundsTappedSpy.count(), 1); + QVERIFY(buttonDragThreshold->property("pressed").toBool()); + QCOMPARE(dragThresholdTappedSpy.count(), 1); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); + QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0); + 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 + 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); + touchSeq.stationary(1).stationary(2).press(3, p3, window).commit(); + QQuickTouchUtils::flush(window); + QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool()); + QVERIFY(buttonWithinBounds->property("pressed").toBool()); + QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool()); +} + +void tst_TapHandler::componentUserBehavioralOverride() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "buttonOverrideHandler.qml"); + QQuickView * window = windowPtr.data(); + + QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("Overridden"); + QVERIFY(button); + QQuickTapHandler *innerTapHandler = button->findChild<QQuickTapHandler*>("Overridden"); + QVERIFY(innerTapHandler); + QQuickTapHandler *userTapHandler = button->findChild<QQuickTapHandler*>("override"); + QVERIFY(userTapHandler); + QSignalSpy tappedSpy(button, SIGNAL(tapped())); + QSignalSpy innerGrabChangedSpy(innerTapHandler, SIGNAL(grabChanged(QQuickEventPoint::GrabTransition, QQuickEventPoint *))); + QSignalSpy userGrabChangedSpy(userTapHandler, SIGNAL(grabChanged(QQuickEventPoint::GrabTransition, QQuickEventPoint *))); + QSignalSpy innerPressedChangedSpy(innerTapHandler, SIGNAL(pressedChanged())); + QSignalSpy userPressedChangedSpy(userTapHandler, SIGNAL(pressedChanged())); + + // Press + QPoint p1 = button->mapToScene(button->clipRect().center()).toPoint(); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(userPressedChangedSpy.count(), 1); + QCOMPARE(innerPressedChangedSpy.count(), 0); + QCOMPARE(innerGrabChangedSpy.count(), 0); + QCOMPARE(userGrabChangedSpy.count(), 1); + + // Release + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1); + QTRY_COMPARE(userPressedChangedSpy.count(), 2); + QCOMPARE(innerPressedChangedSpy.count(), 0); + QCOMPARE(tappedSpy.count(), 1); // only because the override handler makes that happen + QCOMPARE(innerGrabChangedSpy.count(), 0); + QCOMPARE(userGrabChangedSpy.count(), 2); +} + +void tst_TapHandler::rightLongPressIgnoreWheel() +{ + QScopedPointer<QQuickView> windowPtr; + createView(windowPtr, "rightTapHandler.qml"); + QQuickView * window = windowPtr.data(); + + QQuickTapHandler *tap = window->rootObject()->findChild<QQuickTapHandler*>(); + QVERIFY(tap); + QSignalSpy tappedSpy(tap, SIGNAL(tapped(QQuickEventPoint *))); + QSignalSpy longPressedSpy(tap, SIGNAL(longPressed())); + QPoint p1(100, 100); + + // Mouse wheel with ScrollBegin phase (because as soon as two fingers are touching + // the trackpad, it will send such an event: QTBUG-71955) + { + QWheelEvent wheelEvent(p1, p1, QPoint(0, 0), QPoint(0, 0), + Qt::NoButton, Qt::NoModifier, Qt::ScrollBegin, false, Qt::MouseEventNotSynthesized); + QGuiApplication::sendEvent(window, &wheelEvent); + } + + // Press + QTest::mousePress(window, Qt::RightButton, Qt::NoModifier, p1); + QTRY_COMPARE(tap->isPressed(), true); + + // Mouse wheel ScrollEnd phase + QWheelEvent wheelEvent(p1, p1, QPoint(0, 0), QPoint(0, 0), + Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd, false, Qt::MouseEventNotSynthesized); + QGuiApplication::sendEvent(window, &wheelEvent); + QTRY_COMPARE(longPressedSpy.count(), 1); + QCOMPARE(tap->isPressed(), true); + QCOMPARE(tappedSpy.count(), 0); + + // Release + QTest::mouseRelease(window, Qt::RightButton, Qt::NoModifier, p1, 500); + QTRY_COMPARE(tap->isPressed(), false); + QCOMPARE(tappedSpy.count(), 0); +} + +QTEST_MAIN(tst_TapHandler) + +#include "tst_qquicktaphandler.moc" + diff --git a/tests/auto/quick/propertyrequirements/propertyrequirements.pro b/tests/auto/quick/propertyrequirements/propertyrequirements.pro new file mode 100644 index 0000000000..8fe574e0bf --- /dev/null +++ b/tests/auto/quick/propertyrequirements/propertyrequirements.pro @@ -0,0 +1,7 @@ +CONFIG += testcase +TARGET = tst_propertyrequirements +macos:CONFIG -= app_bundle + +SOURCES += tst_propertyrequirements.cpp + +QT += qml-private testlib diff --git a/tests/auto/quick/propertyrequirements/tst_propertyrequirements.cpp b/tests/auto/quick/propertyrequirements/tst_propertyrequirements.cpp new file mode 100644 index 0000000000..5781a007b6 --- /dev/null +++ b/tests/auto/quick/propertyrequirements/tst_propertyrequirements.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Kevin Krammer <kevin.krammer@kdab.com> +** 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 <qtest.h> +#include <QtQml/qqmlcomponent.h> +#include <QtQml/qqmlengine.h> +#include <QtQml/private/qqmlmetatype_p.h> +#include <QtCore/QDebug> +#include <QtCore/QHash> +#include <QtCore/QSet> + +class tst_PropertyRequirements : public QObject +{ + Q_OBJECT +public: + tst_PropertyRequirements(); + +private slots: + void constantOrNotifyableMain(); + void constantOrNotifyableFull(); + +private: + typedef QList<QQmlType> Failures; + + /*! + All properties that do not pass the check and the affected QML types + + Key: Property name formatted as C++-class-name::property-name + Value: List of QQmlType which have the property + */ + typedef QHash<QString, Failures> FailuresByProperty; + + enum TestDepth { + MainTypeOnly, //! Check only the properties of the main C++ type for each QML type + WithSuperClasses //! Check the super classes for each C++ type as well + }; + + void testAllQmlTypes(TestDepth testDepth, FailuresByProperty &failuresByProperty); + void testQmlType(TestDepth testDepth, const QQmlType &qmlType, FailuresByProperty &failuresByProperty); +}; + + +tst_PropertyRequirements::tst_PropertyRequirements() +{ +} + +void tst_PropertyRequirements::constantOrNotifyableMain() +{ + FailuresByProperty failuresByProperty; + + // test + testAllQmlTypes(MainTypeOnly, failuresByProperty); + + // report + QHash<QString, QStringList> occurrences; + for (auto it = failuresByProperty.constBegin(); it != failuresByProperty.constEnd(); ++it) { + + occurrences[it.value().at(0).qmlTypeName()].append(it.key()); + } + + QStringList messages; + for (auto it = occurrences.constBegin(); it != occurrences.constEnd(); ++it) { + const QString occurrencePattern("%1:\n\t%2"); + + QStringList properties = it.value(); + properties.sort(); + messages.append(occurrencePattern.arg(it.key(), properties.join("\n\t"))); + } + messages.sort(); + + const QString message("\nThe following QML Types have properties which are neither CONSTANT nor NOTIFYable:\n"); + QWARN(qPrintable(message + messages.join("\n"))); + + // TODO enable once technical debt is fixes + // QCOMPARE(failuresByProperty.count(), 0); +} + +void tst_PropertyRequirements::constantOrNotifyableFull() +{ + FailuresByProperty failuresByProperty; + + // test + testAllQmlTypes(WithSuperClasses, failuresByProperty); + + // report + QStringList messages; + for (auto it = failuresByProperty.constBegin(); it != failuresByProperty.constEnd(); ++it) { + + QSet<QString> occurrences; + for (const QQmlType &qmlType : it.value()) { + static const QString occurrencePattern("%1 (%2)"); + + occurrences.insert(occurrencePattern.arg(qmlType.metaObject()->className(), + qmlType.qmlTypeName())); + + } + + static const QString messagePattern("\nProperty %1 neither CONSTANT nor NOTIFYable. Affected types:\n\t%2"); + QStringList occurrencesList = occurrences.toList(); + occurrencesList.sort(); + messages.append(messagePattern.arg(it.key(), occurrencesList.join("\n\t"))); + + } + messages.sort(); + + QWARN(qPrintable(messages.join("\n"))); + + // TODO enable once technical debt is fixes + // QCOMPARE(failuresByProperty.count(), 0); +} + +void tst_PropertyRequirements::testAllQmlTypes(TestDepth testDepth, FailuresByProperty &failuresByProperty) +{ + const QVector<QByteArray> qmlData { + "import QtQml 2.2\nQtObject {}", + "import QtQml.Models 2.2\nListModel {}", + "import QtQuick 2.5\nItem {}", + "import QtQuick.Window 2.2\nWindow {}", + "import QtQuick.Dialogs 1.2\nDialog {}", + "import QtQuick.Layouts 1.2\nGridLayout {}", + "import QtQuick.Controls 2.2\nButton {}", + "import QtQuick.Templates 2.2\nButton {}" + }; + + QQmlEngine engine; + QSet<QString> seenTypes; + + for (const QByteArray &data : qmlData) { + QQmlComponent component(&engine); + component.setData(data, QUrl()); + + for (const QQmlType &qmlType : QQmlMetaType::qmlTypes()) { + if (!seenTypes.contains(qmlType.qmlTypeName())) { + testQmlType(testDepth, qmlType, failuresByProperty); + } + } + seenTypes.unite(QSet<QString>::fromList(QQmlMetaType::qmlTypeNames())); + } +} + +void tst_PropertyRequirements::testQmlType(TestDepth testDepth, const QQmlType &qmlType, FailuresByProperty &failuresByProperty) +{ + QList<const QMetaObject*> inheritanceHierarchy; + + const QMetaObject *mo = qmlType.metaObject(); + while (mo) { + inheritanceHierarchy.prepend(mo); + mo = mo->superClass(); + } + + // check if this type is derived from QObject and even can have signals + // i.e. weed out the Q_GADGET classes + if (inheritanceHierarchy.isEmpty() + || inheritanceHierarchy.constFirst()->className() != QByteArrayLiteral("QObject")) { + return; + } + + if (testDepth == MainTypeOnly) { + inheritanceHierarchy.clear(); + inheritanceHierarchy.append(qmlType.metaObject()); + } + + for (const QMetaObject *metaClass : qAsConst(inheritanceHierarchy)) { + for (int idx = metaClass->propertyOffset(); idx < metaClass->propertyCount(); ++idx) { + const QMetaProperty property = metaClass->property(idx); + + // needs to be either CONSTANT or have a NOTIFY signal + if (!property.isConstant() && !property.hasNotifySignal()) { + static const QString fullNamePattern("%1::%2"); + const QString fullPropertyName = fullNamePattern.arg(metaClass->className(), property.name()); + + failuresByProperty[fullPropertyName].append(qmlType); + } + } + } +} + +QTEST_MAIN(tst_PropertyRequirements) + +#include "tst_propertyrequirements.moc" diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp index e843f9e5a1..1bfeb94161 100644 --- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp +++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp @@ -42,9 +42,11 @@ #include <QtQml/qqmlengine.h> #include <QtQml/qqmlproperty.h> #include <QtQuick/private/qquickaccessibleattached_p.h> +#include <QtQuick/private/qquicklistview_p.h> +#include <QtQuick/private/qquicktext_p.h> #include "../../shared/util.h" - +#include "../shared/visualtestutil.h" #define EXPECT(cond) \ do { \ @@ -143,7 +145,7 @@ void tst_QQuickAccessible::commonTests() view->setSource(testFileUrl(accessibleRoleFileName)); view->show(); // view->setFocus(); - QVERIFY(view->rootObject() != 0); + QVERIFY(view->rootObject() != nullptr); QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(view); QVERIFY(iface); @@ -160,10 +162,10 @@ void tst_QQuickAccessible::quickAttachedProperties() component.setData("import QtQuick 2.0\nItem {\n" "}", QUrl()); QObject *object = component.create(); - QVERIFY(object != 0); + QVERIFY(object != nullptr); QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object); - QCOMPARE(attachedObject, static_cast<QObject*>(0)); + QCOMPARE(attachedObject, static_cast<QObject*>(nullptr)); delete object; } @@ -181,7 +183,7 @@ void tst_QQuickAccessible::quickAttachedProperties() "Accessible.role: Accessible.Button\n" "}", QUrl()); QObject *object = component.create(); - QVERIFY(object != 0); + QVERIFY(object != nullptr); QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object); QVERIFY(attachedObject); @@ -207,7 +209,7 @@ void tst_QQuickAccessible::quickAttachedProperties() "Accessible.description: \"Duck\"\n" "}", QUrl()); QObject *object = component.create(); - QVERIFY(object != 0); + QVERIFY(object != nullptr); QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object); QVERIFY(attachedObject); @@ -224,6 +226,72 @@ void tst_QQuickAccessible::quickAttachedProperties() } delete object; } + + // Check overriding of attached role for Text + { + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nText {\n" + "Accessible.role: Accessible.Button\n" + "Accessible.name: \"TextButton\"\n" + "Accessible.description: \"Text Button\"\n" + "}", QUrl()); + QObject *object = component.create(); + QVERIFY(object != nullptr); + + QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object); + QVERIFY(attachedObject); + if (attachedObject) { + QVariant p = attachedObject->property("role"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toInt(), int(QAccessible::PushButton)); + p = attachedObject->property("name"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("TextButton")); + p = attachedObject->property("description"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("Text Button")); + } + delete object; + } + // Check overriding of attached role for Text + { + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nListView {\n" + "id: list\n" + "model: 5\n" + "delegate: Text {\n" + "objectName: \"acc_text\"\n" + "Accessible.role: Accessible.Button\n" + "Accessible.name: \"TextButton\"\n" + "Accessible.description: \"Text Button\"\n" + "}\n" + "}", QUrl()); + QObject *object = component.create(); + QVERIFY(object != nullptr); + + QQuickListView *listview = qobject_cast<QQuickListView *>(object); + QVERIFY(listview != nullptr); + QQuickItem *contentItem = listview->contentItem(); + QQuickText *childItem = QQuickVisualTestUtil::findItem<QQuickText>(contentItem, "acc_text"); + QVERIFY(childItem != nullptr); + + QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(childItem); + QVERIFY(attachedObject); + if (attachedObject) { + QVariant p = attachedObject->property("role"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toInt(), int(QAccessible::PushButton)); + p = attachedObject->property("name"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("TextButton")); + p = attachedObject->property("description"); + QCOMPARE(p.isNull(), false); + QCOMPARE(p.toString(), QLatin1String("Text Button")); + } + delete object; + } QTestAccessibility::clearEvents(); } @@ -282,7 +350,7 @@ QAccessibleInterface *topLevelChildAt(QAccessibleInterface *iface, int x, int y) { QAccessibleInterface *child = iface->childAt(x, y); if (!child) - return 0; + return nullptr; QAccessibleInterface *childOfChild; while ( ( childOfChild = child->childAt(x, y)) ) { diff --git a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp index 34b9fb6b07..8026bafb9e 100644 --- a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp +++ b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp @@ -67,6 +67,7 @@ private slots: void progressAndStatusChanges(); void playingAndPausedChanges(); void noCaching(); + void sourceChangesOnFrameChanged(); }; void tst_qquickanimatedimage::cleanup() @@ -132,6 +133,16 @@ void tst_qquickanimatedimage::frameCount() QVERIFY(anim->isPlaying()); QCOMPARE(anim->frameCount(), 3); + QSignalSpy frameCountChangedSpy(anim, &QQuickAnimatedImage::frameCountChanged); + + const QUrl origSource = anim->source(); + anim->setSource(QUrl()); + QCOMPARE(anim->frameCount(), 0); + QCOMPARE(frameCountChangedSpy.count(), 1); + anim->setSource(origSource); + QCOMPARE(anim->frameCount(), 3); + QCOMPARE(frameCountChangedSpy.count(), 2); + delete anim; } @@ -142,7 +153,7 @@ void tst_qquickanimatedimage::mirror_running() QQuickView window; window.setSource(testFileUrl("hearts.qml")); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(window.rootObject()); QVERIFY(anim); @@ -324,7 +335,7 @@ void tst_qquickanimatedimage::sourceSizeChanges() QQmlContext *ctxt = engine.rootContext(); ctxt->setContextProperty("srcImage", ""); QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage*>(component.create()); - QVERIFY(anim != 0); + QVERIFY(anim != nullptr); QSignalSpy sourceSizeSpy(anim, SIGNAL(sourceSizeChanged())); @@ -387,7 +398,7 @@ void tst_qquickanimatedimage::sourceSizeChanges_intermediate() ctxt->setContextProperty("srcImage", ""); QScopedPointer<QQuickAnimatedImage> anim(qobject_cast<QQuickAnimatedImage*>(component.create())); - QVERIFY(anim != 0); + QVERIFY(anim != nullptr); ctxt->setContextProperty("srcImage", testFileUrl("hearts.gif")); QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready); @@ -412,7 +423,7 @@ void tst_qquickanimatedimage::qtbug_16520() QQuickRectangle *root = qobject_cast<QQuickRectangle *>(component.create()); QVERIFY(root); QQuickAnimatedImage *anim = root->findChild<QQuickAnimatedImage*>("anim"); - QVERIFY(anim != 0); + QVERIFY(anim != nullptr); anim->setProperty("source", server.urlString("/stickman.gif")); QTRY_COMPARE(anim->opacity(), qreal(0)); @@ -435,7 +446,7 @@ void tst_qquickanimatedimage::progressAndStatusChanges() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->status(), QQuickImage::Ready); QTRY_COMPARE(obj->progress(), 1.0); @@ -489,7 +500,7 @@ void tst_qquickanimatedimage::playingAndPausedChanges() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickAnimatedImage *obj = qobject_cast<QQuickAnimatedImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->status(), QQuickAnimatedImage::Null); QTRY_VERIFY(obj->isPlaying()); QTRY_VERIFY(!obj->isPaused()); @@ -555,8 +566,8 @@ void tst_qquickanimatedimage::noCaching() window_nocache.setSource(testFileUrl("colors_nocache.qml")); window.show(); window_nocache.show(); - QTest::qWaitForWindowExposed(&window); - QTest::qWaitForWindowExposed(&window_nocache); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(QTest::qWaitForWindowExposed(&window_nocache)); QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(window.rootObject()); QVERIFY(anim); @@ -580,6 +591,33 @@ void tst_qquickanimatedimage::noCaching() } } +void tst_qquickanimatedimage::sourceChangesOnFrameChanged() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("colors.qml")); + QVector<QQuickAnimatedImage*> images; + + // Run multiple animations in parallel, this should be fast + for (int loops = 0; loops < 25; ++loops) { + QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(component.create()); + + // QTBUG-67427: this should not produce a segfault + QObject::connect(anim, + &QQuickAnimatedImage::frameChanged, + [this, anim]() { anim->setSource(testFileUrl("hearts.gif")); }); + + QVERIFY(anim); + QVERIFY(anim->isPlaying()); + + images.append(anim); + } + + for (auto *anim : images) + QTRY_COMPARE(anim->source(), testFileUrl("hearts.gif")); + + qDeleteAll(images); +} + QTEST_MAIN(tst_qquickanimatedimage) #include "tst_qquickanimatedimage.moc" diff --git a/tests/auto/quick/qquickanimatedsprite/BLACKLIST b/tests/auto/quick/qquickanimatedsprite/BLACKLIST new file mode 100644 index 0000000000..7eb242876a --- /dev/null +++ b/tests/auto/quick/qquickanimatedsprite/BLACKLIST @@ -0,0 +1,3 @@ +# QTBUG-65613 +[test_largeAnimation] +b2qt 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/qquickanimatedsprite.pro b/tests/auto/quick/qquickanimatedsprite/qquickanimatedsprite.pro index 81c73be831..a337473d99 100644 --- a/tests/auto/quick/qquickanimatedsprite/qquickanimatedsprite.pro +++ b/tests/auto/quick/qquickanimatedsprite/qquickanimatedsprite.pro @@ -8,7 +8,7 @@ macx:CONFIG -= app_bundle TESTDATA = data/* -QT += core-private gui-private qml-private quick-private network testlib +QT += core-private gui-private qml-private quick-private network testlib qmltest OTHER_FILES += \ - data/largeAnimation.qml + $$files(data/*.qml) diff --git a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp index 820c804065..d2bbf9e6b1 100644 --- a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp +++ b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp @@ -28,9 +28,11 @@ #include <QtTest/QtTest> #include "../../shared/util.h" #include <QtQuick/qquickview.h> +#include <QtQuickTest/QtQuickTest> #include <private/qabstractanimation_p.h> #include <private/qquickanimatedsprite_p.h> #include <private/qquickitem_p.h> +#include <QtCore/qscopedpointer.h> #include <QtGui/qpainter.h> #include <QtGui/qopenglcontext.h> #include <QtGui/qopenglfunctions.h> @@ -52,6 +54,8 @@ private slots: void test_largeAnimation(); void test_reparenting(); void test_changeSourceToSmallerImgKeepingBigFrameSize(); + void test_infiniteLoops(); + void test_implicitSize(); }; void tst_qquickanimatedsprite::initTestCase() @@ -62,11 +66,11 @@ void tst_qquickanimatedsprite::initTestCase() void tst_qquickanimatedsprite::test_properties() { - QQuickView *window = new QQuickView(0); + QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("basic.qml")); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QVERIFY(window->rootObject()); QQuickAnimatedSprite* sprite = window->rootObject()->findChild<QQuickAnimatedSprite*>("sprite"); @@ -77,21 +81,24 @@ 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()); - - delete window; } void tst_qquickanimatedsprite::test_runningChangedSignal() { - QQuickView *window = new QQuickView(0); + QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("runningChange.qml")); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QVERIFY(window->rootObject()); QQuickAnimatedSprite* sprite = window->rootObject()->findChild<QQuickAnimatedSprite*>("sprite"); @@ -100,12 +107,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); - - delete window; + QCOMPARE(finishedSpy.count(), 1); } template <typename T> @@ -117,7 +127,7 @@ static bool isWithinRange(T min, T value, T max) void tst_qquickanimatedsprite::test_frameChangedSignal() { - QQuickView *window = new QQuickView(0); + QScopedPointer<QQuickView> window(new QQuickView); window->setSource(testFileUrl("frameChange.qml")); window->show(); @@ -126,7 +136,7 @@ void tst_qquickanimatedsprite::test_frameChangedSignal() QQuickAnimatedSprite* sprite = window->rootObject()->findChild<QQuickAnimatedSprite*>("sprite"); QSignalSpy frameChangedSpy(sprite, SIGNAL(currentFrameChanged(int))); QVERIFY(sprite); - QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QVERIFY(!sprite->running()); QVERIFY(!sprite->paused()); @@ -154,8 +164,6 @@ void tst_qquickanimatedsprite::test_frameChangedSignal() prevFrame = frame; } QCOMPARE(loopCounter, 3); - - delete window; } void tst_qquickanimatedsprite::test_largeAnimation_data() @@ -214,11 +222,11 @@ void tst_qquickanimatedsprite::test_largeAnimation() { QFETCH(bool, frameSync); - QQuickView *window = new QQuickView(0); + QScopedPointer<QQuickView> window(new QQuickView); window->engine()->addImageProvider(QLatin1String("test"), new AnimationImageProvider); window->setSource(testFileUrl("largeAnimation.qml")); window->show(); - QVERIFY(QTest::qWaitForWindowExposed(window)); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QVERIFY(window->rootObject()); QQuickAnimatedSprite* sprite = window->rootObject()->findChild<QQuickAnimatedSprite*>("sprite"); @@ -264,7 +272,6 @@ void tst_qquickanimatedsprite::test_largeAnimation() maxTextureSize /= 512; QVERIFY(maxFrame > maxTextureSize); // make sure we go beyond the texture width limitation QCOMPARE(loopCounter, sprite->loops()); - delete window; } void tst_qquickanimatedsprite::test_reparenting() @@ -279,20 +286,20 @@ void tst_qquickanimatedsprite::test_reparenting() QVERIFY(sprite); QTRY_VERIFY(sprite->running()); - sprite->setParentItem(0); + sprite->setParentItem(nullptr); sprite->setParentItem(window.rootObject()); // don't crash (QTBUG-51162) sprite->polish(); - QTRY_COMPARE(QQuickItemPrivate::get(sprite)->polishScheduled, true); - QTRY_COMPARE(QQuickItemPrivate::get(sprite)->polishScheduled, false); + QVERIFY(QQuickTest::qIsPolishScheduled(sprite)); + QVERIFY(QQuickTest::qWaitForItemPolished(sprite)); } class KillerThread : public QThread { Q_OBJECT protected: - void run() Q_DECL_OVERRIDE { + void run() override { sleep(3); qFatal("Either the GUI or the render thread is stuck in an infinite loop."); } @@ -313,7 +320,7 @@ void tst_qquickanimatedsprite::test_changeSourceToSmallerImgKeepingBigFrameSize( QQmlProperty big(sprite, "big"); big.write(QVariant::fromValue(false)); - KillerThread *killer = new KillerThread; + QScopedPointer<KillerThread> killer(new KillerThread); killer->start(); // will kill us in case the GUI or render thread enters an infinite loop QTest::qWait(50); // let it draw with the new source. @@ -322,7 +329,66 @@ void tst_qquickanimatedsprite::test_changeSourceToSmallerImgKeepingBigFrameSize( killer->terminate(); killer->wait(); - delete killer; +} + +void tst_qquickanimatedsprite::test_implicitSize() +{ + QQuickView window; + window.setSource(testFileUrl("basic.qml")); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(window.rootObject()); + + QQuickAnimatedSprite* sprite = window.rootObject()->findChild<QQuickAnimatedSprite*>("sprite"); + QVERIFY(sprite); + QCOMPARE(sprite->frameWidth(), 31); + QCOMPARE(sprite->frameHeight(), 30); + QCOMPARE(sprite->implicitWidth(), 31); + QCOMPARE(sprite->implicitHeight(), 30); + + // Ensure that implicitWidth matches frameWidth. + QSignalSpy frameWidthChangedSpy(sprite, SIGNAL(frameWidthChanged(int))); + QVERIFY(frameWidthChangedSpy.isValid()); + + QSignalSpy frameImplicitWidthChangedSpy(sprite, SIGNAL(implicitWidthChanged())); + QVERIFY(frameImplicitWidthChangedSpy.isValid()); + + sprite->setFrameWidth(20); + QCOMPARE(frameWidthChangedSpy.count(), 1); + QCOMPARE(frameImplicitWidthChangedSpy.count(), 1); + + // Ensure that implicitHeight matches frameHeight. + QSignalSpy frameHeightChangedSpy(sprite, SIGNAL(frameHeightChanged(int))); + QVERIFY(frameHeightChangedSpy.isValid()); + + QSignalSpy frameImplicitHeightChangedSpy(sprite, SIGNAL(implicitHeightChanged())); + QVERIFY(frameImplicitHeightChangedSpy.isValid()); + + sprite->setFrameHeight(20); + QCOMPARE(frameHeightChangedSpy.count(), 1); + 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) diff --git a/tests/auto/quick/qquickanimations/BLACKLIST b/tests/auto/quick/qquickanimations/BLACKLIST deleted file mode 100644 index e45c141d17..0000000000 --- a/tests/auto/quick/qquickanimations/BLACKLIST +++ /dev/null @@ -1,40 +0,0 @@ -# QTBUG-45466 QTBUG-29062 -[simpleProperty] -osx-10.9 developer-build -[badTypes] -windows msvc-2010 32bit developer-build -[mixedTypes] -windows msvc-2010 32bit developer-build -[properties] -windows msvc-2010 32bit developer-build -[propertiesTransition] -windows msvc-2010 32bit developer-build -[pathTransition] -windows msvc-2010 32bit developer-build -[disabledTransition] -windows msvc-2010 32bit developer-build -[rotation] -windows msvc-2010 32bit developer-build -[startStopSignals] -windows msvc-2010 32bit developer-build -[runningTrueBug] -windows msvc-2010 32bit developer-build -[nonTransitionBug] -windows msvc-2010 32bit developer-build -[registrationBug] -windows msvc-2010 32bit developer-build -[alwaysRunToEndRestartBug] -windows msvc-2010 32bit developer-build -[loopingBug] -windows msvc-2010 32bit developer-build -[pathAnimationInOutBackBug] -windows msvc-2010 32bit developer-build -[reparent] -windows msvc-2012 64bit developer-build -windows msvc-2010 32bit developer-build -[simpleAnchor] -windows msvc-2010 32bit developer-build -[simplePath] -windows gcc developer-build -windows msvc-2010 32bit developer-build - 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/data/replacingTransitions.qml b/tests/auto/quick/qquickanimations/data/replacingTransitions.qml new file mode 100644 index 0000000000..ff7c50cd67 --- /dev/null +++ b/tests/auto/quick/qquickanimations/data/replacingTransitions.qml @@ -0,0 +1,51 @@ +import QtQuick 2.9 + +Rectangle { + id: theRoot + property alias model: theModel + property alias addTimer: addToModel + property alias addTransition: addTrans + property alias displaceTransition: displaceTrans + + width: 400 + height: 400 + + ListModel { + id: theModel + } + Timer { + id: addToModel + interval: 1000 + running: false + repeat: true + onTriggered: { + theModel.insert(0, {"name": "item " + theModel.count}) + if (theModel.count > 2) + stop() + } + } + Component { + id: listDelegate + Text { + text: name + } + } + ListView { + id: listView + + property int animationDuration: 10000 + + anchors.fill: parent + model: theModel + delegate: listDelegate + add: Transition { + id: addTrans + NumberAnimation { properties: "x"; from: 400; duration: listView.animationDuration } + NumberAnimation { properties: "y"; from: 400; duration: listView.animationDuration } + } + addDisplaced: Transition { + id: displaceTrans + NumberAnimation { properties: "x,y"; duration: listView.animationDuration } + } + } +} diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp index fbd6c9c97e..961506372a 100644 --- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp +++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp @@ -29,12 +29,15 @@ #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcomponent.h> #include <QtQuick/qquickview.h> +#include <QtQml/private/qqmltimer_p.h> +#include <QtQml/private/qqmllistmodel_p.h> #include <QtQml/private/qanimationgroupjob_p.h> #include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickitemanimation_p.h> #include <QtQuick/private/qquickitemanimation_p_p.h> #include <QtQuick/private/qquicktransition_p.h> #include <QtQuick/private/qquickanimation_p.h> +#include <QtQuick/private/qquickanimatorjob_p.h> #include <QtQuick/private/qquickpathinterpolator_p.h> #include <QtQuick/private/qquickitem_p.h> #include <QEasingCurve> @@ -103,6 +106,9 @@ private slots: void defaultPropertyWarning(); void pathSvgAnimation(); void pathLineUnspecifiedXYBug(); + void unsetAnimatorProxyJobWindow(); + void finished(); + void replacingTransitions(); }; #define QTIMED_COMPARE(lhs, rhs) do { \ @@ -118,12 +124,16 @@ void tst_qquickanimations::simpleProperty() { QQuickRectangle rect; QQuickPropertyAnimation animation; + QSignalSpy fromChangedSpy(&animation, &QQuickPropertyAnimation::fromChanged); + QSignalSpy toChangedSpy(&animation, &QQuickPropertyAnimation::toChanged); animation.setTargetObject(&rect); animation.setProperty("x"); animation.setTo(200); QCOMPARE(animation.target(), &rect); QCOMPARE(animation.property(), QLatin1String("x")); QCOMPARE(animation.to().toReal(), 200.0); + QCOMPARE(fromChangedSpy.count(), 0); + QCOMPARE(toChangedSpy.count(), 1); animation.start(); QVERIFY(animation.isRunning()); QTest::qWait(animation.duration()); @@ -137,18 +147,25 @@ void tst_qquickanimations::simpleProperty() animation.setCurrentTime(125); QCOMPARE(animation.currentTime(), 125); QCOMPARE(rect.x(),100.0); + animation.setFrom(100); + QCOMPARE(fromChangedSpy.count(), 1); + QCOMPARE(toChangedSpy.count(), 1); } void tst_qquickanimations::simpleNumber() { QQuickRectangle rect; QQuickNumberAnimation animation; + QSignalSpy fromChangedSpy(&animation, &QQuickNumberAnimation::fromChanged); + QSignalSpy toChangedSpy(&animation, &QQuickNumberAnimation::toChanged); animation.setTargetObject(&rect); animation.setProperty("x"); animation.setTo(200); QCOMPARE(animation.target(), &rect); QCOMPARE(animation.property(), QLatin1String("x")); QCOMPARE(animation.to(), qreal(200)); + QCOMPARE(fromChangedSpy.count(), 0); + QCOMPARE(toChangedSpy.count(), 1); animation.start(); QVERIFY(animation.isRunning()); QTest::qWait(animation.duration()); @@ -162,18 +179,25 @@ void tst_qquickanimations::simpleNumber() animation.setCurrentTime(125); QCOMPARE(animation.currentTime(), 125); QCOMPARE(rect.x(), qreal(100)); + animation.setFrom(100); + QCOMPARE(fromChangedSpy.count(), 1); + QCOMPARE(toChangedSpy.count(), 1); } void tst_qquickanimations::simpleColor() { QQuickRectangle rect; QQuickColorAnimation animation; + QSignalSpy fromChangedSpy(&animation, &QQuickColorAnimation::fromChanged); + QSignalSpy toChangedSpy(&animation, &QQuickColorAnimation::toChanged); animation.setTargetObject(&rect); animation.setProperty("color"); animation.setTo(QColor("red")); QCOMPARE(animation.target(), &rect); QCOMPARE(animation.property(), QLatin1String("color")); QCOMPARE(animation.to(), QColor("red")); + QCOMPARE(fromChangedSpy.count(), 0); + QCOMPARE(toChangedSpy.count(), 1); animation.start(); QVERIFY(animation.isRunning()); QTest::qWait(animation.duration()); @@ -191,6 +215,8 @@ void tst_qquickanimations::simpleColor() rect.setColor(QColor("green")); animation.setFrom(QColor("blue")); QCOMPARE(animation.from(), QColor("blue")); + QCOMPARE(fromChangedSpy.count(), 1); + QCOMPARE(toChangedSpy.count(), 1); animation.restart(); QCOMPARE(rect.color(), QColor("blue")); QVERIFY(animation.isRunning()); @@ -202,6 +228,8 @@ void tst_qquickanimations::simpleRotation() { QQuickRectangle rect; QQuickRotationAnimation animation; + QSignalSpy fromChangedSpy(&animation, &QQuickRotationAnimation::fromChanged); + QSignalSpy toChangedSpy(&animation, &QQuickRotationAnimation::toChanged); animation.setTargetObject(&rect); animation.setProperty("rotation"); animation.setTo(270); @@ -209,6 +237,8 @@ void tst_qquickanimations::simpleRotation() QCOMPARE(animation.property(), QLatin1String("rotation")); QCOMPARE(animation.to(), qreal(270)); QCOMPARE(animation.direction(), QQuickRotationAnimation::Numerical); + QCOMPARE(fromChangedSpy.count(), 0); + QCOMPARE(toChangedSpy.count(), 1); animation.start(); QVERIFY(animation.isRunning()); QTest::qWait(animation.duration()); @@ -222,6 +252,9 @@ void tst_qquickanimations::simpleRotation() animation.setCurrentTime(125); QCOMPARE(animation.currentTime(), 125); QCOMPARE(rect.rotation(), qreal(135)); + animation.setFrom(90); + QCOMPARE(fromChangedSpy.count(), 1); + QCOMPARE(toChangedSpy.count(), 1); } void tst_qquickanimations::simplePath() @@ -731,7 +764,7 @@ void tst_qquickanimations::badTypes() QQuickItemPrivate::get(rect)->setState("state1"); - QQuickRectangle *myRect = 0; + QQuickRectangle *myRect = nullptr; QTRY_VERIFY(myRect = rect->findChild<QQuickRectangle*>("MyRect")); QTRY_COMPARE(myRect->x(),qreal(200)); } @@ -1124,7 +1157,7 @@ void tst_qquickanimations::easingProperties() animationComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickPropertyAnimation *animObject = qobject_cast<QQuickPropertyAnimation*>(animationComponent.create()); - QVERIFY(animObject != 0); + QVERIFY(animObject != nullptr); QCOMPARE(animObject->easing().type(), QEasingCurve::InOutQuad); } @@ -1135,7 +1168,7 @@ void tst_qquickanimations::easingProperties() animationComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickPropertyAnimation *animObject = qobject_cast<QQuickPropertyAnimation*>(animationComponent.create()); - QVERIFY(animObject != 0); + QVERIFY(animObject != nullptr); QCOMPARE(animObject->easing().type(), QEasingCurve::OutBounce); QCOMPARE(animObject->easing().amplitude(), 5.0); } @@ -1147,7 +1180,7 @@ void tst_qquickanimations::easingProperties() animationComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickPropertyAnimation *animObject = qobject_cast<QQuickPropertyAnimation*>(animationComponent.create()); - QVERIFY(animObject != 0); + QVERIFY(animObject != nullptr); QCOMPARE(animObject->easing().type(), QEasingCurve::OutElastic); QCOMPARE(animObject->easing().amplitude(), 5.0); QCOMPARE(animObject->easing().period(), 3.0); @@ -1160,7 +1193,7 @@ void tst_qquickanimations::easingProperties() animationComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickPropertyAnimation *animObject = qobject_cast<QQuickPropertyAnimation*>(animationComponent.create()); - QVERIFY(animObject != 0); + QVERIFY(animObject != nullptr); QCOMPARE(animObject->easing().type(), QEasingCurve::InOutBack); QCOMPARE(animObject->easing().overshoot(), 2.0); } @@ -1172,9 +1205,9 @@ void tst_qquickanimations::easingProperties() animationComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickPropertyAnimation *animObject = qobject_cast<QQuickPropertyAnimation*>(animationComponent.create()); - QVERIFY(animObject != 0); + QVERIFY(animObject != nullptr); QCOMPARE(animObject->easing().type(), QEasingCurve::BezierSpline); - QList<QPointF> points = animObject->easing().cubicBezierSpline(); + QVector<QPointF> points = animObject->easing().toCubicSpline(); QCOMPARE(points.count(), 3); QCOMPARE(points.at(0), QPointF(0.5, 0.2)); QCOMPARE(points.at(1), QPointF(0.13, 0.65)); @@ -1295,7 +1328,7 @@ void tst_qquickanimations::nonTransitionBug() QQmlComponent c(&engine, testFileUrl("nonTransitionBug.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQuickRectangle *mover = rect->findChild<QQuickRectangle*>("mover"); @@ -1321,7 +1354,7 @@ void tst_qquickanimations::registrationBug() QQmlComponent c(&engine, testFileUrl("registrationBug.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QTRY_COMPARE(rect->property("value"), QVariant(int(100))); } @@ -1331,10 +1364,10 @@ void tst_qquickanimations::doubleRegistrationBug() QQmlComponent c(&engine, testFileUrl("doubleRegistrationBug.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickAbstractAnimation *anim = rect->findChild<QQuickAbstractAnimation*>("animation"); - QVERIFY(anim != 0); + QVERIFY(anim != nullptr); QTRY_COMPARE(anim->qtAnimation()->state(), QAbstractAnimationJob::Stopped); } @@ -1372,7 +1405,7 @@ void tst_qquickanimations::transitionAssignmentBug() QQmlComponent c(&engine, testFileUrl("transitionAssignmentBug.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->property("nullObject").toBool(), false); } @@ -1384,7 +1417,7 @@ void tst_qquickanimations::pauseBindingBug() QQmlComponent c(&engine, testFileUrl("pauseBindingBug.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickAbstractAnimation *anim = rect->findChild<QQuickAbstractAnimation*>("animation"); QCOMPARE(anim->qtAnimation()->state(), QAbstractAnimationJob::Paused); @@ -1398,7 +1431,7 @@ void tst_qquickanimations::pauseBug() QQmlComponent c(&engine, testFileUrl("pauseBug.qml")); QQuickAbstractAnimation *anim = qobject_cast<QQuickAbstractAnimation*>(c.create()); - QVERIFY(anim != 0); + QVERIFY(anim != nullptr); QCOMPARE(anim->qtAnimation()->state(), QAbstractAnimationJob::Paused); QCOMPARE(anim->isPaused(), true); QCOMPARE(anim->isRunning(), true); @@ -1415,14 +1448,14 @@ void tst_qquickanimations::loopingBug() QObject *obj = c.create(); QQuickAbstractAnimation *anim = obj->findChild<QQuickAbstractAnimation*>(); - QVERIFY(anim != 0); + QVERIFY(anim != nullptr); QCOMPARE(anim->qtAnimation()->totalDuration(), 300); QCOMPARE(anim->isRunning(), true); QTRY_COMPARE(static_cast<QAnimationGroupJob*>(anim->qtAnimation())->firstChild()->currentLoop(), 2); QTRY_COMPARE(anim->isRunning(), false); QQuickRectangle *rect = obj->findChild<QQuickRectangle*>(); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->rotation(), qreal(90)); delete obj; @@ -1567,6 +1600,129 @@ void tst_qquickanimations::pathLineUnspecifiedXYBug() QCOMPARE(redRect->y(), qreal(0)); } +void tst_qquickanimations::unsetAnimatorProxyJobWindow() +{ + QQuickWindow window; + QQuickItem item(window.contentItem()); + QQuickAbstractAnimation animation(&item); + QAbstractAnimationJob *job = new QAbstractAnimationJob; + QQuickAnimatorProxyJob proxy(job, &animation); + QQuickItem dummy; + item.setParentItem(&dummy); + QSignalSpy spy(&window, SIGNAL(sceneGraphInitialized())); + window.show(); + if (spy.count() < 1) + spy.wait(); + 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); + } +} + +void tst_qquickanimations::replacingTransitions() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("replacingTransitions.qml")); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create())); + if (!c.errors().isEmpty()) + qDebug() << c.errorString(); + QVERIFY(rect); + + QQmlTimer *addTimer = rect->property("addTimer").value<QQmlTimer*>(); + QVERIFY(addTimer); + QCOMPARE(addTimer->isRunning(), false); + + QQuickTransition *addTrans = rect->property("addTransition").value<QQuickTransition*>(); + QVERIFY(addTrans); + QCOMPARE(addTrans->running(), false); + + QQuickTransition *displaceTrans = rect->property("displaceTransition").value<QQuickTransition*>(); + QVERIFY(displaceTrans); + QCOMPARE(displaceTrans->running(), false); + + QQmlListModel *model = rect->property("model").value<QQmlListModel *>(); + QVERIFY(model); + QCOMPARE(model->count(), 0); + + addTimer->start(); + QTest::qWait(1000 + 1000 + 10000); + + QTRY_COMPARE(addTimer->isRunning(), false); + QTRY_COMPARE(addTrans->running(), false); + QTRY_COMPARE(displaceTrans->running(), false); + QCOMPARE(model->count(), 3); +} + QTEST_MAIN(tst_qquickanimations) #include "tst_qquickanimations.moc" diff --git a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp index e428a1fc6e..3526eb98be 100644 --- a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp +++ b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp @@ -67,7 +67,7 @@ void tst_qquickapplication::cleanup() { if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) { QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); - QTest::waitForEvents(); + QCoreApplication::processEvents(); } } @@ -88,31 +88,37 @@ void tst_qquickapplication::active() QQuickWindow window; item->setParentItem(window.contentItem()); - // not active - QVERIFY(!item->property("active").toBool()); - QVERIFY(!item->property("active2").toBool()); - - // active - window.show(); - window.requestActivate(); - QTest::qWaitForWindowActive(&window); - QCOMPARE(QGuiApplication::focusWindow(), &window); - QVERIFY(item->property("active").toBool()); - QVERIFY(item->property("active2").toBool()); - - QWindowSystemInterface::handleWindowActivated(0); - -#ifdef Q_OS_OSX - // OS X has the concept of "reactivation" - QTRY_VERIFY(QGuiApplication::focusWindow() != &window); - QVERIFY(item->property("active").toBool()); - QVERIFY(item->property("active2").toBool()); -#else - // not active again - QTRY_VERIFY(QGuiApplication::focusWindow() != &window); - QVERIFY(!item->property("active").toBool()); - QVERIFY(!item->property("active2").toBool()); -#endif + // If the platform plugin has the ApplicationState capability, app activation originate from it + // as a result of a system event. We therefore have to simulate these events here. + if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) { + + // Flush pending events, in case the platform have already queued real application state events + QWindowSystemInterface::flushWindowSystemEvents(); + + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); + QWindowSystemInterface::flushWindowSystemEvents(); + QVERIFY(item->property("active").toBool()); + QVERIFY(item->property("active2").toBool()); + + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); + QWindowSystemInterface::flushWindowSystemEvents(); + QVERIFY(!item->property("active").toBool()); + QVERIFY(!item->property("active2").toBool()); + } else { + // Otherwise, app activation is triggered by window activation. + window.show(); + window.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + QCOMPARE(QGuiApplication::focusWindow(), &window); + QVERIFY(item->property("active").toBool()); + QVERIFY(item->property("active2").toBool()); + + // not active again + QWindowSystemInterface::handleWindowActivated(nullptr); + QTRY_VERIFY(QGuiApplication::focusWindow() != &window); + QVERIFY(!item->property("active").toBool()); + QVERIFY(!item->property("active2").toBool()); + } } void tst_qquickapplication::state() @@ -165,13 +171,13 @@ void tst_qquickapplication::state() // triggered by window activation. window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QCOMPARE(QGuiApplication::focusWindow(), &window); QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationActive); QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationActive); // not active again - QWindowSystemInterface::handleWindowActivated(0); + QWindowSystemInterface::handleWindowActivated(nullptr); QTRY_VERIFY(QGuiApplication::focusWindow() != &window); QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationInactive); QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationInactive); diff --git a/tests/auto/quick/qquickbehaviors/BLACKLIST b/tests/auto/quick/qquickbehaviors/BLACKLIST deleted file mode 100644 index 9be4da176d..0000000000 --- a/tests/auto/quick/qquickbehaviors/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[currentValue] -windows diff --git a/tests/auto/quick/qquickbehaviors/data/ItemWithInnerBehavior.qml b/tests/auto/quick/qquickbehaviors/data/ItemWithInnerBehavior.qml new file mode 100644 index 0000000000..0ac7f87c42 --- /dev/null +++ b/tests/auto/quick/qquickbehaviors/data/ItemWithInnerBehavior.qml @@ -0,0 +1,11 @@ +import QtQuick 2.4 + +Item { + id: root + + property bool someValue + Behavior on someValue { + objectName: "behavior" + ScriptAction { script: { parent.behaviorTriggered = true }} + } +} diff --git a/tests/auto/quick/qquickbehaviors/data/aliased.qml b/tests/auto/quick/qquickbehaviors/data/aliased.qml index e65e035d83..1840cdd22e 100644 --- a/tests/auto/quick/qquickbehaviors/data/aliased.qml +++ b/tests/auto/quick/qquickbehaviors/data/aliased.qml @@ -17,6 +17,7 @@ Rectangle { anchors.fill: parent value: accelerating ? 400 : 0 Behavior on value { + objectName: "behavior" NumberAnimation { duration: 500 } diff --git a/tests/auto/quick/qquickbehaviors/data/oneway.qml b/tests/auto/quick/qquickbehaviors/data/oneway.qml new file mode 100644 index 0000000000..0b438b80f6 --- /dev/null +++ b/tests/auto/quick/qquickbehaviors/data/oneway.qml @@ -0,0 +1,20 @@ +import QtQuick 2.0 +Rectangle { + width: 400 + height: 400 + Rectangle { + id: rect + objectName: "MyRectOneWay" + width: 100; height: 100; color: "green" + Behavior on x { + id: behavior + objectName: "MyBehaviorOneWay"; + enabled: (behavior.targetValue === 0) + NumberAnimation { + id: ani + objectName: "MyAnimationOneWay"; + duration: 200; + } + } + } +} diff --git a/tests/auto/quick/qquickbehaviors/data/overwrittenbehavior.qml b/tests/auto/quick/qquickbehaviors/data/overwrittenbehavior.qml new file mode 100644 index 0000000000..e627c45782 --- /dev/null +++ b/tests/auto/quick/qquickbehaviors/data/overwrittenbehavior.qml @@ -0,0 +1,14 @@ +import QtQuick 2.4 + +Item { + property bool behaviorTriggered + property bool someProperty + + ItemWithInnerBehavior { + //the existence of this property triggers the bug + property bool iDoAbsolutelyNothing + + Component.onCompleted: parent.someProperty = true + someValue: parent.someProperty + } +} diff --git a/tests/auto/quick/qquickbehaviors/data/qtbug21549-2.qml b/tests/auto/quick/qquickbehaviors/data/qtbug21549-2.qml index d2da8d1b27..f87febf958 100644 --- a/tests/auto/quick/qquickbehaviors/data/qtbug21549-2.qml +++ b/tests/auto/quick/qquickbehaviors/data/qtbug21549-2.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquickbehaviors/qquickbehaviors.pro b/tests/auto/quick/qquickbehaviors/qquickbehaviors.pro index 51bc42c390..fd64eb1d40 100644 --- a/tests/auto/quick/qquickbehaviors/qquickbehaviors.pro +++ b/tests/auto/quick/qquickbehaviors/qquickbehaviors.pro @@ -7,5 +7,5 @@ include (../../shared/util.pri) macx:CONFIG -= app_bundle TESTDATA = data/* - +DISTFILES = $$files(data/*) QT += core-private gui-private qml-private quick-private testlib diff --git a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp index 80c76a377b..6367f327da 100644 --- a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp +++ b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp @@ -72,6 +72,8 @@ private slots: void currentValue(); void disabledWriteWhileRunning(); void aliasedProperty(); + void innerBehaviorOverwritten(); + void oneWay(); }; void tst_qquickbehaviors::simpleBehavior() @@ -392,7 +394,7 @@ void tst_qquickbehaviors::delayedRegistration() QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickItem *innerRect = rect->property("myItem").value<QQuickItem*>(); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); QCOMPARE(innerRect->property("x").toInt(), int(0)); @@ -409,7 +411,7 @@ void tst_qquickbehaviors::startOnCompleted() QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickItem *innerRect = rect->findChild<QQuickRectangle*>(); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); QCOMPARE(innerRect->property("x").toInt(), int(0)); @@ -426,7 +428,7 @@ void tst_qquickbehaviors::multipleChangesToValueType() QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); QQuickText *text = rect->findChild<QQuickText *>(); - QVERIFY(text != 0); + QVERIFY(text != nullptr); QFont value; value.setPointSize(24); @@ -515,6 +517,7 @@ void tst_qquickbehaviors::disabledWriteWhileRunning() myRect->setProperty("x", 200); QCOMPARE(myAnimation->isRunning(), true); QTRY_VERIFY(myRect->x() != qreal(0) && myRect->x() != qreal(200)); + QCOMPARE(myBehavior->targetValue(), 200); // grabbed before starting the animation // set disabled while animation is in progress myBehavior->setProperty("enabled", false); @@ -525,6 +528,7 @@ void tst_qquickbehaviors::disabledWriteWhileRunning() myRect->setProperty("x", 100); QCOMPARE(myAnimation->isRunning(), false); QCOMPARE(myRect->x(), qreal(100)); + QCOMPARE(myBehavior->targetValue(), 100); QTest::qWait(200); QCOMPARE(myRect->x(), qreal(100)); } @@ -545,17 +549,20 @@ void tst_qquickbehaviors::disabledWriteWhileRunning() // initial values QCOMPARE(myBehavior->enabled(), true); + QCOMPARE(myBehavior->targetValue(), QVariant()); QCOMPARE(myAnimation->isRunning(), false); QCOMPARE(myRect->x(), qreal(0)); // start animation myRect->setProperty("x", 200); QCOMPARE(myAnimation->isRunning(), true); + QCOMPARE(myBehavior->targetValue(), 200); QTRY_VERIFY(myRect->x() != qreal(0) && myRect->x() != qreal(200)); //set second value myRect->setProperty("x", 300); QCOMPARE(myAnimation->isRunning(), true); + QCOMPARE(myBehavior->targetValue(), 300); QTRY_VERIFY(myRect->x() != qreal(0) && myRect->x() != qreal(200)); // set disabled while animation is in progress @@ -567,6 +574,7 @@ void tst_qquickbehaviors::disabledWriteWhileRunning() myRect->setProperty("x", 100); QCOMPARE(myAnimation->isRunning(), false); QCOMPARE(myRect->x(), qreal(100)); + QCOMPARE(myBehavior->targetValue(), 100); QTest::qWait(200); QCOMPARE(myRect->x(), qreal(100)); } @@ -579,7 +587,12 @@ void tst_qquickbehaviors::aliasedProperty() QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create())); QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); + QQuickBehavior* behavior = + qobject_cast<QQuickBehavior*>(rect->findChild<QQuickBehavior*>("behavior")); + QSignalSpy targetValueSpy(behavior, SIGNAL(targetValueChanged())); QQuickItemPrivate::get(rect.data())->setState("moved"); + QCOMPARE(behavior->targetValue(), 400); + QCOMPARE(targetValueSpy.count(), 1); QScopedPointer<QQuickRectangle> acc(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("acc"))); QScopedPointer<QQuickRectangle> range(qobject_cast<QQuickRectangle*>(acc->findChild<QQuickRectangle*>("range"))); QTRY_VERIFY(acc->property("value").toDouble() > 0); @@ -589,6 +602,51 @@ void tst_qquickbehaviors::aliasedProperty() //i.e. the behavior has been triggered } +void tst_qquickbehaviors::innerBehaviorOverwritten() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("overwrittenbehavior.qml")); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(c.create())); + QQuickBehavior* behavior = + qobject_cast<QQuickBehavior*>(item->findChild<QQuickBehavior*>("behavior")); + QVERIFY(item->property("behaviorTriggered").toBool()); + QCOMPARE(behavior->targetValue(), true); +} + +void tst_qquickbehaviors::oneWay() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("oneway.qml")); + QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(c.create()));; + QVERIFY2(!rect.isNull(), qPrintable(c.errorString())); + QQuickBehavior* behavior = + qobject_cast<QQuickBehavior*>(rect->findChild<QQuickBehavior*>("MyBehaviorOneWay")); + QCOMPARE(behavior->enabled(), false); + QCOMPARE(behavior->targetValue(), QVariant()); + + QSignalSpy targetValueSpy(behavior, SIGNAL(targetValueChanged())); + QQuickRectangle *myRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRectOneWay")); + myRect->setProperty("x", 100); + QCOMPARE(behavior->targetValue(), 100); + QCOMPARE(targetValueSpy.count(), 1); + QCOMPARE(behavior->enabled(), false); + qreal x = myRect->x(); + QCOMPARE(x, qreal(100)); //should change immediately + QQuickNumberAnimation *myAnimation = + qobject_cast<QQuickNumberAnimation*>(behavior->findChild<QQuickNumberAnimation*>("MyAnimationOneWay")); + QCOMPARE(myAnimation->isRunning(), false); + + myRect->setProperty("x", 0); + QCOMPARE(behavior->targetValue(), 0); + QCOMPARE(targetValueSpy.count(), 2); + QCOMPARE(behavior->enabled(), true); + QCOMPARE(myAnimation->isRunning(), true); + QVERIFY(myRect->x() > 0.0); + QTRY_VERIFY(myRect->x() < 100.0); + QTRY_COMPARE(myRect->x(), qreal(0)); + QCOMPARE(myAnimation->isRunning(), false); +} + QTEST_MAIN(tst_qquickbehaviors) #include "tst_qquickbehaviors.moc" diff --git a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp index 71b0160c8e..9292e1886a 100644 --- a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp +++ b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp @@ -101,7 +101,7 @@ void tst_qquickborderimage::noSource() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->source(), QUrl()); QCOMPARE(obj->width(), 0.); QCOMPARE(obj->height(), 0.); @@ -153,7 +153,7 @@ void tst_qquickborderimage::imageSource() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); if (remote) QTRY_COMPARE(obj->status(), QQuickBorderImage::Loading); @@ -183,7 +183,7 @@ void tst_qquickborderimage::clearSource() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->status(), QQuickBorderImage::Ready); QCOMPARE(obj->width(), 120.); QCOMPARE(obj->height(), 120.); @@ -203,7 +203,7 @@ void tst_qquickborderimage::resized() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 300.); QCOMPARE(obj->height(), 300.); QCOMPARE(obj->sourceSize().width(), 120); @@ -220,7 +220,7 @@ void tst_qquickborderimage::smooth() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 300.); QCOMPARE(obj->height(), 300.); QCOMPARE(obj->smooth(), true); @@ -235,7 +235,7 @@ void tst_qquickborderimage::mirror() QQuickView *window = new QQuickView; window->setSource(testFileUrl("mirror.qml")); QQuickBorderImage *image = qobject_cast<QQuickBorderImage*>(window->rootObject()); - QVERIFY(image != 0); + QVERIFY(image != nullptr); QImage screenshot = window->grabWindow(); @@ -248,7 +248,7 @@ void tst_qquickborderimage::mirror() screenshot = window->grabWindow(); window->show(); - QTest::qWaitForWindowExposed(window); + QVERIFY(QTest::qWaitForWindowExposed(window)); if (window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) QSKIP("QTBUG-53823"); QCOMPARE(screenshot, srcPixmap); @@ -263,7 +263,7 @@ void tst_qquickborderimage::tileModes() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 100.); QCOMPARE(obj->height(), 300.); QCOMPARE(obj->horizontalTileMode(), QQuickBorderImage::Repeat); @@ -276,7 +276,7 @@ void tst_qquickborderimage::tileModes() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 300.); QCOMPARE(obj->height(), 150.); QCOMPARE(obj->horizontalTileMode(), QQuickBorderImage::Round); @@ -304,7 +304,7 @@ void tst_qquickborderimage::sciSource() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); if (remote) QTRY_COMPARE(obj->status(), QQuickBorderImage::Loading); @@ -352,7 +352,7 @@ void tst_qquickborderimage::invalidSciFile() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 300.); QCOMPARE(obj->height(), 300.); QCOMPARE(obj->status(), QQuickImageBase::Error); @@ -380,7 +380,7 @@ void tst_qquickborderimage::validSciFiles() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 300.); QCOMPARE(obj->height(), 300.); QCOMPARE(obj->horizontalTileMode(), QQuickBorderImage::Round); @@ -397,7 +397,7 @@ void tst_qquickborderimage::pendingRemoteRequest() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->status(), QQuickBorderImage::Loading); // verify no crash @@ -450,7 +450,7 @@ void tst_qquickborderimage::statusChanges() QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); qRegisterMetaType<QQuickImageBase::Status>(); QSignalSpy spy(obj, SIGNAL(statusChanged(QQuickImageBase::Status))); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); obj->setSource(source); if (remote) server.sendDelayedItem(); @@ -473,7 +473,7 @@ void tst_qquickborderimage::sourceSizeChanges() QQmlContext *ctxt = engine.rootContext(); ctxt->setContextProperty("srcImage", ""); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QSignalSpy sourceSizeSpy(obj, SIGNAL(sourceSizeChanged())); @@ -539,7 +539,7 @@ void tst_qquickborderimage::progressAndStatusChanges() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickBorderImage *obj = qobject_cast<QQuickBorderImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->status(), QQuickBorderImage::Ready); QTRY_COMPARE(obj->progress(), 1.0); @@ -590,13 +590,15 @@ void tst_qquickborderimage::borderImageMesh() window->setSource(testFileUrl("nonmesh.qml")); window->show(); - QTest::qWaitForWindowExposed(window); + QVERIFY(QTest::qWaitForWindowExposed(window)); QImage nonmesh = window->grabWindow(); window->setSource(testFileUrl("mesh.qml")); QImage mesh = window->grabWindow(); - QVERIFY(QQuickVisualTestUtil::compareImages(mesh, nonmesh)); + QString errorMessage; + QVERIFY2(QQuickVisualTestUtil::compareImages(mesh, nonmesh, &errorMessage), + qPrintable(errorMessage)); } #endif QTEST_MAIN(tst_qquickborderimage) diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml index 565f906fb1..8238d87313 100644 --- a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml +++ b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml @@ -151,9 +151,11 @@ CanvasTestCase { {mimeType:"image/bmp"}, {mimeType:"image/jpeg"}, {mimeType:"image/x-portable-pixmap"}, - //{mimeType:"image/tiff"}, QTBUG-23980 {mimeType:"image/xpm"}, ]; + if (hasImageFormats) + imageTypes.push({ mimeType: "image/tiff" }); + for (var i = 0; i < imageTypes.length; i++) { ctx.fillStyle = "red"; ctx.fillRect(0, 0, c.width, c.height); diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_gradient.qml b/tests/auto/quick/qquickcanvasitem/data/tst_gradient.qml index 00a12f2edc..7c87d896fb 100644 --- a/tests/auto/quick/qquickcanvasitem/data/tst_gradient.qml +++ b/tests/auto/quick/qquickcanvasitem/data/tst_gradient.qml @@ -33,7 +33,7 @@ CanvasTestCase { //comparePixel(ctx, 75,25, 63,63,191,255,3); ctx.reset(); - var g = ctx.createLinearGradient(0, 0, 100, 0); + g = ctx.createLinearGradient(0, 0, 100, 0); g.addColorStop(0, '#ff0'); g.addColorStop(1, '#00f'); ctx.fillStyle = g; @@ -44,7 +44,7 @@ CanvasTestCase { ctx.reset(); - var g = ctx.createLinearGradient(0, 0, 100, 0); + g = ctx.createLinearGradient(0, 0, 100, 0); g.addColorStop(0, 'rgba(255,255,0, 0)'); g.addColorStop(1, 'rgba(0,0,255, 1)'); ctx.fillStyle = g; @@ -55,7 +55,7 @@ CanvasTestCase { ctx.reset(); canvas.width = 200; - var g = ctx.createLinearGradient(0, 0, 200, 0); + g = ctx.createLinearGradient(0, 0, 200, 0); g.addColorStop(0, '#ff0'); g.addColorStop(0.5, '#0ff'); g.addColorStop(1, '#f0f'); @@ -69,7 +69,7 @@ CanvasTestCase { ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); - var g = ctx.createLinearGradient(25, 0, 75, 0); + g = ctx.createLinearGradient(25, 0, 75, 0); g.addColorStop(0.4, '#0f0'); g.addColorStop(0.6, '#0f0'); @@ -82,7 +82,7 @@ CanvasTestCase { ctx.reset(); ctx.canvas.width = 200; - var g = ctx.createLinearGradient(0, 0, 200, 0); + g = ctx.createLinearGradient(0, 0, 200, 0); g.addColorStop(0, '#f00'); g.addColorStop(0, '#ff0'); g.addColorStop(0.25, '#00f'); @@ -110,7 +110,7 @@ CanvasTestCase { ctx.canvas.width = 100; ctx.reset(); - var g = ctx.createLinearGradient(0, 0, 100, 0); + g = ctx.createLinearGradient(0, 0, 100, 0); var ps = [ 0, 1/10, 1/4, 1/3, 1/2, 3/4, 1 ]; for (var p = 0; p < ps.length; ++p) { @@ -129,7 +129,7 @@ CanvasTestCase { ctx.reset(); - var g = ctx.createLinearGradient(0, 0, 100, 0); + g = ctx.createLinearGradient(0, 0, 100, 0); g.addColorStop(0, '#0f0'); g.addColorStop(1, '#0f0'); ctx.fillStyle = g; @@ -139,7 +139,7 @@ CanvasTestCase { ctx.reset(); - var g = ctx.createLinearGradient(0, 0, 0, 50); + g = ctx.createLinearGradient(0, 0, 0, 50); g.addColorStop(0, '#ff0'); g.addColorStop(1, '#00f'); ctx.fillStyle = g; @@ -154,7 +154,7 @@ CanvasTestCase { ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); - var g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction) + g = ctx.createLinearGradient(50, 25, 50, 25); // zero-length line (undefined direction) g.addColorStop(0, '#f00'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; @@ -278,7 +278,7 @@ CanvasTestCase { //comparePixel(ctx, 98,48, 0,255,0,255); ctx.reset(); - var tol = 1; // tolerance to avoid antialiasing artifacts + tol = 1; // tolerance to avoid antialiasing artifacts ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50); @@ -410,243 +410,243 @@ CanvasTestCase { ctx.reset(); try { var err = false; ctx.createRadialGradient(0, 0, -0.1, 0, 0, 1); - } catch (e) { if (e.code != DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: ctx.createRadialGradient(0, 0, -0.1, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: ctx.createRadialGradient(0, 0, -0.1, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, 0, 0, -0.1); - } catch (e) { if (e.code != DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: ctx.createRadialGradient(0, 0, 1, 0, 0, -0.1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: ctx.createRadialGradient(0, 0, 1, 0, 0, -0.1)"); } + try { err = false; ctx.createRadialGradient(0, 0, -0.1, 0, 0, -0.1); - } catch (e) { if (e.code != DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: ctx.createRadialGradient(0, 0, -0.1, 0, 0, -0.1)"); } + } catch (e) { if (e.code !== DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: ctx.createRadialGradient(0, 0, -0.1, 0, 0, -0.1)"); } ctx.reset(); - try { var err = false; + try { err = false; ctx.createRadialGradient(Infinity, 0, 1, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(-Infinity, 0, 1, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(-Infinity, 0, 1, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(-Infinity, 0, 1, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(NaN, 0, 1, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(NaN, 0, 1, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(NaN, 0, 1, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, 1, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, -Infinity, 1, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, -Infinity, 1, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, -Infinity, 1, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, NaN, 1, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, NaN, 1, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, NaN, 1, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, Infinity, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, -Infinity, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, -Infinity, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, -Infinity, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, NaN, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, NaN, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, NaN, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, Infinity, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, Infinity, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, Infinity, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, -Infinity, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, -Infinity, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, -Infinity, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, NaN, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, NaN, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, NaN, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, 0, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, 0, -Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, -Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, -Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, 0, NaN, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, NaN, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, NaN, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, 0, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, 0, 0, -Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, 0, -Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, 0, -Infinity)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, 0, 0, NaN); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, 0, NaN)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, 0, NaN)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, 1, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, 0, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, Infinity, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, Infinity, 0, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, 0, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, Infinity, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, 1, 0, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, 0, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, 0, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, 1, 0, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, 0, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, 0, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, Infinity, 1, 0, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, 0, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, Infinity, 1, 0, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, Infinity, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, 0, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, Infinity, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, Infinity, 0, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, 0, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, 0, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, Infinity, 0, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, 0, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, 0, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, Infinity, 0, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, 0, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, Infinity, 0, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, 1, Infinity, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, Infinity, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, Infinity, 0, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, 1, Infinity, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, Infinity, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, Infinity, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, 1, Infinity, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, Infinity, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, Infinity, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, 1, Infinity, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, Infinity, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, Infinity, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, 1, 0, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, 0, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, 0, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, 1, 0, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, 0, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, 0, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(Infinity, 0, 1, 0, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, 0, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(Infinity, 0, 1, 0, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, Infinity, 0, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, 0, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, 0, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, Infinity, Infinity, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, Infinity, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, Infinity, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, Infinity, Infinity, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, Infinity, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, Infinity, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, Infinity, Infinity, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, Infinity, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, Infinity, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, Infinity, Infinity, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, Infinity, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, Infinity, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, Infinity, 0, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, 0, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, 0, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, Infinity, 0, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, 0, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, 0, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, Infinity, 0, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, 0, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, Infinity, 0, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, 1, Infinity, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, Infinity, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, Infinity, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, 1, Infinity, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, Infinity, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, Infinity, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, 1, Infinity, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, Infinity, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, Infinity, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, 1, Infinity, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, Infinity, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, Infinity, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, 1, 0, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, 0, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, 0, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, 1, 0, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, 0, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, 0, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, Infinity, 1, 0, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, 0, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, Infinity, 1, 0, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, 0, Infinity, Infinity, 0, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, Infinity, 0, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, Infinity, 0, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, Infinity, Infinity, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, Infinity, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, Infinity, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, Infinity, Infinity, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, Infinity, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, Infinity, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, 0, Infinity, Infinity, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, Infinity, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, Infinity, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, 0, Infinity, 0, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, 0, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, 0, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, Infinity, 0, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, 0, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, 0, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, 0, Infinity, 0, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, 0, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, Infinity, 0, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, Infinity, Infinity, 1); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, Infinity, Infinity, 1)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, Infinity, Infinity, 1)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, Infinity, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, Infinity, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, Infinity, Infinity, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, Infinity, 0, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, Infinity, 0, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, Infinity, 0, Infinity)"); } + try { err = false; ctx.createRadialGradient(0, 0, 1, 0, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, Infinity, Infinity)"); } + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createRadialGradient(0, 0, 1, 0, Infinity, Infinity)"); } ctx.reset(); @@ -792,73 +792,73 @@ CanvasTestCase { ctx.reset(); try { var err = false; ctx.createLinearGradient(Infinity, 0, 1, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, 0, 1, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, 0, 1, 0)"); } + try { err = false; ctx.createLinearGradient(-Infinity, 0, 1, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(-Infinity, 0, 1, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(-Infinity, 0, 1, 0)"); } + try { err = false; ctx.createLinearGradient(NaN, 0, 1, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(NaN, 0, 1, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(NaN, 0, 1, 0)"); } + try { err = false; ctx.createLinearGradient(0, Infinity, 1, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, Infinity, 1, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, Infinity, 1, 0)"); } + try { err = false; ctx.createLinearGradient(0, -Infinity, 1, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, -Infinity, 1, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, -Infinity, 1, 0)"); } + try { err = false; ctx.createLinearGradient(0, NaN, 1, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, NaN, 1, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, NaN, 1, 0)"); } + try { err = false; ctx.createLinearGradient(0, 0, Infinity, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, Infinity, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, Infinity, 0)"); } + try { err = false; ctx.createLinearGradient(0, 0, -Infinity, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, -Infinity, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, -Infinity, 0)"); } + try { err = false; ctx.createLinearGradient(0, 0, NaN, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, NaN, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, NaN, 0)"); } + try { err = false; ctx.createLinearGradient(0, 0, 1, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, 1, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, 1, Infinity)"); } + try { err = false; ctx.createLinearGradient(0, 0, 1, -Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, 1, -Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, 1, -Infinity)"); } + try { err = false; ctx.createLinearGradient(0, 0, 1, NaN); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, 1, NaN)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, 1, NaN)"); } + try { err = false; ctx.createLinearGradient(Infinity, Infinity, 1, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, Infinity, 1, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, Infinity, 1, 0)"); } + try { err = false; ctx.createLinearGradient(Infinity, Infinity, Infinity, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, Infinity, Infinity, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, Infinity, Infinity, 0)"); } + try { err = false; ctx.createLinearGradient(Infinity, Infinity, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, Infinity, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, Infinity, Infinity, Infinity)"); } + try { err = false; ctx.createLinearGradient(Infinity, Infinity, 1, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, Infinity, 1, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, Infinity, 1, Infinity)"); } + try { err = false; ctx.createLinearGradient(Infinity, 0, Infinity, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, 0, Infinity, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, 0, Infinity, 0)"); } + try { err = false; ctx.createLinearGradient(Infinity, 0, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, 0, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, 0, Infinity, Infinity)"); } + try { err = false; ctx.createLinearGradient(Infinity, 0, 1, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, 0, 1, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(Infinity, 0, 1, Infinity)"); } + try { err = false; ctx.createLinearGradient(0, Infinity, Infinity, 0); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, Infinity, Infinity, 0)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, Infinity, Infinity, 0)"); } + try { err = false; ctx.createLinearGradient(0, Infinity, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, Infinity, Infinity, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, Infinity, Infinity, Infinity)"); } + try { err = false; ctx.createLinearGradient(0, Infinity, 1, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, Infinity, 1, Infinity)"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, Infinity, 1, Infinity)"); } + try { err = false; ctx.createLinearGradient(0, 0, Infinity, Infinity); - } catch (e) { if (e.code != DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, Infinity, Infinity)"); } + } catch (e) { if (e.code !== DOMException.NOT_SUPPORTED_ERR) fail("Failed assertion: expected exception of type NOT_SUPPORTED_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type NOT_SUPPORTED_ERR: ctx.createLinearGradient(0, 0, Infinity, Infinity)"); } ctx.reset(); var g = ctx.createLinearGradient(0, 0, 200, 0); @@ -918,29 +918,29 @@ CanvasTestCase { var g = ctx.createLinearGradient(0, 0, 100, 0); try { var err = false; g.addColorStop(0, ""); - } catch (e) { if (e.code != DOMException.SYNTAX_ERR) fail("Failed assertion: expected exception of type SYNTAX_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type SYNTAX_ERR: g.addColorStop(0, \"\")"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.SYNTAX_ERR) fail("Failed assertion: expected exception of type SYNTAX_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type SYNTAX_ERR: g.addColorStop(0, \"\")"); } + try { err = false; g.addColorStop(0, 'undefined'); - } catch (e) { if (e.code != DOMException.SYNTAX_ERR) fail("Failed assertion: expected exception of type SYNTAX_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type SYNTAX_ERR: g.addColorStop(0, 'undefined')"); } + } catch (e) { if (e.code !== DOMException.SYNTAX_ERR) fail("Failed assertion: expected exception of type SYNTAX_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type SYNTAX_ERR: g.addColorStop(0, 'undefined')"); } ctx.reset(); g = ctx.createLinearGradient(0, 0, 100, 0); - try { var err = false; + try { err = false; g.addColorStop(-1, '#000'); - } catch (e) { if (e.code != DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: g.addColorStop(-1, '#000')"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: g.addColorStop(-1, '#000')"); } + try { err = false; g.addColorStop(2, '#000'); - } catch (e) { if (e.code != DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: g.addColorStop(2, '#000')"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: g.addColorStop(2, '#000')"); } + try { err = false; g.addColorStop(Infinity, '#000'); - } catch (e) { if (e.code != DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: g.addColorStop(Infinity, '#000')"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: g.addColorStop(Infinity, '#000')"); } + try { err = false; g.addColorStop(-Infinity, '#000'); - } catch (e) { if (e.code != DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: g.addColorStop(-Infinity, '#000')"); } - try { var err = false; + } catch (e) { if (e.code !== DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: g.addColorStop(-Infinity, '#000')"); } + try { err = false; g.addColorStop(NaN, '#000'); - } catch (e) { if (e.code != DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: g.addColorStop(NaN, '#000')"); } + } catch (e) { if (e.code !== DOMException.INDEX_SIZE_ERR) fail("Failed assertion: expected exception of type INDEX_SIZE_ERR, got: "+e.message); err = true; } finally { verify(err, "should throw exception of type INDEX_SIZE_ERR: g.addColorStop(NaN, '#000')"); } ctx.reset(); diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml b/tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml index 7095602ea2..76b99a765e 100644 --- a/tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml +++ b/tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml @@ -6,6 +6,10 @@ CanvasTestCase { name: "imagedata" function init_data() { return testData("2d"); } function test_rounding(row) { + if ((Qt.platform.pluginName === "offscreen") + || (Qt.platform.pluginName === "minimal")) + skip("ctx.getImageData crashes on offscreen/minimal platforms"); + var canvas = createCanvasObject(row); var ctx = canvas.getContext('2d'); var size = 17 diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_invalidContext.qml b/tests/auto/quick/qquickcanvasitem/data/tst_invalidContext.qml new file mode 100644 index 0000000000..dd14aef433 --- /dev/null +++ b/tests/auto/quick/qquickcanvasitem/data/tst_invalidContext.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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.4 +import QtTest 1.1 + +Item { + id: root + width: 500 + height: 500 + + Timer { + id: timer + interval: 1 + running: true + repeat: true + onTriggered: { + if (myCanvas.parent == root) { + myCanvas.parent = null + } else { + myCanvas.parent = root + } + } + } + + Canvas { + id: myCanvas + anchors.fill: parent + property var paintContext: null + + function paint() { + paintContext.fillStyle = Qt.rgba(1, 0, 0, 1); + paintContext.fillRect(0, 0, width, height); + requestAnimationFrame(paint); + } + + onAvailableChanged: { + if (available) { + paintContext = getContext("2d") + requestAnimationFrame(paint); + } + } + } + + TestCase { + name: "invalidContext" + when: myCanvas.parent === null && myCanvas.paintContext !== null + + function test_paintContextInvalid() { + verify(myCanvas.paintContext); + var caught = false; + try { + console.log(myCanvas.paintContext.fillStyle); + } catch(e) { + caught = true; + } + verify(caught); + timer.running = false + } + } +} 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/qquickcanvasitem/data/tst_strokeStyle.qml b/tests/auto/quick/qquickcanvasitem/data/tst_strokeStyle.qml index 22803a19ce..a3f1ab0a9b 100644 --- a/tests/auto/quick/qquickcanvasitem/data/tst_strokeStyle.qml +++ b/tests/auto/quick/qquickcanvasitem/data/tst_strokeStyle.qml @@ -3,6 +3,8 @@ import QtQuick 2.0 CanvasTestCase { id:testCase name: "strokeStyle" + property color anotherColor: "#0000ff" + property color emptyColor function init_data() { return testData("2d"); } function test_default(row) { var canvas = createCanvasObject(row); @@ -46,4 +48,37 @@ CanvasTestCase { comparePixel(ctx,0,0,255,255,255,255); canvas.destroy() } + function test_colorFromObjectToString(row) { + var canvas = createCanvasObject(row); + var ctx = canvas.getContext('2d'); + + ctx.reset(); + ctx.strokeStyle = anotherColor + ctx.strokeStyle = "red"; + compare(ctx.strokeStyle, "#ff0000"); + + ctx.strokeStyle = anotherColor + ctx.strokeStyle = "black"; + compare(ctx.strokeStyle, "#000000"); + + ctx.strokeStyle = "white"; + ctx.strokeStyle = anotherColor + compare(ctx.strokeStyle, "#0000ff"); + canvas.destroy() + } + function test_withInvalidColor(row) { + var canvas = createCanvasObject(row); + var ctx = canvas.getContext('2d'); + + ctx.reset(); + ctx.strokeStyle = emptyColor + compare(ctx.strokeStyle, "#000000"); + ctx.strokeStyle = "red"; + compare(ctx.strokeStyle, "#ff0000"); + ctx.strokeStyle = emptyColor + compare(ctx.strokeStyle, "#000000"); + ctx.strokeStyle = anotherColor; + compare(ctx.strokeStyle, "#0000ff"); + canvas.destroy() + } } diff --git a/tests/auto/quick/qquickcanvasitem/qquickcanvasitem.pro b/tests/auto/quick/qquickcanvasitem/qquickcanvasitem.pro index c6d2a69f8c..70e5a05f8d 100644 --- a/tests/auto/quick/qquickcanvasitem/qquickcanvasitem.pro +++ b/tests/auto/quick/qquickcanvasitem/qquickcanvasitem.pro @@ -5,6 +5,8 @@ TARGET=tst_qquickcanvasitem CONFIG += qmltestcase SOURCES += tst_qquickcanvasitem.cpp +exists($$[QT_INSTALL_PLUGINS]/imageformats): DEFINES += HAS_IMAGE_FORMATS + TESTDATA = data/* OTHER_FILES += \ @@ -50,7 +52,8 @@ OTHER_FILES += \ data/transparent.png \ data/transparent50.png \ data/yellow.png \ - data/yellow75.png + data/yellow75.png \ + data/tst_invalidContext.qml CONFIG += insignificant_test # QTBUG-41043 diff --git a/tests/auto/quick/qquickcanvasitem/tst_qquickcanvasitem.cpp b/tests/auto/quick/qquickcanvasitem/tst_qquickcanvasitem.cpp index bde2b4809b..dad8df0682 100644 --- a/tests/auto/quick/qquickcanvasitem/tst_qquickcanvasitem.cpp +++ b/tests/auto/quick/qquickcanvasitem/tst_qquickcanvasitem.cpp @@ -26,4 +26,29 @@ ** ****************************************************************************/ #include <QtQuickTest/quicktest.h> -QUICK_TEST_MAIN(qquickcanvasitem) +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlcontext.h> + +class Setup : public QObject +{ + Q_OBJECT + +public: + Setup() {} + +public slots: + void qmlEngineAvailable(QQmlEngine *engine) + { + engine->rootContext()->setContextProperty("hasImageFormats", QVariant( +#ifdef HAS_IMAGE_FORMATS + true +#else + false +#endif + )); + } +}; + +QUICK_TEST_MAIN_WITH_SETUP(qquickcanvasitem, Setup) + +#include "tst_qquickcanvasitem.moc" diff --git a/tests/auto/quick/qquickdesignersupport/data/Component01.qml b/tests/auto/quick/qquickdesignersupport/data/Component01.qml new file mode 100644 index 0000000000..463417445c --- /dev/null +++ b/tests/auto/quick/qquickdesignersupport/data/Component01.qml @@ -0,0 +1,51 @@ +import QtQuick 2.9 +import QtQuick.Window 2.3 + +Item { + visible: true + width: 640 + height: 480 + objectName: "componentRoot" + + Rectangle { + objectName: "topLevelComplete" + id: rectangle + x: 378 + y: 91 + width: 100 + height: 100 + color: "#ffffff" + } + + Item { + id: element + x: 14 + y: 39 + width: 120 + height: 120 + + Rectangle { + id: rectangle1 + objectName: "implemented" + x: 43 + y: 52 + width: 110 + height: 110 + color: "#ffffff" + + Component.onCompleted: { + rectangle1.color = "blue" + } + } + } + + Component02 { + id: element1 + x: 88 + y: 251 + } + + Component.onCompleted: { + rectangle.color = "red" + } +} diff --git a/tests/auto/quick/qquickdesignersupport/data/Component02.qml b/tests/auto/quick/qquickdesignersupport/data/Component02.qml new file mode 100644 index 0000000000..7bbad0c917 --- /dev/null +++ b/tests/auto/quick/qquickdesignersupport/data/Component02.qml @@ -0,0 +1,24 @@ +import QtQuick 2.9 +import QtQuick.Window 2.3 + +Item { + id: element1 + width: 200 + height: 200 + objectName: "inner" + + + Rectangle { + id: rectangle2 + objectName: "most inner" + x: 59 + y: 51 + width: 200 + height: 200 + color: "#ffffff" + } + + Component.onCompleted: { + rectangle2.color = "green" + } +} 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/componentTest.qml b/tests/auto/quick/qquickdesignersupport/data/componentTest.qml new file mode 100644 index 0000000000..a30cfafc90 --- /dev/null +++ b/tests/auto/quick/qquickdesignersupport/data/componentTest.qml @@ -0,0 +1,33 @@ +import QtQuick 2.9 +import QtQuick.Window 2.3 + +Item { + visible: true + width: 640 + height: 480 + + Component01 { + id: rectangle + x: 205 + y: 70 + width: 251 + height: 242 + } + + Item { + id: element + x: 14 + y: 39 + width: 285 + height: 304 + + Rectangle { + id: rectangle1 + x: 43 + y: 52 + width: 200 + height: 200 + color: "#ffffff" + } + } +} 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/qquickdesignersupport.pro b/tests/auto/quick/qquickdesignersupport/qquickdesignersupport.pro index 6e1ad6b95e..6212a996f1 100644 --- a/tests/auto/quick/qquickdesignersupport/qquickdesignersupport.pro +++ b/tests/auto/quick/qquickdesignersupport/qquickdesignersupport.pro @@ -12,4 +12,8 @@ TESTDATA = data/* QT += core-private gui-private qml-private quick-private testlib DISTFILES += \ - data/TestComponent.qml + data/TestComponent.qml \ + data/test.qml \ + data/componentTest.qml \ + data/Component01.qml \ + data/Component02.qml diff --git a/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp b/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp index 9463f7b4d5..b44977bd5a 100644 --- a/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp +++ b/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp @@ -61,6 +61,7 @@ private slots: void statesPropertyChanges(); void testNotifyPropertyChangeCallBack(); void testFixResourcePathsForObjectCallBack(); + void testComponentOnCompleteSignal(); }; void tst_qquickdesignersupport::customData() @@ -102,7 +103,7 @@ void tst_qquickdesignersupport::customData() QVERIFY(QQuickDesignerSupportProperties::hasBindingForProperty(newItem, view->engine()->contextForObject(newItem), "width", - 0)); + nullptr)); //Check if reseting property does work after setting binding QQuickDesignerSupportProperties::doResetProperty(newItem, view->rootContext(), "width"); @@ -136,7 +137,7 @@ void tst_qquickdesignersupport::customDataBindings() QVERIFY(QQuickDesignerSupportProperties::hasBindingForProperty(testComponent, view->engine()->contextForObject(testComponent), "x", - 0)); + nullptr)); QCOMPARE(testComponent->property("x").toInt(), 200); @@ -149,7 +150,7 @@ void tst_qquickdesignersupport::customDataBindings() QVERIFY(!QQuickDesignerSupportProperties::hasBindingForProperty(testComponent, view->engine()->contextForObject(testComponent), "x", - 0)); + nullptr)); //Reset the binding to the default QQuickDesignerSupportProperties::doResetProperty(testComponent, @@ -159,7 +160,7 @@ void tst_qquickdesignersupport::customDataBindings() QVERIFY(QQuickDesignerSupportProperties::hasBindingForProperty(testComponent, view->engine()->contextForObject(testComponent), "x", - 0)); + nullptr)); QCOMPARE(testComponent->property("x").toInt(), 200); @@ -173,7 +174,7 @@ void tst_qquickdesignersupport::customDataBindings() QVERIFY(QQuickDesignerSupportProperties::hasBindingForProperty(testComponent, view->engine()->contextForObject(testComponent), "x", - 0)); + nullptr)); QCOMPARE(testComponent->property("x").toInt(), 300); @@ -188,7 +189,7 @@ void tst_qquickdesignersupport::customDataBindings() QVERIFY(QQuickDesignerSupportProperties::hasBindingForProperty(testComponent, view->engine()->contextForObject(testComponent), "x", - 0)); + nullptr)); QCOMPARE(testComponent->property("x").toInt(), 200); } @@ -209,15 +210,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 @@ -417,7 +418,7 @@ void tst_qquickdesignersupport::statesPropertyChanges() } -static QObject * s_object = 0; +static QObject * s_object = nullptr; static QQuickDesignerSupport::PropertyName s_propertyName; static void notifyPropertyChangeCallBackFunction(QObject *object, const QQuickDesignerSupport::PropertyName &propertyName) @@ -450,7 +451,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); @@ -476,7 +477,7 @@ void tst_qquickdesignersupport::testFixResourcePathsForObjectCallBack() QVERIFY(rootItem); - s_object = 0; + s_object = nullptr; QQuickDesignerSupportItems::registerFixResourcePathsForObjectCallBack(fixResourcePathsForObjectCallBackPointer); @@ -490,6 +491,101 @@ void tst_qquickdesignersupport::testFixResourcePathsForObjectCallBack() QCOMPARE(simpleItem , s_object); } +void doComponentCompleteRecursive(QObject *object) +{ + if (object) { + QQuickItem *item = qobject_cast<QQuickItem*>(object); + + if (item && DesignerSupport::isComponentComplete(item)) + return; + + DesignerSupport::emitComponentCompleteSignalForAttachedProperty(object); + + QList<QObject*> childList = object->children(); + + if (item) { + foreach (QQuickItem *childItem, item->childItems()) { + if (!childList.contains(childItem)) + childList.append(childItem); + } + } + + foreach (QObject *child, childList) + doComponentCompleteRecursive(child); + + if (item) { + static_cast<QQmlParserStatus*>(item)->componentComplete(); + } else { + QQmlParserStatus *qmlParserStatus = dynamic_cast< QQmlParserStatus*>(object); + if (qmlParserStatus) + qmlParserStatus->componentComplete(); + } + } +} + +void tst_qquickdesignersupport::testComponentOnCompleteSignal() +{ + { + QScopedPointer<QQuickView> view(new QQuickView); + view->engine()->setOutputWarningsToStandardError(false); + view->setSource(testFileUrl("componentTest.qml")); + + QVERIFY(view->errors().isEmpty()); + QQuickItem *rootItem = view->rootObject(); + QVERIFY(rootItem); + + QQuickItem *item = findItem<QQuickItem>(view->rootObject(), QLatin1String("topLevelComplete")); + QVERIFY(item); + QCOMPARE(item->property("color").value<QColor>(), QColor("red")); + + item = findItem<QQuickItem>(view->rootObject(), QLatin1String("implemented")); + QVERIFY(item); + QCOMPARE(item->property("color").value<QColor>(), QColor("blue")); + + item = findItem<QQuickItem>(view->rootObject(), QLatin1String("most inner")); + QVERIFY(item); + QCOMPARE(item->property("color").value<QColor>(), QColor("green")); + } + + { + ComponentCompleteDisabler disableComponentComplete; + + QScopedPointer<QQuickView> view(new QQuickView); + view->engine()->setOutputWarningsToStandardError(false); + view->setSource(testFileUrl("componentTest.qml")); + + QVERIFY(view->errors().isEmpty()); + QQuickItem *rootItem = view->rootObject(); + QVERIFY(rootItem); + + QQuickItem *item = findItem<QQuickItem>(view->rootObject(), QLatin1String("topLevelComplete")); + QVERIFY(item); + QCOMPARE(item->property("color").value<QColor>(), QColor("white")); + + item = findItem<QQuickItem>(view->rootObject(), QLatin1String("implemented")); + QVERIFY(item); + QCOMPARE(item->property("color").value<QColor>(), QColor("white")); + + item = findItem<QQuickItem>(view->rootObject(), QLatin1String("most inner")); + QVERIFY(item); + QCOMPARE(item->property("color").value<QColor>(), QColor("white")); + + doComponentCompleteRecursive(rootItem); + + item = findItem<QQuickItem>(view->rootObject(), QLatin1String("topLevelComplete")); + QVERIFY(item); + QCOMPARE(item->property("color").value<QColor>(), QColor("red")); + + item = findItem<QQuickItem>(view->rootObject(), QLatin1String("implemented")); + QVERIFY(item); + QCOMPARE(item->property("color").value<QColor>(), QColor("blue")); + + item = findItem<QQuickItem>(view->rootObject(), QLatin1String("most inner")); + QVERIFY(item); + QCOMPARE(item->property("color").value<QColor>(), QColor("green")); + } +} + QTEST_MAIN(tst_qquickdesignersupport) diff --git a/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp b/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp index 6a919d048e..9d832066af 100644 --- a/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp +++ b/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp @@ -57,16 +57,8 @@ class TestDropTarget : public QQuickItem { Q_OBJECT public: - TestDropTarget(QQuickItem *parent = 0) + TestDropTarget(QQuickItem *parent = nullptr) : QQuickItem(parent) - , enterEvents(0) - , moveEvents(0) - , leaveEvents(0) - , dropEvents(0) - , acceptAction(Qt::MoveAction) - , defaultAction(Qt::IgnoreAction) - , proposedAction(Qt::IgnoreAction) - , accept(true) { setFlags(ItemAcceptsDrops); } @@ -119,16 +111,16 @@ public: event->setAccepted(accept); } - int enterEvents; - int moveEvents; - int leaveEvents; - int dropEvents; - Qt::DropAction acceptAction; - Qt::DropAction defaultAction; - Qt::DropAction proposedAction; + int enterEvents = 0; + int moveEvents = 0; + int leaveEvents = 0; + int dropEvents = 0; + Qt::DropAction acceptAction = Qt::MoveAction; + Qt::DropAction defaultAction = Qt::IgnoreAction; + Qt::DropAction proposedAction = Qt::IgnoreAction; Qt::DropActions supportedActions; QPointF position; - bool accept; + bool accept = true; }; class tst_QQuickDrag: public QObject @@ -199,16 +191,16 @@ void tst_QQuickDrag::active() evaluate<void>(item, "Drag.active = false"); QCOMPARE(evaluate<bool>(item, "Drag.active"), false); QCOMPARE(evaluate<bool>(item, "dragActive"), false); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); dropTarget.reset(); evaluate<void>(item, "Drag.cancel()"); QCOMPARE(evaluate<bool>(item, "Drag.active"), false); QCOMPARE(evaluate<bool>(item, "dragActive"), false); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); dropTarget.reset(); @@ -232,8 +224,8 @@ void tst_QQuickDrag::active() evaluate<void>(item, "Drag.cancel()"); QCOMPARE(evaluate<bool>(item, "Drag.active"), false); QCOMPARE(evaluate<bool>(item, "dragActive"), false); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); // Enter events aren't sent to items without the QQuickItem::ItemAcceptsDrops flag. @@ -243,16 +235,16 @@ void tst_QQuickDrag::active() evaluate<void>(item, "Drag.active = true"); QCOMPARE(evaluate<bool>(item, "Drag.active"), true); QCOMPARE(evaluate<bool>(item, "dragActive"), true); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); dropTarget.reset(); evaluate<void>(item, "Drag.active = false"); QCOMPARE(evaluate<bool>(item, "Drag.active"), false); QCOMPARE(evaluate<bool>(item, "dragActive"), false); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); dropTarget.setFlags(QQuickItem::ItemAcceptsDrops); @@ -271,8 +263,8 @@ void tst_QQuickDrag::active() evaluate<void>(item, "Drag.active = false"); QCOMPARE(evaluate<bool>(item, "Drag.active"), false); QCOMPARE(evaluate<bool>(item, "dragActive"), false); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); // Follow up events aren't sent to items if the enter event isn't accepted. @@ -283,16 +275,16 @@ void tst_QQuickDrag::active() evaluate<void>(item, "Drag.active = true"); QCOMPARE(evaluate<bool>(item, "Drag.active"), true); QCOMPARE(evaluate<bool>(item, "dragActive"), true); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); dropTarget.reset(); evaluate<void>(item, "Drag.active = false"); QCOMPARE(evaluate<bool>(item, "Drag.active"), false); QCOMPARE(evaluate<bool>(item, "dragActive"), false); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); dropTarget.accept = true; @@ -311,8 +303,8 @@ void tst_QQuickDrag::active() evaluate<void>(item, "Drag.active = false"); QCOMPARE(evaluate<bool>(item, "Drag.active"), false); QCOMPARE(evaluate<bool>(item, "dragActive"), false); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); // Events are sent to hidden or disabled items. @@ -322,8 +314,8 @@ void tst_QQuickDrag::active() evaluate<void>(item, "Drag.active = true"); QCOMPARE(evaluate<bool>(item, "Drag.active"), true); QCOMPARE(evaluate<bool>(item, "dragActive"), true); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); evaluate<void>(item, "Drag.active = false"); @@ -346,8 +338,8 @@ void tst_QQuickDrag::active() evaluate<void>(item, "Drag.active = true"); QCOMPARE(evaluate<bool>(item, "Drag.active"), true); QCOMPARE(evaluate<bool>(item, "dragActive"), true); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); evaluate<void>(item, "Drag.active = false"); @@ -510,8 +502,8 @@ void tst_QQuickDrag::drop() QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.IgnoreAction"), true); QCOMPARE(evaluate<bool>(item, "Drag.active"), false); QCOMPARE(evaluate<bool>(item, "dragActive"), false); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1); QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); @@ -522,8 +514,8 @@ void tst_QQuickDrag::drop() QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.IgnoreAction"), true); QCOMPARE(evaluate<bool>(item, "Drag.active"), false); QCOMPARE(evaluate<bool>(item, "dragActive"), false); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); @@ -638,8 +630,8 @@ void tst_QQuickDrag::move() outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); item->setPosition(QPointF(110, 50)); QCoreApplication::processEvents(); - QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(nullptr)); QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 1); QCOMPARE(outerTarget.moveEvents, 0); QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 1); QCOMPARE(leftTarget .moveEvents, 0); QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); @@ -751,7 +743,7 @@ void tst_QQuickDrag::parentChange() QCOMPARE(dropTarget2.enterEvents, 1); // Removing then parent item sends a leave event. - item->setParentItem(0); + item->setParentItem(nullptr); QCOMPARE(dropTarget1.enterEvents, 1); QCOMPARE(dropTarget1.moveEvents, 1); QCOMPARE(dropTarget1.leaveEvents, 1); @@ -775,7 +767,7 @@ void tst_QQuickDrag::parentChange() item->setParentItem(window2.contentItem()); QCoreApplication::processEvents(); - item->setParentItem(0); + item->setParentItem(nullptr); QCoreApplication::processEvents(); QCOMPARE(dropTarget1.enterEvents, 1); QCOMPARE(dropTarget1.moveEvents, 1); @@ -1046,7 +1038,7 @@ class RecursingDropTarget : public TestDropTarget { public: RecursingDropTarget(const QString &script, int type, QQuickItem *parent) - : TestDropTarget(parent), script(script), type(type), item(0) {} + : TestDropTarget(parent), script(script), type(type), item(nullptr) {} void setItem(QQuickItem *i) { item = i; } diff --git a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp index fedca98205..cf01cc927b 100644 --- a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp +++ b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp @@ -185,14 +185,19 @@ void tst_QQuickDropArea::containsDrag_external() QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + const qreal dpr = window.devicePixelRatio(); + const QPoint nativePos1 = QPoint(50, 50) * dpr; + const QPoint nativePos2 = QPoint(150, 50) * dpr; + QWindowSystemInterface::handleDrag(&window, &data, nativePos1, Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), true); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 0); evaluate<void>(dropArea, "{ enterEvents = 0; exitEvents = 0 }"); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, nativePos1, Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); @@ -200,13 +205,15 @@ void tst_QQuickDropArea::containsDrag_external() evaluate<void>(dropArea, "{ enterEvents = 0; exitEvents = 0 }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(150, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, nativePos2, Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 0); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, nativePos1, Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), true); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); @@ -214,13 +221,15 @@ void tst_QQuickDropArea::containsDrag_external() evaluate<void>(dropArea, "{ enterEvents = 0; exitEvents = 0 }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(150, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, nativePos2, Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); QCOMPARE(evaluate<bool>(dropArea, "hasDrag"), false); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 1); - QWindowSystemInterface::handleDrop(&window, &data, QPoint(150, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrop(&window, &data, nativePos2, Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); } void tst_QQuickDropArea::keys_internal() @@ -355,80 +364,96 @@ void tst_QQuickDropArea::keys_external() QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "text/x-red" << "text/x-blue"); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); evaluate<void>(dropArea, "keys = \"text/x-blue\""); QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "text/x-blue"); QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "text/x-blue"); evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "text/x-red" << "text/x-blue"); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); evaluate<void>(dropArea, "keys = \"text/x-red\""); QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "text/x-red"); QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "text/x-red"); evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "text/x-red" << "text/x-blue"); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); evaluate<void>(dropArea, "keys = \"text/x-green\""); QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "text/x-green"); QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "text/x-green"); evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); evaluate<void>(dropArea, "keys = [\"text/x-red\", \"text/x-green\"]"); QCOMPARE(dropArea->property("keys").toStringList(), QStringList() << "text/x-red" << "text/x-green"); QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList() << "text/x-red" << "text/x-green"); evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "text/x-red" << "text/x-blue"); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); data.removeFormat("text/x-red"); data.removeFormat("text/x-blue"); evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); evaluate<void>(dropArea, "keys = []"); QCOMPARE(dropArea->property("keys").toStringList(), QStringList()); QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList()); evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList()); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); data.setData("text/x-red", "red"); data.setData("text/x-blue", "blue"); QCOMPARE(dropArea->property("keys").toStringList(), QStringList()); QCOMPARE(dropArea->property("dropKeys").toStringList(), QStringList()); evaluate<void>(dropArea, "{ enterEvents = 0; dragKeys = undefined }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); QCOMPARE(dropArea->property("dragKeys").toStringList(), QStringList() << "text/x-red" << "text/x-blue"); - QWindowSystemInterface::handleDrop(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrop(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); } void tst_QQuickDropArea::source_internal() @@ -460,8 +485,8 @@ void tst_QQuickDropArea::source_internal() QQuickItem *dragSource = dropArea->findChild<QQuickItem *>("dragSource"); QVERIFY(dragSource); - QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(dropArea, "drag.source"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(dropArea, "drag.source"), static_cast<QObject *>(nullptr)); evaluate<void>(dragItem, "Drag.active = true"); QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(dragItem)); @@ -469,8 +494,8 @@ void tst_QQuickDropArea::source_internal() QCOMPARE(evaluate<QObject *>(dropArea, "eventSource"), static_cast<QObject *>(dragItem)); evaluate<void>(dragItem, "Drag.active = false"); - QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(dropArea, "drag.source"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(dropArea, "drag.source"), static_cast<QObject *>(nullptr)); evaluate<void>(dropArea, "{ eventSource = null }"); @@ -482,8 +507,8 @@ void tst_QQuickDropArea::source_internal() QCOMPARE(evaluate<QObject *>(dropArea, "eventSource"), static_cast<QObject *>(dragSource)); evaluate<void>(dragItem, "Drag.active = false"); - QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(0)); - QCOMPARE(evaluate<QObject *>(dropArea, "drag.source"), static_cast<QObject *>(0)); + QCOMPARE(evaluate<QObject *>(dropArea, "source"), static_cast<QObject *>(nullptr)); + QCOMPARE(evaluate<QObject *>(dropArea, "drag.source"), static_cast<QObject *>(nullptr)); } // Setting a source can't be emulated using the QWindowSystemInterface API. @@ -583,7 +608,9 @@ void tst_QQuickDropArea::position_external() QMimeData data; - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + const qreal dpr = window.devicePixelRatio(); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50) * dpr, Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1); QCOMPARE(evaluate<int>(dropArea, "moveEvents"), 1); QCOMPARE(evaluate<qreal>(dropArea, "drag.x"), qreal(50)); @@ -594,7 +621,8 @@ void tst_QQuickDropArea::position_external() QCOMPARE(evaluate<qreal>(dropArea, "eventY"), qreal(50)); evaluate<void>(dropArea, "{ enterEvents = 0; moveEvents = 0; eventX = -1; eventY = -1 }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(40, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(40, 50) * dpr, Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea, "moveEvents"), 1); QCOMPARE(evaluate<qreal>(dropArea, "drag.x"), qreal(40)); @@ -605,7 +633,8 @@ void tst_QQuickDropArea::position_external() QCOMPARE(evaluate<qreal>(dropArea, "eventY"), qreal(50)); evaluate<void>(dropArea, "{ enterEvents = 0; moveEvents = 0; eventX = -1; eventY = -1 }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(75, 25), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(75, 25) * dpr, Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea, "moveEvents"), 1); QCOMPARE(evaluate<qreal>(dropArea, "drag.x"), qreal(75)); @@ -615,7 +644,8 @@ void tst_QQuickDropArea::position_external() QCOMPARE(evaluate<qreal>(dropArea, "eventX"), qreal(75)); QCOMPARE(evaluate<qreal>(dropArea, "eventY"), qreal(25)); - QWindowSystemInterface::handleDrop(&window, &data, QPoint(75, 25), Qt::CopyAction); + QWindowSystemInterface::handleDrop(&window, &data, QPoint(75, 25) * dpr, Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); } void tst_QQuickDropArea::drop_internal() @@ -926,7 +956,8 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); //Same as in the first case, dropArea2 already contains a drag, dropArea1 will get the event QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); @@ -935,7 +966,8 @@ void tst_QQuickDropArea::simultaneousDrags() QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); @@ -943,7 +975,8 @@ void tst_QQuickDropArea::simultaneousDrags() QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); @@ -961,7 +994,8 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); @@ -972,7 +1006,8 @@ void tst_QQuickDropArea::simultaneousDrags() // external then internal. evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); @@ -1006,7 +1041,8 @@ void tst_QQuickDropArea::simultaneousDrags() QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1); @@ -1102,7 +1138,8 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); @@ -1112,7 +1149,8 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); @@ -1122,7 +1160,8 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); @@ -1142,7 +1181,8 @@ void tst_QQuickDropArea::simultaneousDrags() evaluate<void>(dropArea1, "{ enterEvents = 0; exitEvents = 0 }"); evaluate<void>(dropArea2, "{ enterEvents = 0; exitEvents = 0 }"); - QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false); QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0); @@ -1150,7 +1190,8 @@ void tst_QQuickDropArea::simultaneousDrags() QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0); QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 1); - QWindowSystemInterface::handleDrop(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrop(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); } void tst_QQuickDropArea::dropStuff() @@ -1175,8 +1216,10 @@ void tst_QQuickDropArea::dropStuff() QCOMPARE(evaluate<QVariant>(dropArea, "array"), QVariant()); - QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction); - QWindowSystemInterface::handleDrop(&window, &data, QPoint(50, 50), Qt::CopyAction); + QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); + QWindowSystemInterface::handleDrop(&window, &data, QPoint(50, 50), Qt::CopyAction, + Qt::MouseButtons(), Qt::KeyboardModifiers()); QCOMPARE(evaluate<int>(dropArea, "array.byteLength"), 3); QCOMPARE(evaluate<QByteArray>(dropArea, "array"), QByteArray("red")); } diff --git a/tests/auto/quick/qquickflickable/BLACKLIST b/tests/auto/quick/qquickflickable/BLACKLIST deleted file mode 100644 index f35397f119..0000000000 --- a/tests/auto/quick/qquickflickable/BLACKLIST +++ /dev/null @@ -1,21 +0,0 @@ -# QTBUG-36804 -osx-10.10 -[rebound] -osx-10.10 -[movingAndFlicking:vertical] -osx-10.10 -[movingAndFlicking:both] -osx-10.10 -[movingAndFlicking:horizontal] -osx-10.10 -[stopAtBounds] -osx-10.10 -windows developer-build -[returnToBounds] -osx -[pressWhileFlicking] -osx-10.10 -[flickVelocity] -osx-10.10 -[nestedSliderUsingTouch:keepNeither] -ubuntu-16.04 diff --git a/tests/auto/quick/qquickflickable/data/nestedStopAtBounds.qml b/tests/auto/quick/qquickflickable/data/nestedStopAtBounds.qml index 81187f3c2f..902920babc 100644 --- a/tests/auto/quick/qquickflickable/data/nestedStopAtBounds.qml +++ b/tests/auto/quick/qquickflickable/data/nestedStopAtBounds.qml @@ -18,6 +18,8 @@ Flickable { height: 300 color: "yellow" + objectName: "yellowRect" + Flickable { id: inner objectName: "innerFlickable" @@ -30,6 +32,7 @@ Flickable { Rectangle { anchors.fill: parent anchors.margins: 100 + objectName: "blueRect" color: "blue" } MouseArea { diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index ef6e444580..65a08ce87f 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -38,6 +38,7 @@ #include <private/qqmlvaluetype_p.h> #include <math.h> #include "../../shared/util.h" +#include "../shared/geometrytestutil.h" #include "../shared/viewtestutil.h" #include "../shared/visualtestutil.h" @@ -56,14 +57,20 @@ class TouchDragArea : public QQuickItem Q_PROPERTY(bool keepTouchGrab READ keepTouchGrab WRITE setKeepTouchGrab NOTIFY keepTouchGrabChanged) public: - TouchDragArea(QQuickItem *parent = 0) + TouchDragArea(QQuickItem *parent = nullptr) : QQuickItem(parent) , touchEvents(0) , touchUpdates(0) , touchReleases(0) , ungrabs(0) , m_active(false) - { } + { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + setAcceptTouchEvents(true); +#else + setAcceptedMouseButtons(Qt::LeftButton); // not really, but we want touch events +#endif + } QPointF pos() const { return m_pos; } @@ -196,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); @@ -219,7 +228,7 @@ void tst_qquickflickable::create() QQmlComponent c(&engine, testFileUrl("flickable01.qml")); QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->isAtXBeginning(), true); QCOMPARE(obj->isAtXEnd(), false); QCOMPARE(obj->isAtYBeginning(), true); @@ -244,7 +253,7 @@ void tst_qquickflickable::horizontalViewportSize() QQmlComponent c(&engine, testFileUrl("flickable02.qml")); QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->contentWidth(), 800.); QCOMPARE(obj->contentHeight(), 300.); QCOMPARE(obj->isAtXBeginning(), true); @@ -261,7 +270,7 @@ void tst_qquickflickable::verticalViewportSize() QQmlComponent c(&engine, testFileUrl("flickable03.qml")); QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->contentWidth(), 200.); QCOMPARE(obj->contentHeight(), 6000.); QCOMPARE(obj->isAtXBeginning(), true); @@ -278,7 +287,7 @@ void tst_qquickflickable::visibleAreaRatiosUpdate() QQmlComponent c(&engine, testFileUrl("ratios.qml")); QQuickItem *obj = qobject_cast<QQuickItem*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); // check initial ratio values QCOMPARE(obj->property("heightRatioIs").toDouble(), obj->property("heightRatioShould").toDouble()); QCOMPARE(obj->property("widthRatioIs").toDouble(), obj->property("widthRatioShould").toDouble()); @@ -300,7 +309,7 @@ void tst_qquickflickable::properties() QQmlComponent c(&engine, testFileUrl("flickable04.qml")); QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->isInteractive(), false); QCOMPARE(obj->boundsBehavior(), QQuickFlickable::StopAtBounds); QCOMPARE(obj->pressDelay(), 200); @@ -361,10 +370,10 @@ void tst_qquickflickable::rebound() window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); QQuickTransition *rebound = window->rootObject()->findChild<QQuickTransition*>("rebound"); QVERIFY(rebound); @@ -500,7 +509,7 @@ void tst_qquickflickable::pressDelay() QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); QSignalSpy spy(flickable, SIGNAL(pressDelayChanged())); @@ -528,7 +537,7 @@ void tst_qquickflickable::pressDelay() QCOMPARE(clickedSpy.count(),0); // On release the clicked signal should be emitted - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); QCOMPARE(clickedSpy.count(),1); // Press and release position should match @@ -546,7 +555,7 @@ void tst_qquickflickable::pressDelay() QCOMPARE(clickedSpy.count(),0); // On release the press, release and clicked signal should be emitted - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(180, 180)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(180, 180)); QCOMPARE(clickedSpy.count(),1); // Press and release position should match @@ -567,7 +576,7 @@ void tst_qquickflickable::pressDelay() QTRY_VERIFY(!mouseArea->property("pressed").toBool()); // On release the clicked signal should *not* be emitted - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 190)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 190)); QCOMPARE(clickedSpy.count(),1); } @@ -581,13 +590,13 @@ void tst_qquickflickable::nestedPressDelay() QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(outer != 0); + QVERIFY(outer != nullptr); QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); - QVERIFY(inner != 0); + QVERIFY(inner != nullptr); moveAndPress(window.data(), QPoint(150, 150)); // the MouseArea is not pressed immediately @@ -607,7 +616,7 @@ void tst_qquickflickable::nestedPressDelay() QVERIFY(inner->property("moving").toBool()); QVERIFY(inner->property("dragging").toBool()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); QVERIFY(!inner->property("dragging").toBool()); QTRY_VERIFY(!inner->property("moving").toBool()); @@ -627,7 +636,7 @@ void tst_qquickflickable::nestedPressDelay() QVERIFY(!outer->property("moving").toBool()); QVERIFY(!outer->property("dragging").toBool()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(20, 150)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(20, 150)); QVERIFY(!inner->property("dragging").toBool()); QTRY_VERIFY(!inner->property("moving").toBool()); @@ -646,7 +655,7 @@ void tst_qquickflickable::nestedPressDelay() QVERIFY(inner->property("moving").toBool()); QVERIFY(inner->property("dragging").toBool()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(90, 150)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(90, 150)); QVERIFY(!inner->property("dragging").toBool()); QTRY_VERIFY(!inner->property("moving").toBool()); @@ -661,13 +670,13 @@ void tst_qquickflickable::filterReplayedPress() QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(outer != 0); + QVERIFY(outer != nullptr); QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); - QVERIFY(inner != 0); + QVERIFY(inner != nullptr); QQuickItem *filteringMouseArea = outer->findChild<QQuickItem *>("filteringMouseArea"); QVERIFY(filteringMouseArea); @@ -690,7 +699,7 @@ void tst_qquickflickable::filterReplayedPress() QCOMPARE(filteringMouseArea->property("pressed").toBool(), true); QCOMPARE(filteringMouseArea->keepMouseGrab(), true); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); } @@ -704,13 +713,13 @@ void tst_qquickflickable::nestedClickThenFlick() QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *outer = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(outer != 0); + QVERIFY(outer != nullptr); QQuickFlickable *inner = window->rootObject()->findChild<QQuickFlickable*>("innerFlickable"); - QVERIFY(inner != 0); + QVERIFY(inner != nullptr); moveAndPress(window.data(), QPoint(150, 150)); @@ -718,7 +727,7 @@ void tst_qquickflickable::nestedClickThenFlick() QVERIFY(!outer->property("pressed").toBool()); QTRY_VERIFY(outer->property("pressed").toBool()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); QVERIFY(!outer->property("pressed").toBool()); @@ -736,7 +745,7 @@ void tst_qquickflickable::nestedClickThenFlick() QVERIFY(!outer->property("moving").toBool()); QVERIFY(inner->property("moving").toBool()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(80, 100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(80, 100)); } void tst_qquickflickable::flickableDirection() @@ -778,13 +787,20 @@ void tst_qquickflickable::resizeContent() QQuickItem *root = qobject_cast<QQuickItem*>(c.create()); QQuickFlickable *obj = findItem<QQuickFlickable>(root, "flick"); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->contentX(), 0.); QCOMPARE(obj->contentY(), 0.); QCOMPARE(obj->contentWidth(), 300.); QCOMPARE(obj->contentHeight(), 300.); + QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(obj); + QSizeChangeListener sizeListener(fp->contentItem); + QMetaObject::invokeMethod(root, "resizeContent"); + for (const QSize sizeOnGeometryChanged : sizeListener) { + // Check that we have the correct size on all signals + QCOMPARE(sizeOnGeometryChanged, QSize(600, 600)); + } QCOMPARE(obj->contentX(), 100.); QCOMPARE(obj->contentY(), 100.); @@ -803,15 +819,15 @@ void tst_qquickflickable::returnToBounds() window->rootContext()->setContextProperty("setRebound", setRebound); window->setSource(testFileUrl("resize.qml")); window->show(); - QTest::qWaitForWindowActive(window.data()); - QVERIFY(window->rootObject() != 0); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *obj = findItem<QQuickFlickable>(window->rootObject(), "flick"); QQuickTransition *rebound = window->rootObject()->findChild<QQuickTransition*>("rebound"); QVERIFY(rebound); QSignalSpy reboundSpy(rebound, SIGNAL(runningChanged())); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->contentX(), 0.); QCOMPARE(obj->contentY(), 0.); QCOMPARE(obj->contentWidth(), 300.); @@ -848,10 +864,10 @@ void tst_qquickflickable::wheel() window->setSource(testFileUrl("wheel.qml")); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flick = window->rootObject()->findChild<QQuickFlickable*>("flick"); - QVERIFY(flick != 0); + QVERIFY(flick != nullptr); QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flick); QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded())); @@ -902,10 +918,10 @@ void tst_qquickflickable::trackpad() window->setSource(testFileUrl("wheel.qml")); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flick = window->rootObject()->findChild<QQuickFlickable*>("flick"); - QVERIFY(flick != 0); + QVERIFY(flick != nullptr); QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded())); QPoint pos(200, 200); @@ -979,10 +995,10 @@ void tst_qquickflickable::movingAndFlicking() QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged())); QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); @@ -1142,10 +1158,10 @@ void tst_qquickflickable::movingAndDragging() QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); QSignalSpy vDragSpy(flickable, SIGNAL(draggingVerticallyChanged())); QSignalSpy hDragSpy(flickable, SIGNAL(draggingHorizontallyChanged())); @@ -1187,7 +1203,7 @@ void tst_qquickflickable::movingAndDragging() QCOMPARE(moveStartSpy.count(), 1); QCOMPARE(dragStartSpy.count(), 1); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, moveFrom + moveByWithoutSnapBack*3); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, moveFrom + moveByWithoutSnapBack*3); QVERIFY(!flickable->isDragging()); QVERIFY(!flickable->isDraggingHorizontally()); @@ -1260,7 +1276,7 @@ void tst_qquickflickable::movingAndDragging() QCOMPARE(dragStartSpy.count(), 1); QCOMPARE(dragEndSpy.count(), 0); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, moveFrom + moveByWithSnapBack*3); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, moveFrom + moveByWithSnapBack*3); // should now start snapping back to bounds (moving but not dragging) QVERIFY(flickable->isMoving()); @@ -1311,10 +1327,10 @@ void tst_qquickflickable::flickOnRelease() window->setSource(testFileUrl("flickable03.qml")); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); // Vertical with a quick press-move-release: should cause a flick in release. QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged())); @@ -1325,18 +1341,13 @@ void tst_qquickflickable::flickOnRelease() // working even with small movements. moveAndPress(window.data(), QPoint(50, 300)); QTest::mouseMove(window.data(), QPoint(50, 10), 10); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(50, 10), 10); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 10), 10); QCOMPARE(vFlickSpy.count(), 1); // wait for any motion to end QTRY_VERIFY(!flickable->isMoving()); -#ifdef Q_OS_MAC -# if QT_CONFIG(opengl) - QEXPECT_FAIL("", "QTBUG-26094 stopping on a full pixel doesn't work on OS X", Continue); -# endif -#endif // Stop on a full pixel after user interaction QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY())); } @@ -1350,10 +1361,10 @@ void tst_qquickflickable::pressWhileFlicking() QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); QSignalSpy vMoveSpy(flickable, SIGNAL(movingVerticallyChanged())); QSignalSpy hMoveSpy(flickable, SIGNAL(movingHorizontallyChanged())); @@ -1379,13 +1390,13 @@ void tst_qquickflickable::pressWhileFlicking() QCOMPARE(hFlickSpy.count(), 0); QCOMPARE(flickSpy.count(), 1); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(20, 50)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(20, 50)); QTRY_VERIFY(!flickable->isFlicking()); QVERIFY(!flickable->isFlickingVertically()); QVERIFY(flickable->isMoving()); QVERIFY(flickable->isMovingVertically()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(20,50)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(20,50)); QVERIFY(!flickable->isFlicking()); QVERIFY(!flickable->isFlickingVertically()); QTRY_VERIFY(!flickable->isMoving()); @@ -1400,10 +1411,10 @@ void tst_qquickflickable::disabled() window->setSource(testFileUrl("disabled.qml")); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flick = window->rootObject()->findChild<QQuickFlickable*>("flickable"); - QVERIFY(flick != 0); + QVERIFY(flick != nullptr); moveAndPress(window.data(), QPoint(50, 90)); @@ -1413,11 +1424,11 @@ void tst_qquickflickable::disabled() QVERIFY(!flick->isMoving()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(50, 60)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 60)); // verify that mouse clicks on other elements still work (QTBUG-20584) moveAndPress(window.data(), QPoint(50, 10)); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(50, 10)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 10)); QTRY_VERIFY(window->rootObject()->property("clicked").toBool()); } @@ -1431,10 +1442,10 @@ void tst_qquickflickable::flickVelocity() QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); // flick up flick(window.data(), QPoint(20,190), QPoint(20, 50), 200); @@ -1479,7 +1490,7 @@ void tst_qquickflickable::margins() QQuickItem *root = window->rootObject(); QVERIFY(root); QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(root); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); // starting state QCOMPARE(obj->contentX(), -40.); @@ -1558,10 +1569,10 @@ void tst_qquickflickable::cancelOnMouseGrab() QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); moveAndPress(window.data(), QPoint(10, 10)); // drag out of bounds @@ -1596,20 +1607,20 @@ void tst_qquickflickable::clickAndDragWhenTransformed() QQuickViewTestUtil::moveMouseAway(view.data()); view->show(); QVERIFY(QTest::qWaitForWindowActive(view.data())); - QVERIFY(view->rootObject() != 0); + QVERIFY(view->rootObject() != nullptr); QQuickFlickable *flickable = view->rootObject()->findChild<QQuickFlickable*>("flickable"); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); // click outside child rect moveAndPress(view.data(), QPoint(190, 190)); QTRY_COMPARE(flickable->property("itemPressed").toBool(), false); - QTest::mouseRelease(view.data(), Qt::LeftButton, 0, QPoint(190, 190)); + QTest::mouseRelease(view.data(), Qt::LeftButton, Qt::NoModifier, QPoint(190, 190)); // click inside child rect moveAndPress(view.data(), QPoint(200, 200)); QTRY_COMPARE(flickable->property("itemPressed").toBool(), true); - QTest::mouseRelease(view.data(), Qt::LeftButton, 0, QPoint(200, 200)); + QTest::mouseRelease(view.data(), Qt::LeftButton, Qt::NoModifier, QPoint(200, 200)); const int threshold = qApp->styleHints()->startDragDistance(); @@ -1640,10 +1651,10 @@ void tst_qquickflickable::flickTwiceUsingTouches() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); QCOMPARE(flickable->contentY(), 0.0f); flickWithTouch(window.data(), QPoint(100, 400), QPoint(100, 240)); @@ -1771,7 +1782,7 @@ void tst_qquickflickable::nestedStopAtBounds() QCOMPARE(outer->isMoving(), true); QCOMPARE(inner->isDragging(), false); QCOMPARE(inner->isMoving(), false); - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); QVERIFY(!outer->isDragging()); QTRY_VERIFY(!outer->isMoving()); @@ -1793,7 +1804,7 @@ void tst_qquickflickable::nestedStopAtBounds() QCOMPARE(outer->isMoving(), false); QCOMPARE(inner->isDragging(), true); QCOMPARE(inner->isMoving(), true); - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); QVERIFY(!inner->isDragging()); QTRY_VERIFY(!inner->isMoving()); @@ -1817,7 +1828,7 @@ void tst_qquickflickable::nestedStopAtBounds() QCOMPARE(outer->isMoving(), true); QCOMPARE(inner->isDragging(), false); QCOMPARE(inner->isMoving(), false); - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); QVERIFY(!outer->isDragging()); QTRY_VERIFY(!outer->isMoving()); @@ -1841,7 +1852,7 @@ void tst_qquickflickable::nestedStopAtBounds() QCOMPARE(outer->isMoving(), true); QCOMPARE(inner->isDragging(), false); QCOMPARE(inner->isMoving(), false); - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); QVERIFY(!outer->isDragging()); QTRY_VERIFY(!outer->isMoving()); @@ -1908,6 +1919,10 @@ void tst_qquickflickable::stopAtBounds() else QCOMPARE(transpose ? flickable->isAtYBeginning() : flickable->isAtXBeginning(), true); + QSignalSpy atXBeginningChangedSpy(flickable, &QQuickFlickable::atXBeginningChanged); + QSignalSpy atYBeginningChangedSpy(flickable, &QQuickFlickable::atYBeginningChanged); + QSignalSpy atXEndChangedSpy(flickable, &QQuickFlickable::atXEndChanged); + QSignalSpy atYEndChangedSpy(flickable, &QQuickFlickable::atYEndChanged); // drag back towards boundary for (int i = 0; i < 24; ++i) { axis += invert ? threshold / 3 : -threshold / 3; @@ -1919,6 +1934,11 @@ void tst_qquickflickable::stopAtBounds() else QCOMPARE(transpose ? flickable->isAtYBeginning() : flickable->isAtXBeginning(), false); + QCOMPARE(atXBeginningChangedSpy.count(), (!transpose && !invert) ? 1 : 0); + QCOMPARE(atYBeginningChangedSpy.count(), ( transpose && !invert) ? 1 : 0); + QCOMPARE(atXEndChangedSpy.count(), (!transpose && invert) ? 1 : 0); + QCOMPARE(atYEndChangedSpy.count(), ( transpose && invert) ? 1 : 0); + // Drag away from the aligned boundary again. // None of the mouse movements will position the view at the boundary exactly, // but the view should end up aligned on the boundary @@ -1937,7 +1957,7 @@ void tst_qquickflickable::stopAtBounds() QCOMPARE(transpose ? flickable->contentY() : flickable->contentX(), 0.0); } - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); if (transpose) { flickable->setContentY(invert ? 100 : 0); @@ -1973,10 +1993,10 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch() QQuickViewTestUtil::centerOnScreen(window.data()); QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); QCOMPARE(flickable->contentY(), 50.0f); flickWithTouch(window.data(), QPoint(100, 300), QPoint(100, 200)); @@ -1993,21 +2013,21 @@ void tst_qquickflickable::nestedSliderUsingTouch_data() { QTest::addColumn<bool>("keepMouseGrab"); QTest::addColumn<bool>("keepTouchGrab"); - QTest::addColumn<int>("updates"); + QTest::addColumn<int>("minUpdates"); QTest::addColumn<int>("releases"); QTest::addColumn<int>("ungrabs"); QTest::newRow("keepBoth") << true << true << 8 << 1 << 0; QTest::newRow("keepMouse") << true << false << 8 << 1 << 0; QTest::newRow("keepTouch") << false << true << 8 << 1 << 0; - QTest::newRow("keepNeither") << false << false << 6 << 0 << 1; + QTest::newRow("keepNeither") << false << false << 5 << 0 << 1; } void tst_qquickflickable::nestedSliderUsingTouch() { QFETCH(bool, keepMouseGrab); QFETCH(bool, keepTouchGrab); - QFETCH(int, updates); + QFETCH(int, minUpdates); QFETCH(int, releases); QFETCH(int, ungrabs); @@ -2019,7 +2039,7 @@ void tst_qquickflickable::nestedSliderUsingTouch() QQuickViewTestUtil::moveMouseAway(window); window->show(); QVERIFY(QTest::qWaitForWindowActive(window)); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); QVERIFY(flickable); @@ -2043,7 +2063,7 @@ void tst_qquickflickable::nestedSliderUsingTouch() QTest::touchEvent(window, touchDevice).release(0, p0, window); QQuickTouchUtils::flush(window); QTRY_COMPARE(tda->touchPointStates.first(), Qt::TouchPointPressed); - QTRY_COMPARE(tda->touchUpdates, updates); + QTRY_VERIFY(tda->touchUpdates >= minUpdates); QTRY_COMPARE(tda->touchReleases, releases); QTRY_COMPARE(tda->ungrabs, ungrabs); } @@ -2058,11 +2078,11 @@ void tst_qquickflickable::pressDelayWithLoader() QQuickViewTestUtil::moveMouseAway(window.data()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); // do not crash moveAndPress(window.data(), QPoint(150, 150)); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 150)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150)); } // QTBUG-34507 @@ -2077,7 +2097,7 @@ void tst_qquickflickable::movementFromProgrammaticFlick() QVERIFY(QTest::qWaitForWindowActive(window.data())); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); // verify that the signals for movement and flicking are called in the right order flickable->flick(0, -1000); @@ -2132,7 +2152,7 @@ void tst_qquickflickable::ratios_smallContent() QQuickItem *root = window->rootObject(); QVERIFY(root); QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(root); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); //doublecheck the item, as specified by contentWidth/Height, fits in the view //use tryCompare to allow a bit of stabilization in component's properties @@ -2189,7 +2209,7 @@ void tst_qquickflickable::keepGrab() QTest::mouseMove(window.data(), pos); QTest::qWait(10); } - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(310, 310)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(310, 310)); QTest::qWait(10); QCOMPARE(flickable->contentX(), 0.0); @@ -2204,7 +2224,7 @@ void tst_qquickflickable::keepGrab() QTest::mouseMove(window.data(), pos); QTest::qWait(10); } - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(310, 310)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(310, 310)); QTest::qWait(10); QVERIFY(flickable->contentX() != 0.0); @@ -2236,11 +2256,11 @@ void tst_qquickflickable::overshoot() flickable->setBoundsMovement(QQuickFlickable::BoundsMovement(boundsMovement)); // drag past the beginning - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(10, 10)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(10, 10)); QTest::mouseMove(window.data(), QPoint(20, 20)); QTest::mouseMove(window.data(), QPoint(30, 30)); QTest::mouseMove(window.data(), QPoint(40, 40)); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(50, 50)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::DragOverBounds)) { QVERIFY(flickable->property("minContentX").toReal() < 0.0); @@ -2305,11 +2325,11 @@ void tst_qquickflickable::overshoot() QMetaObject::invokeMethod(flickable, "reset"); // drag past the end - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(50, 50)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); QTest::mouseMove(window.data(), QPoint(40, 40)); QTest::mouseMove(window.data(), QPoint(30, 30)); QTest::mouseMove(window.data(), QPoint(20, 20)); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(10, 10)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(10, 10)); if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::DragOverBounds)) { QVERIFY(flickable->property("maxContentX").toReal() > 200.0); @@ -2449,6 +2469,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/qquickflipable/tst_qquickflipable.cpp b/tests/auto/quick/qquickflipable/tst_qquickflipable.cpp index 9c892488f4..b4082b3d34 100644 --- a/tests/auto/quick/qquickflipable/tst_qquickflipable.cpp +++ b/tests/auto/quick/qquickflipable/tst_qquickflipable.cpp @@ -61,7 +61,7 @@ void tst_qquickflipable::create() QQmlComponent c(&engine, testFileUrl("test-flipable.qml")); QQuickFlipable *obj = qobject_cast<QQuickFlipable*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); delete obj; } @@ -71,9 +71,9 @@ void tst_qquickflipable::checkFrontAndBack() QQmlComponent c(&engine, testFileUrl("test-flipable.qml")); QQuickFlipable *obj = qobject_cast<QQuickFlipable*>(c.create()); - QVERIFY(obj != 0); - QVERIFY(obj->front() != 0); - QVERIFY(obj->back() != 0); + QVERIFY(obj != nullptr); + QVERIFY(obj->front() != nullptr); + QVERIFY(obj->back() != nullptr); delete obj; } @@ -83,9 +83,9 @@ void tst_qquickflipable::setFrontAndBack() QQmlComponent c(&engine, testFileUrl("test-flipable.qml")); QQuickFlipable *obj = qobject_cast<QQuickFlipable*>(c.create()); - QVERIFY(obj != 0); - QVERIFY(obj->front() != 0); - QVERIFY(obj->back() != 0); + QVERIFY(obj != nullptr); + QVERIFY(obj->front() != nullptr); + QVERIFY(obj->back() != nullptr); QString message = c.url().toString() + ":3:1: QML Flipable: front is a write-once property"; QTest::ignoreMessage(QtWarningMsg, qPrintable(message)); @@ -102,7 +102,7 @@ void tst_qquickflipable::flipFlipable() QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("flip-flipable.qml")); QQuickFlipable *obj = qobject_cast<QQuickFlipable*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->side(), QQuickFlipable::Front); obj->setProperty("flipped", QVariant(true)); QTRY_COMPARE(obj->side(), QQuickFlipable::Back); @@ -116,7 +116,7 @@ void tst_qquickflipable::QTBUG_9161_crash() QQuickView *window = new QQuickView; window->setSource(testFileUrl("crash.qml")); QQuickItem *root = window->rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); window->show(); delete window; } @@ -126,7 +126,7 @@ void tst_qquickflipable::QTBUG_8474_qgv_abort() QQuickView *window = new QQuickView; window->setSource(testFileUrl("flipable-abort.qml")); QQuickItem *root = window->rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); window->show(); delete window; } diff --git a/tests/auto/quick/qquickfocusscope/BLACKLIST b/tests/auto/quick/qquickfocusscope/BLACKLIST deleted file mode 100644 index cc3c8b6e8a..0000000000 --- a/tests/auto/quick/qquickfocusscope/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[canvasFocus] -osx-10.11 diff --git a/tests/auto/quick/qquickfocusscope/tst_qquickfocusscope.cpp b/tests/auto/quick/qquickfocusscope/tst_qquickfocusscope.cpp index 5ac7fa7015..e59bb7266c 100644 --- a/tests/auto/quick/qquickfocusscope/tst_qquickfocusscope.cpp +++ b/tests/auto/quick/qquickfocusscope/tst_qquickfocusscope.cpp @@ -67,15 +67,15 @@ void tst_qquickfocusscope::basic() QQuickRectangle *item1 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item1")); QQuickRectangle *item2 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item2")); QQuickRectangle *item3 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item3")); - QVERIFY(item0 != 0); - QVERIFY(item1 != 0); - QVERIFY(item2 != 0); - QVERIFY(item3 != 0); + QVERIFY(item0 != nullptr); + QVERIFY(item1 != nullptr); + QVERIFY(item2 != nullptr); + QVERIFY(item3 != nullptr); view->show(); view->requestActivate(); - QTest::qWaitForWindowActive(view); + QVERIFY(QTest::qWaitForWindowActive(view)); QTRY_COMPARE(view, qGuiApp->focusWindow()); QVERIFY(view->isTopLevel()); @@ -111,16 +111,16 @@ void tst_qquickfocusscope::nested() QQuickFocusScope *item3 = findItem<QQuickFocusScope>(view->rootObject(), QLatin1String("item3")); QQuickFocusScope *item4 = findItem<QQuickFocusScope>(view->rootObject(), QLatin1String("item4")); QQuickFocusScope *item5 = findItem<QQuickFocusScope>(view->rootObject(), QLatin1String("item5")); - QVERIFY(item1 != 0); - QVERIFY(item2 != 0); - QVERIFY(item3 != 0); - QVERIFY(item4 != 0); - QVERIFY(item5 != 0); + QVERIFY(item1 != nullptr); + QVERIFY(item2 != nullptr); + QVERIFY(item3 != nullptr); + QVERIFY(item4 != nullptr); + QVERIFY(item5 != nullptr); view->show(); view->requestActivate(); - QTest::qWaitForWindowActive(view); + QVERIFY(QTest::qWaitForWindowActive(view)); QTRY_COMPARE(view, qGuiApp->focusWindow()); QVERIFY(item1->hasActiveFocus()); @@ -140,10 +140,10 @@ void tst_qquickfocusscope::noFocus() QQuickRectangle *item1 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item1")); QQuickRectangle *item2 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item2")); QQuickRectangle *item3 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item3")); - QVERIFY(item0 != 0); - QVERIFY(item1 != 0); - QVERIFY(item2 != 0); - QVERIFY(item3 != 0); + QVERIFY(item0 != nullptr); + QVERIFY(item1 != nullptr); + QVERIFY(item2 != nullptr); + QVERIFY(item3 != nullptr); view->show(); view->requestActivate(); @@ -179,15 +179,15 @@ void tst_qquickfocusscope::textEdit() QQuickTextEdit *item1 = findItem<QQuickTextEdit>(view->rootObject(), QLatin1String("item1")); QQuickRectangle *item2 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item2")); QQuickTextEdit *item3 = findItem<QQuickTextEdit>(view->rootObject(), QLatin1String("item3")); - QVERIFY(item0 != 0); - QVERIFY(item1 != 0); - QVERIFY(item2 != 0); - QVERIFY(item3 != 0); + QVERIFY(item0 != nullptr); + QVERIFY(item1 != nullptr); + QVERIFY(item2 != nullptr); + QVERIFY(item3 != nullptr); view->show(); view->requestActivate(); - QTest::qWaitForWindowActive(view); + QVERIFY(QTest::qWaitForWindowActive(view)); QTRY_COMPARE(view, qGuiApp->focusWindow()); QVERIFY(item0->hasActiveFocus()); @@ -231,16 +231,16 @@ void tst_qquickfocusscope::forceFocus() QQuickFocusScope *item3 = findItem<QQuickFocusScope>(view->rootObject(), QLatin1String("item3")); QQuickRectangle *item4 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item4")); QQuickRectangle *item5 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item5")); - QVERIFY(item0 != 0); - QVERIFY(item1 != 0); - QVERIFY(item2 != 0); - QVERIFY(item3 != 0); - QVERIFY(item4 != 0); - QVERIFY(item5 != 0); + QVERIFY(item0 != nullptr); + QVERIFY(item1 != nullptr); + QVERIFY(item2 != nullptr); + QVERIFY(item3 != nullptr); + QVERIFY(item4 != nullptr); + QVERIFY(item5 != nullptr); view->show(); view->requestActivate(); - QTest::qWaitForWindowActive(view); + QVERIFY(QTest::qWaitForWindowActive(view)); QTRY_COMPARE(view, qGuiApp->focusWindow()); QVERIFY(item0->hasActiveFocus()); @@ -277,7 +277,7 @@ void tst_qquickfocusscope::noParentFocus() view->show(); view->requestActivate(); - QTest::qWaitForWindowActive(view); + QVERIFY(QTest::qWaitForWindowActive(view)); QTRY_COMPARE(view, qGuiApp->focusWindow()); QVERIFY(!view->rootObject()->property("focus1").toBool()); @@ -298,15 +298,15 @@ void tst_qquickfocusscope::signalEmission() QQuickRectangle *item2 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item2")); QQuickRectangle *item3 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item3")); QQuickRectangle *item4 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("item4")); - QVERIFY(item1 != 0); - QVERIFY(item2 != 0); - QVERIFY(item3 != 0); - QVERIFY(item4 != 0); + QVERIFY(item1 != nullptr); + QVERIFY(item2 != nullptr); + QVERIFY(item3 != nullptr); + QVERIFY(item4 != nullptr); view->show(); view->requestActivate(); - QTest::qWaitForWindowActive(view); + QVERIFY(QTest::qWaitForWindowActive(view)); QTRY_COMPARE(view, qGuiApp->focusWindow()); QVariant blue(QColor("blue")); diff --git a/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp b/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp index a38b62eb16..87a5bd469a 100644 --- a/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp +++ b/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp @@ -77,7 +77,7 @@ void tst_qquickfontloader::noFont() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create()); - QVERIFY(fontObject != 0); + QVERIFY(fontObject != nullptr); QCOMPARE(fontObject->name(), QString("")); QCOMPARE(fontObject->source(), QUrl("")); QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Null); @@ -92,7 +92,7 @@ void tst_qquickfontloader::namedFont() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create()); - QVERIFY(fontObject != 0); + QVERIFY(fontObject != nullptr); QCOMPARE(fontObject->source(), QUrl("")); QCOMPARE(fontObject->name(), QString("Helvetica")); QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Ready); @@ -105,7 +105,7 @@ void tst_qquickfontloader::localFont() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create()); - QVERIFY(fontObject != 0); + QVERIFY(fontObject != nullptr); QVERIFY(fontObject->source() != QUrl("")); QTRY_COMPARE(fontObject->name(), QString("OCRA")); QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Ready); @@ -119,7 +119,7 @@ void tst_qquickfontloader::failLocalFont() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create()); - QVERIFY(fontObject != 0); + QVERIFY(fontObject != nullptr); QVERIFY(fontObject->source() != QUrl("")); QTRY_COMPARE(fontObject->name(), QString("")); QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Error); @@ -133,7 +133,7 @@ void tst_qquickfontloader::webFont() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create()); - QVERIFY(fontObject != 0); + QVERIFY(fontObject != nullptr); QVERIFY(fontObject->source() != QUrl("")); QTRY_COMPARE(fontObject->name(), QString("OCRA")); QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Ready); @@ -149,7 +149,7 @@ void tst_qquickfontloader::redirWebFont() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create()); - QVERIFY(fontObject != 0); + QVERIFY(fontObject != nullptr); QVERIFY(fontObject->source() != QUrl("")); QTRY_COMPARE(fontObject->name(), QString("OCRA")); QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Ready); @@ -164,7 +164,7 @@ void tst_qquickfontloader::failWebFont() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create()); - QVERIFY(fontObject != 0); + QVERIFY(fontObject != nullptr); QVERIFY(fontObject->source() != QUrl("")); QTRY_COMPARE(fontObject->name(), QString("")); QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Error); @@ -179,7 +179,7 @@ void tst_qquickfontloader::changeFont() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(component.create()); - QVERIFY(fontObject != 0); + QVERIFY(fontObject != nullptr); QSignalSpy nameSpy(fontObject, SIGNAL(nameChanged())); QSignalSpy statusSpy(fontObject, SIGNAL(statusChanged())); @@ -218,7 +218,7 @@ void tst_qquickfontloader::changeFontSourceViaState() QCOMPARE(&window, qGuiApp->focusWindow()); QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(qvariant_cast<QObject *>(window.rootObject()->property("fontloader"))); - QVERIFY(fontObject != 0); + QVERIFY(fontObject != nullptr); QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Ready); QVERIFY(fontObject->source() != QUrl("")); QTRY_COMPARE(fontObject->name(), QString("OCRA")); diff --git a/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp b/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp index 6e516f51e1..ef61c45225 100644 --- a/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp +++ b/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp @@ -127,7 +127,7 @@ void tst_QuickFontMetrics::functions() QFontMetricsF expected = QFontMetricsF(QFont()); QCOMPARE(metrics.elidedText(text, mode, width, flags), expected.elidedText(text, mode, width, flags)); - QCOMPARE(metrics.advanceWidth(text), expected.width(text)); + QCOMPARE(metrics.advanceWidth(text), expected.horizontalAdvance(text)); QCOMPARE(metrics.boundingRect(text), expected.boundingRect(text)); QCOMPARE(metrics.tightBoundingRect(text), expected.tightBoundingRect(text)); } diff --git a/tests/auto/quick/qquickframebufferobject/BLACKLIST b/tests/auto/quick/qquickframebufferobject/BLACKLIST new file mode 100644 index 0000000000..93dd7e9d1c --- /dev/null +++ b/tests/auto/quick/qquickframebufferobject/BLACKLIST @@ -0,0 +1,4 @@ +# QTBUG-65614 +b2qt +[testThatStuffWorks] +b2qt diff --git a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp index d4922599be..6aff66d61e 100644 --- a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp +++ b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp @@ -192,7 +192,8 @@ void tst_QQuickFramebufferObject::testThatStuffWorks() item->setMsaa(msaa); view.show(); - QTest::qWaitForWindowExposed(&view); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); QImage result = view.grabWindow(); @@ -231,7 +232,8 @@ void tst_QQuickFramebufferObject::testInvalidate() item->setTextureSize(QSize(200, 200)); view.show(); - QTest::qWaitForWindowExposed(&view); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); QCOMPARE(frameInfo.fboSize, QSize(200, 200)); @@ -240,7 +242,7 @@ void tst_QQuickFramebufferObject::testInvalidate() item->update(); QTRY_COMPARE(frameInfo.createFBOCount, 1); - QCOMPARE(frameInfo.fboSize, QSize(300, 300)); + QTRY_COMPARE(frameInfo.fboSize, QSize(300, 300)); } QTEST_MAIN(tst_QQuickFramebufferObject) diff --git a/tests/auto/quick/qquickgridview/BLACKLIST b/tests/auto/quick/qquickgridview/BLACKLIST deleted file mode 100644 index 9eb9940aa5..0000000000 --- a/tests/auto/quick/qquickgridview/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[snapOneRow:horizontal, right to left] -windows diff --git a/tests/auto/quick/qquickgridview/data/attachedProperties.qml b/tests/auto/quick/qquickgridview/data/attachedProperties.qml index 43d9da97fc..b1662dac44 100644 --- a/tests/auto/quick/qquickgridview/data/attachedProperties.qml +++ b/tests/auto/quick/qquickgridview/data/attachedProperties.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquickgridview/data/margins2.qml b/tests/auto/quick/qquickgridview/data/margins2.qml new file mode 100644 index 0000000000..346933d3c9 --- /dev/null +++ b/tests/auto/quick/qquickgridview/data/margins2.qml @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 + +Item { + id: root + height: 1000 + width: 1000 + + GridView { + id: grid + objectName: "grid" + height: 500 + width: parent.width + topMargin: 20 + leftMargin: 200 + rightMargin: 200 + bottomMargin: 30 + cellWidth: (grid.width - grid.leftMargin - grid.rightMargin) / 3 + model: 9 + delegate: Rectangle { + border.width: 1 + objectName: "child" + width: grid.cellWidth + height: 100 + Text { + anchors.centerIn: parent + text: modelData + } + } + } +} diff --git a/tests/auto/quick/qquickgridview/data/mirroring.qml b/tests/auto/quick/qquickgridview/data/mirroring.qml index b9aff501c1..b99f50b854 100644 --- a/tests/auto/quick/qquickgridview/data/mirroring.qml +++ b/tests/auto/quick/qquickgridview/data/mirroring.qml @@ -2,29 +2,30 @@ // changes in right-to-left layout direction import QtQuick 2.0 +import QtQml.Models 2.12 Rectangle { color: "lightgray" width: 340 height: 370 - VisualItemModel { + ObjectModel { id: itemModel objectName: "itemModel" Rectangle { objectName: "item1" height: 110; width: 120; color: "#FFFEF0" - Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text1"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } Rectangle { objectName: "item2" height: 130; width: 150; color: "#F0FFF7" - Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text2"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } Rectangle { objectName: "item3" height: 170; width: 190; color: "#F4F0FF" - Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text3"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } } diff --git a/tests/auto/quick/qquickgridview/data/qtbug49218.qml b/tests/auto/quick/qquickgridview/data/qtbug49218.qml new file mode 100644 index 0000000000..1a55fe5b3a --- /dev/null +++ b/tests/auto/quick/qquickgridview/data/qtbug49218.qml @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.4 + +Item { + width: 500 + height: 160 + visible: true + + property var model1: ["1","2","3","4","5","6","7","8","9","10", + "11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30", + "31","32","33","34","a"] + property var model2: ["a","b","c","d","e","f","g","h","i","j","k","l","m","1"] + property bool useModel1: true + + function changeModel() { + useModel1 = !useModel1 + grid.loadModel(useModel1 ? model1 : model2) + } + + function scrollToTop() { + grid.contentY = grid.originY; + } + + GridView { + id: grid + anchors.fill: parent + + model: ListModel { + } + + onCurrentIndexChanged: { + positionViewAtIndex(currentIndex, GridView.Contain) + } + + Component.onCompleted: { + loadModel(model1) + grid.currentIndex = 34 + grid.positionViewAtIndex(34, GridView.Contain) + } + + function loadModel(m) { + var remove = {}; + var add = {}; + var i; + for (i=0; i < model.count; ++i) + remove[model.get(i).name] = true; + for (i=0; i < m.length; ++i) + if (remove[m[i]]) + delete remove[m[i]]; + else + add[m[i]] = true; + + for (i=model.count-1; i>= 0; --i) + if (remove[model.get(i).name]) + model.remove(i, 1); + + for (i=0; i<m.length; ++i) + if (add[m[i]]) + model.insert(i, { "name": m[i] }) + } + + delegate: Rectangle { + height: grid.cellHeight + width: grid.cellWidth + color: GridView.isCurrentItem ? "gray" : "white" + Text { + anchors.fill: parent + text: name + } + MouseArea { + anchors.fill: parent + onClicked: { + grid.currentIndex = index + } + } + } + } +} diff --git a/tests/auto/quick/qquickgridview/data/qtbug57225.qml b/tests/auto/quick/qquickgridview/data/qtbug57225.qml new file mode 100644 index 0000000000..3871e5d273 --- /dev/null +++ b/tests/auto/quick/qquickgridview/data/qtbug57225.qml @@ -0,0 +1,95 @@ +import QtQuick 2.0 + +Rectangle { + id: root + width: 200 + height: 200 + + property int duration: 100 + property int count: grid.count + + Component { + id: myDelegate + Rectangle { + id: wrapper + + property string nameData: name + property bool removalStarted: false + property real minX: 0 + property real minY: 0 + + onXChanged: if (removalStarted) grid.recordPosition(x, y) + onYChanged: if (removalStarted) grid.recordPosition(x, y) + + objectName: "wrapper" + width: 80 + height: 80 + border.width: 1 + Column { + Text { text: index } + Text { + text: wrapper.x + ", " + wrapper.y + } + Text { + id: textName + objectName: "textName" + text: name + } + } + color: GridView.isCurrentItem ? "lightsteelblue" : "white" + + GridView.onRemove: SequentialAnimation { + PropertyAction { target: wrapper; property: "removalStarted"; value: true } + PropertyAction { target: wrapper; property: "GridView.delayRemove"; value: true } + NumberAnimation { target: wrapper; property: "scale"; to: 0.5; duration: root.duration; easing.type: Easing.InOutQuad } + PropertyAction { target: wrapper; property: "GridView.delayRemove"; value: false } + PropertyAction { target: grid; property: "animationDone"; value: true } + } + + } + } + + GridView { + id: grid + + property int displaceTransitionsDone: 0 + property bool animationDone: false + property point minimumPosition: Qt.point(0, 0) + + signal delegateMoved(real x, real y) + + objectName: "grid" + focus: true + anchors.fill: parent + cacheBuffer: 0 + cellWidth: 80 + cellHeight: 80 + model: testModel + delegate: myDelegate + + displaced: Transition { + id: transition + SequentialAnimation { + NumberAnimation { + properties: "x,y" + duration: root.duration + easing.type: Easing.OutBounce + } + ScriptAction { script: grid.displaceTransitionsDone += 1 } + } + } + + function recordPosition(index, x, y) { + if (x < minimumPosition.x || y < minimumPosition.y) { + minimumPosition = Qt.point(x, y) + } + } + } + + Rectangle { + anchors.fill: grid + color: "lightsteelblue" + opacity: 0.2 + } +} + diff --git a/tests/auto/quick/qquickgridview/data/releaseItems.qml b/tests/auto/quick/qquickgridview/data/releaseItems.qml new file mode 100644 index 0000000000..19d58550a4 --- /dev/null +++ b/tests/auto/quick/qquickgridview/data/releaseItems.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +GridView { + width: 400 + height: 400 + model: 100 + delegate: Rectangle { + height: 100; width: 100 + color: index % 2 ? "lightsteelblue" : "lightgray" + } + contentHeight: contentItem.children.length * 40 +} diff --git a/tests/auto/quick/qquickgridview/data/unrequestedItems.qml b/tests/auto/quick/qquickgridview/data/unrequestedItems.qml index bedb90b849..4afe5ac8b3 100644 --- a/tests/auto/quick/qquickgridview/data/unrequestedItems.qml +++ b/tests/auto/quick/qquickgridview/data/unrequestedItems.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 Item { width: 240 @@ -38,7 +39,7 @@ Item { } - VisualDataModel { + DelegateModel { id: visualModel delegate: myDelegate diff --git a/tests/auto/quick/qquickgridview/qquickgridview.pro b/tests/auto/quick/qquickgridview/qquickgridview.pro index 3c33cc78fb..5051f8bc62 100644 --- a/tests/auto/quick/qquickgridview/qquickgridview.pro +++ b/tests/auto/quick/qquickgridview/qquickgridview.pro @@ -10,5 +10,5 @@ include (../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private qml-private quick-private testlib +QT += core-private gui-private qml-private quick-private testlib qmltest diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp index 1acc36c9b0..3b704d7fa4 100644 --- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp +++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp @@ -29,6 +29,7 @@ #include <QtTest/QtTest> #include <QtCore/qstringlistmodel.h> #include <QtQuick/qquickview.h> +#include <QtQuickTest/QtQuickTest> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcomponent.h> #include <QtQml/qqmlcontext.h> @@ -46,6 +47,8 @@ #include <QtGui/qguiapplication.h> #include "qplatformdefs.h" +#include <math.h> + Q_DECLARE_METATYPE(QQuickGridView::Flow) Q_DECLARE_METATYPE(Qt::LayoutDirection) Q_DECLARE_METATYPE(QQuickItemView::VerticalLayoutDirection) @@ -151,6 +154,8 @@ private slots: void multipleTransitions(); void multipleTransitions_data(); void multipleDisplaced(); + void regression_QTBUG_57225(); + void regression_QTBUG_57225_data(); void inserted_leftToRight_RtL_TtB(); void inserted_leftToRight_RtL_TtB_data(); @@ -206,9 +211,11 @@ private slots: void contentHeightWithDelayRemove(); void QTBUG_45640(); + void QTBUG_49218(); void QTBUG_48870_fastModelUpdates(); void keyNavigationEnabled(); + void releaseItems(); private: QList<int> toIntList(const QVariantList &list); @@ -281,7 +288,7 @@ private: if (m_view) { if (QString(QTest::currentTestFunction()) != testForView) { delete m_view; - m_view = 0; + m_view = nullptr; } else { m_view->setSource(QUrl()); return m_view; @@ -310,7 +317,7 @@ private: QString testForView; }; -tst_QQuickGridView::tst_QQuickGridView() : m_view(0) +tst_QQuickGridView::tst_QQuickGridView() : m_view(nullptr) { } @@ -320,7 +327,7 @@ void tst_QQuickGridView::init() if (m_view && QString(QTest::currentTestFunction()) != testForView) { testForView = QString(); delete m_view; - m_view = 0; + m_view = nullptr; } #endif } @@ -330,7 +337,7 @@ void tst_QQuickGridView::cleanupTestCase() #ifdef SHARE_VIEWS testForView = QString(); delete m_view; - m_view = 0; + m_view = nullptr; #endif } @@ -354,10 +361,10 @@ void tst_QQuickGridView::items() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QTRY_COMPARE(gridview->count(), model.count()); QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count()); @@ -365,10 +372,10 @@ void tst_QQuickGridView::items() for (int i = 0; i < model.count(); ++i) { QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(i)); } @@ -402,17 +409,17 @@ void tst_QQuickGridView::changed() qApp->processEvents(); QQuickFlickable *gridview = findItem<QQuickFlickable>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); model.modifyItem(1, "Will", "9876"); QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(1)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(1)); delete window; @@ -433,10 +440,10 @@ void tst_QQuickGridView::inserted_basic() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); model.insertItem(1, "Will", "9876"); @@ -444,10 +451,10 @@ void tst_QQuickGridView::inserted_basic() QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(1)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(1)); // Checks that onAdd is called @@ -466,10 +473,10 @@ void tst_QQuickGridView::inserted_basic() QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item name = findItem<QQuickText>(contentItem, "textName", 0); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(0)); number = findItem<QQuickText>(contentItem, "textNumber", 0); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(0)); QTRY_COMPARE(gridview->currentIndex(), 1); @@ -520,16 +527,16 @@ void tst_QQuickGridView::inserted_defaultLayout(QQuickGridView::Flow flow, qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); if (flow == QQuickGridView::FlowTopToBottom) { insertIndex = insertIndex_ttb; insertCount = insertCount_ttb; } if (setContentPos(gridview, contentYRowOffset)) - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QList<QPair<QString, QString> > newData; for (int i=0; i<insertCount; i++) @@ -565,7 +572,7 @@ void tst_QQuickGridView::inserted_defaultLayout(QQuickGridView::Flow flow, QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); QCOMPARE(item->position(), expectedItemPos(gridview, i, rowOffsetAfterMove)); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QCOMPARE(name->text(), model.name(i)); } @@ -710,18 +717,18 @@ void tst_QQuickGridView::insertBeforeVisible() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); gridview->setCacheBuffer(cacheBuffer); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); // trigger a refill (not just setting contentY) so that the visibleItems grid is updated int firstVisibleIndex = 12; // move to an index where the top item is not visible gridview->setContentY(firstVisibleIndex/3 * 60.0); gridview->setCurrentIndex(firstVisibleIndex); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QTRY_COMPARE(gridview->currentIndex(), firstVisibleIndex); QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", firstVisibleIndex); @@ -738,7 +745,7 @@ void tst_QQuickGridView::insertBeforeVisible() // now, moving to the top of the view should position the inserted items correctly int itemsOffsetAfterMove = (insertCount / 3) * -60.0; gridview->setCurrentIndex(0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QTRY_COMPARE(gridview->currentIndex(), 0); QTRY_COMPARE(gridview->contentY(), 0.0 + itemsOffsetAfterMove); @@ -750,7 +757,7 @@ void tst_QQuickGridView::insertBeforeVisible() QCOMPARE(item->x(), (i%3)*80.0); QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove); name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -794,19 +801,19 @@ void tst_QQuickGridView::removed_basic() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); model.removeItem(1); QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count()); QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(1)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(1)); @@ -828,10 +835,10 @@ void tst_QQuickGridView::removed_basic() QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count()); name = findItem<QQuickText>(contentItem, "textName", 0); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(0)); number = findItem<QQuickText>(contentItem, "textNumber", 0); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(0)); @@ -884,7 +891,7 @@ void tst_QQuickGridView::removed_basic() QTRY_VERIFY(gridview->currentItem() != oldCurrent); gridview->setContentY(0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); // Confirm items positioned correctly itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); @@ -907,7 +914,7 @@ void tst_QQuickGridView::removed_basic() model.removeItem(20); QTRY_COMPARE(gridview->currentIndex(), 20); - QTRY_VERIFY(gridview->currentItem() != 0); + QTRY_VERIFY(gridview->currentItem() != nullptr); // remove item before current, but visible gridview->setCurrentIndex(8); @@ -950,9 +957,9 @@ void tst_QQuickGridView::removed_defaultLayout(QQuickGridView::Flow flow, qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); if (flow == QQuickGridView::FlowTopToBottom) { removeIndex = removeIndex_ttb; @@ -960,7 +967,7 @@ void tst_QQuickGridView::removed_defaultLayout(QQuickGridView::Flow flow, firstVisible = firstVisible_ttb; } if (setContentPos(gridview, contentYRowOffset)) - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); model.removeItems(removeIndex, removeCount); gridview->forceLayout(); @@ -991,7 +998,7 @@ void tst_QQuickGridView::removed_defaultLayout(QQuickGridView::Flow flow, QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); QCOMPARE(item->position(), expectedItemPos(gridview, i, rowOffsetAfterMove)); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -1138,7 +1145,7 @@ void tst_QQuickGridView::removed_defaultLayout_data() QTest::newRow("remove multiple, after visible, content not at start") << 2.0 // show 6-23 << 16+4 << 5 - << 15+10 << 7 + << 15 << 7 << 0.0 << "Item6" << "Item10"; QTest::newRow("remove multiple, mix of items from within and after visible items") @@ -1167,16 +1174,16 @@ void tst_QQuickGridView::addOrRemoveBeforeVisible() window->setSource(testFileUrl("gridview1.qml")); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0); QTRY_COMPARE(name->text(), QString("Item0")); gridview->setCurrentIndex(0); qApp->processEvents(); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); // scroll down until item 0 is no longer drawn // (bug not triggered if we just move using content y, since that doesn't @@ -1187,7 +1194,7 @@ void tst_QQuickGridView::addOrRemoveBeforeVisible() QTRY_COMPARE(gridview->currentIndex(), 24); QTRY_COMPARE(gridview->contentY(), 220.0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 0)); // 0 shouldn't be visible if (doAdd) { @@ -1245,10 +1252,10 @@ void tst_QQuickGridView::clear() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QVERIFY(gridview != 0); + QVERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); model.clear(); gridview->forceLayout(); @@ -1263,7 +1270,7 @@ void tst_QQuickGridView::clear() model.addItem("New", "1"); gridview->forceLayout(); QTRY_COMPARE(gridview->count(), 1); - QVERIFY(gridview->currentItem() != 0); + QVERIFY(gridview->currentItem() != nullptr); QCOMPARE(gridview->currentIndex(), 0); delete window; @@ -1298,13 +1305,13 @@ void tst_QQuickGridView::moved_defaultLayout(QQuickGridView::Flow flow, qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QQuickItem *currentItem = gridview->currentItem(); - QTRY_VERIFY(currentItem != 0); + QTRY_VERIFY(currentItem != nullptr); if (flow == QQuickGridView::FlowTopToBottom) { from = from_ttb; @@ -1312,10 +1319,10 @@ void tst_QQuickGridView::moved_defaultLayout(QQuickGridView::Flow flow, count = count_ttb; } if (setContentPos(gridview, contentYRowOffset)) - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); model.moveItems(from, to, count); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); // Confirm items positioned correctly and indexes correct QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); @@ -1339,7 +1346,7 @@ void tst_QQuickGridView::moved_defaultLayout(QQuickGridView::Flow flow, QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); QCOMPARE(item->position(), expectedItemPos(gridview, i, rowOffsetAfterMove)); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); // current index should have been updated @@ -1553,8 +1560,8 @@ void tst_QQuickGridView::multipleChanges(bool condensed) qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QTRY_VERIFY(gridview != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); for (int i=0; i<changes.count(); i++) { switch (changes[i].type) { @@ -1582,10 +1589,10 @@ void tst_QQuickGridView::multipleChanges(bool condensed) break; } if (condensed) { - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); } } - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QCOMPARE(gridview->count(), newCount); QCOMPARE(gridview->count(), model.count()); @@ -1594,16 +1601,16 @@ void tst_QQuickGridView::multipleChanges(bool condensed) QQuickText *name; QQuickText *number; QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); for (int i=0; i < model.count() && i < itemCount; ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); number = findItem<QQuickText>(contentItem, "textNumber", i); - QVERIFY(number != 0); + QVERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(i)); } @@ -1798,7 +1805,7 @@ void tst_QQuickGridView::swapWithFirstItem() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); // ensure content position is stable gridview->setContentY(0); @@ -1814,7 +1821,7 @@ void tst_QQuickGridView::currentIndex() for (int i = 0; i < 60; i++) initModel.addItem("Item" + QString::number(i), QString::number(i)); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setGeometry(0,0,240,320); window->show(); @@ -1827,17 +1834,18 @@ void tst_QQuickGridView::currentIndex() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QVERIFY(gridview != 0); - QTRY_VERIFY(!QQuickItemPrivate::get(gridview)->polishScheduled); + QVERIFY(gridview != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); // currentIndex is initialized to 35 // currentItem should be in view QCOMPARE(gridview->currentIndex(), 35); QCOMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 35)); - QCOMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y()); + // Wait for possible animation to finish + QTRY_COMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y()); QCOMPARE(gridview->contentY(), 400.0); // changing model should reset currentIndex to 0 @@ -1914,7 +1922,7 @@ void tst_QQuickGridView::noCurrentIndex() for (int i = 0; i < 60; i++) model.addItem("Item" + QString::number(i), QString::number(i)); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setGeometry(0,0,240,320); QQmlContext *ctxt = window->rootContext(); @@ -1926,10 +1934,10 @@ void tst_QQuickGridView::noCurrentIndex() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QVERIFY(gridview != 0); + QVERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); // current index should be -1 QCOMPARE(gridview->currentIndex(), -1); @@ -1967,17 +1975,17 @@ void tst_QQuickGridView::keyNavigation() window->rootContext()->setContextProperty("testModel", &model); window->setSource(testFileUrl("gridview1.qml")); window->show(); - QTest::qWaitForWindowActive(window); + QVERIFY(QTest::qWaitForWindowActive(window)); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); gridview->setFlow(flow); gridview->setLayoutDirection(layoutDirection); gridview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); window->requestActivate(); - QTest::qWaitForWindowActive(window); + QVERIFY(QTest::qWaitForWindowActive(window)); QTRY_COMPARE(qGuiApp->focusWindow(), window); QCOMPARE(gridview->currentIndex(), 0); @@ -2176,10 +2184,10 @@ void tst_QQuickGridView::changeFlow() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); // Confirm items positioned correctly and indexes correct int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); @@ -2190,10 +2198,10 @@ void tst_QQuickGridView::changeFlow() QTRY_COMPARE(item->x(), qreal((i%3)*80)); QTRY_COMPARE(item->y(), qreal((i/3)*60)); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(i)); } @@ -2208,10 +2216,10 @@ void tst_QQuickGridView::changeFlow() QTRY_COMPARE(item->x(), qreal((i/5)*80)); QTRY_COMPARE(item->y(), qreal((i%5)*60)); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(i)); } @@ -2226,10 +2234,10 @@ void tst_QQuickGridView::changeFlow() QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width())); QTRY_COMPARE(item->y(), qreal((i%5)*60)); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(i)); } gridview->setContentX(100); @@ -2246,10 +2254,10 @@ void tst_QQuickGridView::changeFlow() QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80)); QTRY_COMPARE(item->y(), qreal((i/3)*60)); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(i)); } @@ -2262,7 +2270,7 @@ void tst_QQuickGridView::defaultValues() QQmlComponent c(&engine, testFileUrl("gridview3.qml")); QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create()); - QTRY_VERIFY(obj != 0); + QTRY_VERIFY(obj != nullptr); QTRY_COMPARE(obj->model(), QVariant()); QTRY_VERIFY(!obj->delegate()); QTRY_COMPARE(obj->currentIndex(), -1); @@ -2289,14 +2297,14 @@ void tst_QQuickGridView::properties() QQmlComponent c(&engine, testFileUrl("gridview2.qml")); QQuickGridView *obj = qobject_cast<QQuickGridView*>(c.create()); - QTRY_VERIFY(obj != 0); + QTRY_VERIFY(obj != nullptr); QTRY_VERIFY(obj->model() != QVariant()); - QTRY_VERIFY(obj->delegate() != 0); + QTRY_VERIFY(obj->delegate() != nullptr); QTRY_COMPARE(obj->currentIndex(), 0); - QTRY_VERIFY(obj->currentItem() != 0); + QTRY_VERIFY(obj->currentItem() != nullptr); QTRY_COMPARE(obj->count(), 4); - QTRY_VERIFY(obj->highlight() != 0); - QTRY_VERIFY(obj->highlightItem() != 0); + QTRY_VERIFY(obj->highlight() != nullptr); + QTRY_VERIFY(obj->highlightItem() != nullptr); QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false); QTRY_COMPARE(obj->flow(), QQuickGridView::FlowLeftToRight); QTRY_COMPARE(obj->isWrapEnabled(), true); @@ -2481,10 +2489,10 @@ void tst_QQuickGridView::positionViewAtBeginningEnd() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); // positionViewAtBeginning gridview->setContentY(150); @@ -2568,13 +2576,13 @@ void tst_QQuickGridView::positionViewAtIndex() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); window->rootObject()->setProperty("enforceRange", enforceRange); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); if (topToBottom) gridview->setContentX(initContentPos); @@ -2680,7 +2688,7 @@ void tst_QQuickGridView::snapping() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); gridview->setHeight(220); QCOMPARE(gridview->height(), 220.); @@ -2709,12 +2717,12 @@ void tst_QQuickGridView::mirroring() QQuickView *windowA = createView(); windowA->setSource(testFileUrl("mirroring.qml")); QQuickGridView *gridviewA = findItem<QQuickGridView>(windowA->rootObject(), "view"); - QTRY_VERIFY(gridviewA != 0); + QTRY_VERIFY(gridviewA != nullptr); QQuickView *windowB = createView(); windowB->setSource(testFileUrl("mirroring.qml")); QQuickGridView *gridviewB = findItem<QQuickGridView>(windowB->rootObject(), "view"); - QTRY_VERIFY(gridviewA != 0); + QTRY_VERIFY(gridviewA != nullptr); qApp->processEvents(); QList<QString> objectNames; @@ -2781,16 +2789,16 @@ void tst_QQuickGridView::resetModel() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QTRY_COMPARE(gridview->count(), model.rowCount()); for (int i = 0; i < model.rowCount(); ++i) { QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i); - QTRY_VERIFY(display != 0); + QTRY_VERIFY(display != nullptr); QTRY_COMPARE(display->text(), strings.at(i)); } @@ -2802,7 +2810,7 @@ void tst_QQuickGridView::resetModel() for (int i = 0; i < model.rowCount(); ++i) { QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i); - QTRY_VERIFY(display != 0); + QTRY_VERIFY(display != nullptr); QTRY_COMPARE(display->text(), strings.at(i)); } @@ -2825,18 +2833,18 @@ void tst_QQuickGridView::enforceRange() window->setSource(testFileUrl("gridview-enforcerange.qml")); window->show(); qApp->processEvents(); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0); QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0); QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); // view should be positioned at the top of the range. QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0); @@ -2844,10 +2852,10 @@ void tst_QQuickGridView::enforceRange() QTRY_COMPARE(gridview->contentY(), -100.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(0)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(0)); // Check currentIndex is updated when contentItem moves @@ -2883,17 +2891,17 @@ void tst_QQuickGridView::enforceRange_rightToLeft() window->setSource(testFileUrl("gridview-enforcerange.qml")); window->show(); QTRY_VERIFY(window->isExposed()); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QCOMPARE(gridview->preferredHighlightBegin(), 100.0); QCOMPARE(gridview->preferredHighlightEnd(), 100.0); QCOMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); // view should be positioned at the top of the range. QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0); @@ -2902,10 +2910,10 @@ void tst_QQuickGridView::enforceRange_rightToLeft() QTRY_COMPARE(gridview->contentY(), 0.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(0)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(0)); // Check currentIndex is updated when contentItem moves @@ -2934,7 +2942,7 @@ void tst_QQuickGridView::QTBUG_8456() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QTRY_COMPARE(gridview->currentIndex(), 0); @@ -2951,10 +2959,10 @@ void tst_QQuickGridView::manualHighlight() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QTRY_COMPARE(gridview->currentIndex(), 0); QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0)); @@ -3012,14 +3020,14 @@ void tst_QQuickGridView::footer() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); gridview->setFlow(flow); gridview->setLayoutDirection(layoutDirection); gridview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QQuickText *footer = findItem<QQuickText>(contentItem, "footer"); QVERIFY(footer); @@ -3072,7 +3080,7 @@ void tst_QQuickGridView::footer() // if header is toggled, it shouldn't affect the footer position window->rootObject()->setProperty("showHeader", true); - QVERIFY(findItem<QQuickItem>(contentItem, "header") != 0); + QVERIFY(findItem<QQuickItem>(contentItem, "header") != nullptr); QTRY_COMPARE(footer->position(), posWhenNoItems); window->rootObject()->setProperty("showHeader", false); @@ -3209,9 +3217,9 @@ void tst_QQuickGridView::initialZValues() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QVERIFY(gridview->currentItem()); QTRY_COMPARE(gridview->currentItem()->z(), gridview->property("itemZ").toReal()); @@ -3261,14 +3269,14 @@ void tst_QQuickGridView::header() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); gridview->setFlow(flow); gridview->setLayoutDirection(layoutDirection); gridview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QQuickText *header = findItem<QQuickText>(contentItem, "header"); QVERIFY(header); @@ -3289,7 +3297,7 @@ void tst_QQuickGridView::header() QCOMPARE(item->position(), firstDelegatePos); model.clear(); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QCOMPARE(header->position(), initialHeaderPos); // header should stay where it is if (flow == QQuickGridView::FlowLeftToRight) QCOMPARE(gridview->contentHeight(), header->height()); @@ -3338,11 +3346,11 @@ void tst_QQuickGridView::header() qApp->processEvents(); gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); gridview->setFlow(flow); gridview->setLayoutDirection(layoutDirection); gridview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); gridview->setWidth(240); gridview->setHeight(320); @@ -3483,14 +3491,14 @@ void tst_QQuickGridView::extents() qApp->processEvents(); QQuickGridView *gridview = qobject_cast<QQuickGridView*>(window->rootObject()); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); gridview->setFlow(flow); gridview->setLayoutDirection(layoutDirection); gridview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); QVERIFY(header); @@ -3599,10 +3607,10 @@ void tst_QQuickGridView::resetModel_headerFooter() qApp->processEvents(); QQuickGridView *gridview = qobject_cast<QQuickGridView*>(window->rootObject()); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); QVERIFY(header); @@ -3645,10 +3653,10 @@ void tst_QQuickGridView::resizeViewAndRepaint() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); // item at index 10 should not be currently visible QVERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10)); @@ -3721,15 +3729,15 @@ void tst_QQuickGridView::resizeGrid() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); // set the width to slightly larger than 3 items across, to test // items are aligned correctly in right-to-left window->rootObject()->setWidth(260); window->rootObject()->setHeight(320); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QCOMPARE(gridview->contentX(), initialContentPos.x()); QCOMPARE(gridview->contentY(), initialContentPos.y()); @@ -3746,14 +3754,14 @@ void tst_QQuickGridView::resizeGrid() QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); QCOMPARE(item->position(), expectedItemPos(gridview, i, 0)); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QCOMPARE(name->text(), model.name(i)); } // change from 3x5 grid to 4x7 window->rootObject()->setWidth(window->rootObject()->width() + 80); window->rootObject()->setHeight(window->rootObject()->height() + 60*2); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); // other than in LeftToRight+RightToLeft layout, the first item should not move // if view is resized @@ -3778,7 +3786,7 @@ void tst_QQuickGridView::resizeGrid() QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); QCOMPARE(item->position(), expectedItemPos(gridview, i, 0)); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QCOMPARE(name->text(), model.name(i)); } @@ -3855,10 +3863,10 @@ void tst_QQuickGridView::changeColumnCount() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); // a single column of 6 items are visible int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); @@ -3872,7 +3880,7 @@ void tst_QQuickGridView::changeColumnCount() // now 6x3 grid is visible, plus 1 extra below for refill gridview->setWidth(240); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); QCOMPARE(itemCount, 6*3 + 1); for (int i = 0; i < model.count() && i < itemCount; ++i) { @@ -3884,7 +3892,7 @@ void tst_QQuickGridView::changeColumnCount() // back to single column gridview->setWidth(100); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); QCOMPARE(itemCount, 6); for (int i = 0; i < model.count() && i < itemCount; ++i) { @@ -3932,14 +3940,14 @@ void tst_QQuickGridView::indexAt_itemAt() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QTRY_COMPARE(gridview->count(), model.count()); - QQuickItem *item = 0; + QQuickItem *item = nullptr; if (index >= 0) { item = findItem<QQuickItem>(contentItem, "wrapper", index); QVERIFY(item); @@ -4071,7 +4079,7 @@ void tst_QQuickGridView::attachedProperties_QTBUG_32836() qApp->processEvents(); QQuickGridView *gridview = qobject_cast<QQuickGridView*>(window->rootObject()); - QVERIFY(gridview != 0); + QVERIFY(gridview != nullptr); QQuickItem *header = gridview->headerItem(); QVERIFY(header); @@ -4129,10 +4137,10 @@ void tst_QQuickGridView::margins() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QCOMPARE(gridview->contentX(), -30.); QCOMPARE(gridview->originX(), 0.); @@ -4192,10 +4200,10 @@ void tst_QQuickGridView::margins() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QTRY_COMPARE(gridview->contentX(), -240+50.); QTRY_COMPARE(gridview->originX(), -100. * 10); @@ -4210,7 +4218,7 @@ void tst_QQuickGridView::margins() // remove item before visible and check that left margin is maintained // and originX is updated gridview->setContentX(-400); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); model.removeItems(0, 4); gridview->forceLayout(); QTRY_COMPARE(model.count(), gridview->count()); @@ -4241,6 +4249,23 @@ void tst_QQuickGridView::margins() delete window; } + { + QQuickView *window = createView(); + + window->setSource(testFileUrl("margins2.qml")); + window->show(); + qApp->processEvents(); + + QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); + QVERIFY(gridview != nullptr); + QQuickItem *contentItem = gridview->contentItem(); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); + QCOMPARE(contentItem->x(), 200); + QCOMPARE(contentItem->y(), 20); + + delete window; + } } void tst_QQuickGridView::creationContext() @@ -4312,15 +4337,15 @@ void tst_QQuickGridView::snapToRow() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); gridview->setFlow(flow); gridview->setLayoutDirection(layoutDirection); gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode)); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); qreal origContentY = gridview->contentY(); qreal origContentX = gridview->contentX(); @@ -4333,7 +4358,7 @@ void tst_QQuickGridView::snapToRow() // click to stop it. Otherwise we wouldn't know how much further it will go. We don't want to it // to hit the endExtent, yet. - QTest::mouseClick(window, Qt::LeftButton, 0, flickEnd); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, flickEnd); QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops if (flow == QQuickGridView::FlowLeftToRight) @@ -4380,24 +4405,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() @@ -4410,6 +4445,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); @@ -4419,20 +4457,20 @@ void tst_QQuickGridView::snapOneRow() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); gridview->setFlow(flow); gridview->setLayoutDirection(layoutDirection); gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode)); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QQuickItem *contentItem = gridview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); 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); @@ -4446,7 +4484,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() @@ -4464,7 +4502,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() @@ -4500,10 +4538,10 @@ void tst_QQuickGridView::unaligned() qApp->processEvents(); QQuickGridView *gridview = qobject_cast<QQuickGridView*>(window->rootObject()); - QVERIFY(gridview != 0); + QVERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); for (int i = 0; i < 10; ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); @@ -4516,7 +4554,7 @@ void tst_QQuickGridView::unaligned() // appending for (int i = 10; i < 18; ++i) { model.addItem("Item" + QString::number(i), ""); - QQuickItem *item = 0; + QQuickItem *item = nullptr; QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i)); QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth())); QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight())); @@ -4525,7 +4563,7 @@ void tst_QQuickGridView::unaligned() // inserting for (int i = 0; i < 10; ++i) { model.insertItem(i, "Item" + QString::number(i), ""); - QQuickItem *item = 0; + QQuickItem *item = nullptr; QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i)); QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth())); QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight())); @@ -4536,7 +4574,7 @@ void tst_QQuickGridView::unaligned() gridview->forceLayout(); QTRY_COMPARE(model.count(), gridview->count()); for (int i = 0; i < 18; ++i) { - QQuickItem *item = 0; + QQuickItem *item = nullptr; QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper", i)); QCOMPARE(item->x(), qreal(i%9)*gridview->cellWidth()); QCOMPARE(item->y(), qreal(i/9)*gridview->cellHeight()); @@ -4586,7 +4624,7 @@ void tst_QQuickGridView::populateTransitions() QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), 0); QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 18); } else { - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QCOMPARE(gridview->property("countPopulateTransitions").toInt(), 0); QCOMPARE(gridview->property("countAddTransitions").toInt(), 0); } @@ -4598,7 +4636,7 @@ void tst_QQuickGridView::populateTransitions() QTRY_COMPARE(item->x(), (i%3)*80.0); QTRY_COMPARE(item->y(), (i/3)*60.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -4622,7 +4660,7 @@ void tst_QQuickGridView::populateTransitions() for (int i = 0; i < 30; i++) model.addItem("item" + QString::number(i), ""); window->rootContext()->setContextProperty("testModel", &model); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), usePopulateTransition ? 18 : 0); QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0); @@ -4634,7 +4672,7 @@ void tst_QQuickGridView::populateTransitions() QTRY_COMPARE(item->x(), (i%3)*80.0); QTRY_COMPARE(item->y(), (i/3)*60.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -4652,7 +4690,7 @@ void tst_QQuickGridView::populateTransitions() QTRY_COMPARE(item->x(), (i%3)*80.0); QTRY_COMPARE(item->y(), (i/3)*60.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -4707,14 +4745,14 @@ void tst_QQuickGridView::addTransitions() window->show(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); if (contentYRowOffset != 0) { gridview->setContentY(contentYRowOffset * 60.0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); } QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); @@ -4788,7 +4826,7 @@ void tst_QQuickGridView::addTransitions() QCOMPARE(item->x(), (i%3)*80.0); QCOMPARE(item->y(), (i/3)*60.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QCOMPARE(name->text(), model.name(i)); } @@ -4912,14 +4950,14 @@ void tst_QQuickGridView::moveTransitions() window->show(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQuickText *name; if (contentYRowOffset != 0) { gridview->setContentY(contentYRowOffset * 60.0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); } QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); @@ -4986,7 +5024,7 @@ void tst_QQuickGridView::moveTransitions() QCOMPARE(item->x(), (i%3)*80.0); QCOMPARE(item->y(), (i/3)*60.0 + pixelOffset); name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -5157,14 +5195,14 @@ void tst_QQuickGridView::removeTransitions() window->show(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); if (contentYRowOffset != 0) { gridview->setContentY(contentYRowOffset * 60.0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); } QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); @@ -5240,7 +5278,7 @@ void tst_QQuickGridView::removeTransitions() QCOMPARE(item->x(), (i%3)*80.0); QCOMPARE(item->y(), gridview->contentY() + ((i-firstVisibleIndex)/3) * 60.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -5375,10 +5413,10 @@ void tst_QQuickGridView::displacedTransitions() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); gridview->setProperty("displaceTransitionsDone", false); @@ -5399,7 +5437,7 @@ void tst_QQuickGridView::displacedTransitions() break; case ListChange::Moved: model.moveItems(change.index, change.to, change.count); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); break; case ListChange::SetCurrent: case ListChange::SetContentY: @@ -5459,7 +5497,7 @@ void tst_QQuickGridView::displacedTransitions() QCOMPARE(item->x(), (i%3)*80.0); QCOMPARE(item->y(), (i/3)*60.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -5594,14 +5632,14 @@ void tst_QQuickGridView::multipleTransitions() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); if (contentY != 0) { gridview->setContentY(contentY); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); } int timeBetweenActions = window->rootObject()->property("timeBetweenActions").toInt(); @@ -5638,7 +5676,7 @@ void tst_QQuickGridView::multipleTransitions() case ListChange::Moved: model.moveItems(changes[i].index, changes[i].to, changes[i].count); gridview->forceLayout(); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); if (i == changes.count() - 1) { QTRY_VERIFY(!gridview->property("runningMoveTargets").toBool()); QTRY_VERIFY(!gridview->property("runningMoveDisplaced").toBool()); @@ -5648,12 +5686,12 @@ void tst_QQuickGridView::multipleTransitions() break; case ListChange::SetCurrent: gridview->setCurrentIndex(changes[i].index); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); gridview->forceLayout(); break; case ListChange::SetContentY: gridview->setContentY(changes[i].pos); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); gridview->forceLayout(); break; case ListChange::Polish: @@ -5681,7 +5719,7 @@ void tst_QQuickGridView::multipleTransitions() QTRY_COMPARE(item->x(), (i%3)*80.0); QTRY_COMPARE(item->y(), (i/3)*60.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -5764,10 +5802,10 @@ void tst_QQuickGridView::multipleDisplaced() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(gridview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); model.moveItems(12, 8, 1); QTest::qWait(window->rootObject()->property("duration").toInt() / 2); @@ -5788,13 +5826,72 @@ void tst_QQuickGridView::multipleDisplaced() QTRY_COMPARE(item->x(), (i%3)*80.0); QTRY_COMPARE(item->y(), (i/3)*60.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } delete window; } +void tst_QQuickGridView::regression_QTBUG_57225() +{ + QFETCH(int, initialCount); + QFETCH(int, removeIndex); + QFETCH(int, removeCount); + QFETCH(int, expectedDisplaceTransitions); + + // deleting all visible items should not cause a repositioning of said items. + + QaimModel model; + for (int i = 0; i < initialCount; i++) + model.addItem("Original item" + QString::number(i), ""); + + QQuickView *window = createView(); + QQmlContext *ctxt = window->rootContext(); + ctxt->setContextProperty("testModel", &model); + window->setSource(testFileUrl("qtbug57225.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); + QVERIFY(gridview != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); + + model.removeItems(removeIndex, removeCount); + QTRY_VERIFY(gridview->property("animationDone").toBool()); + + // verify that none of the removed items has moved to a negative position + QPoint minimumPosition = gridview->property("minimumPosition").toPoint(); + QVERIFY(minimumPosition.x() >= 0); + QVERIFY(minimumPosition.y() >= 0); + + // wait some more time to let the displaced transition happen + QTest::qWait(window->rootObject()->property("duration").toInt()); + QTRY_VERIFY2(gridview->property("displaceTransitionsDone").toInt() >= expectedDisplaceTransitions, + QByteArray::number(gridview->property("displaceTransitionsDone").toInt()).constData()); + + delete window; +} + +void tst_QQuickGridView::regression_QTBUG_57225_data() +{ + QTest::addColumn<int>("initialCount"); + QTest::addColumn<int>("removeIndex"); + QTest::addColumn<int>("removeCount"); + QTest::addColumn<int>("expectedDisplaceTransitions"); + + // no displace transitions should happen + QTest::newRow("remove all visible items") << + 20 << 0 << 8 << 0; + + // check that the removal animation is performed + QTest::newRow("remove items in between") << + 20 << 1 << 2 << 3; + + QTest::newRow("remove items in between - 2") << + 20 << 2 << 3 << 1; +} + void tst_QQuickGridView::cacheBuffer() { QQuickView *window = createView(); @@ -5809,11 +5906,11 @@ void tst_QQuickGridView::cacheBuffer() qApp->processEvents(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QVERIFY(gridview != 0); + QVERIFY(gridview != nullptr); QQuickItem *contentItem = gridview->contentItem(); - QVERIFY(contentItem != 0); - QVERIFY(gridview->delegate() != 0); + QVERIFY(contentItem != nullptr); + QVERIFY(gridview->delegate() != nullptr); QVERIFY(gridview->model() != 0); // Confirm items positioned correctly @@ -5832,8 +5929,8 @@ void tst_QQuickGridView::cacheBuffer() // items will be created one at a time for (int i = itemCount; i < qMin(itemCount+9,model.count()); ++i) { - QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0); - QQuickItem *item = 0; + QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == nullptr); + QQuickItem *item = nullptr; while (!item) { bool b = false; controller.incubateWhile(&b); @@ -5867,11 +5964,11 @@ void tst_QQuickGridView::cacheBuffer() QTRY_COMPARE(item->y(), (i/3)*60.0); } - QVERIFY(findItem<QQuickItem>(gridview, "wrapper", 34) == 0); + QVERIFY(findItem<QQuickItem>(gridview, "wrapper", 34) == nullptr); // ensure buffered items are created for (int i = 34; i < qMin(44,model.count()); ++i) { - QQuickItem *item = 0; + QQuickItem *item = nullptr; while (!item) { qGuiApp->processEvents(); // allow refill to happen bool b = false; @@ -5900,7 +5997,7 @@ void tst_QQuickGridView::asynchronous() QQuickItem *rootObject = qobject_cast<QQuickItem*>(window->rootObject()); QVERIFY(rootObject); - QQuickGridView *gridview = 0; + QQuickGridView *gridview = nullptr; while (!gridview) { bool b = false; controller.incubateWhile(&b); @@ -5909,8 +6006,8 @@ void tst_QQuickGridView::asynchronous() // items will be created one at a time for (int i = 0; i < 12; ++i) { - QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == 0); - QQuickItem *item = 0; + QVERIFY(findItem<QQuickItem>(gridview, "wrapper", i) == nullptr); + QQuickItem *item = nullptr; while (!item) { bool b = false; controller.incubateWhile(&b); @@ -5941,7 +6038,7 @@ void tst_QQuickGridView::unrequestedVisibility() for (int i = 0; i < 30; i++) model.addItem("Item" + QString::number(i), QString::number(i)); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setGeometry(0,0,240,320); QQmlContext *ctxt = window->rootContext(); @@ -5955,16 +6052,16 @@ void tst_QQuickGridView::unrequestedVisibility() qApp->processEvents(); QQuickGridView *leftview = findItem<QQuickGridView>(window->rootObject(), "leftGrid"); - QTRY_VERIFY(leftview != 0); + QTRY_VERIFY(leftview != nullptr); QQuickGridView *rightview = findItem<QQuickGridView>(window->rootObject(), "rightGrid"); - QTRY_VERIFY(rightview != 0); + QTRY_VERIFY(rightview != nullptr); QQuickItem *leftContent = leftview->contentItem(); - QTRY_VERIFY(leftContent != 0); + QTRY_VERIFY(leftContent != nullptr); QQuickItem *rightContent = rightview->contentItem(); - QTRY_VERIFY(rightContent != 0); + QTRY_VERIFY(rightContent != nullptr); rightview->setCurrentIndex(12); @@ -6031,7 +6128,7 @@ void tst_QQuickGridView::unrequestedVisibility() // move a non-visible item into view model.moveItems(10, 9, 1); - QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); QTRY_VERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1)); QCOMPARE(delegateVisible(item), false); @@ -6054,7 +6151,7 @@ void tst_QQuickGridView::unrequestedVisibility() // move a visible item out of view model.moveItems(5, 3, 1); - QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3)); QCOMPARE(delegateVisible(item), false); @@ -6067,7 +6164,7 @@ void tst_QQuickGridView::unrequestedVisibility() // move a non-visible item into view model.moveItems(3, 5, 1); - QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3)); QCOMPARE(delegateVisible(item), false); @@ -6080,7 +6177,7 @@ void tst_QQuickGridView::unrequestedVisibility() // move a visible item out of view model.moveItems(9, 10, 1); - QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3)); QCOMPARE(delegateVisible(item), false); @@ -6093,7 +6190,7 @@ void tst_QQuickGridView::unrequestedVisibility() // move a non-visible item into view model.moveItems(10, 9, 1); - QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3)); QCOMPARE(delegateVisible(item), false); @@ -6379,10 +6476,10 @@ void tst_QQuickGridView::displayMargin() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickGridView *gridview = window->rootObject()->findChild<QQuickGridView*>(); - QVERIFY(gridview != 0); + QVERIFY(gridview != nullptr); QQuickItem *content = gridview->contentItem(); - QVERIFY(content != 0); + QVERIFY(content != nullptr); QQuickItem *item0; QQuickItem *item97; @@ -6395,7 +6492,7 @@ void tst_QQuickGridView::displayMargin() QCOMPARE(delegateVisible(item97), true); // GridView staggers item creation, so the 118th item should be outside the end margin. - QVERIFY(findItem<QQuickItem>(content, "delegate", 117) == 0); + QVERIFY(findItem<QQuickItem>(content, "delegate", 117) == nullptr); // the first delegate should still be within the begin margin gridview->positionViewAtIndex(20, QQuickGridView::Beginning); @@ -6418,13 +6515,13 @@ void tst_QQuickGridView::negativeDisplayMargin() QQuickItem *listview = window->rootObject(); QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid"); - QVERIFY(gridview != 0); + QVERIFY(gridview != nullptr); QTRY_COMPARE(gridview->property("createdItems").toInt(), 11); QCOMPARE(gridview->property("destroyedItem").toInt(), 0); QQuickItem *content = gridview->contentItem(); - QVERIFY(content != 0); + QVERIFY(content != nullptr); QVERIFY(item = findItem<QQuickItem>(content, "delegate", 0)); QCOMPARE(delegateVisible(item), true); @@ -6523,7 +6620,7 @@ void tst_QQuickGridView::contentHeightWithDelayRemove() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickGridView *gridview = window->rootObject()->findChild<QQuickGridView*>(); - QTRY_VERIFY(gridview != 0); + QTRY_VERIFY(gridview != nullptr); const int initialCount(gridview->count()); const int eventualCount(initialCount + countDelta); @@ -6554,7 +6651,7 @@ void tst_QQuickGridView::QTBUG_45640() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickGridView *gridview = qobject_cast<QQuickGridView*>(window->rootObject()); - QVERIFY(gridview != 0); + QVERIFY(gridview != nullptr); QCOMPARE(gridview->contentY(), qreal(-50.0)); @@ -6565,6 +6662,36 @@ void tst_QQuickGridView::QTBUG_45640() delete window; } +void tst_QQuickGridView::QTBUG_49218() +{ + QQuickView *window = createView(); + window->setSource(testFileUrl("qtbug49218.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickItem *rootItem = qobject_cast<QQuickItem*>(window->rootObject()); + QQuickGridView *gridview = qobject_cast<QQuickGridView *>(rootItem->childItems().first()); + QVERIFY(gridview != nullptr); + + auto processEventsAndForceLayout = [&gridview] () { + for (int pass = 0; pass < 2; ++pass) { + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); + gridview->forceLayout(); + } + }; + QMetaObject::invokeMethod(rootItem, "scrollToTop"); + processEventsAndForceLayout(); + QMetaObject::invokeMethod(rootItem, "changeModel"); + processEventsAndForceLayout(); + QMetaObject::invokeMethod(rootItem, "changeModel"); + processEventsAndForceLayout(); + QMetaObject::invokeMethod(rootItem, "scrollToTop"); + processEventsAndForceLayout(); + + QCOMPARE(gridview->indexAt(gridview->cellWidth() - 10, gridview->cellHeight() - 10), 0); + delete window; +} + void tst_QQuickGridView::keyNavigationEnabled() { QScopedPointer<QQuickView> window(createView()); @@ -6643,11 +6770,11 @@ void tst_QQuickGridView::QTBUG_48870_fastModelUpdates() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickGridView *view = findItem<QQuickGridView>(window->rootObject(), "view"); - QTRY_VERIFY(view != 0); + QTRY_VERIFY(view != nullptr); QQuickItemViewPrivate *priv = QQuickItemViewPrivate::get(view); bool nonUnique; - FxViewItem *item = Q_NULLPTR; + FxViewItem *item = nullptr; int expectedIdx; QVERIFY(testVisibleItems(priv, &nonUnique, &item, &expectedIdx)); @@ -6666,6 +6793,18 @@ void tst_QQuickGridView::QTBUG_48870_fastModelUpdates() } } +void tst_QQuickGridView::releaseItems() +{ + QScopedPointer<QQuickView> view(createView()); + view->setSource(testFileUrl("releaseItems.qml")); + + QQuickGridView *gridview = qobject_cast<QQuickGridView *>(view->rootObject()); + QVERIFY(gridview); + + // don't crash (QTBUG-61294) + gridview->setModel(123); +} + QTEST_MAIN(tst_QQuickGridView) #include "tst_qquickgridview.moc" diff --git a/tests/auto/quick/qquickimage/data/car.ktx b/tests/auto/quick/qquickimage/data/car.ktx Binary files differnew file mode 100644 index 0000000000..2aefdd306b --- /dev/null +++ b/tests/auto/quick/qquickimage/data/car.ktx diff --git a/tests/auto/quick/qquickimage/data/logo.pkm b/tests/auto/quick/qquickimage/data/logo.pkm Binary files differnew file mode 100644 index 0000000000..c0987c5c36 --- /dev/null +++ b/tests/auto/quick/qquickimage/data/logo.pkm diff --git a/tests/auto/quick/qquickimage/data/pattern.pkm b/tests/auto/quick/qquickimage/data/pattern.pkm Binary files differnew file mode 100644 index 0000000000..d986e89b2d --- /dev/null +++ b/tests/auto/quick/qquickimage/data/pattern.pkm diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp index 36d99ad48d..d1f46a3912 100644 --- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp +++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp @@ -62,6 +62,7 @@ public: tst_qquickimage(); private slots: + void initTestCase(); void cleanup(); void noSource(); void imageSource(); @@ -97,12 +98,22 @@ private slots: private: QQmlEngine engine; + QSGRendererInterface::GraphicsApi graphicsApi = QSGRendererInterface::Unknown; }; tst_qquickimage::tst_qquickimage() { } +void tst_qquickimage::initTestCase() +{ + QQmlDataTest::initTestCase(); + QScopedPointer<QQuickView> window(new QQuickView(0)); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + graphicsApi = window->rendererInterface()->graphicsApi(); +} + void tst_qquickimage::cleanup() { QQuickWindow window; @@ -116,7 +127,7 @@ void tst_qquickimage::noSource() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->source(), QUrl()); QCOMPARE(obj->status(), QQuickImage::Null); QCOMPARE(obj->width(), 0.); @@ -150,8 +161,27 @@ void tst_qquickimage::imageSource_data() QTest::newRow("remote svg") << "/heart.svg" << 595.0 << 841.0 << true << false << false << ""; if (QImageReader::supportedImageFormats().contains("svgz")) QTest::newRow("remote svgz") << "/heart.svgz" << 595.0 << 841.0 << true << false << false << ""; + if (graphicsApi == QSGRendererInterface::OpenGL) { + QTest::newRow("texturefile pkm format") << testFileUrl("logo.pkm").toString() << 256.0 << 256.0 << false << false << true << ""; + QTest::newRow("texturefile ktx format") << testFileUrl("car.ktx").toString() << 146.0 << 80.0 << false << false << true << ""; + QTest::newRow("texturefile async") << testFileUrl("logo.pkm").toString() << 256.0 << 256.0 << false << true << true << ""; + } QTest::newRow("remote not found") << "/no-such-file.png" << 0.0 << 0.0 << true << false << true << "<Unknown File>:2:1: QML Image: Error transferring {{ServerBaseUrl}}/no-such-file.png - server replied: Not found"; + QTest::newRow("extless") << testFileUrl("colors").toString() << 120.0 << 120.0 << false << false << true << ""; + QTest::newRow("extless no cache") << testFileUrl("colors").toString() << 120.0 << 120.0 << false << false << false << ""; + QTest::newRow("extless async") << testFileUrl("colors1").toString() << 120.0 << 120.0 << false << true << true << ""; + QTest::newRow("extless not found") << testFileUrl("no-such-file").toString() << 0.0 << 0.0 << false + << false << true << "<Unknown File>:2:1: QML Image: Cannot open: " + testFileUrl("no-such-file").toString(); + // Test that texture file is preferred over image file, when supported. + // Since pattern.pkm has different size than pattern.png, these tests verify that the right file has been loaded + if (graphicsApi == QSGRendererInterface::OpenGL) { + QTest::newRow("extless prefer-tex") << testFileUrl("pattern").toString() << 64.0 << 64.0 << false << false << true << ""; + QTest::newRow("extless prefer-tex async") << testFileUrl("pattern").toString() << 64.0 << 64.0 << false << true << true << ""; + } else { + QTest::newRow("extless ignore-tex") << testFileUrl("pattern").toString() << 200.0 << 200.0 << false << false << true << ""; + QTest::newRow("extless ignore-tex async") << testFileUrl("pattern").toString() << 200.0 << 200.0 << false << true << true << ""; + } } @@ -195,7 +225,7 @@ void tst_qquickimage::imageSource() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); if (async) QVERIFY(obj->asynchronous()); @@ -233,7 +263,7 @@ void tst_qquickimage::clearSource() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->status(), QQuickImage::Ready); QCOMPARE(obj->width(), 120.); QCOMPARE(obj->height(), 120.); @@ -255,7 +285,7 @@ void tst_qquickimage::resized() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 300.); QCOMPARE(obj->height(), 300.); QCOMPARE(obj->fillMode(), QQuickImage::Stretch); @@ -265,13 +295,13 @@ void tst_qquickimage::resized() void tst_qquickimage::preserveAspectRatio() { - QScopedPointer<QQuickView> window(new QQuickView(0)); + QScopedPointer<QQuickView> window(new QQuickView(nullptr)); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); window->setSource(testFileUrl("aspectratio.qml")); QQuickImage *image = qobject_cast<QQuickImage*>(window->rootObject()); - QVERIFY(image != 0); + QVERIFY(image != nullptr); image->setWidth(80.0); QCOMPARE(image->width(), 80.); QCOMPARE(image->height(), 80.); @@ -279,7 +309,7 @@ void tst_qquickimage::preserveAspectRatio() window->setSource(testFileUrl("aspectratio.qml")); image = qobject_cast<QQuickImage*>(window->rootObject()); image->setHeight(60.0); - QVERIFY(image != 0); + QVERIFY(image != nullptr); QCOMPARE(image->height(), 60.); QCOMPARE(image->width(), 60.); } @@ -290,7 +320,7 @@ void tst_qquickimage::smooth() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 300.); QCOMPARE(obj->height(), 300.); QCOMPARE(obj->smooth(), true); @@ -301,6 +331,10 @@ void tst_qquickimage::smooth() void tst_qquickimage::mirror() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QMap<QQuickImage::FillMode, QImage> screenshots; QList<QQuickImage::FillMode> fillModes; fillModes << QQuickImage::Stretch << QQuickImage::PreserveAspectFit << QQuickImage::PreserveAspectCrop @@ -315,7 +349,7 @@ void tst_qquickimage::mirror() window->setSource(testFileUrl("mirror.qml")); QQuickImage *obj = window->rootObject()->findChild<QQuickImage*>("image"); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); obj->setFillMode(fillMode); obj->setProperty("mirror", true); @@ -399,13 +433,24 @@ void tst_qquickimage::svg() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); - QCOMPARE(obj->width(), 212.0); + QVERIFY(obj != nullptr); + QCOMPARE(obj->width(), 300.0); QCOMPARE(obj->height(), 300.0); obj->setSourceSize(QSize(200,200)); - QCOMPARE(obj->width(), 141.0); + QCOMPARE(obj->width(), 200.0); QCOMPARE(obj->height(), 200.0); + obj->setSourceSize(QSize(100,0)); + QCOMPARE(obj->width(), 100.0); + // Due to aspect ratio calculations we can't get a precise + // check for all setups, so we allow a small margin of error + QVERIFY(qAbs(obj->height() - 141) < 1); + + // Setting it to a size bigger than the actual file, SVG formats + // can scale up although other image formats cannot + obj->setSourceSize(QSize(800,0)); + QCOMPARE(obj->width(), 800.0); + QVERIFY(qAbs(obj->height() - 1131) < 1); delete obj; } @@ -469,7 +514,7 @@ void tst_qquickimage::geometry() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), itemWidth); QCOMPARE(obj->paintedWidth(), paintedWidth); @@ -492,7 +537,7 @@ void tst_qquickimage::big() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 100.0); QCOMPARE(obj->height(), 256.0); @@ -501,6 +546,10 @@ void tst_qquickimage::big() void tst_qquickimage::tiling_QTBUG_6716() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QFETCH(QString, source); QQuickView view(testFileUrl(source)); @@ -509,7 +558,7 @@ void tst_qquickimage::tiling_QTBUG_6716() QQuickImage *tiling = findItem<QQuickImage>(view.rootObject(), "tiling"); - QVERIFY(tiling != 0); + QVERIFY(tiling != nullptr); QImage img = view.grabWindow(); for (int x = 0; x < tiling->width(); ++x) { for (int y = 0; y < tiling->height(); ++y) { @@ -540,7 +589,7 @@ void tst_qquickimage::noLoading() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->status(), QQuickImage::Ready); QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(QUrl))); @@ -587,7 +636,7 @@ void tst_qquickimage::paintedWidthHeight() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 200.0); QCOMPARE(obj->height(), 25.0); QCOMPARE(obj->paintedWidth(), 25.0); @@ -602,7 +651,7 @@ void tst_qquickimage::paintedWidthHeight() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 26.0); QCOMPARE(obj->height(), 175.0); QCOMPARE(obj->paintedWidth(), 26.0); @@ -623,7 +672,7 @@ void tst_qquickimage::sourceSize_QTBUG_14303() QSignalSpy sourceSizeSpy(obj, SIGNAL(sourceSizeChanged())); - QTRY_VERIFY(obj != 0); + QTRY_VERIFY(obj != nullptr); QTRY_COMPARE(obj->status(), QQuickImage::Ready); QTRY_COMPARE(obj->sourceSize().width(), 200); @@ -645,7 +694,7 @@ void tst_qquickimage::sourceSize_QTBUG_14303() void tst_qquickimage::sourceSize_QTBUG_16389() { - QScopedPointer<QQuickView> window(new QQuickView(0)); + QScopedPointer<QQuickView> window(new QQuickView(nullptr)); window->setSource(testFileUrl("qtbug_16389.qml")); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); @@ -669,7 +718,7 @@ void tst_qquickimage::sourceSize_QTBUG_16389() // QTBUG-15690 void tst_qquickimage::nullPixmapPaint() { - QScopedPointer<QQuickView> window(new QQuickView(0)); + QScopedPointer<QQuickView> window(new QQuickView(nullptr)); window->setSource(testFileUrl("nullpixmap.qml")); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); @@ -679,7 +728,7 @@ void tst_qquickimage::nullPixmapPaint() server.serveDirectory(dataDirectory(), TestHTTPServer::Delay); QQuickImage *image = qobject_cast<QQuickImage*>(window->rootObject()); - QTRY_VERIFY(image != 0); + QTRY_VERIFY(image != nullptr); image->setSource(server.url("/no-such-file.png")); QQmlTestMessageHandler messageHandler; @@ -709,7 +758,7 @@ void tst_qquickimage::imageCrash_QTBUG_22125() // shouldn't crash when deleting cancelled QQmlPixmapReplys. server.sendDelayedItem(); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QCoreApplication::processEvents(); } @@ -742,7 +791,7 @@ void tst_qquickimage::sourceSize() QFETCH(qreal, implicitWidth); QFETCH(qreal, implicitHeight); - QScopedPointer<QQuickView> window(new QQuickView(0)); + QScopedPointer<QQuickView> window(new QQuickView(nullptr)); QQmlContext *ctxt = window->rootContext(); ctxt->setContextProperty("srcWidth", sourceWidth); ctxt->setContextProperty("srcHeight", sourceHeight); @@ -773,7 +822,7 @@ void tst_qquickimage::sourceSizeChanges() QQmlContext *ctxt = engine.rootContext(); ctxt->setContextProperty("srcImage", ""); QQuickImage *img = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(img != 0); + QVERIFY(img != nullptr); QSignalSpy sourceSizeSpy(img, SIGNAL(sourceSizeChanged())); @@ -839,7 +888,7 @@ void tst_qquickimage::progressAndStatusChanges() QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->status(), QQuickImage::Ready); QTRY_COMPARE(obj->progress(), 1.0); @@ -956,7 +1005,7 @@ void tst_qquickimage::highdpi() ctxt->setContextProperty("srcImage", testFileUrl("heart-highdpi@2x.png")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->width(), 150.0); QCOMPARE(obj->height(), 150.0); @@ -1034,6 +1083,10 @@ void tst_qquickimage::highDpiFillModesAndSizes() void tst_qquickimage::hugeImages() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QQuickView view; view.setSource(testFileUrl("hugeImages.qml")); view.setGeometry(0, 0, 200, 200); diff --git a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp index 98f3972cef..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; @@ -76,7 +77,7 @@ private: class TestQImageProvider : public QQuickImageProvider { public: - TestQImageProvider(bool *deleteWatch = 0, bool forceAsync = false) + TestQImageProvider(bool *deleteWatch = nullptr, bool forceAsync = false) : QQuickImageProvider(Image, (forceAsync ? ForceAsynchronousImageLoading : Flags())) , deleteWatch(deleteWatch) { @@ -114,7 +115,7 @@ Q_DECLARE_METATYPE(TestQImageProvider*); class TestQPixmapProvider : public QQuickImageProvider { public: - TestQPixmapProvider(bool *deleteWatch = 0) + TestQPixmapProvider(bool *deleteWatch = nullptr) : QQuickImageProvider(Pixmap), deleteWatch(deleteWatch) { } @@ -217,7 +218,7 @@ void tst_qquickimageprovider::runTest(bool async, QQuickImageProvider *provider) QQmlEngine engine; engine.addImageProvider("test", provider); - QVERIFY(engine.imageProvider("test") != 0); + QVERIFY(engine.imageProvider("test") != nullptr); QString componentStr = "import QtQuick 2.0\nImage { source: \"" + source + "\"; " + (async ? "asynchronous: true; " : "") @@ -225,7 +226,7 @@ void tst_qquickimageprovider::runTest(bool async, QQuickImageProvider *provider) QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); // From this point on, treat forced async providers as async behaviour-wise if (engine.imageProvider(QUrl(source).host()) == provider) @@ -314,14 +315,14 @@ void tst_qquickimageprovider::requestPixmap_async() QQuickImageProvider *provider = new TestQPixmapProvider(); engine.addImageProvider("test", provider); - QVERIFY(engine.imageProvider("test") != 0); + QVERIFY(engine.imageProvider("test") != nullptr); // pixmaps are loaded synchronously regardless of 'asynchronous' value QString componentStr = "import QtQuick 2.0\nImage { asynchronous: true; source: \"image://test/pixmap-async-test.png\" }"; QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); delete obj; } @@ -341,14 +342,14 @@ void tst_qquickimageprovider::removeProvider() QQmlEngine engine; engine.addImageProvider("test", provider); - QVERIFY(engine.imageProvider("test") != 0); + QVERIFY(engine.imageProvider("test") != nullptr); // add provider, confirm it works QString componentStr = "import QtQuick 2.0\nImage { source: \"" + newImageFileName() + "\" }"; QQmlComponent component(&engine); component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickImage *obj = qobject_cast<QQuickImage*>(component.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->status(), QQuickImage::Ready); @@ -384,7 +385,7 @@ void tst_qquickimageprovider::imageProviderId() TestQImageProvider *provider = new TestQImageProvider(&deleteWatch); engine.addImageProvider(providerId, provider); - QVERIFY(engine.imageProvider(providerId) != 0); + QVERIFY(engine.imageProvider(providerId) != nullptr); engine.removeImageProvider(providerId); QVERIFY(deleteWatch); @@ -393,7 +394,7 @@ void tst_qquickimageprovider::imageProviderId() class TestThreadProvider : public QQuickImageProvider { public: - TestThreadProvider() : QQuickImageProvider(Image), ok(false) {} + TestThreadProvider() : QQuickImageProvider(Image) {} ~TestThreadProvider() {} @@ -417,7 +418,7 @@ class TestThreadProvider : public QQuickImageProvider QWaitCondition cond; QMutex mutex; - bool ok; + bool ok = false; }; @@ -428,7 +429,7 @@ void tst_qquickimageprovider::threadTest() TestThreadProvider *provider = new TestThreadProvider; engine.addImageProvider("test_thread", provider); - QVERIFY(engine.imageProvider("test_thread") != 0); + QVERIFY(engine.imageProvider("test_thread") != nullptr); QString componentStr = "import QtQuick 2.0\nItem { \n" "Image { source: \"image://test_thread/blue\"; asynchronous: true; }\n" @@ -440,7 +441,7 @@ void tst_qquickimageprovider::threadTest() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QObject *obj = component.create(); //MUST not deadlock - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QList<QQuickImage *> images = obj->findChildren<QQuickImage *>(); QCOMPARE(images.count(), 4); QTest::qWait(100); @@ -459,7 +460,7 @@ class TestImageResponse : public QQuickImageResponse, public QRunnable { public: TestImageResponse(QMutex *lock, QWaitCondition *condition, bool *ok, const QString &id, const QSize &requestedSize) - : m_lock(lock), m_condition(condition), m_ok(ok), m_id(id), m_requestedSize(requestedSize), m_texture(0) + : m_lock(lock), m_condition(condition), m_ok(ok), m_id(id), m_requestedSize(requestedSize), m_texture(nullptr) { setAutoDelete(false); } @@ -495,7 +496,7 @@ class TestImageResponse : public QQuickImageResponse, public QRunnable class TestAsyncProvider : public QQuickAsyncImageProvider { public: - TestAsyncProvider() : ok(false) + TestAsyncProvider() { pool.setMaxThreadCount(4); } @@ -512,7 +513,7 @@ class TestAsyncProvider : public QQuickAsyncImageProvider QThreadPool pool; QMutex lock; QWaitCondition condition; - bool ok; + bool ok = false; }; @@ -523,7 +524,7 @@ void tst_qquickimageprovider::asyncTextureTest() TestAsyncProvider *provider = new TestAsyncProvider; engine.addImageProvider("test_async", provider); - QVERIFY(engine.imageProvider("test_async") != 0); + QVERIFY(engine.imageProvider("test_async") != nullptr); QString componentStr = "import QtQuick 2.0\nItem { \n" "Image { source: \"image://test_async/blue\"; }\n" @@ -535,7 +536,7 @@ void tst_qquickimageprovider::asyncTextureTest() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QObject *obj = component.create(); //MUST not deadlock - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QList<QQuickImage *> images = obj->findChildren<QQuickImage *>(); QCOMPARE(images.count(), 4); @@ -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/qquickitem/data/mainWindowQtBug60123.qml b/tests/auto/quick/qquickitem/data/mainWindowQtBug60123.qml new file mode 100644 index 0000000000..eeecd48cb2 --- /dev/null +++ b/tests/auto/quick/qquickitem/data/mainWindowQtBug60123.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 + +Rectangle { + width: 400 + height: 200 + color: "white" + property string lastEvent: "" + + Rectangle { + id: buttonRect + width: 50 + height: 50 + color: "black" + + MouseArea { + anchors.fill: parent + onPressed: { + lastEvent = "pressed" + buttonRect.color = "yellow" + } + onReleased: { + lastEvent = "released" + buttonRect.color = "black" + } + onCanceled: { + lastEvent = "canceled" + buttonRect.color = "green" + } + } + } +} diff --git a/tests/auto/quick/qquickitem/qquickitem.pro b/tests/auto/quick/qquickitem/qquickitem.pro index 9aca5926f2..003981d4de 100644 --- a/tests/auto/quick/qquickitem/qquickitem.pro +++ b/tests/auto/quick/qquickitem/qquickitem.pro @@ -11,3 +11,8 @@ TESTDATA = data/* QT += core-private gui-private qml-private quick-private testlib +qtHaveModule(widgets): { + DEFINES += TEST_QTBUG_60123 + QT += widgets +} + diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index 10a3a0bfa8..7e132f97b6 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -41,15 +41,25 @@ #include "../shared/viewtestutil.h" #include <QSignalSpy> +#ifdef TEST_QTBUG_60123 +#include <QWidget> +#include <QMainWindow> +#endif + class TestItem : public QQuickItem { Q_OBJECT public: - TestItem(QQuickItem *parent = 0) + TestItem(QQuickItem *parent = nullptr) : QQuickItem(parent), focused(false), pressCount(0), releaseCount(0) , wheelCount(0), acceptIncomingTouchEvents(true) , touchEventReached(false), timestamp(0) - , lastWheelEventPos(0, 0), lastWheelEventGlobalPos(0, 0) {} + , lastWheelEventPos(0, 0), lastWheelEventGlobalPos(0, 0) + { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + setAcceptTouchEvents(true); +#endif + } bool focused; int pressCount; @@ -95,7 +105,7 @@ class TestPolishItem : public QQuickItem { Q_OBJECT public: - TestPolishItem(QQuickItem *parent = 0) + TestPolishItem(QQuickItem *parent = nullptr) : QQuickItem(parent), wasPolished(false) { } @@ -117,7 +127,7 @@ class TestFocusScope : public QQuickFocusScope { Q_OBJECT public: - TestFocusScope(QQuickItem *parent = 0) : QQuickFocusScope(parent), focused(false) {} + TestFocusScope(QQuickItem *parent = nullptr) : QQuickFocusScope(parent), focused(false) {} bool focused; protected: @@ -183,18 +193,22 @@ private slots: void shortcutOverride(); +#ifdef TEST_QTBUG_60123 + void qtBug60123(); +#endif + private: enum PaintOrderOp { NoOp, Append, Remove, StackBefore, StackAfter, SetZ }; - void ensureFocus(QWindow *w) { + bool ensureFocus(QWindow *w) { if (w->width() <=0 || w->height() <= 0) w->setGeometry(100, 100, 400, 300); w->show(); w->requestActivate(); - QTest::qWaitForWindowActive(w); + return QTest::qWaitForWindowActive(w); } }; @@ -250,7 +264,7 @@ struct FocusData { }; struct FocusState : public QHash<QQuickItem *, FocusData> { - FocusState() : activeFocusItem(0) {} + FocusState() : activeFocusItem(nullptr) {} FocusState &operator<<(QQuickItem *item) { insert(item, FocusData()); return *this; @@ -285,7 +299,7 @@ struct FocusState : public QHash<QQuickItem *, FocusData> void tst_qquickitem::simpleFocus() { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); @@ -324,7 +338,7 @@ void tst_qquickitem::simpleFocus() l1c3->setFocus(false); focusState[l1c3].set(false, false); - focusState.active(0); + focusState.active(nullptr); FVERIFY(); l2c1->setFocus(true); @@ -337,7 +351,7 @@ void tst_qquickitem::simpleFocus() void tst_qquickitem::scopedFocus() { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *l1c1 = new TestItem(window.contentItem()); @@ -417,7 +431,7 @@ void tst_qquickitem::addedToWindow() { { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *item = new TestItem; @@ -437,7 +451,7 @@ void tst_qquickitem::addedToWindow() { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *item = new TestItem(window.contentItem()); @@ -466,7 +480,7 @@ void tst_qquickitem::addedToWindow() { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *tree = new TestItem; @@ -490,7 +504,7 @@ void tst_qquickitem::addedToWindow() { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *tree = new TestFocusScope; QQuickItem *c1 = new TestItem(tree); @@ -518,7 +532,7 @@ void tst_qquickitem::addedToWindow() { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *tree = new TestFocusScope; QQuickItem *c1 = new TestItem(tree); @@ -544,7 +558,7 @@ void tst_qquickitem::addedToWindow() { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *child = new TestItem(window.contentItem()); QQuickItem *tree = new TestFocusScope; @@ -584,7 +598,7 @@ void tst_qquickitem::changeParent() // Parent to no parent { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *child = new TestItem(window.contentItem()); @@ -597,16 +611,16 @@ void tst_qquickitem::changeParent() focusState.active(child); FVERIFY(); - child->setParentItem(0); + child->setParentItem(nullptr); focusState[child].set(true, false); - focusState.active(0); + focusState.active(nullptr); FVERIFY(); } // Different parent, same focus scope { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *child = new TestItem(window.contentItem()); QQuickItem *child2 = new TestItem(window.contentItem()); @@ -627,7 +641,7 @@ void tst_qquickitem::changeParent() // Different parent, different focus scope { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *child = new TestItem(window.contentItem()); QQuickItem *child2 = new TestFocusScope(window.contentItem()); @@ -644,12 +658,12 @@ void tst_qquickitem::changeParent() item->setParentItem(child2); focusState[item].set(true, false); - focusState.active(0); + focusState.active(nullptr); FVERIFY(); } { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *child = new TestItem(window.contentItem()); QQuickItem *child2 = new TestFocusScope(window.contentItem()); @@ -661,7 +675,7 @@ void tst_qquickitem::changeParent() item->setFocus(true); focusState[item].set(true, false); - focusState.active(0); + focusState.active(nullptr); FVERIFY(); item->setParentItem(child); @@ -671,7 +685,7 @@ void tst_qquickitem::changeParent() } { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *child = new TestItem(window.contentItem()); QQuickItem *child2 = new TestFocusScope(window.contentItem()); @@ -697,7 +711,7 @@ void tst_qquickitem::changeParent() // child is deleted, then its parent changes again to a valid parent { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem *item = new TestFocusScope(window.contentItem()); QQuickItem *child = new TestItem(item); @@ -714,10 +728,10 @@ void tst_qquickitem::changeParent() focusState.active(child); FVERIFY(); - item->setParentItem(0); + item->setParentItem(nullptr); focusState[child].set(true, false); focusState[item].set(true, false); - focusState.active(0); + focusState.active(nullptr); FVERIFY(); focusState.remove(child); @@ -736,7 +750,7 @@ void tst_qquickitem::multipleFocusClears() QQuickView view; view.setSource(testFileUrl("multipleFocusClears.qml")); view.show(); - ensureFocus(&view); + QVERIFY(ensureFocus(&view)); QTRY_COMPARE(QGuiApplication::focusWindow(), &view); } @@ -745,7 +759,7 @@ void tst_qquickitem::focusSubItemInNonFocusScope() QQuickView view; view.setSource(testFileUrl("focusSubItemInNonFocusScope.qml")); view.show(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickItem *dummyItem = view.rootObject()->findChild<QQuickItem *>("dummyItem"); QVERIFY(dummyItem); @@ -767,7 +781,7 @@ void tst_qquickitem::focusSubItemInNonFocusScope() void tst_qquickitem::parentItemWithFocus() { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); { QQuickItem parent; @@ -866,7 +880,7 @@ void tst_qquickitem::parentItemWithFocus() void tst_qquickitem::reparentFocusedItem() { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QTRY_COMPARE(QGuiApplication::focusWindow(), &window); QQuickItem parent(window.contentItem()); @@ -937,7 +951,7 @@ void tst_qquickitem::setParentItem() QCOMPARE(root->childItems().at(0), child1); QCOMPARE(root->childItems().at(1), child2); - child1->setParentItem(0); + child1->setParentItem(nullptr); QVERIFY(!child1->parent()); QVERIFY(!child1->parentItem()); QCOMPARE(root->childItems().count(), 1); @@ -1033,7 +1047,7 @@ void tst_qquickitem::enabled() void tst_qquickitem::enabledFocus() { QQuickWindow window; - ensureFocus(&window); + QVERIFY(ensureFocus(&window)); QQuickFocusScope root; @@ -1224,56 +1238,56 @@ void tst_qquickitem::mouseGrab() child2->setSize(QSizeF(200, 100)); child2->setParentItem(window.contentItem()); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50,50)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); QTest::qWait(100); QVERIFY2(window.mouseGrabberItem() == child1.data(), msgItem(window.mouseGrabberItem()).constData()); QTest::qWait(100); QCOMPARE(child1->pressCount, 1); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50,50)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); QTest::qWait(50); - QVERIFY2(window.mouseGrabberItem() == 0, msgItem(window.mouseGrabberItem()).constData()); + QVERIFY2(window.mouseGrabberItem() == nullptr, msgItem(window.mouseGrabberItem()).constData()); QCOMPARE(child1->releaseCount, 1); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50,50)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); QTest::qWait(50); QVERIFY2(window.mouseGrabberItem() == child1.data(), msgItem(window.mouseGrabberItem()).constData()); QCOMPARE(child1->pressCount, 2); child1->setEnabled(false); - QVERIFY2(window.mouseGrabberItem() == 0, msgItem(window.mouseGrabberItem()).constData()); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50,50)); + QVERIFY2(window.mouseGrabberItem() == nullptr, msgItem(window.mouseGrabberItem()).constData()); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); QTest::qWait(50); QCOMPARE(child1->releaseCount, 1); child1->setEnabled(true); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50,50)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); QTest::qWait(50); QVERIFY2(window.mouseGrabberItem() == child1.data(), msgItem(window.mouseGrabberItem()).constData()); QCOMPARE(child1->pressCount, 3); child1->setVisible(false); - QVERIFY2(window.mouseGrabberItem() == 0, msgItem(window.mouseGrabberItem())); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50,50)); + QVERIFY2(window.mouseGrabberItem() == nullptr, msgItem(window.mouseGrabberItem())); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); QCOMPARE(child1->releaseCount, 1); child1->setVisible(true); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50,50)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); QTest::qWait(50); QVERIFY2(window.mouseGrabberItem() == child1.data(), msgItem(window.mouseGrabberItem()).constData()); QCOMPARE(child1->pressCount, 4); child2->grabMouse(); QVERIFY2(window.mouseGrabberItem() == child2.data(), msgItem(window.mouseGrabberItem()).constData()); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50,50)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); QTest::qWait(50); QCOMPARE(child1->releaseCount, 1); QCOMPARE(child2->releaseCount, 1); child2->grabMouse(); QVERIFY2(window.mouseGrabberItem() == child2.data(), msgItem(window.mouseGrabberItem()).constData()); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50,50)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); QTest::qWait(50); QCOMPARE(child1->pressCount, 4); QCOMPARE(child2->pressCount, 1); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50,50)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); QTest::qWait(50); QCOMPARE(child1->releaseCount, 1); QCOMPARE(child2->releaseCount, 2); @@ -1294,14 +1308,14 @@ void tst_qquickitem::touchEventAcceptIgnore() TestWindow window; window.resize(100, 100); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); QScopedPointer<TestItem> item(new TestItem); item->setSize(QSizeF(100, 100)); item->setParentItem(window.contentItem()); item->acceptIncomingTouchEvents = itemSupportsTouch; - static QTouchDevice* device = 0; + static QTouchDevice* device = nullptr; if (!device) { device =new QTouchDevice; device->setType(QTouchDevice::TouchScreen); @@ -1405,7 +1419,7 @@ void tst_qquickitem::polishOnCompleted() QQuickView view; view.setSource(testFileUrl("polishOnCompleted.qml")); view.show(); - QTest::qWaitForWindowExposed(&view); + QVERIFY(QTest::qWaitForWindowExposed(&view)); TestPolishItem *item = qobject_cast<TestPolishItem*>(view.rootObject()); QVERIFY(item); @@ -1437,7 +1451,7 @@ void tst_qquickitem::wheelEvent() QQuickWindow window; window.resize(width, height); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); TestItem *item = new TestItem; item->setSize(QSizeF(width, height)); @@ -1469,7 +1483,7 @@ class HoverItem : public QQuickItem { Q_OBJECT public: - HoverItem(QQuickItem *parent = 0) + HoverItem(QQuickItem *parent = nullptr) : QQuickItem(parent), hoverEnterCount(0), hoverMoveCount(0), hoverLeaveCount(0) { } void resetCounters() { @@ -1515,7 +1529,7 @@ void tst_qquickitem::hoverEvent_data() // ### For some unknown reason QTest::mouseMove() isn't working correctly. static void sendMouseMove(QObject *object, const QPoint &position) { - QMouseEvent moveEvent(QEvent::MouseMove, position, Qt::NoButton, Qt::NoButton, 0); + QMouseEvent moveEvent(QEvent::MouseMove, position, Qt::NoButton, Qt::NoButton, nullptr); QGuiApplication::sendEvent(object, &moveEvent); } @@ -1731,54 +1745,54 @@ void tst_qquickitem::acceptedMouseButtons() item.setSize(QSizeF(200,100)); item.setParentItem(window.contentItem()); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50, 50)); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); QCOMPARE(item.pressCount, 0); QCOMPARE(item.releaseCount, 0); - QTest::mousePress(&window, Qt::RightButton, 0, QPoint(50, 50)); - QTest::mouseRelease(&window, Qt::RightButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::RightButton, Qt::NoModifier, QPoint(50, 50)); + QTest::mouseRelease(&window, Qt::RightButton, Qt::NoModifier, QPoint(50, 50)); QCOMPARE(item.pressCount, 0); QCOMPARE(item.releaseCount, 0); - QTest::mousePress(&window, Qt::MiddleButton, 0, QPoint(50, 50)); - QTest::mouseRelease(&window, Qt::MiddleButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::MiddleButton, Qt::NoModifier, QPoint(50, 50)); + QTest::mouseRelease(&window, Qt::MiddleButton, Qt::NoModifier, QPoint(50, 50)); QCOMPARE(item.pressCount, 0); QCOMPARE(item.releaseCount, 0); item.setAcceptedMouseButtons(Qt::LeftButton); QCOMPARE(item.acceptedMouseButtons(), Qt::MouseButtons(Qt::LeftButton)); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50, 50)); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); QCOMPARE(item.pressCount, 1); QCOMPARE(item.releaseCount, 1); - QTest::mousePress(&window, Qt::RightButton, 0, QPoint(50, 50)); - QTest::mouseRelease(&window, Qt::RightButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::RightButton, Qt::NoModifier, QPoint(50, 50)); + QTest::mouseRelease(&window, Qt::RightButton, Qt::NoModifier, QPoint(50, 50)); QCOMPARE(item.pressCount, 1); QCOMPARE(item.releaseCount, 1); - QTest::mousePress(&window, Qt::MiddleButton, 0, QPoint(50, 50)); - QTest::mouseRelease(&window, Qt::MiddleButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::MiddleButton, Qt::NoModifier, QPoint(50, 50)); + QTest::mouseRelease(&window, Qt::MiddleButton, Qt::NoModifier, QPoint(50, 50)); QCOMPARE(item.pressCount, 1); QCOMPARE(item.releaseCount, 1); item.setAcceptedMouseButtons(Qt::RightButton | Qt::MiddleButton); QCOMPARE(item.acceptedMouseButtons(), Qt::MouseButtons(Qt::RightButton | Qt::MiddleButton)); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50, 50)); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); QCOMPARE(item.pressCount, 1); QCOMPARE(item.releaseCount, 1); - QTest::mousePress(&window, Qt::RightButton, 0, QPoint(50, 50)); - QTest::mouseRelease(&window, Qt::RightButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::RightButton, Qt::NoModifier, QPoint(50, 50)); + QTest::mouseRelease(&window, Qt::RightButton, Qt::NoModifier, QPoint(50, 50)); QCOMPARE(item.pressCount, 2); QCOMPARE(item.releaseCount, 2); - QTest::mousePress(&window, Qt::MiddleButton, 0, QPoint(50, 50)); - QTest::mouseRelease(&window, Qt::MiddleButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::MiddleButton, Qt::NoModifier, QPoint(50, 50)); + QTest::mouseRelease(&window, Qt::MiddleButton, Qt::NoModifier, QPoint(50, 50)); QCOMPARE(item.pressCount, 3); QCOMPARE(item.releaseCount, 3); } @@ -1786,7 +1800,7 @@ void tst_qquickitem::acceptedMouseButtons() static void gc(QQmlEngine &engine) { engine.collectGarbage(); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QCoreApplication::processEvents(); } @@ -1812,7 +1826,7 @@ void tst_qquickitem::visualParentOwnership() gc(engine); QVERIFY(!newItem.isNull()); - newItem->setParentItem(0); + newItem->setParentItem(nullptr); gc(engine); QVERIFY(newItem.isNull()); @@ -1869,7 +1883,7 @@ void tst_qquickitem::visualParentOwnershipWindow() gc(engine); QVERIFY(!newItem.isNull()); - newItem->setParentItem(0); + newItem->setParentItem(nullptr); gc(engine); QVERIFY(newItem.isNull()); @@ -2045,10 +2059,10 @@ void tst_qquickitem::ignoreButtonPressNotInAcceptedMouseButtons() item.setAcceptedMouseButtons(Qt::LeftButton); QCOMPARE(item.acceptedMouseButtons(), Qt::MouseButtons(Qt::LeftButton)); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50, 50)); - QTest::mousePress(&window, Qt::RightButton, 0, QPoint(50, 50)); // ignored because it's not LeftButton - QTest::mouseRelease(&window, Qt::RightButton, 0, QPoint(50, 50)); // ignored because it didn't grab the RightButton press - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); + QTest::mousePress(&window, Qt::RightButton, Qt::NoModifier, QPoint(50, 50)); // ignored because it's not LeftButton + QTest::mouseRelease(&window, Qt::RightButton, Qt::NoModifier, QPoint(50, 50)); // ignored because it didn't grab the RightButton press + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); QCOMPARE(item.pressCount, 1); QCOMPARE(item.releaseCount, 1); @@ -2058,7 +2072,7 @@ void tst_qquickitem::shortcutOverride() { QQuickView view; view.setSource(testFileUrl("shortcutOverride.qml")); - ensureFocus(&view); + QVERIFY(ensureFocus(&view)); QCOMPARE(view.rootObject()->property("escapeHandlerActivationCount").toInt(), 0); QCOMPARE(view.rootObject()->property("shortcutActivationCount").toInt(), 0); @@ -2087,6 +2101,51 @@ void tst_qquickitem::shortcutOverride() QCOMPARE(view.rootObject()->property("shortcutActivationCount").toInt(), 1); } +#ifdef TEST_QTBUG_60123 +void tst_qquickitem::qtBug60123() +{ + QMainWindow main; + main.resize(400, 200); + + QQuickView window; + QQuickView window2; + window.setSource(testFileUrl("mainWindowQtBug60123.qml")); + window2.setSource(testFileUrl("mainWindowQtBug60123.qml")); + + // Create central widget for the main window + QWidget *baseWidget = new QWidget(&main); + baseWidget->resize(400, 200); + baseWidget->setMaximumHeight(200); + baseWidget->setMaximumWidth(400); + main.setCentralWidget(baseWidget); + + // Create container widgets for both windows + QWidget *containers = QWidget::createWindowContainer(&window, baseWidget); + QWidget *containers2 = QWidget::createWindowContainer(&window2, baseWidget); + containers->setGeometry(0, 0, 100, 100); + containers2->setGeometry(100, 100, 100, 100); + + // Show and activate the main window + main.show(); + QVERIFY(QTest::qWaitForWindowExposed(&main)); + + // Activate window, test press and release events + auto activateWindowAndTestPress = [] (QQuickView* testWindow) { + testWindow->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(testWindow)); + QTest::mousePress(testWindow, Qt::LeftButton, Qt::NoModifier, QPoint(10, 10)); + QCOMPARE(testWindow->rootObject()->property("lastEvent").toString(), QString("pressed")); + QTest::mouseRelease(testWindow, Qt::LeftButton, Qt::NoModifier, QPoint(10, 10)); + QCOMPARE(testWindow->rootObject()->property("lastEvent").toString(), QString("released")); + }; + + // First press after switching focus window resulted in cancelled event + activateWindowAndTestPress(&window); + activateWindowAndTestPress(&window2); + activateWindowAndTestPress(&window); +} +#endif + QTEST_MAIN(tst_qquickitem) #include "tst_qquickitem.moc" diff --git a/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop.qml b/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop.qml new file mode 100644 index 0000000000..889e480f3b --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop.qml @@ -0,0 +1,13 @@ +import QtQuick 2.6 + +Item { + visible: true + Item { + visible: false + Item { + objectName: "hiddenChild" + activeFocusOnTab: true + focus: true + } + } +} diff --git a/tests/auto/quick/qquickitem2/data/mapCoordinates.qml b/tests/auto/quick/qquickitem2/data/mapCoordinates.qml index b410b445c5..596dedab90 100644 --- a/tests/auto/quick/qquickitem2/data/mapCoordinates.qml +++ b/tests/auto/quick/qquickitem2/data/mapCoordinates.qml @@ -39,6 +39,11 @@ Item { Item { id: itemB; objectName: "itemB"; x: 100; y: 100 } } + Component { + id: itemComponent + Item { x: 150; y: 150 } + } + function mapAToB(x, y) { var pos = itemA.mapToItem(itemB, x, y) return Qt.point(pos.x, pos.y) @@ -69,6 +74,18 @@ Item { return Qt.point(pos.x, pos.y) } + function mapOrphanToGlobal(x, y) { + var obj = itemComponent.createObject(null); + var pos = obj.mapToGlobal(x, y) + return Qt.point(pos.x, pos.y) + } + + function mapOrphanFromGlobal(x, y) { + var obj = itemComponent.createObject(null); + var pos = obj.mapFromGlobal(x, y) + return Qt.point(pos.x, pos.y) + } + function checkMapAToInvalid(x, y) { try { itemA.mapToItem(1122, x, y) diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp index 09e89ff85f..7107f4d995 100644 --- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp @@ -64,6 +64,7 @@ private slots: void activeFocusOnTab8(); void activeFocusOnTab9(); void activeFocusOnTab10(); + void activeFocusOnTab_infiniteLoop(); void nextItemInFocusChain(); void nextItemInFocusChain2(); @@ -193,7 +194,7 @@ class KeyTestItem : public QQuickItem { Q_OBJECT public: - KeyTestItem(QQuickItem *parent=0) : QQuickItem(parent), mKey(0) {} + KeyTestItem(QQuickItem *parent=nullptr) : QQuickItem(parent), mKey(0) {} protected: void keyPressEvent(QKeyEvent *e) { @@ -240,7 +241,7 @@ class HollowTestItem : public QQuickItem Q_PROPERTY(qreal holeRadius READ holeRadius WRITE setHoleRadius) public: - HollowTestItem(QQuickItem *parent = 0) + HollowTestItem(QQuickItem *parent = nullptr) : QQuickItem(parent), m_isPressed(false), m_isHovered(false), @@ -301,7 +302,7 @@ class TabFenceItem : public QQuickItem Q_OBJECT public: - TabFenceItem(QQuickItem *parent = Q_NULLPTR) + TabFenceItem(QQuickItem *parent = nullptr) : QQuickItem(parent) { QQuickItemPrivate *d = QQuickItemPrivate::get(this); @@ -316,7 +317,7 @@ class TabFenceItem2 : public QQuickItem Q_OBJECT public: - TabFenceItem2(QQuickItem *parent = Q_NULLPTR) + TabFenceItem2(QQuickItem *parent = nullptr) : QQuickItem(parent) { QQuickItemPrivate *d = QQuickItemPrivate::get(this); @@ -343,7 +344,7 @@ void tst_QQuickItem::initTestCase() void tst_QQuickItem::cleanup() { QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); - inputMethodPrivate->testContext = 0; + inputMethodPrivate->testContext = nullptr; } void tst_QQuickItem::activeFocusOnTab() @@ -351,7 +352,7 @@ void tst_QQuickItem::activeFocusOnTab() if (!qt_tab_all_widgets()) QSKIP("This function doesn't support NOT iterating all."); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("activeFocusOnTab.qml")); @@ -463,7 +464,7 @@ void tst_QQuickItem::activeFocusOnTab2() if (!qt_tab_all_widgets()) QSKIP("This function doesn't support NOT iterating all."); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("activeFocusOnTab.qml")); @@ -503,7 +504,7 @@ void tst_QQuickItem::activeFocusOnTab3() if (!qt_tab_all_widgets()) QSKIP("This function doesn't support NOT iterating all."); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("activeFocusOnTab3.qml")); @@ -685,7 +686,7 @@ void tst_QQuickItem::activeFocusOnTab4() if (!qt_tab_all_widgets()) QSKIP("This function doesn't support NOT iterating all."); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("activeFocusOnTab4.qml")); @@ -717,7 +718,7 @@ void tst_QQuickItem::activeFocusOnTab5() if (!qt_tab_all_widgets()) QSKIP("This function doesn't support NOT iterating all."); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("activeFocusOnTab4.qml")); @@ -751,7 +752,7 @@ void tst_QQuickItem::activeFocusOnTab6() if (qt_tab_all_widgets()) QSKIP("This function doesn't support iterating all."); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("activeFocusOnTab6.qml")); @@ -809,7 +810,7 @@ void tst_QQuickItem::activeFocusOnTab7() if (qt_tab_all_widgets()) QSKIP("This function doesn't support iterating all."); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(300,300)); window->setSource(testFileUrl("activeFocusOnTab7.qml")); @@ -842,7 +843,7 @@ void tst_QQuickItem::activeFocusOnTab7() void tst_QQuickItem::activeFocusOnTab8() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(300,300)); window->setSource(testFileUrl("activeFocusOnTab8.qml")); @@ -894,7 +895,7 @@ void tst_QQuickItem::activeFocusOnTab9() if (qt_tab_all_widgets()) QSKIP("This function doesn't support iterating all."); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(300,300)); window->setSource(testFileUrl("activeFocusOnTab9.qml")); @@ -945,7 +946,7 @@ void tst_QQuickItem::activeFocusOnTab10() if (!qt_tab_all_widgets()) QSKIP("This function doesn't support NOT iterating all."); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(300,300)); window->setSource(testFileUrl("activeFocusOnTab9.qml")); @@ -1023,12 +1024,28 @@ void tst_QQuickItem::activeFocusOnTab10() delete window; } +void tst_QQuickItem::activeFocusOnTab_infiniteLoop() +{ + // see QTBUG-68271 + // create a window where the currently focused item is not visible + QScopedPointer<QQuickView>window(new QQuickView()); + window->setSource(testFileUrl("activeFocusOnTab_infiniteLoop.qml")); + window->show(); + auto *hiddenChild = findItem<QQuickItem>(window->rootObject(), "hiddenChild"); + QVERIFY(hiddenChild); + + // move the focus - this used to result in an infinite loop + auto *item = hiddenChild->nextItemInFocusChain(); + // focus is moved to the root object since there is no other candidate + QCOMPARE(item, window->rootObject()); +} + void tst_QQuickItem::nextItemInFocusChain() { if (!qt_tab_all_widgets()) QSKIP("This function doesn't support NOT iterating all."); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("activeFocusOnTab.qml")); @@ -1104,7 +1121,7 @@ void tst_QQuickItem::nextItemInFocusChain2() if (qt_tab_all_widgets()) QSKIP("This function doesn't support iterating all."); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("activeFocusOnTab6.qml")); @@ -1149,7 +1166,7 @@ void tst_QQuickItem::nextItemInFocusChain2() void tst_QQuickItem::nextItemInFocusChain3() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("nextItemInFocusChain3.qml")); @@ -1177,7 +1194,7 @@ void verifyTabFocusChain(QQuickView *window, const char **focusChain, bool forwa void tst_QQuickItem::tabFence() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("tabFence.qml")); @@ -1188,12 +1205,12 @@ void tst_QQuickItem::tabFence() QVERIFY(window->rootObject()->hasActiveFocus()); const char *rootTabFocusChain[] = { - "input1", "input2", "input3", "input1", Q_NULLPTR + "input1", "input2", "input3", "input1", nullptr }; verifyTabFocusChain(window, rootTabFocusChain, true /* forward */); const char *rootBacktabFocusChain[] = { - "input3", "input2", "input1", "input3", Q_NULLPTR + "input3", "input2", "input1", "input3", nullptr }; verifyTabFocusChain(window, rootBacktabFocusChain, false /* forward */); @@ -1204,19 +1221,19 @@ void tst_QQuickItem::tabFence() QVERIFY(item->hasActiveFocus()); const char *fence1TabFocusChain[] = { - "input12", "input13", "input11", "input12", Q_NULLPTR + "input12", "input13", "input11", "input12", nullptr }; verifyTabFocusChain(window, fence1TabFocusChain, true /* forward */); const char *fence1BacktabFocusChain[] = { - "input11", "input13", "input12", "input11", Q_NULLPTR + "input11", "input13", "input12", "input11", nullptr }; verifyTabFocusChain(window, fence1BacktabFocusChain, false /* forward */); } void tst_QQuickItem::qtbug_50516() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("qtbug_50516.qml")); @@ -1261,7 +1278,7 @@ void tst_QQuickItem::qtbug_50516_2() QFETCH(QString, item1); QFETCH(QString, item2); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl(filename)); @@ -1282,7 +1299,7 @@ void tst_QQuickItem::qtbug_50516_2() void tst_QQuickItem::keys() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(240,320)); KeysTestObject *testObject = new KeysTestObject; @@ -1471,7 +1488,7 @@ void tst_QQuickItem::standardKeys() void tst_QQuickItem::keysProcessingOrder() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(240,320)); KeysTestObject *testObject = new KeysTestObject; @@ -1532,7 +1549,7 @@ void tst_QQuickItem::keysim() QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); inputMethodPrivate->testContext = &platformInputContext; - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(240,320)); window->setSource(testFileUrl("keysim.qml")); @@ -1650,7 +1667,7 @@ bool anchorsMirrored(QQuickItem *rootItem, const char * itemString) void tst_QQuickItem::layoutMirroring() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("layoutmirroring.qml")); window->show(); @@ -1801,7 +1818,7 @@ void tst_QQuickItem::layoutMirroringIllegalParent() component.setData("import QtQuick 2.0; QtObject { LayoutMirroring.enabled: true; LayoutMirroring.childrenInherit: true }", QUrl::fromLocalFile("")); QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1:21: QML QtObject: LayoutDirection attached property only works with Items and Windows"); QObject *object = component.create(); - QVERIFY(object != 0); + QVERIFY(object != nullptr); } void tst_QQuickItem::keyNavigation_data() @@ -1815,7 +1832,7 @@ void tst_QQuickItem::keyNavigation() { QFETCH(QString, source); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(240,320)); window->setSource(testFileUrl(source)); @@ -1892,7 +1909,7 @@ void tst_QQuickItem::keyNavigation() void tst_QQuickItem::keyNavigation_RightToLeft() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(240,320)); window->setSource(testFileUrl("keynavigationtest.qml")); @@ -1947,7 +1964,7 @@ void tst_QQuickItem::keyNavigation_RightToLeft() void tst_QQuickItem::keyNavigation_skipNotVisible() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(240,320)); window->setSource(testFileUrl("keynavigationtest.qml")); @@ -2022,7 +2039,7 @@ void tst_QQuickItem::keyNavigation_skipNotVisible() void tst_QQuickItem::keyNavigation_implicitSetting() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(240,320)); window->setSource(testFileUrl("keynavigationtest_implicit.qml")); @@ -2149,7 +2166,7 @@ void tst_QQuickItem::keyNavigation_implicitSetting() void tst_QQuickItem::keyNavigation_focusReason() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(240,320)); FocusEventFilter focusEventFilter; @@ -2210,7 +2227,7 @@ void tst_QQuickItem::keyNavigation_focusReason() void tst_QQuickItem::keyNavigation_loop() { // QTBUG-47229 - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(240,320)); window->setSource(testFileUrl("keynavigationtest_loop.qml")); @@ -2325,18 +2342,18 @@ void tst_QQuickItem::mapCoordinates() QFETCH(int, x); QFETCH(int, y); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(300, 300)); window->setSource(testFileUrl("mapCoordinates.qml")); window->show(); qApp->processEvents(); QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QQuickItem *a = findItem<QQuickItem>(window->rootObject(), "itemA"); - QVERIFY(a != 0); + QVERIFY(a != nullptr); QQuickItem *b = findItem<QQuickItem>(window->rootObject(), "itemB"); - QVERIFY(b != 0); + QVERIFY(b != nullptr); QVariant result; @@ -2364,6 +2381,16 @@ void tst_QQuickItem::mapCoordinates() Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromGlobal(QPointF(x, y))); + // for orphans we are primarily testing that we don't crash. + // when orphaned the final position is the original position of the item translated by x,y + QVERIFY(QMetaObject::invokeMethod(root, "mapOrphanToGlobal", + Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); + QCOMPARE(result.value<QPointF>(), QPointF(150,150) + QPointF(x, y)); + + QVERIFY(QMetaObject::invokeMethod(root, "mapOrphanFromGlobal", + Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y))); + QCOMPARE(result.value<QPointF>(), -QPointF(150,150) + QPointF(x, y)); + QString warning1 = testFileUrl("mapCoordinates.qml").toString() + ":35:5: QML Item: mapToItem() given argument \"1122\" which is neither null nor an Item"; QString warning2 = testFileUrl("mapCoordinates.qml").toString() + ":35:5: QML Item: mapFromItem() given argument \"1122\" which is neither null nor an Item"; @@ -2396,18 +2423,18 @@ void tst_QQuickItem::mapCoordinatesRect() QFETCH(int, width); QFETCH(int, height); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(300, 300)); window->setSource(testFileUrl("mapCoordinatesRect.qml")); window->show(); qApp->processEvents(); QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QQuickItem *a = findItem<QQuickItem>(window->rootObject(), "itemA"); - QVERIFY(a != 0); + QVERIFY(a != nullptr); QQuickItem *b = findItem<QQuickItem>(window->rootObject(), "itemB"); - QVERIFY(b != 0); + QVERIFY(b != nullptr); QVariant result; @@ -2478,7 +2505,7 @@ void tst_QQuickItem::transforms() component.setData("import QtQuick 2.3\nItem { transform: "+qml+"}", QUrl::fromLocalFile("")); QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); QVERIFY(item); - QCOMPARE(item->itemTransform(0,0), transform); + QCOMPARE(item->itemTransform(nullptr,nullptr), transform); } void tst_QQuickItem::childrenProperty() @@ -2486,7 +2513,7 @@ void tst_QQuickItem::childrenProperty() QQmlComponent component(&engine, testFileUrl("childrenProperty.qml")); QObject *o = component.create(); - QVERIFY(o != 0); + QVERIFY(o != nullptr); QCOMPARE(o->property("test1").toBool(), true); QCOMPARE(o->property("test2").toBool(), true); @@ -2501,7 +2528,7 @@ void tst_QQuickItem::resourcesProperty() QQmlComponent component(&engine, testFileUrl("resourcesProperty.qml")); QObject *object = component.create(); - QVERIFY(object != 0); + QVERIFY(object != nullptr); QQmlProperty property(object, "resources", component.creationContext()); @@ -2533,7 +2560,7 @@ void tst_QQuickItem::resourcesProperty() void tst_QQuickItem::propertyChanges() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(300, 300)); window->setSource(testFileUrl("propertychanges.qml")); window->show(); @@ -2624,7 +2651,7 @@ void tst_QQuickItem::nonexistentPropertyConnection() void tst_QQuickItem::childrenRect() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("childrenRect.qml")); window->setBaseSize(QSize(240,320)); window->show(); @@ -2653,7 +2680,7 @@ void tst_QQuickItem::childrenRect() // QTBUG-11383 void tst_QQuickItem::childrenRectBug() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); QString warning = testFileUrl("childrenRectBug.qml").toString() + ":7:5: QML Item: Binding loop detected for property \"height\""; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); @@ -2674,7 +2701,7 @@ void tst_QQuickItem::childrenRectBug() // QTBUG-11465 void tst_QQuickItem::childrenRectBug2() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); QString warning1 = testFileUrl("childrenRectBug2.qml").toString() + ":7:5: QML Item: Binding loop detected for property \"width\""; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); @@ -2708,7 +2735,7 @@ void tst_QQuickItem::childrenRectBug2() // QTBUG-12722 void tst_QQuickItem::childrenRectBug3() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("childrenRectBug3.qml")); window->show(); @@ -2719,7 +2746,7 @@ void tst_QQuickItem::childrenRectBug3() // QTBUG-38732 void tst_QQuickItem::childrenRectBottomRightCorner() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("childrenRectBottomRightCorner.qml")); window->show(); @@ -2811,7 +2838,7 @@ void tst_QQuickItem::changeListener() { QQuickWindow window; window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); QQuickItem *item = new QQuickItem; TestListener itemListener; @@ -2994,7 +3021,7 @@ void tst_QQuickItem::changeListener() // QTBUG-13893 void tst_QQuickItem::transformCrash() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("transformCrash.qml")); window->show(); @@ -3003,7 +3030,7 @@ void tst_QQuickItem::transformCrash() void tst_QQuickItem::implicitSize() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("implicitsize.qml")); window->show(); @@ -3076,14 +3103,14 @@ void tst_QQuickItem::qtbug_16871() { QQmlComponent component(&engine, testFileUrl("qtbug_16871.qml")); QObject *o = component.create(); - QVERIFY(o != 0); + QVERIFY(o != nullptr); delete o; } void tst_QQuickItem::visibleChildren() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("visiblechildren.qml")); window->show(); @@ -3141,7 +3168,7 @@ void tst_QQuickItem::visibleChildren() void tst_QQuickItem::parentLoop() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); #if QT_CONFIG(regularexpression) QRegularExpression msgRegexp = QRegularExpression("QQuickItem::setParentItem: Parent QQuickItem\\(.*\\) is already part of the subtree of QQuickItem\\(.*\\)"); @@ -3231,7 +3258,7 @@ void tst_QQuickItem::contains() QFETCH(bool, insideTarget); QFETCH(QList<QPoint>, points); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->rootContext()->setContextProperty("circleShapeTest", circleTest); window->setBaseSize(QSize(400, 400)); window->setSource(testFileUrl("hollowTestItem.qml")); @@ -3253,12 +3280,12 @@ void tst_QQuickItem::contains() QCOMPARE(hollowItem->isHovered(), insideTarget); // check mouse press - QTest::mousePress(window, Qt::LeftButton, 0, point); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, point); QTest::qWait(10); QCOMPARE(hollowItem->isPressed(), insideTarget); // check mouse release - QTest::mouseRelease(window, Qt::LeftButton, 0, point); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, point); QTest::qWait(10); QCOMPARE(hollowItem->isPressed(), false); } @@ -3299,16 +3326,20 @@ void tst_QQuickItem::childAt() QCOMPARE(parent.childAt(75, 75), &child2); QCOMPARE(parent.childAt(149, 149), &child2); QCOMPARE(parent.childAt(25, 200), &child3); - QCOMPARE(parent.childAt(0, 150), static_cast<QQuickItem *>(0)); - QCOMPARE(parent.childAt(300, 300), static_cast<QQuickItem *>(0)); + QCOMPARE(parent.childAt(0, 150), static_cast<QQuickItem *>(nullptr)); + QCOMPARE(parent.childAt(300, 300), static_cast<QQuickItem *>(nullptr)); } void tst_QQuickItem::grab() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabToImage not functional on offscreen/minimimal platforms"); + QQuickView view; view.setSource(testFileUrl("grabToImage.qml")); view.show(); - QTest::qWaitForWindowExposed(&view); + QVERIFY(QTest::qWaitForWindowExposed(&view)); QQuickItem *root = qobject_cast<QQuickItem *>(view.rootObject()); QVERIFY(root); diff --git a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp index 5419778cfc..1a289a2087 100644 --- a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp +++ b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp @@ -36,6 +36,9 @@ #include "../../shared/util.h" +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qpa/qplatformintegration.h> + class tst_QQuickItemLayer: public QQmlDataTest { Q_OBJECT @@ -54,7 +57,7 @@ public: } private slots: - void initTestCase() Q_DECL_OVERRIDE; + void initTestCase() override; void layerEnabled(); void layerSmooth(); #if QT_CONFIG(opengl) @@ -86,55 +89,52 @@ private slots: private: void mirroringCheck(int mirroring, int x, bool shouldMirror, const QImage &fb); - bool m_isMesaSoftwareRasterizer; - int m_mesaVersion; - bool m_isOpenGLRenderer; + bool m_isMesaSoftwareRasterizer = false; + int m_mesaVersion = 0; + bool m_isOpenGLRenderer = true; }; -tst_QQuickItemLayer::tst_QQuickItemLayer() - : m_isMesaSoftwareRasterizer(false) - , m_mesaVersion(0) - , m_isOpenGLRenderer(true) -{ -} +tst_QQuickItemLayer::tst_QQuickItemLayer() { } void tst_QQuickItemLayer::initTestCase() { QQmlDataTest::initTestCase(); #if QT_CONFIG(opengl) - QWindow window; - QOpenGLContext context; - window.setSurfaceType(QWindow::OpenGLSurface); - window.create(); - QVERIFY(context.create()); - QVERIFY(context.makeCurrent(&window)); - const char *vendor = (const char *)context.functions()->glGetString(GL_VENDOR); - const char *renderer = (const char *)context.functions()->glGetString(GL_RENDERER); - m_isMesaSoftwareRasterizer = strcmp(vendor, "Mesa Project") == 0 - && strcmp(renderer, "Software Rasterizer") == 0; - if (m_isMesaSoftwareRasterizer) { - // Expects format: <OpenGL version> Mesa <Mesa version>[-devel] [...] - const char *version = (const char *)context.functions()->glGetString(GL_VERSION); - QList<QByteArray> list = QByteArray(version).split(' '); - if (list.size() >= 3) { - list = list.at(2).split('-').at(0).split('.'); - int major = 0; - int minor = 0; - int patch = 0; - if (list.size() >= 1) - major = list.at(0).toInt(); - if (list.size() >= 2) - minor = list.at(1).toInt(); - if (list.size() >= 3) - patch = list.at(2).toInt(); - m_mesaVersion = QT_VERSION_CHECK(major, minor, patch); + if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { + QWindow window; + QOpenGLContext context; + window.setSurfaceType(QWindow::OpenGLSurface); + window.create(); + QVERIFY(context.create()); + QVERIFY(context.makeCurrent(&window)); + const char *vendor = (const char *)context.functions()->glGetString(GL_VENDOR); + const char *renderer = (const char *)context.functions()->glGetString(GL_RENDERER); + m_isMesaSoftwareRasterizer = strcmp(vendor, "Mesa Project") == 0 + && strcmp(renderer, "Software Rasterizer") == 0; + if (m_isMesaSoftwareRasterizer) { + // Expects format: <OpenGL version> Mesa <Mesa version>[-devel] [...] + const char *version = (const char *)context.functions()->glGetString(GL_VERSION); + QList<QByteArray> list = QByteArray(version).split(' '); + if (list.size() >= 3) { + list = list.at(2).split('-').at(0).split('.'); + int major = 0; + int minor = 0; + int patch = 0; + if (list.size() >= 1) + major = list.at(0).toInt(); + if (list.size() >= 2) + minor = list.at(1).toInt(); + if (list.size() >= 3) + patch = list.at(2).toInt(); + m_mesaVersion = QT_VERSION_CHECK(major, minor, patch); + } } + window.create(); } - window.create(); #endif QQuickView view; view.showNormal(); - QTest::qWaitForWindowExposed(&view); + QVERIFY(QTest::qWaitForWindowExposed(&view)); if (view.rendererInterface()->graphicsApi() != QSGRendererInterface::OpenGL) m_isOpenGLRenderer = false; } @@ -147,6 +147,11 @@ void tst_QQuickItemLayer::layerSmooth() { if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("Smooth.qml"); QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); QCOMPARE(fb.pixel(fb.width() - 1, 0), qRgb(0, 0, 0xff)); @@ -166,6 +171,11 @@ void tst_QQuickItemLayer::layerEnabled() { if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("Enabled.qml"); // Verify the banding QCOMPARE(fb.pixel(0, 0), fb.pixel(0, 1)); @@ -181,6 +191,7 @@ void tst_QQuickItemLayer::layerMipmap() { if (m_isMesaSoftwareRasterizer) QSKIP("Mipmapping does not work with the Mesa Software Rasterizer."); + QImage fb = runTest("Mipmap.qml"); QVERIFY(fb.pixel(0, 0) != 0xff000000); QVERIFY(fb.pixel(0, 0) != 0xffffffff); @@ -195,6 +206,11 @@ void tst_QQuickItemLayer::layerEffect() { if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("Effect.qml"); QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); QCOMPARE(fb.pixel(fb.width() - 1, 0), qRgb(0, 0xff, 0)); @@ -286,7 +302,7 @@ void tst_QQuickItemLayer::layerVisibility() view.show(); - QTest::qWaitForWindowExposed(&view); + QVERIFY(QTest::qWaitForWindowExposed(&view)); QImage fb = view.grabWindow(); uint pixel = fb.pixel(0, 0); @@ -451,6 +467,10 @@ void tst_QQuickItemLayer::itemEffect() void tst_QQuickItemLayer::rectangleEffect() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("RectangleEffect.qml"); QCOMPARE(fb.pixel(0, 0), qRgb(0, 0xff, 0)); QCOMPARE(fb.pixel(199, 0), qRgb(0, 0xff, 0)); @@ -488,7 +508,7 @@ void tst_QQuickItemLayer::textureMirroring() view.show(); - QTest::qWaitForWindowExposed(&view); + QVERIFY(QTest::qWaitForWindowExposed(&view)); QImage fb = view.grabWindow(); diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml index 22205c18f0..b72bc60835 100644 --- a/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml +++ b/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml index 248652e82b..364e2cc9b2 100644 --- a/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml +++ b/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml index ff7ce6221b..f6c1199218 100644 --- a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml +++ b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are @@ -47,7 +57,6 @@ Container { Text { objectName: "qtbug51927-text" text: qsTr("Hello World") - anchors.centerIn: parent renderType: Text.QtRendering } } diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml index 9def782d4a..7439fe00e9 100644 --- a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml +++ b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml new file mode 100644 index 0000000000..39500cc19d --- /dev/null +++ b/tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Layouts 1.3 + +Rectangle { + width: 100 + height: 100 + color: "black" + + property alias layout: layout + property alias item1: r1 + + RowLayout { + id: layout + anchors.fill: parent + visible: false + spacing: 0 + + Rectangle { + id: r1 + color: "red" + + layer.enabled: true + + Layout.fillWidth: true + Layout.fillHeight: true + } + } +} diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml index 4346c5283e..07af6a77ac 100644 --- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml +++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml @@ -68,6 +68,66 @@ Item { return [item.x, item.y, item.width, item.height]; } + Component { + id: itemsWithAnchorsLayout_Component + RowLayout { + spacing: 2 + Item { + anchors.fill: parent + implicitWidth: 10 + implicitHeight: 10 + } + Item { + anchors.centerIn: parent + implicitWidth: 10 + implicitHeight: 10 + } + Item { + anchors.left: parent.left + implicitWidth: 10 + implicitHeight: 10 + } + Item { + anchors.right: parent.right + implicitWidth: 10 + implicitHeight: 10 + } + Item { + anchors.top: parent.top + implicitWidth: 10 + implicitHeight: 10 + } + Item { + anchors.bottom: parent.bottom + implicitWidth: 10 + implicitHeight: 10 + } + Item { + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + implicitWidth: 10 + implicitHeight: 10 + } + Item { + anchors.margins: 42 // although silly, it should not cause a warning from the Layouts POV + implicitWidth: 10 + implicitHeight: 10 + } + } + } + + function test_warnAboutLayoutItemsWithAnchors() + { + var fullPath = Qt.resolvedUrl("tst_rowlayout.qml") + for (var i = 0; i < 7; ++i) { + ignoreWarning(fullPath + ":" + (75 + 5*i) +":17: QML Item: Detected anchors on an item that is managed by a layout. " + + "This is undefined behavior; use Layout.alignment instead.") + } + var layout = itemsWithAnchorsLayout_Component.createObject(container) + waitForRendering(layout) + layout.destroy() + } + function test_fixedAndExpanding() { var test_layoutStr = 'import QtQuick 2.2; \ @@ -263,6 +323,41 @@ Item { col.destroy() } + function test_dynamicSizeAdaptationsForInitiallyInvisibleItemsInLayout() { + var test_layoutStr = + 'import QtQuick 2.2; \ + import QtQuick.Layouts 1.0; \ + RowLayout { \ + id: row; \ + width: 10; \ + spacing: 0; \ + property alias r1: _r1; \ + Rectangle { \ + id: _r1; \ + visible: false; \ + height: 10; \ + Layout.fillWidth: true; \ + color: "#8080ff"; \ + } \ + property alias r2: _r2; \ + Rectangle { \ + id: _r2; \ + height: 10; \ + Layout.fillWidth: true; \ + color: "#c0c0ff"; \ + } \ + } ' + + var lay = Qt.createQmlObject(test_layoutStr, container, ''); + compare(lay.r1.width, 0) + compare(lay.r2.width, 10) + lay.r1.visible = true; + waitForRendering(lay) + compare(lay.r1.width, 5) + compare(lay.r2.width, 5) + lay.destroy() + } + Component { id: layoutItem_Component Rectangle { @@ -475,6 +570,23 @@ Item { { tag: "expandPrefToExplicitMin", layoutHints: [24, -1, -1], childHints: [11, 21, 31], expected:[24, 24, 31]}, { tag: "boundPrefToExplicitMax", layoutHints: [-1, -1, 19], childHints: [11, 21, 31], expected:[11, 19, 19]}, { tag: "boundAllToExplicitMax", layoutHints: [-1, -1, 9], childHints: [11, 21, 31], expected:[ 9, 9, 9]}, + + /** + * Test how fractional size hint values are rounded. Some hints are ceiled towards the closest integer. + * Note some of these tests are not authorative, but are here to demonstrate current behavior. + * To summarize, it seems to be: + * - min: always ceiled + * - pref: Ceils only implicit (!) hints. Might also be ceiled if explicit + preferred size is less than implicit minimum size, but that's just a + side-effect of that preferred should never be less than minimum. + (tag "ceilShrinkMinToPref" below) + * - max: never ceiled + */ + { tag: "ceilImplicitMin", layoutHints: [ -1, -1, -1], childHints: [ .1, 1.1, 9.1], expected:[ 1, 2, 9.1]}, + { tag: "ceilExplicitMin", layoutHints: [1.1, -1, -1], childHints: [ .1, 2.1, 9.1], expected:[ 2, 3, 9.1]}, + { tag: "ceilImplicitMin2", layoutHints: [ -1, 4.1, -1], childHints: [ .1, 1.1, 9.1], expected:[ 1, 4.1, 9.1]}, + { tag: "ceilShrinkMinToPref", layoutHints: [ -1, 2.1, -1], childHints: [ 5, 6.1, 8.1], expected:[ 3, 3, 8.1]}, + { tag: "ceilExpandMaxToPref", layoutHints: [ -1, 6.1, -1], childHints: [1.1, 3.1, 3.1], expected:[ 2, 6.1, 6.1]}, ]; } @@ -917,6 +1029,7 @@ Item { fixed.implicitWidth = 100 waitForRendering(layout) + wait(0); // Trigger processEvents() (allow LayoutRequest to be processed) compare(itemRect(fixed), [0,0,100,20]) compare(itemRect(filler), [100,0,100,20]) } @@ -969,5 +1082,23 @@ Item { // Shouldn't crash upon destroying containerUser. } + + /* + Tests that a layout-managed item that sets layer.enabled to true + still renders something. This is a simpler test case that only + reproduces the issue when the layout that manages it is made visible + after component completion, but QTBUG-63269 has a more complex example + where this (setting visible to true afterwards) isn't necessary. + */ + function test_layerEnabled() { + var component = Qt.createComponent("rowlayout/LayerEnabled.qml"); + compare(component.status, Component.Ready); + + var rootRect = createTemporaryObject(component, container); + verify(rootRect); + rootRect.layout.visible = true; + waitForRendering(rootRect.layout) + compare(rootRect.item1.width, 100) + } } } diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST index d259c11219..e22d52294f 100644 --- a/tests/auto/quick/qquicklistview/BLACKLIST +++ b/tests/auto/quick/qquicklistview/BLACKLIST @@ -1,7 +1,6 @@ -[QTBUG_38209] -* [enforceRange_withoutHighlight] osx #QTBUG-53863 [populateTransitions] opensuse-42.1 +#QTBUG-65964 diff --git a/tests/auto/quick/qquicklistview/data/addoncompleted.qml b/tests/auto/quick/qquicklistview/data/addoncompleted.qml new file mode 100644 index 0000000000..57265cb2c0 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/addoncompleted.qml @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.9 + +Rectangle { + width: 640 + height: 480 + color: "green" + + ListModel { + id: listModel + ListElement { name: "a" } + ListElement { name: "b" } + ListElement { name: "c" } + ListElement { name: "d" } + ListElement { name: "e" } + ListElement { name: "f" } + ListElement { name: "g" } + ListElement { name: "h" } + ListElement { name: "i" } + ListElement { name: "j" } + } + + ListView { + anchors.fill: parent + model: listModel + objectName: "view" + + delegate: Rectangle { + height: 15 + width: 15 + color: "blue" + objectName: name + Component.onCompleted: { + if (name.length === 1 && listModel.get(index + 1).name.length === 1) { + for (var i = 0; i < 10; ++i) + listModel.insert(index + 1, {name: name + i}); + } + } + } + } +} diff --git a/tests/auto/quick/qquicklistview/data/appendDuringScrollDown.qml b/tests/auto/quick/qquicklistview/data/appendDuringScrollDown.qml new file mode 100644 index 0000000000..af35c29143 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/appendDuringScrollDown.qml @@ -0,0 +1,28 @@ +import QtQuick 2.6 + +ListView { + width: 320; height: 240 + focus: true + delegate: Text { + height: 40; width: parent.width + text: model.text + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + } + highlight: Rectangle { color: "red" } + model: ListModel { + ListElement { text: "0" } + ListElement { text: "1" } + ListElement { text: "2" } + ListElement { text: "3" } + ListElement { text: "4" } + ListElement { text: "5" } + ListElement { text: "6" } + ListElement { text: "7" } + ListElement { text: "8" } + ListElement { text: "9" } + } + + readonly property Item topItem: itemAt(0, contentY) + onTopItemChanged: model.append({ "text": "new" }) +} diff --git a/tests/auto/quick/qquicklistview/data/attachedProperties.qml b/tests/auto/quick/qquicklistview/data/attachedProperties.qml index ffba4196f6..09714b2c6e 100644 --- a/tests/auto/quick/qquicklistview/data/attachedProperties.qml +++ b/tests/auto/quick/qquicklistview/data/attachedProperties.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquicklistview/data/flickBothDirections.qml b/tests/auto/quick/qquicklistview/data/flickBothDirections.qml index 5d80ce4110..b491981edb 100644 --- a/tests/auto/quick/qquicklistview/data/flickBothDirections.qml +++ b/tests/auto/quick/qquicklistview/data/flickBothDirections.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are @@ -53,6 +63,7 @@ Rectangle { contentWidth: initialContentWidth contentHeight: initialContentHeight flickableDirection: initialFlickableDirection + pixelAligned: true delegate: Rectangle { width: list.orientation == ListView.Vertical ? 120 : 10 height: list.orientation == ListView.Vertical ? 20 : 110 diff --git a/tests/auto/quick/qquicklistview/data/itemlist-flicker.qml b/tests/auto/quick/qquicklistview/data/itemlist-flicker.qml index c0cc807bc0..89daadaaa5 100644 --- a/tests/auto/quick/qquicklistview/data/itemlist-flicker.qml +++ b/tests/auto/quick/qquicklistview/data/itemlist-flicker.qml @@ -1,33 +1,34 @@ // This example demonstrates placing items in a view using -// a VisualItemModel +// an ObjectModel import QtQuick 2.0 +import QtQml.Models 2.12 Rectangle { color: "lightgray" width: 240 height: 320 - VisualItemModel { + ObjectModel { id: itemModel objectName: "itemModel" Rectangle { objectName: "item1" height: view.height / 3 width: view.width; color: "#FFFEF0" - Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text1"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } Rectangle { objectName: "item2" height: view.height / 3 width: view.width; color: "#F0FFF7" - Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text2"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } Rectangle { objectName: "item3" height: view.height / 3 width: view.width; color: "#F4F0FF" - Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text3"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } } diff --git a/tests/auto/quick/qquicklistview/data/itemlist.qml b/tests/auto/quick/qquicklistview/data/itemlist.qml index 5c7ecdd5e8..00910ae60c 100644 --- a/tests/auto/quick/qquicklistview/data/itemlist.qml +++ b/tests/auto/quick/qquicklistview/data/itemlist.qml @@ -1,33 +1,34 @@ // This example demonstrates placing items in a view using -// a VisualItemModel +// an ObjectModel import QtQuick 2.0 +import QtQml.Models 2.12 Rectangle { color: "lightgray" width: 240 height: 320 - VisualItemModel { + ObjectModel { id: itemModel objectName: "itemModel" Rectangle { objectName: "item1" height: ListView.view ? ListView.view.height : 0 width: view.width; color: "#FFFEF0" - Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text1"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } Rectangle { objectName: "item2" height: ListView.view ? ListView.view.height : 0 width: view.width; color: "#F0FFF7" - Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text2"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } Rectangle { objectName: "item3" height: ListView.view ? ListView.view.height : 0 width: view.width; color: "#F4F0FF" - Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text3"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } } diff --git a/tests/auto/quick/qquicklistview/data/listview-itematindex.qml b/tests/auto/quick/qquicklistview/data/listview-itematindex.qml new file mode 100644 index 0000000000..fba8b11933 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/listview-itematindex.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +ListView { + width: 400 + height: 400 + focus: true + model: 3 + + delegate: Text { + width: parent.width + height: 10 + property int idx: index + text: index + } +} diff --git a/tests/auto/quick/qquicklistview/data/listview-sections-package.qml b/tests/auto/quick/qquicklistview/data/listview-sections-package.qml index 8bad73b5f6..4297ab1c69 100644 --- a/tests/auto/quick/qquicklistview/data/listview-sections-package.qml +++ b/tests/auto/quick/qquicklistview/data/listview-sections-package.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 Rectangle { width: 240 @@ -54,7 +55,7 @@ Rectangle { } } }, - VisualDataModel { + DelegateModel { id: visualModel model: testModel delegate: myDelegate diff --git a/tests/auto/quick/qquicklistview/data/listviewtest-package.qml b/tests/auto/quick/qquicklistview/data/listviewtest-package.qml index 452fe29b49..c26bbece03 100644 --- a/tests/auto/quick/qquicklistview/data/listviewtest-package.qml +++ b/tests/auto/quick/qquicklistview/data/listviewtest-package.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 Rectangle { id: root @@ -120,7 +121,7 @@ Rectangle { id: headerFooter Rectangle { height: 30; width: 240; color: "blue" } }, - VisualDataModel { + DelegateModel { id: visualModel model: testModel diff --git a/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml b/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml index 086f31fd70..e0acaf49e4 100644 --- a/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml +++ b/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml b/tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml new file mode 100644 index 0000000000..bd913b2ce1 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/programmaticFlickAtBounds3.qml @@ -0,0 +1,19 @@ +import QtQuick 2.9 + +ListView { + id: view + width: 200; height: 400 + + property real minOvershoot + onVerticalOvershootChanged: if (verticalOvershoot < minOvershoot) minOvershoot = verticalOvershoot + + highlightRangeMode: ListView.StrictlyEnforceRange + preferredHighlightBegin: 0 + preferredHighlightEnd: 0 + + model: 10 + delegate: Rectangle { + width: 200; height: 50 + color: index % 2 ? "red" : "green" + } +} diff --git a/tests/auto/quick/qquicklistview/data/qtbug34576.qml b/tests/auto/quick/qquicklistview/data/qtbug34576.qml new file mode 100644 index 0000000000..f407d8ebe3 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/qtbug34576.qml @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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.7 + +Rectangle { + id: root + width: 320 + height: 240 + color: "black" + + property int current: list.currentIndex + property int horizontalVelocityZeroCount: 0 + + ListView { + id: list + objectName: "list" + anchors.fill: parent + + focus: true + + orientation: ListView.Horizontal + + snapMode: ListView.SnapToItem + flickableDirection: Flickable.HorizontalFlick + + model: 10 + delegate: Item { + width: root.width / 3 + height: root.height + Rectangle { + anchors.centerIn: parent + width: 50 + height: 50 + color: list.currentIndex === index ? "red" : "white" + } + } + + onHorizontalVelocityChanged: { + if (list.horizontalVelocity === 0.0) + root.horizontalVelocityZeroCount++ + } + + } + + Rectangle { + color: "red" + width: 50 + height: 50 + anchors.left: parent.left + anchors.bottom: parent.bottom + + MouseArea { + anchors.fill: parent + onClicked: { + list.currentIndex--; + } + } + } + + Rectangle { + color: "red" + width: 50 + height: 50 + anchors.right: parent.right + anchors.bottom: parent.bottom + + MouseArea { + anchors.fill: parent + onClicked: { + list.currentIndex++; + } + } + } +} + diff --git a/tests/auto/quick/qquicklistview/data/qtbug61537_modelChangesAsync.qml b/tests/auto/quick/qquicklistview/data/qtbug61537_modelChangesAsync.qml new file mode 100644 index 0000000000..0dc9e6fdb5 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/qtbug61537_modelChangesAsync.qml @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.0 + +Item { + visible: true + width: 640 + height: 480 + + property ListView listView + + Loader { + id: loader + anchors.fill: parent + asynchronous: true + sourceComponent: comp + + onStatusChanged: { + if (status == Loader.Ready) { + // Assign the listview to the root prop late, so + // that the c++ part doesn't start before everything is ready. + listView = item.listView + } + } + } + + Component { + id: comp + Item { + property alias listView: listView + + ListView { + id: listView + + model: ListModel { + id: listModel + ListElement { title: "one" } + ListElement { title: "two" } + } + + anchors.fill: parent + orientation: ListView.Horizontal + + delegate: Item { + id: delegateRoot + objectName: "delegate" + + width: 200 + height: 200 + + Component.onCompleted: { + if (index === listModel.count - 1) { + // Add a new item while the outer Loader is still incubating async. If the new model item + // incubates using e.g QQmlIncubator::AsynchronousIfNested, it will also be loaded async, which + // is not currently supported (the item will not be added to the listview, or end up the wrong + // position, depending on its index and the current state of the refill/layout logic in + // QQuickListView). + // We add the new item here at the last delegates Component.onCompleted to hit the point in time + // when the listview is not expecting any more async items. In that case, the item will only be + // added to the list of visible items if incubated synchronously, which gives us something we + // can test for in the auto-test. + listModel.insert(0, {title: "zero"}); + } + } + + Rectangle { + anchors.fill: parent + border.width: 1 + Text { + anchors.centerIn: parent + text: index + } + } + } + } + } + } +} diff --git a/tests/auto/quick/qquicklistview/data/qtbug63974.qml b/tests/auto/quick/qquicklistview/data/qtbug63974.qml new file mode 100644 index 0000000000..1e0afa54f8 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/qtbug63974.qml @@ -0,0 +1,34 @@ +import QtQuick 2.6 + +ListView { + id: table + height: 200 + width: 100 + + headerPositioning: ListView.OverlayHeader + header: Rectangle { + width: table.width + height: 20 + color: "red" + z: 100 + } + + footerPositioning: ListView.OverlayFooter + footer: Rectangle { + width: table.width + height: 20 + color: "blue" + z: 200 + } + + model: 30 + delegate: Rectangle { + height: 20 + width: table.width + color: "lightgray" + Text { + text: "Item " + index + anchors.centerIn: parent + } + } +} diff --git a/tests/auto/quick/qquicklistview/data/releaseItems.qml b/tests/auto/quick/qquicklistview/data/releaseItems.qml new file mode 100644 index 0000000000..de774e5e08 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/releaseItems.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +ListView { + width: 400 + height: 400 + model: 100 + delegate: Rectangle { + height: 40; width: 400 + color: index % 2 ? "lightsteelblue" : "lightgray" + } + contentHeight: contentItem.children.length * 40 +} diff --git a/tests/auto/quick/qquicklistview/data/repositionResizedDelegate.qml b/tests/auto/quick/qquicklistview/data/repositionResizedDelegate.qml index d79ca100f4..fa16a8529e 100644 --- a/tests/auto/quick/qquicklistview/data/repositionResizedDelegate.qml +++ b/tests/auto/quick/qquicklistview/data/repositionResizedDelegate.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 ListView { id: root @@ -9,7 +10,7 @@ ListView { layoutDirection: (testRightToLeft == true) ? Qt.RightToLeft : Qt.LeftToRight verticalLayoutDirection: (testBottomToTop == true) ? ListView.BottomToTop : ListView.TopToBottom - model: VisualItemModel { + model: ObjectModel { Rectangle { objectName: "red" width: 200; height: 200; color: "red" diff --git a/tests/auto/quick/qquicklistview/data/rightToLeft.qml b/tests/auto/quick/qquicklistview/data/rightToLeft.qml index 6d77de26f4..dec7e0abc1 100644 --- a/tests/auto/quick/qquicklistview/data/rightToLeft.qml +++ b/tests/auto/quick/qquicklistview/data/rightToLeft.qml @@ -2,29 +2,30 @@ // changes in right-to-left layout direction import QtQuick 2.0 +import QtQml.Models 2.12 Rectangle { color: "lightgray" width: 640 height: 320 - VisualItemModel { + ObjectModel { id: itemModel objectName: "itemModel" Rectangle { objectName: "item1" height: view.height; width: 100; color: "#FFFEF0" - Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text1"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } Rectangle { objectName: "item2" height: view.height; width: 200; color: "#F0FFF7" - Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text2"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } Rectangle { objectName: "item3" height: view.height; width: 240; color: "#F4F0FF" - Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text3"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } } diff --git a/tests/auto/quick/qquicklistview/data/roundingErrors.qml b/tests/auto/quick/qquicklistview/data/roundingErrors.qml index bf87415551..4545fcd617 100644 --- a/tests/auto/quick/qquicklistview/data/roundingErrors.qml +++ b/tests/auto/quick/qquicklistview/data/roundingErrors.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquicklistview/data/sectionSnapping.qml b/tests/auto/quick/qquicklistview/data/sectionSnapping.qml new file mode 100644 index 0000000000..2583cc0377 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/sectionSnapping.qml @@ -0,0 +1,49 @@ +import QtQuick 2.0 + +ListView { + width: 400 + height: 400 + preferredHighlightBegin: 100 + preferredHighlightEnd: 100 + highlightRangeMode: ListView.StrictlyEnforceRange + + model: ListModel { + ListElement { section: "1" } + ListElement { section: "1" } + ListElement { section: "1" } + ListElement { section: "2" } + ListElement { section: "2" } + ListElement { section: "2" } + } + + delegate: Rectangle { + width: parent.width + height: 50 + color: index % 2 ? "lightsteelblue" : "steelblue" + Text { + anchors.centerIn: parent + color: "white" + text: model.index + } + } + + section.property: "section" + section.delegate: Rectangle { + width: parent.width + height: 50 + color: "green" + Text { + anchors.centerIn: parent + color: "white" + text: "section" + } + } + + highlight: Rectangle { + y: 100 + z: 100 + width: parent.width + height: 50 + color: "#80FF0000" + } +} diff --git a/tests/auto/quick/qquicklistview/data/setpositiononlayout.qml b/tests/auto/quick/qquicklistview/data/setpositiononlayout.qml new file mode 100644 index 0000000000..6e12eeafca --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/setpositiononlayout.qml @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + width: 200 + height: 720 + + ListView { + anchors.fill: parent + focus: true + highlightMoveDuration: 200 + model: 50 + spacing: 10 + delegate: FocusScope { + implicitHeight: col.height + Column { + id: col + Text { + text: "YYYY" + } + ListView { + id: list + model: 1 + anchors.left: parent.left + anchors.right: parent.right + height: 250 + orientation: ListView.Horizontal + delegate: Rectangle { + id: self + height: 250 + width: 150 + color: "blue" + } + } + } + } + } +} diff --git a/tests/auto/quick/qquicklistview/data/sizeTransitions.qml b/tests/auto/quick/qquicklistview/data/sizeTransitions.qml index eae96c468f..44e4dada60 100644 --- a/tests/auto/quick/qquicklistview/data/sizeTransitions.qml +++ b/tests/auto/quick/qquicklistview/data/sizeTransitions.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquicklistview/data/snapOneItemWrongDirection.qml b/tests/auto/quick/qquicklistview/data/snapOneItemWrongDirection.qml new file mode 100644 index 0000000000..f5b7b35d0c --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/snapOneItemWrongDirection.qml @@ -0,0 +1,18 @@ +import QtQuick 2.0 + +ListView { + width: 400 + height: 400 + focus: true + + model: 10 + delegate: Rectangle { + width: parent.width + height: 50 + color: index % 2 ? "blue" : "green" + } + + snapMode: ListView.SnapOneItem + Keys.onUpPressed: flick(0,500) + Keys.onDownPressed: flick(0,-500) +} diff --git a/tests/auto/quick/qquicklistview/data/snapToItemWithSpacing.qml b/tests/auto/quick/qquicklistview/data/snapToItemWithSpacing.qml new file mode 100644 index 0000000000..50b5abb206 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/snapToItemWithSpacing.qml @@ -0,0 +1,18 @@ +import QtQuick 2.0 + +ListView { + width: 100 + height: 300 + snapMode: ListView.SnapToItem + spacing: 100 + model: 10 + delegate: Rectangle { + height: 100 + width: 100 + color: "blue" + Text { + anchors.centerIn: parent + text: index + } + } +} diff --git a/tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml b/tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml index f57927dbe7..57e7578ba5 100644 --- a/tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml +++ b/tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml b/tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml index af5a6174f9..fd815ea79e 100644 --- a/tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml +++ b/tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml b/tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml index cfd0f3dd44..94fb294474 100644 --- a/tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml +++ b/tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquicklistview/data/strictlyenforcerange-resize.qml b/tests/auto/quick/qquicklistview/data/strictlyenforcerange-resize.qml new file mode 100644 index 0000000000..338af38475 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/strictlyenforcerange-resize.qml @@ -0,0 +1,31 @@ +import QtQuick 2.0 + +ListView { + width: 400 + height: 400 + focus: true + + highlightRangeMode: ListView.StrictlyEnforceRange + highlightMoveVelocity: 200 + preferredHighlightBegin: 150 + preferredHighlightEnd: 150 + + property bool completed + Component.onCompleted: completed = true + + model: 10 + delegate: Item { + width: parent.width + height: ListView.isCurrentItem ? 100 : 50 + + Text { + anchors.centerIn: parent + text: index + } + + Behavior on height { + enabled: completed + SmoothedAnimation { velocity: 200 } + } + } +} diff --git a/tests/auto/quick/qquicklistview/data/unrequestedItems.qml b/tests/auto/quick/qquicklistview/data/unrequestedItems.qml index e3719a8be0..e6cb856c1e 100644 --- a/tests/auto/quick/qquicklistview/data/unrequestedItems.qml +++ b/tests/auto/quick/qquicklistview/data/unrequestedItems.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 Item { width: 240 @@ -34,7 +35,7 @@ Item { } - VisualDataModel { + DelegateModel { id: visualModel delegate: myDelegate diff --git a/tests/auto/quick/qquicklistview/data/usechooserwithoutdefault.qml b/tests/auto/quick/qquicklistview/data/usechooserwithoutdefault.qml new file mode 100644 index 0000000000..45164222f2 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/usechooserwithoutdefault.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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.qmlmodels 1.0 + +Item { + width: 640 + height: 450 + + ListView { + width: 600 + height: 400 + model: 2 + delegate: DelegateChooser { + DelegateChoice { + index: 0 + delegate: Rectangle { + width: 100 + height: 100 + color:"green" + } + } + } + } +} diff --git a/tests/auto/quick/qquicklistview/qquicklistview.pro b/tests/auto/quick/qquicklistview/qquicklistview.pro index a95b6fdf33..fd96c269a2 100644 --- a/tests/auto/quick/qquicklistview/qquicklistview.pro +++ b/tests/auto/quick/qquicklistview/qquicklistview.pro @@ -16,6 +16,7 @@ include (../../shared/util.pri) include (../shared/util.pri) TESTDATA = data/* +DISTFILES += data/* -QT += core-private gui-private qml-private quick-private testlib +QT += core-private gui-private qml-private quick-private testlib qmltest diff --git a/tests/auto/quick/qquicklistview/randomsortmodel.cpp b/tests/auto/quick/qquicklistview/randomsortmodel.cpp index 7affb182c0..7375fe0dbe 100644 --- a/tests/auto/quick/qquicklistview/randomsortmodel.cpp +++ b/tests/auto/quick/qquicklistview/randomsortmodel.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include "randomsortmodel.h" +#include <QRandomGenerator> RandomSortModel::RandomSortModel(QObject* parent): QAbstractListModel(parent) @@ -73,14 +74,14 @@ QVariant RandomSortModel::data(const QModelIndex& index, int role) const void RandomSortModel::randomize() { - const int row = qrand() % mData.count(); + const int row = QRandomGenerator::global()->bounded(mData.count()); int random; bool exists = false; // Make sure we won't end up with two items with the same weight, as that // would make unit-testing much harder do { exists = false; - random = qrand() % (mData.count() * 10); + random = QRandomGenerator::global()->bounded(mData.count() * 10); QList<QPair<QString, int> >::ConstIterator iter, end; for (iter = mData.constBegin(), end = mData.constEnd(); iter != end; ++iter) { if ((*iter).second == random) { diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index ff06c1e1a4..d96590bdae 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 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. @@ -31,6 +31,7 @@ #include <QtCore/QSortFilterProxyModel> #include <QtGui/QStandardItemModel> #include <QtQuick/qquickview.h> +#include <QtQuickTest/QtQuickTest> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcontext.h> #include <QtQml/qqmlexpression.h> @@ -118,6 +119,7 @@ private slots: void noCurrentIndex(); void keyNavigation(); void keyNavigation_data(); + void checkCountForMultiColumnModels(); void enforceRange(); void enforceRange_withoutHighlight(); void spacing(); @@ -131,6 +133,8 @@ private slots: void sectionPropertyChange(); void sectionDelegateChange(); void sectionsItemInsertion(); + void sectionsSnap_data(); + void sectionsSnap(); void cacheBuffer(); void positionViewAtBeginningEnd(); void positionViewAtIndex(); @@ -162,6 +166,7 @@ private slots: void QTBUG_16037(); void indexAt_itemAt_data(); void indexAt_itemAt(); + void itemAtIndex(); void incrementalModel(); void onAdd(); void onAdd_data(); @@ -176,12 +181,15 @@ private slots: void creationContext(); void snapToItem_data(); void snapToItem(); + void snapToItemWithSpacing_QTBUG_59852(); void snapOneItemResize_QTBUG_43555(); void snapOneItem_data(); void snapOneItem(); void snapOneItemCurrentIndexRemoveAnimation(); + void snapOneItemWrongDirection(); void QTBUG_9791(); + void QTBUG_33568(); void QTBUG_11105(); void QTBUG_21742(); @@ -235,6 +243,7 @@ private slots: void QTBUG_38209(); void programmaticFlickAtBounds(); void programmaticFlickAtBounds2(); + void programmaticFlickAtBounds3(); void layoutChange(); @@ -252,8 +261,20 @@ private slots: void QTBUG_50105(); void keyNavigationEnabled(); + void QTBUG_61269_appendDuringScrollDown(); + void QTBUG_61269_appendDuringScrollDown_data(); void QTBUG_50097_stickyHeader_positionViewAtIndex(); + void QTBUG_63974_stickyHeader_positionViewAtIndex_Contain(); void itemFiltered(); + void releaseItems(); + + void QTBUG_34576_velocityZero(); + void QTBUG_61537_modelChangesAsync(); + + void useDelegateChooserWithoutDefault(); + + void addOnCompleted(); + void setPositionOnLayout(); private: template <class T> void items(const QUrl &source); @@ -283,7 +304,7 @@ private: if (m_view) { if (QString(QTest::currentTestFunction()) != testForView) { delete m_view; - m_view = 0; + m_view = nullptr; } else { m_view->setSource(QUrl()); return m_view; @@ -321,7 +342,7 @@ class TestObject : public QObject Q_PROPERTY(int cacheBuffer READ cacheBuffer NOTIFY changedCacheBuffer) public: - TestObject(QObject *parent = 0) + TestObject(QObject *parent = nullptr) : QObject(parent), mError(true), mAnimate(false), mInvalidHighlight(false) , mCacheBuffer(0) {} @@ -350,7 +371,7 @@ public: int mCacheBuffer; }; -tst_QQuickListView::tst_QQuickListView() : m_view(0) +tst_QQuickListView::tst_QQuickListView() : m_view(nullptr) { } @@ -360,7 +381,7 @@ void tst_QQuickListView::init() if (m_view && QString(QTest::currentTestFunction()) != testForView) { testForView = QString(); delete m_view; - m_view = 0; + m_view = nullptr; } #endif qmlRegisterType<QAbstractItemModel>(); @@ -373,7 +394,7 @@ void tst_QQuickListView::cleanupTestCase() #ifdef SHARE_VIEWS testForView = QString(); delete m_view; - m_view = 0; + m_view = nullptr; #endif } @@ -397,16 +418,16 @@ void tst_QQuickListView::items(const QUrl &source) qApp->processEvents(); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->forceLayout(); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QMetaObject::invokeMethod(window->rootObject(), "checkProperties"); QTRY_VERIFY(!testObject->error()); - QTRY_VERIFY(listview->highlightItem() != 0); + QTRY_VERIFY(listview->highlightItem() != nullptr); QTRY_COMPARE(listview->count(), model.count()); QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count()); listview->forceLayout(); @@ -417,10 +438,10 @@ void tst_QQuickListView::items(const QUrl &source) for (int i = 0; i < model.count(); ++i) { QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", i); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(i)); } @@ -442,17 +463,16 @@ void tst_QQuickListView::items(const QUrl &source) QMetaObject::invokeMethod(window->rootObject(), "checkProperties"); QTRY_VERIFY(!testObject->error()); QTRY_VERIFY(listview->currentItem()); - QTRY_VERIFY(listview->highlightItem() != 0); + QTRY_VERIFY(listview->highlightItem() != nullptr); // set an empty model and confirm that items are destroyed T model2; ctxt->setContextProperty("testModel", &model2); - // Force a layout, necessary if ListView is completed before VisualDataModel. + // Force a layout, necessary if ListView is completed before DelegateModel. listview->forceLayout(); - int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); - QTRY_COMPARE(itemCount, 0); + QTRY_VERIFY(findItems<QQuickItem>(contentItem, "wrapper").isEmpty()); QTRY_COMPARE(listview->highlightResizeVelocity(), 1000.0); QTRY_COMPARE(listview->highlightMoveVelocity(), 100000.0); @@ -481,21 +501,21 @@ void tst_QQuickListView::changed(const QUrl &source) qApp->processEvents(); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->forceLayout(); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); - // Force a layout, necessary if ListView is completed before VisualDataModel. + // Force a layout, necessary if ListView is completed before DelegateModel. listview->forceLayout(); model.modifyItem(1, "Will", "9876"); QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(1)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(1)); delete testObject; @@ -523,10 +543,10 @@ void tst_QQuickListView::inserted(const QUrl &source) qApp->processEvents(); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); model.insertItem(1, "Will", "9876"); @@ -534,10 +554,10 @@ void tst_QQuickListView::inserted(const QUrl &source) QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(1)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(1)); // Confirm items positioned correctly @@ -552,10 +572,10 @@ void tst_QQuickListView::inserted(const QUrl &source) QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item name = findItem<QQuickText>(contentItem, "textName", 0); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(0)); number = findItem<QQuickText>(contentItem, "textNumber", 0); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(0)); QTRY_COMPARE(listview->currentIndex(), 1); @@ -622,13 +642,13 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); if (verticalLayoutDirection == QQuickItemView::BottomToTop) { listview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); contentY = -listview->height() - contentY; } listview->setContentY(contentY); @@ -641,7 +661,7 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v model.insertItems(insertIndex, newData); //Wait for polish (updates list to the model changes) - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_COMPARE(listview->property("count").toInt(), model.count()); @@ -695,10 +715,10 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v } QTRY_COMPARE(item->y(), pos); name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); number = findItem<QQuickText>(contentItem, "textNumber", i); - QVERIFY(number != 0); + QVERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(i)); } @@ -817,12 +837,12 @@ void tst_QQuickListView::insertBeforeVisible() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); listview->setCacheBuffer(cacheBuffer); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // trigger a refill (not just setting contentY) so that the visibleItems grid is updated int firstVisibleIndex = 20; // move to an index where the top item is not visible @@ -830,7 +850,7 @@ void tst_QQuickListView::insertBeforeVisible() listview->setCurrentIndex(firstVisibleIndex); qApp->processEvents(); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_COMPARE(listview->currentIndex(), firstVisibleIndex); QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", firstVisibleIndex); QVERIFY(item); @@ -850,7 +870,7 @@ void tst_QQuickListView::insertBeforeVisible() // now, moving to the top of the view should position the inserted items correctly int itemsOffsetAfterMove = (removeCount - insertCount) * 20; listview->setCurrentIndex(0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_COMPARE(listview->currentIndex(), 0); QTRY_COMPARE(listview->contentY(), 0.0 + itemsOffsetAfterMove); @@ -861,7 +881,7 @@ void tst_QQuickListView::insertBeforeVisible() QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); QTRY_COMPARE(item->y(), i*20.0 + itemsOffsetAfterMove); name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -930,19 +950,19 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */) QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); model.removeItem(1); QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count()); QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(1)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 1); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(1)); // Confirm items positioned correctly @@ -959,10 +979,10 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */) QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count()); name = findItem<QQuickText>(contentItem, "textName", 0); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(0)); number = findItem<QQuickText>(contentItem, "textNumber", 0); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(0)); // Confirm items positioned correctly @@ -1012,7 +1032,7 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */) listview->setContentY(20); // That's the top now // let transitions settle. - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); @@ -1026,15 +1046,15 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */) // remove current item beyond visible items. listview->setCurrentIndex(20); listview->setContentY(40); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); model.removeItem(20); QTRY_COMPARE(listview->currentIndex(), 20); - QTRY_VERIFY(listview->currentItem() != 0); + QTRY_VERIFY(listview->currentItem() != nullptr); // remove item before current, but visible listview->setCurrentIndex(8); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); oldCurrent = listview->currentItem(); model.removeItem(6); @@ -1042,7 +1062,7 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */) QTRY_COMPARE(listview->currentItem(), oldCurrent); listview->setContentY(80); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // remove all visible items model.removeItems(1, 18); @@ -1114,20 +1134,20 @@ void tst_QQuickListView::removed_more(const QUrl &source, QQuickItemView::Vertic QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); if (verticalLayoutDirection == QQuickItemView::BottomToTop) { listview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); contentY = -listview->height() - contentY; } listview->setContentY(contentY); model.removeItems(removeIndex, removeCount); //Wait for polish (updates list to the model changes) - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_COMPARE(listview->property("count").toInt(), model.count()); @@ -1162,10 +1182,10 @@ void tst_QQuickListView::removed_more(const QUrl &source, QQuickItemView::Vertic pos = -item0->height() - pos; QTRY_COMPARE(item->y(), pos); name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); number = findItem<QQuickText>(contentItem, "textNumber", i); - QVERIFY(number != 0); + QVERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(i)); } @@ -1296,12 +1316,12 @@ void tst_QQuickListView::clear(const QUrl &source, QQuickItemView::VerticalLayou QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); listview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); model.clear(); @@ -1320,7 +1340,7 @@ void tst_QQuickListView::clear(const QUrl &source, QQuickItemView::VerticalLayou model.addItem("New", "1"); listview->forceLayout(); QTRY_COMPARE(listview->count(), 1); - QVERIFY(listview->currentItem() != 0); + QVERIFY(listview->currentItem() != nullptr); QCOMPARE(listview->currentIndex(), 0); delete testObject; @@ -1354,25 +1374,25 @@ void tst_QQuickListView::moved(const QUrl &source, QQuickItemView::VerticalLayou QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); // always need to wait for view to be painted before the first move() - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); bool waitForPolish = (contentY != 0); if (verticalLayoutDirection == QQuickItemView::BottomToTop) { listview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); contentY = -listview->height() - contentY; } listview->setContentY(contentY); if (waitForPolish) - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); model.moveItems(from, to, count); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); int firstVisibleIndex = -1; @@ -1394,10 +1414,10 @@ void tst_QQuickListView::moved(const QUrl &source, QQuickItemView::VerticalLayou pos = -item->height() - pos; QTRY_COMPARE(item->y(), pos); name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); number = findItem<QQuickText>(contentItem, "textNumber", i); - QVERIFY(number != 0); + QVERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(i)); // current index should have been updated @@ -1584,8 +1604,8 @@ void tst_QQuickListView::multipleChanges(bool condensed) QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(listview != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); for (int i=0; i<changes.count(); i++) { switch (changes[i].type) { @@ -1613,10 +1633,10 @@ void tst_QQuickListView::multipleChanges(bool condensed) continue; } if (!condensed) { - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); } } - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QCOMPARE(listview->count(), newCount); QCOMPARE(listview->count(), model.count()); @@ -1625,16 +1645,16 @@ void tst_QQuickListView::multipleChanges(bool condensed) QQuickText *name; QQuickText *number; QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); for (int i=0; i < model.count() && i < itemCount; ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); number = findItem<QQuickText>(contentItem, "textNumber", i); - QVERIFY(number != 0); + QVERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(i)); } @@ -1832,8 +1852,8 @@ void tst_QQuickListView::swapWithFirstItem() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(listview != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // ensure content position is stable listview->setContentY(0); @@ -1843,6 +1863,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()); @@ -1859,15 +1911,15 @@ void tst_QQuickListView::enforceRange() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QTRY_COMPARE(listview->preferredHighlightBegin(), 100.0); QTRY_COMPARE(listview->preferredHighlightEnd(), 100.0); QTRY_COMPARE(listview->highlightRangeMode(), QQuickListView::StrictlyEnforceRange); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); // view should be positioned at the top of the range. QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0); @@ -1875,10 +1927,10 @@ void tst_QQuickListView::enforceRange() QTRY_COMPARE(listview->contentY(), -100.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", 0); - QTRY_VERIFY(name != 0); + QTRY_VERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(0)); QQuickText *number = findItem<QQuickText>(contentItem, "textNumber", 0); - QTRY_VERIFY(number != 0); + QTRY_VERIFY(number != nullptr); QTRY_COMPARE(number->text(), model.number(0)); // Check currentIndex is updated when contentItem moves @@ -1918,8 +1970,8 @@ void tst_QQuickListView::enforceRange_withoutHighlight() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(listview != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); qreal expectedPos = -100.0; @@ -1959,11 +2011,11 @@ void tst_QQuickListView::spacing() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); @@ -2017,12 +2069,12 @@ void tst_QQuickListView::sections(const QUrl &source) QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); @@ -2092,9 +2144,9 @@ void tst_QQuickListView::sections(const QUrl &source) // check that headers change when item changes listview->setContentY(0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); model.modifyItem(0, "changed", "2"); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); item = findItem<QQuickItem>(contentItem, "wrapper", 1); QTRY_VERIFY(item); @@ -2117,12 +2169,12 @@ void tst_QQuickListView::sectionsDelegate() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); @@ -2146,7 +2198,7 @@ void tst_QQuickListView::sectionsDelegate() model.modifyItem(2, "Three", "aaa"); model.modifyItem(3, "Four", "aaa"); model.modifyItem(4, "Five", "aaa"); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); for (int i = 0; i < 3; ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, @@ -2182,7 +2234,7 @@ void tst_QQuickListView::sectionsDelegate() model.modifyItem(9, "Two", "aaa"); model.modifyItem(10, "Two", "aaa"); model.modifyItem(11, "Two", "aaa"); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_COMPARE(findItems<QQuickItem>(contentItem, "sect_aaa").count(), 1); window->rootObject()->setProperty("sectionProperty", "name"); // ensure view has settled. @@ -2226,30 +2278,30 @@ void tst_QQuickListView::sectionsDragOutsideBounds() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->setCacheBuffer(cacheBuffer); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // QTBUG-17769 // Drag view up beyond bounds - QTest::mousePress(window, Qt::LeftButton, 0, QPoint(20,20)); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(20,20)); QTest::mouseMove(window, QPoint(20,0)); QTest::mouseMove(window, QPoint(20,-50)); QTest::mouseMove(window, QPoint(20,-distance)); - QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(20,-distance)); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(20,-distance)); // view should settle back at 0 QTRY_COMPARE(listview->contentY(), 0.0); - QTest::mousePress(window, Qt::LeftButton, 0, QPoint(20,0)); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(20,0)); QTest::mouseMove(window, QPoint(20,20)); QTest::mouseMove(window, QPoint(20,70)); QTest::mouseMove(window, QPoint(20,distance)); - QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(20,distance)); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(20,distance)); // view should settle back at 0 QTRY_COMPARE(listview->contentY(), 0.0); @@ -2271,18 +2323,18 @@ void tst_QQuickListView::sectionsDelegate_headerVisibility() window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); window->requestActivate(); - QTest::qWaitForWindowActive(window.data()); + QVERIFY(QTest::qWaitForWindowActive(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // ensure section header is maintained in view listview->setCurrentIndex(20); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_VERIFY(qFuzzyCompare(listview->contentY(), 200.0)); QTRY_VERIFY(!listview->isMoving()); listview->setCurrentIndex(0); @@ -2306,10 +2358,10 @@ void tst_QQuickListView::sectionsPositioning() window->rootObject()->setProperty("sectionPositioning", QVariant(int(QQuickViewSection::InlineLabels | QQuickViewSection::CurrentLabelAtStart | QQuickViewSection::NextLabelAtEnd))); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); for (int i = 0; i < 3; ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "sect_" + QString::number(i)); @@ -2327,12 +2379,12 @@ void tst_QQuickListView::sectionsPositioning() // move down a little and check that section header is at top listview->setContentY(10); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QCOMPARE(topItem->y(), 0.); // push the top header up listview->setContentY(110); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); topItem = findVisibleChild(contentItem, "sect_0"); // section header QVERIFY(topItem); QCOMPARE(topItem->y(), 100.); @@ -2347,13 +2399,13 @@ void tst_QQuickListView::sectionsPositioning() // Move past section 0 listview->setContentY(120); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); topItem = findVisibleChild(contentItem, "sect_0"); // section header QVERIFY(!topItem); // Push section footer down listview->setContentY(70); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); bottomItem = findVisibleChild(contentItem, "sect_4"); // section footer QVERIFY(bottomItem); QCOMPARE(bottomItem->y(), 380.); @@ -2365,7 +2417,7 @@ void tst_QQuickListView::sectionsPositioning() model.modifyItem(2, "Three", "aAa"); model.modifyItem(3, "Four", "aaA"); model.modifyItem(4, "Five", "Aaa"); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_COMPARE(listview->currentSection(), QString("aaa")); @@ -2381,7 +2433,7 @@ void tst_QQuickListView::sectionsPositioning() // remove section boundary listview->setContentY(120); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); model.removeItem(5); listview->forceLayout(); QTRY_COMPARE(listview->count(), model.count()); @@ -2398,27 +2450,27 @@ void tst_QQuickListView::sectionsPositioning() // Change the next section listview->setContentY(0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); bottomItem = findVisibleChild(contentItem, "sect_3"); // section footer QVERIFY(bottomItem); QTRY_COMPARE(bottomItem->y(), 300.); model.modifyItem(14, "New", "new"); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_VERIFY(bottomItem = findVisibleChild(contentItem, "sect_new")); // section footer QTRY_COMPARE(bottomItem->y(), 300.); // delegate size increase should push section footer down listview->setContentY(70); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_VERIFY(bottomItem = findVisibleChild(contentItem, "sect_3")); // section footer QTRY_COMPARE(bottomItem->y(), 370.); QQuickItem *inlineSection = findVisibleChild(contentItem, "sect_new"); item = findItem<QQuickItem>(contentItem, "wrapper", 13); QVERIFY(item); item->setHeight(40.); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_COMPARE(bottomItem->y(), 380.); QCOMPARE(inlineSection->y(), 360.); item->setHeight(20.); @@ -2426,14 +2478,14 @@ void tst_QQuickListView::sectionsPositioning() // Turn sticky footer off listview->setContentY(20); window->rootObject()->setProperty("sectionPositioning", QVariant(int(QQuickViewSection::InlineLabels | QQuickViewSection::CurrentLabelAtStart))); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_VERIFY(item = findVisibleChild(contentItem, "sect_new")); // inline label restored QCOMPARE(item->y(), 340.); // Turn sticky header off listview->setContentY(30); window->rootObject()->setProperty("sectionPositioning", QVariant(int(QQuickViewSection::InlineLabels))); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_VERIFY(item = findVisibleChild(contentItem, "sect_aaa")); // inline label restored QCOMPARE(item->y(), 0.); @@ -2464,12 +2516,12 @@ void tst_QQuickListView::sectionPropertyChange() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly for (int i = 0; i < 2; ++i) { @@ -2479,7 +2531,7 @@ void tst_QQuickListView::sectionPropertyChange() } QMetaObject::invokeMethod(window->rootObject(), "switchGroups"); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly for (int i = 0; i < 2; ++i) { @@ -2489,7 +2541,7 @@ void tst_QQuickListView::sectionPropertyChange() } QMetaObject::invokeMethod(window->rootObject(), "switchGroups"); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly for (int i = 0; i < 2; ++i) { @@ -2499,7 +2551,7 @@ void tst_QQuickListView::sectionPropertyChange() } QMetaObject::invokeMethod(window->rootObject(), "switchGrouped"); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly for (int i = 0; i < 2; ++i) { @@ -2509,7 +2561,7 @@ void tst_QQuickListView::sectionPropertyChange() } QMetaObject::invokeMethod(window->rootObject(), "switchGrouped"); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly for (int i = 0; i < 2; ++i) { @@ -2528,12 +2580,12 @@ void tst_QQuickListView::sectionDelegateChange() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = qobject_cast<QQuickListView *>(window->rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); - QQUICK_VERIFY_POLISH(listview); + QQuickTest::qWaitForItemPolished(listview); QVERIFY(findItems<QQuickItem>(contentItem, "section1").count() > 0); QCOMPARE(findItems<QQuickItem>(contentItem, "section2").count(), 0); @@ -2545,7 +2597,7 @@ void tst_QQuickListView::sectionDelegateChange() } QMetaObject::invokeMethod(window->rootObject(), "switchDelegates"); - QQUICK_VERIFY_POLISH(listview); + QQuickTest::qWaitForItemPolished(listview); QCOMPARE(findItems<QQuickItem>(contentItem, "section1").count(), 0); QVERIFY(findItems<QQuickItem>(contentItem, "section2").count() > 0); @@ -2574,10 +2626,10 @@ void tst_QQuickListView::sectionsItemInsertion() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); for (int i = 0; i < 3; ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "sect_" + QString::number(i)); @@ -2593,7 +2645,7 @@ void tst_QQuickListView::sectionsItemInsertion() for (int i = 0; i < 10; i++) model.insertItem(i, "Item" + QString::number(i), QLatin1String("A")); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); QVERIFY(itemCount > 10); @@ -2618,6 +2670,62 @@ void tst_QQuickListView::sectionsItemInsertion() } } +void tst_QQuickListView::sectionsSnap_data() +{ + QTest::addColumn<QQuickListView::SnapMode>("snapMode"); + QTest::addColumn<QPoint>("point"); + QTest::addColumn<int>("duration"); + + QTest::newRow("drag") << QQuickListView::NoSnap << QPoint(100, 45) << 500; + QTest::newRow("flick") << QQuickListView::SnapOneItem << QPoint(100, 60) << 100; +} + +void tst_QQuickListView::sectionsSnap() +{ + QFETCH(QQuickListView::SnapMode, snapMode); + QFETCH(QPoint, point); + QFETCH(int, duration); + + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("sectionSnapping.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); + QTRY_VERIFY(listview != nullptr); + listview->setSnapMode(snapMode); + + QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_COMPARE(listview->currentIndex(), 0); + QCOMPARE(listview->contentY(), qreal(-50)); + + // move down + flick(window.data(), QPoint(100, 100), point, duration); + QTRY_VERIFY(!listview->isMovingVertically()); + QCOMPARE(listview->contentY(), qreal(0)); + + flick(window.data(), QPoint(100, 100), point, duration); + QTRY_VERIFY(!listview->isMovingVertically()); + QCOMPARE(listview->contentY(), qreal(50)); + + flick(window.data(), QPoint(100, 100), point, duration); + QTRY_VERIFY(!listview->isMovingVertically()); + QCOMPARE(listview->contentY(), qreal(150)); + + // move back up + flick(window.data(), point, QPoint(100, 100), duration); + QTRY_VERIFY(!listview->isMovingVertically()); + QCOMPARE(listview->contentY(), qreal(50)); + + flick(window.data(), point, QPoint(100, 100), duration); + QTRY_VERIFY(!listview->isMovingVertically()); + QCOMPARE(listview->contentY(), qreal(0)); + + flick(window.data(), point, QPoint(100, 100), duration); + QTRY_VERIFY(!listview->isMovingVertically()); + QCOMPARE(listview->contentY(), qreal(-50)); +} + void tst_QQuickListView::currentIndex_delayedItemCreation() { QFETCH(bool, setCurrentToZero); @@ -2632,9 +2740,9 @@ void tst_QQuickListView::currentIndex_delayedItemCreation() qApp->processEvents(); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QSignalSpy spy(listview, SIGNAL(currentItemChanged())); //QCOMPARE(listview->currentIndex(), 0); @@ -2659,7 +2767,7 @@ void tst_QQuickListView::currentIndex() for (int i = 0; i < 30; i++) initModel.addItem("Item" + QString::number(i), QString::number(i)); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setGeometry(0,0,240,320); QQmlContext *ctxt = window->rootContext(); @@ -2672,10 +2780,10 @@ void tst_QQuickListView::currentIndex() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // currentIndex is initialized to 20 // currentItem should be in view @@ -2763,7 +2871,7 @@ void tst_QQuickListView::noCurrentIndex() for (int i = 0; i < 30; i++) model.addItem("Item" + QString::number(i), QString::number(i)); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setGeometry(0,0,240,320); QQmlContext *ctxt = window->rootContext(); @@ -2775,10 +2883,10 @@ void tst_QQuickListView::noCurrentIndex() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // current index should be -1 at startup // and we should not have a currentItem or highlightItem @@ -2815,18 +2923,18 @@ void tst_QQuickListView::keyNavigation() window->rootContext()->setContextProperty("testObject", testObject); window->setSource(testFileUrl("listviewtest.qml")); window->show(); - QTest::qWaitForWindowActive(window); + QVERIFY(QTest::qWaitForWindowActive(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); listview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); window->requestActivate(); - QTest::qWaitForWindowActive(window); + QVERIFY(QTest::qWaitForWindowActive(window)); QTRY_COMPARE(qGuiApp->focusWindow(), window); QTest::keyClick(window, forwardsKey); @@ -2928,13 +3036,13 @@ void tst_QQuickListView::itemList() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "view"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QQmlObjectModel *model = window->rootObject()->findChild<QQmlObjectModel*>("itemModel"); - QTRY_VERIFY(model != 0); + QTRY_VERIFY(model != nullptr); QTRY_COMPARE(model->count(), 3); QTRY_COMPARE(listview->currentIndex(), 0); @@ -2967,13 +3075,13 @@ void tst_QQuickListView::itemListFlicker() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "view"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QQmlObjectModel *model = window->rootObject()->findChild<QQmlObjectModel*>("itemModel"); - QTRY_VERIFY(model != 0); + QTRY_VERIFY(model != nullptr); QTRY_COMPARE(model->count(), 3); QTRY_COMPARE(listview->currentIndex(), 0); @@ -3032,13 +3140,13 @@ void tst_QQuickListView::cacheBuffer() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_VERIFY(listview->delegate() != 0); + QTRY_VERIFY(contentItem != nullptr); + QTRY_VERIFY(listview->delegate() != nullptr); QTRY_VERIFY(listview->model() != 0); - QTRY_VERIFY(listview->highlight() != 0); + QTRY_VERIFY(listview->highlight() != nullptr); // Confirm items positioned correctly int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); @@ -3057,8 +3165,8 @@ void tst_QQuickListView::cacheBuffer() // items will be created one at a time for (int i = itemCount; i < qMin(itemCount+10,model.count()); ++i) { - QVERIFY(findItem<QQuickItem>(listview, "wrapper", i) == 0); - QQuickItem *item = 0; + QVERIFY(findItem<QQuickItem>(listview, "wrapper", i) == nullptr); + QQuickItem *item = nullptr; while (!item) { bool b = false; controller.incubateWhile(&b); @@ -3092,11 +3200,11 @@ void tst_QQuickListView::cacheBuffer() QCOMPARE(item->y(), qreal(i*20)); } - QVERIFY(findItem<QQuickItem>(listview, "wrapper", 32) == 0); + QVERIFY(findItem<QQuickItem>(listview, "wrapper", 32) == nullptr); // ensure buffered items are created for (int i = 32; i < qMin(41,model.count()); ++i) { - QQuickItem *item = 0; + QQuickItem *item = nullptr; while (!item) { qGuiApp->processEvents(); // allow refill to happen bool b = false; @@ -3135,10 +3243,10 @@ void tst_QQuickListView::positionViewAtBeginningEnd() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); listview->setContentY(100); @@ -3195,13 +3303,13 @@ void tst_QQuickListView::positionViewAtIndex() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); window->rootObject()->setProperty("enforceRange", enforceRange); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); listview->setContentY(initContentY); @@ -3275,16 +3383,16 @@ void tst_QQuickListView::resetModel() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_COMPARE(listview->count(), model.rowCount()); for (int i = 0; i < model.rowCount(); ++i) { QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i); - QTRY_VERIFY(display != 0); + QTRY_VERIFY(display != nullptr); QTRY_COMPARE(display->text(), strings.at(i)); } @@ -3297,7 +3405,7 @@ void tst_QQuickListView::resetModel() for (int i = 0; i < model.rowCount(); ++i) { QQuickText *display = findItem<QQuickText>(contentItem, "displayText", i); - QTRY_VERIFY(display != 0); + QTRY_VERIFY(display != nullptr); QTRY_COMPARE(display->text(), strings.at(i)); } } @@ -3444,11 +3552,11 @@ void tst_QQuickListView::QTBUG_9791() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_VERIFY(listview->delegate() != 0); + QTRY_VERIFY(contentItem != nullptr); + QTRY_VERIFY(listview->delegate() != nullptr); QTRY_VERIFY(listview->model() != 0); QMetaObject::invokeMethod(listview, "fillModel"); @@ -3469,9 +3577,32 @@ void tst_QQuickListView::QTBUG_9791() QTRY_COMPARE(listview->contentX(), 590.0); } +void tst_QQuickListView::QTBUG_33568() +{ + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("strictlyenforcerange-resize.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); + QVERIFY(listview != nullptr); + + // we want to verify that the change animates smoothly, rather than jumping into place + QSignalSpy spy(listview, SIGNAL(contentYChanged())); + + listview->incrementCurrentIndex(); + QTRY_COMPARE(listview->contentY(), -100.0); + QVERIFY(spy.count() > 1); + + spy.clear(); + listview->incrementCurrentIndex(); + QTRY_COMPARE(listview->contentY(), -50.0); + QVERIFY(spy.count() > 1); +} + void tst_QQuickListView::manualHighlight() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setGeometry(0,0,240,320); QString filename(testFile("manual-highlight.qml")); @@ -3480,10 +3611,10 @@ void tst_QQuickListView::manualHighlight() qApp->processEvents(); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QTRY_COMPARE(listview->currentIndex(), 0); QTRY_COMPARE(listview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0)); @@ -3523,10 +3654,10 @@ void tst_QQuickListView::QTBUG_11105() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); @@ -3560,9 +3691,9 @@ void tst_QQuickListView::initialZValues() qApp->processEvents(); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QVERIFY(listview->currentItem()); QTRY_COMPARE(listview->currentItem()->z(), listview->property("itemZ").toReal()); @@ -3576,7 +3707,7 @@ void tst_QQuickListView::initialZValues() QVERIFY(listview->highlightItem()); QTRY_COMPARE(listview->highlightItem()->z(), listview->property("highlightZ").toReal()); - QQuickText *sectionItem = 0; + QQuickText *sectionItem = nullptr; QTRY_VERIFY(sectionItem = findItem<QQuickText>(contentItem, "section")); QTRY_COMPARE(sectionItem->z(), listview->property("sectionZ").toReal()); } @@ -3614,16 +3745,16 @@ void tst_QQuickListView::header() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); listview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); - QQuickText *header = 0; + QQuickText *header = nullptr; QTRY_VERIFY(header = findItem<QQuickText>(contentItem, "header")); QCOMPARE(header, listview->headerItem()); @@ -3693,11 +3824,11 @@ void tst_QQuickListView::header() QVERIFY(QTest::qWaitForWindowExposed(window)); listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); listview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); listview->setWidth(240); listview->setHeight(320); @@ -3780,10 +3911,10 @@ void tst_QQuickListView::header_delayItemCreation() qApp->processEvents(); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QQuickText *header = findItem<QQuickText>(contentItem, "header"); QVERIFY(header); @@ -3803,13 +3934,13 @@ void tst_QQuickListView::headerChangesViewport() window->setSource(testFileUrl("headerchangesviewport.qml")); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(listview != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); - QQuickText *header = 0; + QQuickText *header = nullptr; QTRY_VERIFY(header = findItem<QQuickText>(contentItem, "header")); QCOMPARE(header, listview->headerItem()); @@ -3850,14 +3981,14 @@ void tst_QQuickListView::footer() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); listview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QQuickText *footer = findItem<QQuickText>(contentItem, "footer"); QVERIFY(footer); @@ -4039,14 +4170,14 @@ void tst_QQuickListView::extents() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); listview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); QVERIFY(header); @@ -4137,10 +4268,10 @@ void tst_QQuickListView::resetModel_headerFooter() qApp->processEvents(); QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); QQuickItem *header = findItem<QQuickItem>(contentItem, "header"); QVERIFY(header); @@ -4180,10 +4311,10 @@ void tst_QQuickListView::resizeView() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); @@ -4199,7 +4330,7 @@ void tst_QQuickListView::resizeView() QCOMPARE(heightRatio.toReal(), 0.4); listview->setHeight(200); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QMetaObject::invokeMethod(window->rootObject(), "heightRatio", Q_RETURN_ARG(QVariant, heightRatio)); QCOMPARE(heightRatio.toReal(), 0.25); @@ -4257,10 +4388,10 @@ void tst_QQuickListView::resizeViewAndRepaint() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // item at index 10 should not be currently visible QVERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10)); @@ -4292,10 +4423,10 @@ void tst_QQuickListView::sizeLessThan1() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Confirm items positioned correctly int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count(); @@ -4316,10 +4447,10 @@ void tst_QQuickListView::QTBUG_14821() qApp->processEvents(); QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); listview->decrementCurrentIndex(); QCOMPARE(listview->currentIndex(), 99); @@ -4344,20 +4475,20 @@ void tst_QQuickListView::resizeDelegate() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QCOMPARE(listview->count(), model.rowCount()); listview->setCurrentIndex(25); listview->setContentY(0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); for (int i = 0; i < 16; ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); - QVERIFY(item != 0); + QVERIFY(item != nullptr); QCOMPARE(item->y(), i*20.0); } @@ -4365,11 +4496,11 @@ void tst_QQuickListView::resizeDelegate() QTRY_COMPARE(listview->highlightItem()->y(), 500.0); window->rootObject()->setProperty("delegateHeight", 30); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); for (int i = 0; i < 11; ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); - QVERIFY(item != 0); + QVERIFY(item != nullptr); QTRY_COMPARE(item->y(), i*30.0); } @@ -4379,11 +4510,11 @@ void tst_QQuickListView::resizeDelegate() listview->setCurrentIndex(1); listview->positionViewAtIndex(25, QQuickListView::Beginning); listview->positionViewAtIndex(5, QQuickListView::Beginning); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); for (int i = 5; i < 16; ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); - QVERIFY(item != 0); + QVERIFY(item != nullptr); QCOMPARE(item->y(), i*30.0); } @@ -4391,11 +4522,11 @@ void tst_QQuickListView::resizeDelegate() QTRY_COMPARE(listview->highlightItem()->y(), 30.0); window->rootObject()->setProperty("delegateHeight", 20); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); for (int i = 5; i < 11; ++i) { QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i); - QVERIFY(item != 0); + QVERIFY(item != nullptr); QTRY_COMPARE(item->y(), 150 + (i-5)*20.0); } @@ -4425,15 +4556,15 @@ void tst_QQuickListView::resizeFirstDelegate() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); - QQuickItem *item = 0; + QQuickItem *item = nullptr; for (int i = 0; i < model.count(); ++i) { item = findItem<QQuickItem>(contentItem, "wrapper", i); - QVERIFY(item != 0); + QVERIFY(item != nullptr); QCOMPARE(item->y(), i*20.0); } @@ -4448,7 +4579,7 @@ void tst_QQuickListView::resizeFirstDelegate() for (int i = 1; i < model.count(); ++i) { item = findItem<QQuickItem>(contentItem, "wrapper", i); - QVERIFY(item != 0); + QVERIFY(item != nullptr); QTRY_COMPARE(item->y(), (i-1)*20.0); } @@ -4467,7 +4598,7 @@ void tst_QQuickListView::resizeFirstDelegate() listview->setCurrentIndex(19); qApp->processEvents(); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // items 0-2 should have been deleted for (int i=0; i<3; i++) { @@ -4497,8 +4628,8 @@ void tst_QQuickListView::repositionResizedDelegate() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); - QTRY_VERIFY(listview != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(listview != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QQuickItem *positioner = findItem<QQuickItem>(window->rootObject(), "positioner"); QVERIFY(positioner); @@ -4513,7 +4644,7 @@ void tst_QQuickListView::repositionResizedDelegate() listview->setContentX(contentPos_itemFirstHalfVisible.x()); listview->setContentY(contentPos_itemFirstHalfVisible.y()); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); prevSpyCount = spy.count(); QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "incrementRepeater")); QTRY_COMPARE(positioner->boundingRect().size(), resizedPositionerRect.size()); @@ -4530,7 +4661,7 @@ void tst_QQuickListView::repositionResizedDelegate() listview->setContentX(contentPos_itemSecondHalfVisible.x()); listview->setContentY(contentPos_itemSecondHalfVisible.y()); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); prevSpyCount = spy.count(); QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "incrementRepeater")); @@ -4589,7 +4720,7 @@ void tst_QQuickListView::QTBUG_16037() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "listview"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QVERIFY(listview->contentHeight() <= 0.0); @@ -4634,13 +4765,13 @@ void tst_QQuickListView::indexAt_itemAt() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); - QQuickItem *item = 0; + QQuickItem *item = nullptr; if (index >= 0) { item = findItem<QQuickItem>(contentItem, "wrapper", index); QVERIFY(item); @@ -4652,32 +4783,50 @@ void tst_QQuickListView::indexAt_itemAt() delete testObject; } +void tst_QQuickListView::itemAtIndex() +{ + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("listview-itematindex.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); + QVERIFY(listview != nullptr); + + QCOMPARE(listview->itemAtIndex(-1), nullptr); + QCOMPARE(listview->itemAtIndex(3), nullptr); + QQuickItem *item = listview->itemAtIndex(0); + QVERIFY(item); + QCOMPARE(item->property("idx"), 0); + item = listview->itemAtIndex(1); + QVERIFY(item); + QCOMPARE(item->property("idx"), 1); + item = listview->itemAtIndex(2); + QVERIFY(item); + QCOMPARE(item->property("idx"), 2); +} + void tst_QQuickListView::incrementalModel() { QScopedPointer<QQuickView> window(createView()); - QSKIP("QTBUG-30716"); IncrementalModel model; QQmlContext *ctxt = window->rootContext(); ctxt->setContextProperty("testModel", &model); window->setSource(testFileUrl("displaylist.qml")); - qApp->processEvents(); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); - listview->forceLayout(); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - - listview->forceLayout(); - QTRY_COMPARE(listview->count(), 20); + QTRY_VERIFY(contentItem != nullptr); + QTRY_COMPARE(listview->count(), 35); listview->positionViewAtIndex(10, QQuickListView::Beginning); - - listview->forceLayout(); - QTRY_COMPARE(listview->count(), 25); + QTRY_COMPARE(listview->count(), 45); } void tst_QQuickListView::onAdd() @@ -4794,17 +4943,17 @@ void tst_QQuickListView::rightToLeft() window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "view"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QQmlObjectModel *model = window->rootObject()->findChild<QQmlObjectModel*>("itemModel"); - QTRY_VERIFY(model != 0); + QTRY_VERIFY(model != nullptr); QTRY_COMPARE(model->count(), 3); QTRY_COMPARE(listview->currentIndex(), 0); @@ -4843,12 +4992,12 @@ void tst_QQuickListView::test_mirroring() QScopedPointer<QQuickView> windowA(createView()); windowA->setSource(testFileUrl("rightToLeft.qml")); QQuickListView *listviewA = findItem<QQuickListView>(windowA->rootObject(), "view"); - QTRY_VERIFY(listviewA != 0); + QTRY_VERIFY(listviewA != nullptr); QScopedPointer<QQuickView> windowB(createView()); windowB->setSource(testFileUrl("rightToLeft.qml")); QQuickListView *listviewB = findItem<QQuickListView>(windowB->rootObject(), "view"); - QTRY_VERIFY(listviewA != 0); + QTRY_VERIFY(listviewA != nullptr); qApp->processEvents(); QList<QString> objectNames; @@ -4911,10 +5060,10 @@ void tst_QQuickListView::margins() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QCOMPARE(listview->contentY(), -30.); QCOMPARE(listview->originY(), 0.); @@ -4923,7 +5072,7 @@ void tst_QQuickListView::margins() listview->positionViewAtEnd(); qreal pos = listview->contentY(); listview->setContentY(pos + 80); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); listview->returnToBounds(); QTRY_COMPARE(listview->contentY(), pos + 50); @@ -4934,7 +5083,7 @@ void tst_QQuickListView::margins() listview->forceLayout(); QTRY_COMPARE(listview->count(), model.count()); listview->setContentY(-50); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); listview->returnToBounds(); QCOMPARE(listview->originY(), 20.); QTRY_COMPARE(listview->contentY(), -10.); @@ -4982,12 +5131,12 @@ void tst_QQuickListView::marginsResize() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "listview"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); listview->setVerticalLayoutDirection(verticalLayoutDirection); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // view is resized after componentCompleted - top margin should still be visible if (orientation == QQuickListView::Vertical) @@ -5121,16 +5270,16 @@ void tst_QQuickListView::snapToItem() QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); listview->setVerticalLayoutDirection(verticalLayoutDirection); listview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode)); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); // confirm that a flick hits an item boundary flick(window, flickStart, flickEnd, 180); @@ -5168,6 +5317,31 @@ void tst_QQuickListView::snapToItem() releaseView(window); } +void tst_QQuickListView::snapToItemWithSpacing_QTBUG_59852() +{ + QQuickView *window = getView(); + + window->setSource(testFileUrl("snapToItemWithSpacing.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + auto *listView = qobject_cast<QQuickListView*>(window->rootObject()); + QVERIFY(listView); + + QVERIFY(QQuickTest::qWaitForItemPolished(listView)); + + // each item in the list is 100 pixels tall, and the spacing is 100 + + listView->setContentY(110); // this is right below the first item + listView->returnToBounds(); + QCOMPARE(listView->contentY(), 200); // the position of the second item + + listView->setContentY(60); // this is right below the middle of the first item + listView->returnToBounds(); + QCOMPARE(listView->contentY(), 0); // it's farther to go to the next item, so snaps to the first + + releaseView(window); +} void tst_QQuickListView::snapOneItemResize_QTBUG_43555() { @@ -5181,18 +5355,18 @@ void tst_QQuickListView::snapOneItemResize_QTBUG_43555() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QSignalSpy currentIndexSpy(listview, SIGNAL(currentIndexChanged())); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_COMPARE(listview->currentIndex(), 5); currentIndexSpy.clear(); window->resize(QSize(400, 320)); QTRY_COMPARE(int(listview->width()), 400); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_COMPARE(listview->currentIndex(), 5); QCOMPARE(currentIndexSpy.count(), 0); @@ -5384,7 +5558,7 @@ void tst_QQuickListView::asynchronous() QQuickItem *rootObject = qobject_cast<QQuickItem*>(window->rootObject()); QVERIFY(rootObject); - QQuickListView *listview = 0; + QQuickListView *listview = nullptr; while (!listview) { bool b = false; controller.incubateWhile(&b); @@ -5393,8 +5567,8 @@ void tst_QQuickListView::asynchronous() // items will be created one at a time for (int i = 0; i < 8; ++i) { - QVERIFY(findItem<QQuickItem>(listview, "wrapper", i) == 0); - QQuickItem *item = 0; + QVERIFY(findItem<QQuickItem>(listview, "wrapper", i) == nullptr); + QQuickItem *item = nullptr; while (!item) { bool b = false; controller.incubateWhile(&b); @@ -5426,38 +5600,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() @@ -5471,6 +5657,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); @@ -5481,21 +5670,21 @@ void tst_QQuickListView::snapOneItem() QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->setOrientation(orientation); listview->setLayoutDirection(layoutDirection); listview->setVerticalLayoutDirection(verticalLayoutDirection); listview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode)); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QTRY_VERIFY(contentItem != nullptr); 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); @@ -5509,7 +5698,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() @@ -5527,7 +5716,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() @@ -5554,21 +5743,39 @@ void tst_QQuickListView::snapOneItemCurrentIndexRemoveAnimation() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QTRY_COMPARE(listview->currentIndex(), 0); QSignalSpy currentIndexSpy(listview, SIGNAL(currentIndexChanged())); QMetaObject::invokeMethod(window->rootObject(), "removeItemZero"); QTRY_COMPARE(listview->property("transitionsRun").toInt(), 1); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QCOMPARE(listview->currentIndex(), 0); QCOMPARE(currentIndexSpy.count(), 0); } +void tst_QQuickListView::snapOneItemWrongDirection() +{ + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("snapOneItemWrongDirection.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); + QTRY_VERIFY(listview != nullptr); + + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); + QTRY_COMPARE(listview->currentIndex(), 0); + + listview->flick(0,500); + QTRY_VERIFY(!listview->isMovingHorizontally()); + QCOMPARE(listview->contentX(), qreal(0)); +} + void tst_QQuickListView::attachedProperties_QTBUG_32836() { QScopedPointer<QQuickView> window(createView()); @@ -5577,7 +5784,7 @@ void tst_QQuickListView::attachedProperties_QTBUG_32836() qApp->processEvents(); QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *header = listview->headerItem(); QVERIFY(header); @@ -5606,7 +5813,7 @@ void tst_QQuickListView::unrequestedVisibility() for (int i = 0; i < 30; i++) model.addItem("Item" + QString::number(i), QString::number(i)); - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setGeometry(0,0,240,320); QQmlContext *ctxt = window->rootContext(); @@ -5711,7 +5918,7 @@ void tst_QQuickListView::unrequestedVisibility() QCOMPARE(delegateVisible(item), false); model.moveItems(19, 1, 1); - QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); QTRY_VERIFY((item = findItem<QQuickItem>(leftContent, wrapperObjectName, 1))); QCOMPARE(delegateVisible(item), false); @@ -5740,7 +5947,7 @@ void tst_QQuickListView::unrequestedVisibility() QCOMPARE(delegateVisible(item), false); model.moveItems(3, 4, 1); - QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); item = findItem<QQuickItem>(leftContent, wrapperObjectName, 4); QVERIFY(item); @@ -5756,7 +5963,7 @@ void tst_QQuickListView::unrequestedVisibility() QCOMPARE(delegateVisible(item), false); model.moveItems(4, 3, 1); - QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); item = findItem<QQuickItem>(leftContent, wrapperObjectName, 4); QVERIFY(item); @@ -5772,7 +5979,7 @@ void tst_QQuickListView::unrequestedVisibility() QCOMPARE(delegateVisible(item), false); model.moveItems(16, 17, 1); - QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); item = findItem<QQuickItem>(leftContent, wrapperObjectName, 4); QVERIFY(item); @@ -5788,7 +5995,7 @@ void tst_QQuickListView::unrequestedVisibility() QCOMPARE(delegateVisible(item), false); model.moveItems(17, 16, 1); - QTRY_COMPARE(QQuickItemPrivate::get(leftview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); item = findItem<QQuickItem>(leftContent, wrapperObjectName, 4); QVERIFY(item); @@ -5848,7 +6055,7 @@ void tst_QQuickListView::populateTransitions() QTRY_COMPARE(listview->property("countPopulateTransitions").toInt(), 0); QTRY_COMPARE(listview->property("countAddTransitions").toInt(), 16); } else { - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QCOMPARE(listview->property("countPopulateTransitions").toInt(), 0); QCOMPARE(listview->property("countAddTransitions").toInt(), 0); } @@ -5860,7 +6067,7 @@ void tst_QQuickListView::populateTransitions() QTRY_COMPARE(item->x(), 0.0); QTRY_COMPARE(item->y(), i*20.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -5895,7 +6102,7 @@ void tst_QQuickListView::populateTransitions() QTRY_COMPARE(item->x(), 0.0); QTRY_COMPARE(item->y(), i*20.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -5913,7 +6120,7 @@ void tst_QQuickListView::populateTransitions() QTRY_COMPARE(item->x(), 0.0); QTRY_COMPARE(item->y(), i*20.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -5958,8 +6165,8 @@ void tst_QQuickListView::sizeTransitions() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(listview != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // the following will start the transition model.addItem(QLatin1String("Test"), ""); @@ -6021,14 +6228,14 @@ void tst_QQuickListView::addTransitions() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); if (contentY != 0) { listview->setContentY(contentY); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); } QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); @@ -6102,7 +6309,7 @@ void tst_QQuickListView::addTransitions() QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); QTRY_COMPARE(item->y(), i*20.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -6217,14 +6424,14 @@ void tst_QQuickListView::moveTransitions() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQuickText *name; if (contentY != 0) { listview->setContentY(contentY); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); } QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); @@ -6287,7 +6494,7 @@ void tst_QQuickListView::moveTransitions() QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); QTRY_COMPARE(item->y(), i*20.0 + itemsOffsetAfterMove); name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -6420,14 +6627,14 @@ void tst_QQuickListView::removeTransitions() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); if (contentY != 0) { listview->setContentY(contentY); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); } QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); @@ -6501,7 +6708,7 @@ void tst_QQuickListView::removeTransitions() QCOMPARE(item->x(), 0.0); QCOMPARE(item->y(), contentY + (i-firstVisibleIndex) * 20.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -6632,10 +6839,10 @@ void tst_QQuickListView::displacedTransitions() QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); listview->setProperty("displaceTransitionsDone", false); @@ -6656,7 +6863,7 @@ void tst_QQuickListView::displacedTransitions() break; case ListChange::Moved: model.moveItems(change.index, change.to, change.count); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); break; case ListChange::SetCurrent: case ListChange::SetContentY: @@ -6716,7 +6923,7 @@ void tst_QQuickListView::displacedTransitions() QCOMPARE(item->x(), 0.0); QCOMPARE(item->y(), i * 20.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -6852,14 +7059,14 @@ void tst_QQuickListView::multipleTransitions() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); if (contentY != 0) { listview->setContentY(contentY); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); } int timeBetweenActions = window->rootObject()->property("timeBetweenActions").toInt(); @@ -6893,7 +7100,7 @@ void tst_QQuickListView::multipleTransitions() break; case ListChange::Moved: model.moveItems(changes[i].index, changes[i].to, changes[i].count); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); if (i == changes.count() - 1) { QTRY_VERIFY(!listview->property("runningMoveTargets").toBool()); QTRY_VERIFY(!listview->property("runningMoveDisplaced").toBool()); @@ -6906,7 +7113,7 @@ void tst_QQuickListView::multipleTransitions() break; case ListChange::SetContentY: listview->setContentY(changes[i].pos); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); break; case ListChange::Polish: break; @@ -6924,7 +7131,7 @@ void tst_QQuickListView::multipleTransitions() QTRY_COMPARE(item->x(), 0.0); QTRY_COMPARE(item->y(), i*20.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -7009,10 +7216,10 @@ void tst_QQuickListView::multipleDisplaced() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); model.moveItems(12, 8, 1); QTest::qWait(window->rootObject()->property("duration").toInt() / 2); @@ -7033,7 +7240,7 @@ void tst_QQuickListView::multipleDisplaced() QTRY_COMPARE(item->x(), 0.0); QTRY_COMPARE(item->y(), i*20.0); QQuickText *name = findItem<QQuickText>(contentItem, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model.name(i)); } @@ -7102,11 +7309,11 @@ void tst_QQuickListView::flickBeyondBounds() QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QTRY_VERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); // Flick view up beyond bounds flick(window.data(), QPoint(10, 10), QPoint(10, -2000), 180); @@ -7214,11 +7421,11 @@ void tst_QQuickListView::destroyItemOnCreation() QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QCOMPARE(window->rootObject()->property("createdIndex").toInt(), -1); model.addItem("new item", ""); @@ -7235,14 +7442,14 @@ void tst_QQuickListView::parentBinding() window->setSource(testFileUrl("parentBinding.qml")); window->show(); - QTest::qWaitForWindowExposed(window.data()); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); - QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); + QVERIFY(contentItem != nullptr); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0); QVERIFY(item); @@ -7271,7 +7478,7 @@ void tst_QQuickListView::accessEmptyCurrentItem_QTBUG_30227() window->setSource(testFileUrl("emptymodel.qml")); QQuickListView *listview = window->rootObject()->findChild<QQuickListView*>(); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); listview->forceLayout(); QMetaObject::invokeMethod(window->rootObject(), "remove"); @@ -7287,7 +7494,7 @@ void tst_QQuickListView::delayedChanges_QTBUG_30555() window->setSource(testFileUrl("delayedChanges.qml")); QQuickListView *listview = window->rootObject()->findChild<QQuickListView*>(); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QCOMPARE(listview->count(), 10); @@ -7306,7 +7513,7 @@ void tst_QQuickListView::outsideViewportChangeNotAffectingView() window->setSource(testFileUrl("outsideViewportChangeNotAffectingView.qml")); QQuickListView *listview = window->rootObject()->findChild<QQuickListView*>(); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); @@ -7340,7 +7547,7 @@ void tst_QQuickListView::testProxyModelChangedAfterMove() window->setSource(testFileUrl("proxytest.qml")); QQuickListView *listview = window->rootObject()->findChild<QQuickListView*>(); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); @@ -7360,7 +7567,7 @@ void tst_QQuickListView::typedModel() QCOMPARE(listview->count(), 6); - QQmlListModel *listModel = 0; + QQmlListModel *listModel = nullptr; listview->setModel(QVariant::fromValue(listModel)); QCOMPARE(listview->count(), 0); @@ -7374,10 +7581,10 @@ void tst_QQuickListView::displayMargin() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = window->rootObject()->findChild<QQuickListView*>(); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *content = listview->contentItem(); - QVERIFY(content != 0); + QVERIFY(content != nullptr); QQuickItem *item0 = findItem<QQuickItem>(content, "delegate", 0); QVERIFY(item0); @@ -7390,7 +7597,7 @@ void tst_QQuickListView::displayMargin() QCOMPARE(delegateVisible(item14), true); // the 15th item should be outside the end margin - QVERIFY(findItem<QQuickItem>(content, "delegate", 14) == 0); + QVERIFY(findItem<QQuickItem>(content, "delegate", 14) == nullptr); // the first delegate should still be within the begin margin listview->positionViewAtIndex(3, QQuickListView::Beginning); @@ -7410,13 +7617,13 @@ void tst_QQuickListView::negativeDisplayMargin() QQuickItem *listview = window->rootObject(); QQuickListView *innerList = findItem<QQuickListView>(window->rootObject(), "innerList"); - QVERIFY(innerList != 0); + QVERIFY(innerList != nullptr); QTRY_COMPARE(innerList->property("createdItems").toInt(), 11); QCOMPARE(innerList->property("destroyedItem").toInt(), 0); QQuickItem *content = innerList->contentItem(); - QVERIFY(content != 0); + QVERIFY(content != nullptr); QQuickItem *item = findItem<QQuickItem>(content, "delegate", 0); QVERIFY(item); @@ -7483,7 +7690,7 @@ void tst_QQuickListView::QTBUG_35920() QQuickListView *listview = qobject_cast<QQuickListView *>(window->rootObject()); QVERIFY(listview); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(10,0)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(10,0)); for (int i = 0; i < 100; ++i) { QTest::mouseMove(window.data(), QPoint(10,i)); if (listview->isMoving()) { @@ -7500,7 +7707,7 @@ void tst_QQuickListView::QTBUG_35920() QCOMPARE(listview->contentY(), contentY); } } - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(10,100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(10,100)); } Q_DECLARE_METATYPE(Qt::Orientation) @@ -7934,12 +8141,12 @@ void tst_QQuickListView::roundingErrors() // QTBUG-37339: drag an item and verify that it doesn't // get prematurely released due to rounding errors - QTest::mousePress(window.data(), Qt::LeftButton, 0, viewPos); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, viewPos); for (int i = 0; i < 150; i += 5) { QTest::mouseMove(window.data(), viewPos - QPoint(i, 0)); QVERIFY(item); } - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(0, 36)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(0, 36)); // maintain position relative to the right edge listview->setLayoutDirection(Qt::RightToLeft); @@ -8044,6 +8251,35 @@ void tst_QQuickListView::programmaticFlickAtBounds2() QTRY_COMPARE(listview->contentY(), qreal(100.0)); } +void tst_QQuickListView::programmaticFlickAtBounds3() +{ + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("programmaticFlickAtBounds3.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = qobject_cast<QQuickListView *>(window->rootObject()); + QVERIFY(listview); + + // flick down + listview->flick(0, 2000); + + // verify scope of the movement + QTRY_VERIFY(listview->property("minOvershoot").toReal() < qreal(-50.0)); + + // reset, and test a second time + listview->cancelFlick(); + listview->returnToBounds(); + QTRY_COMPARE(listview->contentY(), qreal(0.0)); + listview->setProperty("minOvershoot", qreal(0.0)); + + // flick down + listview->flick(0, 2000); + + // verify scope of the movement is the same + QTRY_VERIFY(listview->property("minOvershoot").toReal() < qreal(-50.0)); +} + void tst_QQuickListView::layoutChange() { RandomSortModel *model = new RandomSortModel; @@ -8291,7 +8527,7 @@ void tst_QQuickListView::contentHeightWithDelayRemove() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = window->rootObject()->findChild<QQuickListView*>(); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); const int initialCount(listview->count()); const int eventualCount(initialCount + countDelta); @@ -8320,7 +8556,7 @@ void tst_QQuickListView::QTBUG_48044_currentItemNotVisibleAfterTransition() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = window->rootObject()->findChild<QQuickListView*>(); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); // Expand 2nd header listview->setProperty("transitionsDone", QVariant(false)); @@ -8413,6 +8649,49 @@ void tst_QQuickListView::keyNavigationEnabled() QCOMPARE(listView->currentIndex(), 1); } +void tst_QQuickListView::QTBUG_61269_appendDuringScrollDown_data() +{ + QTest::addColumn<QQuickListView::SnapMode>("snapMode"); + + QTest::newRow("NoSnap") << QQuickListView::NoSnap; + QTest::newRow("SnapToItem") << QQuickListView::SnapToItem; + QTest::newRow("SnapOneItem") << QQuickListView::SnapOneItem; +} + +void tst_QQuickListView::QTBUG_61269_appendDuringScrollDown() // AKA QTBUG-62864 +{ + QFETCH(QQuickListView::SnapMode, snapMode); + + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("appendDuringScrollDown.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + QQuickListView *listView = qobject_cast<QQuickListView *>(window->rootObject()); + listView->setSnapMode(snapMode); + QQuickItem *highlightItem = listView->highlightItem(); + QVERIFY(listView); + QCOMPARE(listView->isKeyNavigationEnabled(), true); + listView->setHighlightMoveVelocity(400); + listView->setHighlightMoveDuration(-1); // let it animate + listView->setFocus(true); + QVERIFY(listView->hasActiveFocus()); + qreal highlightYLimit = listView->height() - highlightItem->height(); // should be 200 + + for (int i = 1; i < 15; ++i) { + QTest::keyClick(window.data(), Qt::Key_Down); + + // Wait for the highlight movement animation to finish. + QTRY_COMPARE(highlightItem->y(), 40.0 * i); + + // As we scroll down, the QML will append rows to its own model. + // Make sure the highlighted row and highlight item stay within the view. + // In QTBUG-62864 and QTBUG-61269, it would go off the bottom. + QVERIFY(highlightItem->y() - listView->contentY() <= highlightYLimit); + } +} + void tst_QQuickListView::QTBUG_48870_fastModelUpdates() { StressTestModel model; @@ -8426,11 +8705,11 @@ void tst_QQuickListView::QTBUG_48870_fastModelUpdates() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QTRY_VERIFY(listview != nullptr); QQuickItemViewPrivate *priv = QQuickItemViewPrivate::get(listview); bool nonUnique; - FxViewItem *item = Q_NULLPTR; + FxViewItem *item = nullptr; int expectedIdx; QVERIFY(testVisibleItems(priv, &nonUnique, &item, &expectedIdx)); @@ -8469,7 +8748,7 @@ void tst_QQuickListView::QTBUG_50097_stickyHeader_positionViewAtIndex() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QTRY_COMPARE(listview->contentY(), -100.0); // the header size, since the header is overlaid listview->setProperty("currentPage", 2); QTRY_COMPARE(listview->contentY(), 400.0); // a full page of items down, sans the original negative header position @@ -8477,6 +8756,46 @@ void tst_QQuickListView::QTBUG_50097_stickyHeader_positionViewAtIndex() QTRY_COMPARE(listview->contentY(), -100.0); // back to the same position: header visible, items not under the header. } +void tst_QQuickListView::QTBUG_63974_stickyHeader_positionViewAtIndex_Contain() +{ + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("qtbug63974.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject()); + QVERIFY(listview != nullptr); + + const qreal headerSize = 20; + const qreal footerSize = 20; + const qreal itemSize = 20; + const int itemCount = 30; + const qreal contentHeight = itemCount * itemSize; + + const qreal initialY = listview->contentY(); + const qreal endPosition = contentHeight + footerSize - listview->height(); + + QVERIFY(qFuzzyCompare(initialY, -headerSize)); + + listview->positionViewAtIndex(itemCount - 1, QQuickListView::Contain); + QTRY_COMPARE(listview->contentY(), endPosition); + + listview->positionViewAtIndex(0, QQuickListView::Contain); + QTRY_COMPARE(listview->contentY(), -headerSize); + + listview->positionViewAtIndex(itemCount - 1, QQuickListView::Visible); + QTRY_COMPARE(listview->contentY(), endPosition); + + listview->positionViewAtIndex(0, QQuickListView::Visible); + QTRY_COMPARE(listview->contentY(), -headerSize); + + listview->positionViewAtIndex(itemCount - 1, QQuickListView::SnapPosition); + QTRY_COMPARE(listview->contentY(), endPosition); + + listview->positionViewAtIndex(0, QQuickListView::SnapPosition); + QTRY_COMPARE(listview->contentY(), -headerSize); +} + void tst_QQuickListView::itemFiltered() { QStringListModel model(QStringList() << "one" << "two" << "three" << "four" << "five" << "six"); @@ -8502,12 +8821,153 @@ void tst_QQuickListView::itemFiltered() window->setContent(QUrl(), &component, component.create()); window->show(); - QTest::qWaitForWindowExposed(window.data()); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); // this should not crash model.setData(model.index(2), QStringLiteral("modified three"), Qt::DisplayRole); } +void tst_QQuickListView::releaseItems() +{ + QScopedPointer<QQuickView> view(createView()); + view->setSource(testFileUrl("releaseItems.qml")); + + QQuickListView *listview = qobject_cast<QQuickListView *>(view->rootObject()); + QVERIFY(listview); + + // don't crash (QTBUG-61294) + listview->setModel(123); +} + +void tst_QQuickListView::QTBUG_34576_velocityZero() +{ + QQuickView *window = new QQuickView(nullptr); + window->setGeometry(0,0,240,320); + + QString filename(testFile("qtbug34576.qml")); + window->setSource(QUrl::fromLocalFile(filename)); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list"); + QVERIFY(listview); + QQuickItem *contentItem = listview->contentItem(); + QVERIFY(contentItem); + QVERIFY(QQuickTest::qWaitForItemPolished(listview)); + + QSignalSpy horizontalVelocitySpy(listview, SIGNAL(horizontalVelocityChanged())); + + // currentIndex is initialized to 0 + QCOMPARE(listview->currentIndex(), 0); + + // set currentIndex to last item currently visible item + window->rootObject()->setProperty("horizontalVelocityZeroCount", QVariant(0)); + listview->setCurrentIndex(2); + QTRY_COMPARE(window->rootObject()->property("current").toInt(), 2); + QCOMPARE(horizontalVelocitySpy.count(), 0); + QCOMPARE(window->rootObject()->property("horizontalVelocityZeroCount").toInt(), 0); + + QSignalSpy currentIndexChangedSpy(listview, SIGNAL(currentIndexChanged())); + + // click button which increases currentIndex + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(295,215)); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(295,215)); + + // verify that currentIndexChanged is triggered + QTRY_VERIFY(currentIndexChangedSpy.count() > 0); + + // since we have set currentIndex to an item out of view, the listview will scroll + QTRY_COMPARE(window->rootObject()->property("current").toInt(), 3); + QTRY_VERIFY(horizontalVelocitySpy.count() > 0); + + // velocity should be always > 0.0 + QTRY_COMPARE(window->rootObject()->property("horizontalVelocityZeroCount").toInt(), 0); + + delete window; +} + +void tst_QQuickListView::QTBUG_61537_modelChangesAsync() +{ + // The purpose of this test if to check that any model changes that happens + // during start-up, while a loader higher up in the chain is still incubating + // async, will not fail. + QQuickView window; + window.setGeometry(0,0,640,480); + + QString filename(testFile("qtbug61537_modelChangesAsync.qml")); + window.setSource(QUrl::fromLocalFile(filename)); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + // The qml file will assign the listview to the 'listView' property once the + // loader is ready with async incubation. So we need to wait for it. + QObject *root = window.rootObject(); + QTRY_VERIFY(root->property("listView").value<QQuickListView *>()); + QQuickListView *listView = root->property("listView").value<QQuickListView *>(); + QVERIFY(listView); + + // Check that the number of delegates we expect to be visible in + // the listview matches the number of items we find if we count. + int reportedCount = listView->count(); + int actualCount = findItems<QQuickItem>(listView, "delegate").count(); + QCOMPARE(reportedCount, actualCount); +} + +void tst_QQuickListView::addOnCompleted() +{ + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("addoncompleted.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "view"); + QTRY_VERIFY(listview != nullptr); + + QQuickItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != nullptr); + + qreal y = -1; + for (char name = 'a'; name <= 'j'; ++name) { + for (int num = 9; num >= 0; --num) { + const QString objName = QString::fromLatin1("%1%2").arg(name).arg(num); + QQuickItem *item = findItem<QQuickItem>(contentItem, objName); + if (!item) { + QVERIFY(name >= 'd'); + y = 9999999; + } else { + const qreal newY = item->y(); + QVERIFY2(newY > y, objName.toUtf8().constData()); + y = newY; + } + } + } +} + +void tst_QQuickListView::setPositionOnLayout() +{ + // Make sure we don't trigger a crash by removing items during layout from setPosition(). + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("setpositiononlayout.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + for (int i = 0; i < 1000; ++i) { + QTest::keyPress(window.data(), Qt::Key_Down); + QTest::qWait(1); + QTest::keyRelease(window.data(), Qt::Key_Down); + } +} + +void tst_QQuickListView::useDelegateChooserWithoutDefault() +{ + // Check that the application doesn't crash + // if the delegate chooser doesn't cover all cells + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("usechooserwithoutdefault.qml")); + window->show(); +}; + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" diff --git a/tests/auto/quick/qquickloader/BLACKLIST b/tests/auto/quick/qquickloader/BLACKLIST new file mode 100644 index 0000000000..a45a300607 --- /dev/null +++ b/tests/auto/quick/qquickloader/BLACKLIST @@ -0,0 +1,4 @@ +# Test fails on qemu when bound to one core, passes on real ARM +# QTBUG-63049 +[asyncToSync1] +b2qt diff --git a/tests/auto/quick/qquickloader/data/bindings.qml b/tests/auto/quick/qquickloader/data/bindings.qml new file mode 100644 index 0000000000..e0eae2a3e5 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/bindings.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests 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 + +Item { + id: root + + property alias game: theGame + property alias loader: theLoader + + Item { + id: theGame + + property bool isReady: false + + onStateChanged: { + if (state == "invalid") { + // The Loader's active property is bound to isReady, so none of its bindings + // should be updated when isReady becomes false + isReady = false; + + player.destroy(); + player = null; + } else if (state == "running") { + player = Qt.createQmlObject("import QtQuick 2.0; Item { property color color: 'black' }", root); + + isReady = true; + } + } + + property Item player + } + + Loader { + id: theLoader + active: theGame.isReady + sourceComponent: Rectangle { + width: 400 + height: 400 + color: game.player.color + + property var game: theGame + } + } +} diff --git a/tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml b/tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml new file mode 100644 index 0000000000..d4c5daecab --- /dev/null +++ b/tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml @@ -0,0 +1,27 @@ +import QtQuick 2.0 +import QtQuick.Window 2.1 + +Item { + width: 400 + height: 400 + objectName: "root Item" + + Loader { + sourceComponent: Rectangle { + objectName: "yellow rectangle" + x: 50; y: 50; width: 300; height: 300 + color: "yellow" + Window { + objectName: "red transient Window" + width: 100 + height: 100 + visible: true // makes it harder, because it wants to become visible before root has a window + color: "red" + title: "red" + flags: Qt.Dialog + onVisibilityChanged: console.log("visibility " + visibility) + onVisibleChanged: console.log("visible " + visible) + } + } + } +} diff --git a/tests/auto/quick/qquickloader/data/itemLoaderWindow.qml b/tests/auto/quick/qquickloader/data/itemLoaderWindow.qml new file mode 100644 index 0000000000..69421448e0 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/itemLoaderWindow.qml @@ -0,0 +1,22 @@ +import QtQuick 2.0 +import QtQuick.Window 2.1 + +Item { + width: 400 + height: 400 + objectName: "root Item" + + Loader { + sourceComponent: Window { + objectName: "red transient Window" + width: 100 + height: 100 + visible: true // makes it harder, because it wants to become visible before root has a window + color: "red" + title: "red" + flags: Qt.Dialog + onVisibilityChanged: console.log("visibility " + visibility) + onVisibleChanged: console.log("visible " + visible) + } + } +} diff --git a/tests/auto/quick/qquickloader/data/parentErrors.qml b/tests/auto/quick/qquickloader/data/parentErrors.qml new file mode 100644 index 0000000000..36607e7f05 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/parentErrors.qml @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests 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 + +Rectangle { + width: 360 + height: 360 + + property alias loader: loader + + Loader { + id: loader + anchors.fill: parent + } + + property Component component: Rectangle { + width: parent.width + height: parent.height + color: "pink" + } +} diff --git a/tests/auto/quick/qquickloader/data/rootContext.qml b/tests/auto/quick/qquickloader/data/rootContext.qml new file mode 100644 index 0000000000..277db43d57 --- /dev/null +++ b/tests/auto/quick/qquickloader/data/rootContext.qml @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the manual tests 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 + +Rectangle { + width: 360 + height: 360 + + property alias loader: loader + + Loader { + id: loader + } + + property Component component: Item { + property bool trigger: false + onTriggerChanged: { + objectInRootContext.doIt() // make sure we can resolve objectInRootContext + loader.active = false + objectInRootContext.doIt() // make sure we can STILL resolve objectInRootContext + anotherProperty = true // see if we can trigger subsequent signal handlers (we shouldn't) + } + property bool anotherProperty: false + onAnotherPropertyChanged: { + // this should never be executed + objectInRootContext.doIt() + } + } +} diff --git a/tests/auto/quick/qquickloader/qquickloader.pro b/tests/auto/quick/qquickloader/qquickloader.pro index 32350388e8..c754c78bec 100644 --- a/tests/auto/quick/qquickloader/qquickloader.pro +++ b/tests/auto/quick/qquickloader/qquickloader.pro @@ -2,13 +2,13 @@ CONFIG += testcase TARGET = tst_qquickloader macx:CONFIG -= app_bundle -INCLUDEPATH += ../../shared/ HEADERS += ../../shared/testhttpserver.h SOURCES += tst_qquickloader.cpp \ ../../shared/testhttpserver.cpp include (../../shared/util.pri) +include (../shared/util.pri) TESTDATA = data/* diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index 3e7439f3e9..fbdd87905b 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -29,12 +29,18 @@ #include <QSignalSpy> +#include <QtQml/QQmlContext> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcomponent.h> #include <QtQml/qqmlincubator.h> +#include <QtQuick/qquickview.h> #include <private/qquickloader_p.h> +#include <private/qquickwindowmodule_p.h> #include "testhttpserver.h" #include "../../shared/util.h" +#include "../shared/geometrytestutil.h" + +Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") class SlowComponent : public QQmlComponent { @@ -49,11 +55,11 @@ class PeriodicIncubationController : public QObject, public QQmlIncubationController { public: - PeriodicIncubationController() : incubated(false) {} + PeriodicIncubationController() {} void start() { startTimer(20); } - bool incubated; + bool incubated = false; protected: virtual void timerEvent(QTimerEvent *) { @@ -74,8 +80,6 @@ public: tst_QQuickLoader(); private slots: - void cleanup(); - void sourceOrComponent(); void sourceOrComponent_data(); void clear(); @@ -113,22 +117,25 @@ private slots: void parented(); void sizeBound(); void QTBUG_30183(); + void transientWindow(); + void nestedTransientWindow(); void sourceComponentGarbageCollection(); -private: - QQmlEngine engine; + void bindings(); + void parentErrors(); + + void rootContext(); + void sourceURLKeepComponent(); + }; -void tst_QQuickLoader::cleanup() -{ - // clear components. otherwise we even bypass the test server by using the cache. - engine.clearComponentCache(); -} +Q_DECLARE_METATYPE(QList<QQmlError>) tst_QQuickLoader::tst_QQuickLoader() { qmlRegisterType<SlowComponent>("LoaderTest", 1, 0, "SlowComponent"); + qRegisterMetaType<QList<QQmlError>>(); } void tst_QQuickLoader::sourceOrComponent() @@ -142,6 +149,7 @@ void tst_QQuickLoader::sourceOrComponent() if (error) QTest::ignoreMessage(QtWarningMsg, errorString.toUtf8().constData()); + QQmlEngine engine; QQmlComponent component(&engine); component.setData(QByteArray( "import QtQuick 2.0\n" @@ -163,14 +171,14 @@ void tst_QQuickLoader::sourceOrComponent() "}") , dataDirectoryUrl()); - QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create()); - QVERIFY(loader != 0); - QCOMPARE(loader->item() == 0, error); + QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create())); + QVERIFY(loader != nullptr); + QCOMPARE(loader->item() == nullptr, error); QCOMPARE(loader->source(), sourceUrl); QCOMPARE(loader->progress(), 1.0); QCOMPARE(loader->status(), error ? QQuickLoader::Error : QQuickLoader::Ready); - QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), error ? 0: 1); + QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), error ? 0: 1); if (!error) { bool sourceComponentIsChildOfLoader = false; @@ -195,8 +203,6 @@ void tst_QQuickLoader::sourceOrComponent() QCOMPARE(loader->property("onItemChangedCount").toInt(), 1); QCOMPARE(loader->property("onLoadedCount").toInt(), error ? 0 : 1); - - delete loader; } void tst_QQuickLoader::sourceOrComponent_data() @@ -218,6 +224,8 @@ void tst_QQuickLoader::sourceOrComponent_data() void tst_QQuickLoader::clear() { + QQmlEngine engine; + { QQmlComponent component(&engine); component.setData(QByteArray( @@ -227,22 +235,20 @@ void tst_QQuickLoader::clear() " Timer { interval: 200; running: true; onTriggered: loader.source = '' }\n" " }") , dataDirectoryUrl()); - QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create()); - QVERIFY(loader != 0); + QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create())); + QVERIFY(loader != nullptr); QVERIFY(loader->item()); QCOMPARE(loader->progress(), 1.0); - QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1); + QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), 1); QTRY_VERIFY(!loader->item()); QCOMPARE(loader->progress(), 0.0); QCOMPARE(loader->status(), QQuickLoader::Null); - QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0); - - delete loader; + QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), 0); } { QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml")); - QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(component.create())); QVERIFY(item); QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0)); @@ -251,18 +257,16 @@ void tst_QQuickLoader::clear() QCOMPARE(loader->progress(), 1.0); QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1); - loader->setSourceComponent(0); + loader->setSourceComponent(nullptr); QVERIFY(!loader->item()); QCOMPARE(loader->progress(), 0.0); QCOMPARE(loader->status(), QQuickLoader::Null); QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0); - - delete item; } { QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml")); - QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(component.create())); QVERIFY(item); QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0)); @@ -271,19 +275,18 @@ void tst_QQuickLoader::clear() QCOMPARE(loader->progress(), 1.0); QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1); - QMetaObject::invokeMethod(item, "clear"); + QMetaObject::invokeMethod(item.data(), "clear"); QVERIFY(!loader->item()); QCOMPARE(loader->progress(), 0.0); QCOMPARE(loader->status(), QQuickLoader::Null); QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0); - - delete item; } } void tst_QQuickLoader::urlToComponent() { + QQmlEngine engine; QQmlComponent component(&engine); component.setData(QByteArray("import QtQuick 2.0\n" "Loader {\n" @@ -293,22 +296,21 @@ void tst_QQuickLoader::urlToComponent() " Timer { interval: 100; running: true; onTriggered: loader.sourceComponent = myComp }\n" "}" ) , dataDirectoryUrl()); - QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create()); + QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create())); QTest::qWait(200); - QTRY_VERIFY(loader != 0); + QTRY_VERIFY(loader != nullptr); QVERIFY(loader->item()); QCOMPARE(loader->progress(), 1.0); - QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1); + QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), 1); QCOMPARE(loader->width(), 10.0); QCOMPARE(loader->height(), 10.0); - - delete loader; } void tst_QQuickLoader::componentToUrl() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml")); - QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(component.create())); QVERIFY(item); QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0)); @@ -323,20 +325,19 @@ void tst_QQuickLoader::componentToUrl() QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1); QCOMPARE(loader->width(), 120.0); QCOMPARE(loader->height(), 60.0); - - delete item; } void tst_QQuickLoader::anchoredLoader() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("/AnchoredLoader.qml")); - QQuickItem *rootItem = qobject_cast<QQuickItem*>(component.create()); - QVERIFY(rootItem != 0); + QScopedPointer<QQuickItem> rootItem(qobject_cast<QQuickItem*>(component.create())); + QVERIFY(rootItem != nullptr); QQuickItem *loader = rootItem->findChild<QQuickItem*>("loader"); QQuickItem *sourceElement = rootItem->findChild<QQuickItem*>("sourceElement"); - QVERIFY(loader != 0); - QVERIFY(sourceElement != 0); + QVERIFY(loader != nullptr); + QVERIFY(sourceElement != nullptr); QCOMPARE(rootItem->width(), 300.0); QCOMPARE(rootItem->height(), 200.0); @@ -350,9 +351,10 @@ void tst_QQuickLoader::anchoredLoader() void tst_QQuickLoader::sizeLoaderToItem() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("/SizeToItem.qml")); - QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create()); - QVERIFY(loader != 0); + QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create())); + QVERIFY(loader != nullptr); QCOMPARE(loader->width(), 120.0); QCOMPARE(loader->height(), 60.0); @@ -385,15 +387,14 @@ void tst_QQuickLoader::sizeLoaderToItem() loader->setHeight(30); QCOMPARE(rect->width(), 180.0); QCOMPARE(rect->height(), 30.0); - - delete loader; } void tst_QQuickLoader::sizeItemToLoader() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("/SizeToLoader.qml")); - QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create()); - QVERIFY(loader != 0); + QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create())); + QVERIFY(loader != nullptr); QCOMPARE(loader->width(), 200.0); QCOMPARE(loader->height(), 80.0); @@ -403,10 +404,16 @@ void tst_QQuickLoader::sizeItemToLoader() QCOMPARE(rect->height(), 80.0); // Check resize - loader->setWidth(180); - loader->setHeight(30); - QCOMPARE(rect->width(), 180.0); - QCOMPARE(rect->height(), 30.0); + QSizeChangeListener sizeListener(rect); + const QSizeF size(180, 30); + loader->setSize(size); + QVERIFY2(!sizeListener.isEmpty(), "There should be at least one signal about the size changed"); + for (const QSizeF sizeOnGeometryChanged : sizeListener) { + // Check that we have the correct size on all signals + QCOMPARE(sizeOnGeometryChanged, size); + } + QCOMPARE(rect->width(), size.width()); + QCOMPARE(rect->height(), size.height()); // Switch mode loader->resetWidth(); // reset explicit size @@ -415,41 +422,37 @@ void tst_QQuickLoader::sizeItemToLoader() rect->setHeight(45); QCOMPARE(loader->width(), 160.0); QCOMPARE(loader->height(), 45.0); - - delete loader; } void tst_QQuickLoader::noResize() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("/NoResize.qml")); - QQuickItem* item = qobject_cast<QQuickItem*>(component.create()); - QVERIFY(item != 0); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(component.create())); + QVERIFY(item != nullptr); QCOMPARE(item->width(), 200.0); QCOMPARE(item->height(), 80.0); - - delete item; } void tst_QQuickLoader::networkRequestUrl() { ThreadedTestHTTPServer server(dataDirectory()); + QQmlEngine engine; QQmlComponent component(&engine); const QString qml = "import QtQuick 2.0\nLoader { property int signalCount : 0; source: \"" + server.baseUrl().toString() + "/Rect120x60.qml\"; onLoaded: signalCount += 1 }"; component.setData(qml.toUtf8(), testFileUrl("../dummy.qml")); if (component.isError()) qDebug() << component.errors(); - QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create()); - QVERIFY(loader != 0); + QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create())); + QVERIFY(loader != nullptr); QTRY_COMPARE(loader->status(), QQuickLoader::Ready); QVERIFY(loader->item()); QCOMPARE(loader->progress(), 1.0); QCOMPARE(loader->property("signalCount").toInt(), 1); - QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1); - - delete loader; + QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), 1); } /* XXX Component waits until all dependencies are loaded. Is this actually possible? */ @@ -457,6 +460,7 @@ void tst_QQuickLoader::networkComponent() { ThreadedTestHTTPServer server(dataDirectory(), TestHTTPServer::Delay); + QQmlEngine engine; QQmlComponent component(&engine); const QString qml = "import QtQuick 2.0\n" "import \"" + server.baseUrl().toString() + "/\" as NW\n" @@ -489,117 +493,108 @@ void tst_QQuickLoader::failNetworkRequest() QTest::ignoreMessage(QtWarningMsg, QString(server.baseUrl().toString() + "/IDontExist.qml: File not found").toUtf8()); + QQmlEngine engine; QQmlComponent component(&engine); const QString qml = "import QtQuick 2.0\nLoader { property int did_load: 123; source: \"" + server.baseUrl().toString() + "/IDontExist.qml\"; onLoaded: did_load=456 }"; component.setData(qml.toUtf8(), server.url("/dummy.qml")); QTRY_COMPARE(component.status(), QQmlComponent::Ready); - QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create()); - QVERIFY(loader != 0); + QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create())); + QVERIFY(loader != nullptr); QTRY_COMPARE(loader->status(), QQuickLoader::Error); QVERIFY(!loader->item()); QCOMPARE(loader->progress(), 1.0); QCOMPARE(loader->property("did_load").toInt(), 123); - QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0); - - delete loader; + QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), 0); } void tst_QQuickLoader::active() { + QQmlEngine engine; + // check that the item isn't instantiated until active is set to true { QQmlComponent component(&engine, testFileUrl("active.1.qml")); - QObject *object = component.create(); - QVERIFY(object != 0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); QQuickLoader *loader = object->findChild<QQuickLoader*>("loader"); QVERIFY(loader->active() == false); // set manually to false QVERIFY(!loader->item()); - QMetaObject::invokeMethod(object, "doSetSourceComponent"); + QMetaObject::invokeMethod(object.data(), "doSetSourceComponent"); QVERIFY(!loader->item()); - QMetaObject::invokeMethod(object, "doSetSource"); + QMetaObject::invokeMethod(object.data(), "doSetSource"); QVERIFY(!loader->item()); - QMetaObject::invokeMethod(object, "doSetActive"); - QVERIFY(loader->item() != 0); - - delete object; + QMetaObject::invokeMethod(object.data(), "doSetActive"); + QVERIFY(loader->item() != nullptr); } // check that the status is Null if active is set to false { QQmlComponent component(&engine, testFileUrl("active.2.qml")); - QObject *object = component.create(); - QVERIFY(object != 0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); QQuickLoader *loader = object->findChild<QQuickLoader*>("loader"); QVERIFY(loader->active() == true); // active is true by default QCOMPARE(loader->status(), QQuickLoader::Ready); int currStatusChangedCount = loader->property("statusChangedCount").toInt(); - QMetaObject::invokeMethod(object, "doSetInactive"); + QMetaObject::invokeMethod(object.data(), "doSetInactive"); QCOMPARE(loader->status(), QQuickLoader::Null); QCOMPARE(loader->property("statusChangedCount").toInt(), (currStatusChangedCount+1)); - - delete object; } // check that the source is not cleared if active is set to false { QQmlComponent component(&engine, testFileUrl("active.3.qml")); - QObject *object = component.create(); - QVERIFY(object != 0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); QQuickLoader *loader = object->findChild<QQuickLoader*>("loader"); QVERIFY(loader->active() == true); // active is true by default QVERIFY(!loader->source().isEmpty()); int currSourceChangedCount = loader->property("sourceChangedCount").toInt(); - QMetaObject::invokeMethod(object, "doSetInactive"); + QMetaObject::invokeMethod(object.data(), "doSetInactive"); QVERIFY(!loader->source().isEmpty()); QCOMPARE(loader->property("sourceChangedCount").toInt(), currSourceChangedCount); - - delete object; } // check that the sourceComponent is not cleared if active is set to false { QQmlComponent component(&engine, testFileUrl("active.4.qml")); - QObject *object = component.create(); - QVERIFY(object != 0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); QQuickLoader *loader = object->findChild<QQuickLoader*>("loader"); QVERIFY(loader->active() == true); // active is true by default - QVERIFY(loader->sourceComponent() != 0); + QVERIFY(loader->sourceComponent() != nullptr); int currSourceComponentChangedCount = loader->property("sourceComponentChangedCount").toInt(); - QMetaObject::invokeMethod(object, "doSetInactive"); - QVERIFY(loader->sourceComponent() != 0); + QMetaObject::invokeMethod(object.data(), "doSetInactive"); + QVERIFY(loader->sourceComponent() != nullptr); QCOMPARE(loader->property("sourceComponentChangedCount").toInt(), currSourceComponentChangedCount); - - delete object; } // check that the item is released if active is set to false { QQmlComponent component(&engine, testFileUrl("active.5.qml")); - QObject *object = component.create(); - QVERIFY(object != 0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); QQuickLoader *loader = object->findChild<QQuickLoader*>("loader"); QVERIFY(loader->active() == true); // active is true by default - QVERIFY(loader->item() != 0); + QVERIFY(loader->item() != nullptr); int currItemChangedCount = loader->property("itemChangedCount").toInt(); - QMetaObject::invokeMethod(object, "doSetInactive"); + QMetaObject::invokeMethod(object.data(), "doSetInactive"); QVERIFY(!loader->item()); QCOMPARE(loader->property("itemChangedCount").toInt(), (currItemChangedCount+1)); - - delete object; } // check that the activeChanged signal is emitted correctly { QQmlComponent component(&engine, testFileUrl("active.6.qml")); - QObject *object = component.create(); - QVERIFY(object != 0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); QQuickLoader *loader = object->findChild<QQuickLoader*>("loader"); QVERIFY(loader->active() == true); // active is true by default @@ -613,34 +608,30 @@ void tst_QQuickLoader::active() QCOMPARE(loader->property("activeChangedCount").toInt(), 2); loader->setActive(false); // change signal should be emitted QCOMPARE(loader->property("activeChangedCount").toInt(), 3); - QMetaObject::invokeMethod(object, "doSetActive"); + QMetaObject::invokeMethod(object.data(), "doSetActive"); QCOMPARE(loader->property("activeChangedCount").toInt(), 4); - QMetaObject::invokeMethod(object, "doSetActive"); + QMetaObject::invokeMethod(object.data(), "doSetActive"); QCOMPARE(loader->property("activeChangedCount").toInt(), 4); - QMetaObject::invokeMethod(object, "doSetInactive"); + QMetaObject::invokeMethod(object.data(), "doSetInactive"); QCOMPARE(loader->property("activeChangedCount").toInt(), 5); loader->setActive(true); // change signal should be emitted QCOMPARE(loader->property("activeChangedCount").toInt(), 6); - - delete object; } // check that the component isn't loaded until active is set to true { QQmlComponent component(&engine, testFileUrl("active.7.qml")); - QObject *object = component.create(); - QVERIFY(object != 0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); QCOMPARE(object->property("success").toBool(), true); - delete object; } // check that the component is loaded if active is not set (true by default) { QQmlComponent component(&engine, testFileUrl("active.8.qml")); - QObject *object = component.create(); - QVERIFY(object != 0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); QCOMPARE(object->property("success").toBool(), true); - delete object; } } @@ -704,14 +695,15 @@ void tst_QQuickLoader::initialPropertyValues() foreach (const QString &warning, expectedWarnings) QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); + QQmlEngine engine; QQmlComponent component(&engine, qmlFile); - QObject *object = component.beginCreate(engine.rootContext()); - QVERIFY(object != 0); + QScopedPointer<QObject> object(component.beginCreate(engine.rootContext())); + QVERIFY(object != nullptr); const int serverBaseUrlPropertyIndex = object->metaObject()->indexOfProperty("serverBaseUrl"); if (serverBaseUrlPropertyIndex != -1) { QMetaProperty prop = object->metaObject()->property(serverBaseUrlPropertyIndex); - QVERIFY(prop.write(object, server.baseUrl().toString())); + QVERIFY(prop.write(object.data(), server.baseUrl().toString())); } component.completeCreate(); @@ -722,20 +714,17 @@ void tst_QQuickLoader::initialPropertyValues() for (int i = 0; i < propertyNames.size(); ++i) QCOMPARE(object->property(propertyNames.at(i).toLatin1().constData()), propertyValues.at(i)); - - delete object; } void tst_QQuickLoader::initialPropertyValuesBinding() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("initialPropertyValues.binding.qml")); - QObject *object = component.create(); - QVERIFY(object != 0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); QVERIFY(object->setProperty("bindable", QVariant(8))); QCOMPARE(object->property("canaryValue").toInt(), 8); - - delete object; } void tst_QQuickLoader::initialPropertyValuesError_data() @@ -750,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") @@ -765,23 +754,24 @@ void tst_QQuickLoader::initialPropertyValuesError() foreach (const QString &warning, expectedWarnings) QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData()); + QQmlEngine engine; QQmlComponent component(&engine, qmlFile); - QObject *object = component.create(); - QVERIFY(object != 0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object != nullptr); QQuickLoader *loader = object->findChild<QQuickLoader*>("loader"); - QVERIFY(loader != 0); + QVERIFY(loader != nullptr); QVERIFY(!loader->item()); - delete object; } // QTBUG-9241 void tst_QQuickLoader::deleteComponentCrash() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("crash.qml")); - QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(component.create())); QVERIFY(item); - item->metaObject()->invokeMethod(item, "setLoaderSource"); + item->metaObject()->invokeMethod(item.data(), "setLoaderSource"); QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->QQuickItem::childItems().at(0)); QVERIFY(loader); @@ -789,73 +779,68 @@ void tst_QQuickLoader::deleteComponentCrash() QCOMPARE(loader->item()->objectName(), QLatin1String("blue")); QCOMPARE(loader->progress(), 1.0); QCOMPARE(loader->status(), QQuickLoader::Ready); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QCoreApplication::processEvents(); QTRY_COMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1); QCOMPARE(loader->source(), testFileUrl("BlueRect.qml")); - - delete item; } void tst_QQuickLoader::nonItem() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("nonItem.qml")); - QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create()); + QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create())); QVERIFY(loader); QVERIFY(loader->item()); - QCOMPARE(loader, loader->item()->parent()); + QCOMPARE(loader.data(), loader->item()->parent()); QPointer<QObject> item = loader->item(); loader->setActive(false); QVERIFY(!loader->item()); QTRY_VERIFY(!item); - - delete loader; } void tst_QQuickLoader::vmeErrors() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("vmeErrors.qml")); QString err = testFileUrl("VmeError.qml").toString() + ":6:26: Cannot assign object type QObject with no default method"; QTest::ignoreMessage(QtWarningMsg, err.toLatin1().constData()); - QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create()); + QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create())); QVERIFY(loader); QVERIFY(!loader->item()); - - delete loader; } // QTBUG-13481 void tst_QQuickLoader::creationContext() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("creationContext.qml")); - QObject *o = component.create(); - QVERIFY(o != 0); + QScopedPointer<QObject> o(component.create()); + QVERIFY(o != nullptr); QCOMPARE(o->property("test").toBool(), true); - - delete o; } void tst_QQuickLoader::QTBUG_16928() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("QTBUG_16928.qml")); - QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(component.create())); QVERIFY(item); QCOMPARE(item->width(), 250.); QCOMPARE(item->height(), 250.); - - delete item; } void tst_QQuickLoader::implicitSize() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("implicitSize.qml")); - QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(component.create())); QVERIFY(item); QCOMPARE(item->width(), 150.); @@ -868,27 +853,24 @@ void tst_QQuickLoader::implicitSize() QSignalSpy implWidthSpy(loader, SIGNAL(implicitWidthChanged())); QSignalSpy implHeightSpy(loader, SIGNAL(implicitHeightChanged())); - QMetaObject::invokeMethod(item, "changeImplicitSize"); + QMetaObject::invokeMethod(item.data(), "changeImplicitSize"); QCOMPARE(loader->property("implicitWidth").toReal(), 200.); QCOMPARE(loader->property("implicitHeight").toReal(), 300.); QCOMPARE(implWidthSpy.count(), 1); QCOMPARE(implHeightSpy.count(), 1); - - delete item; } void tst_QQuickLoader::QTBUG_17114() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("QTBUG_17114.qml")); - QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(component.create())); QVERIFY(item); QCOMPARE(item->property("loaderWidth").toReal(), 32.); QCOMPARE(item->property("loaderHeight").toReal(), 32.); - - delete item; } void tst_QQuickLoader::asynchronous_data() @@ -903,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() @@ -911,13 +893,14 @@ void tst_QQuickLoader::asynchronous() QFETCH(QUrl, qmlFile); QFETCH(QStringList, expectedWarnings); + QQmlEngine engine; PeriodicIncubationController *controller = new PeriodicIncubationController; QQmlIncubationController *previous = engine.incubationController(); engine.setIncubationController(controller); delete previous; QQmlComponent component(&engine, testFileUrl("asynchronous.qml")); - QQuickItem *root = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> root(qobject_cast<QQuickItem*>(component.create())); QVERIFY(root); QQuickLoader *loader = root->findChild<QQuickLoader*>("loader"); @@ -929,7 +912,7 @@ void tst_QQuickLoader::asynchronous() QVERIFY(!loader->item()); QCOMPARE(loader->progress(), 0.0); root->setProperty("comp", qmlFile.toString()); - QMetaObject::invokeMethod(root, "loadComponent"); + QMetaObject::invokeMethod(root.data(), "loadComponent"); QVERIFY(!loader->item()); if (expectedWarnings.isEmpty()) { @@ -945,19 +928,18 @@ void tst_QQuickLoader::asynchronous() QTRY_COMPARE(loader->progress(), 1.0); QTRY_COMPARE(loader->status(), QQuickLoader::Error); } - - delete root; } void tst_QQuickLoader::asynchronous_clear() { + QQmlEngine engine; PeriodicIncubationController *controller = new PeriodicIncubationController; QQmlIncubationController *previous = engine.incubationController(); engine.setIncubationController(controller); delete previous; QQmlComponent component(&engine, testFileUrl("asynchronous.qml")); - QQuickItem *root = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> root(qobject_cast<QQuickItem*>(component.create())); QVERIFY(root); QQuickLoader *loader = root->findChild<QQuickLoader*>("loader"); @@ -965,7 +947,7 @@ void tst_QQuickLoader::asynchronous_clear() QVERIFY(!loader->item()); root->setProperty("comp", "BigComponent.qml"); - QMetaObject::invokeMethod(root, "loadComponent"); + QMetaObject::invokeMethod(root.data(), "loadComponent"); QVERIFY(!loader->item()); controller->start(); @@ -974,7 +956,7 @@ void tst_QQuickLoader::asynchronous_clear() // clear before component created root->setProperty("comp", ""); - QMetaObject::invokeMethod(root, "loadComponent"); + QMetaObject::invokeMethod(root.data(), "loadComponent"); QVERIFY(!loader->item()); QCOMPARE(engine.incubationController()->incubatingObjectCount(), 0); @@ -984,7 +966,7 @@ void tst_QQuickLoader::asynchronous_clear() // check loading component root->setProperty("comp", "BigComponent.qml"); - QMetaObject::invokeMethod(root, "loadComponent"); + QMetaObject::invokeMethod(root.data(), "loadComponent"); QVERIFY(!loader->item()); QCOMPARE(loader->status(), QQuickLoader::Loading); @@ -994,19 +976,18 @@ void tst_QQuickLoader::asynchronous_clear() QCOMPARE(loader->progress(), 1.0); QCOMPARE(loader->status(), QQuickLoader::Ready); QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1); - - delete root; } void tst_QQuickLoader::simultaneousSyncAsync() { + QQmlEngine engine; PeriodicIncubationController *controller = new PeriodicIncubationController; QQmlIncubationController *previous = engine.incubationController(); engine.setIncubationController(controller); delete previous; QQmlComponent component(&engine, testFileUrl("simultaneous.qml")); - QQuickItem *root = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> root(qobject_cast<QQuickItem*>(component.create())); QVERIFY(root); QQuickLoader *asyncLoader = root->findChild<QQuickLoader*>("asyncLoader"); @@ -1016,7 +997,7 @@ void tst_QQuickLoader::simultaneousSyncAsync() QVERIFY(!asyncLoader->item()); QVERIFY(!syncLoader->item()); - QMetaObject::invokeMethod(root, "loadComponents"); + QMetaObject::invokeMethod(root.data(), "loadComponents"); QVERIFY(!asyncLoader->item()); QVERIFY(syncLoader->item()); @@ -1027,8 +1008,6 @@ void tst_QQuickLoader::simultaneousSyncAsync() QTRY_VERIFY(asyncLoader->item()); QCOMPARE(asyncLoader->progress(), 1.0); QCOMPARE(asyncLoader->status(), QQuickLoader::Ready); - - delete root; } void tst_QQuickLoader::asyncToSync1() @@ -1040,7 +1019,7 @@ void tst_QQuickLoader::asyncToSync1() delete previous; QQmlComponent component(&engine, testFileUrl("asynchronous.qml")); - QQuickItem *root = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> root(qobject_cast<QQuickItem*>(component.create())); QVERIFY(root); QQuickLoader *loader = root->findChild<QQuickLoader*>("loader"); @@ -1048,7 +1027,7 @@ void tst_QQuickLoader::asyncToSync1() QVERIFY(!loader->item()); root->setProperty("comp", "BigComponent.qml"); - QMetaObject::invokeMethod(root, "loadComponent"); + QMetaObject::invokeMethod(root.data(), "loadComponent"); QVERIFY(!loader->item()); controller->start(); @@ -1061,19 +1040,18 @@ void tst_QQuickLoader::asyncToSync1() QCOMPARE(loader->progress(), 1.0); QCOMPARE(loader->status(), QQuickLoader::Ready); QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1); - - delete root; } void tst_QQuickLoader::asyncToSync2() { + QQmlEngine engine; PeriodicIncubationController *controller = new PeriodicIncubationController; QQmlIncubationController *previous = engine.incubationController(); engine.setIncubationController(controller); delete previous; QQmlComponent component(&engine, testFileUrl("asynchronous.qml")); - QQuickItem *root = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> root(qobject_cast<QQuickItem*>(component.create())); QVERIFY(root); QQuickLoader *loader = root->findChild<QQuickLoader*>("loader"); @@ -1081,7 +1059,7 @@ void tst_QQuickLoader::asyncToSync2() QVERIFY(!loader->item()); root->setProperty("comp", "BigComponent.qml"); - QMetaObject::invokeMethod(root, "loadComponent"); + QMetaObject::invokeMethod(root.data(), "loadComponent"); QVERIFY(!loader->item()); controller->start(); @@ -1094,12 +1072,11 @@ void tst_QQuickLoader::asyncToSync2() QCOMPARE(loader->progress(), 1.0); QCOMPARE(loader->status(), QQuickLoader::Ready); QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1); - - delete root; } void tst_QQuickLoader::loadedSignal() { + QQmlEngine engine; PeriodicIncubationController *controller = new PeriodicIncubationController; QQmlIncubationController *previous = engine.incubationController(); engine.setIncubationController(controller); @@ -1110,84 +1087,79 @@ void tst_QQuickLoader::loadedSignal() // and then immediately setting active to false, causes the // loader to be deactivated, including disabling the incubator. QQmlComponent component(&engine, testFileUrl("loadedSignal.qml")); - QObject *obj = component.create(); + QScopedPointer<QObject> obj(component.create()); - QMetaObject::invokeMethod(obj, "triggerLoading"); + QMetaObject::invokeMethod(obj.data(), "triggerLoading"); QTest::qWait(100); // ensure that loading would have finished if it wasn't deactivated QCOMPARE(obj->property("loadCount").toInt(), 0); QVERIFY(obj->property("success").toBool()); - QMetaObject::invokeMethod(obj, "triggerLoading"); + QMetaObject::invokeMethod(obj.data(), "triggerLoading"); QTest::qWait(100); QCOMPARE(obj->property("loadCount").toInt(), 0); QVERIFY(obj->property("success").toBool()); - QMetaObject::invokeMethod(obj, "triggerMultipleLoad"); + QMetaObject::invokeMethod(obj.data(), "triggerMultipleLoad"); controller->start(); QTest::qWait(100); QTRY_COMPARE(obj->property("loadCount").toInt(), 1); // only one loaded signal should be emitted. QVERIFY(obj->property("success").toBool()); - - delete obj; } { // ensure that an error doesn't result in the onLoaded signal being emitted. QQmlComponent component(&engine, testFileUrl("loadedSignal.2.qml")); - QObject *obj = component.create(); + QScopedPointer<QObject> obj(component.create()); - QMetaObject::invokeMethod(obj, "triggerLoading"); + QMetaObject::invokeMethod(obj.data(), "triggerLoading"); QTest::qWait(100); QCOMPARE(obj->property("loadCount").toInt(), 0); QVERIFY(obj->property("success").toBool()); - - delete obj; } } void tst_QQuickLoader::parented() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("parented.qml")); - QQuickItem *root = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> root(qobject_cast<QQuickItem*>(component.create())); QVERIFY(root); QQuickItem *item = root->findChild<QQuickItem*>("comp"); QVERIFY(item); - QCOMPARE(item->parentItem(), root); + QCOMPARE(item->parentItem(), root.data()); QCOMPARE(item->width(), 300.); QCOMPARE(item->height(), 300.); - - delete root; } void tst_QQuickLoader::sizeBound() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("sizebound.qml")); - QQuickItem *root = qobject_cast<QQuickItem*>(component.create()); + QScopedPointer<QQuickItem> root(qobject_cast<QQuickItem*>(component.create())); QVERIFY(root); QQuickLoader *loader = root->findChild<QQuickLoader*>("loader"); - QVERIFY(loader != 0); + QVERIFY(loader != nullptr); QVERIFY(loader->item()); QCOMPARE(loader->width(), 50.0); QCOMPARE(loader->height(), 60.0); - QMetaObject::invokeMethod(root, "switchComponent"); + QMetaObject::invokeMethod(root.data(), "switchComponent"); QCOMPARE(loader->width(), 80.0); QCOMPARE(loader->height(), 90.0); - - delete root; } void tst_QQuickLoader::QTBUG_30183() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("/QTBUG_30183.qml")); - QQuickLoader *loader = qobject_cast<QQuickLoader*>(component.create()); - QVERIFY(loader != 0); + QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create())); + QVERIFY(loader != nullptr); QCOMPARE(loader->width(), 240.0); QCOMPARE(loader->height(), 120.0); @@ -1196,19 +1168,98 @@ void tst_QQuickLoader::QTBUG_30183() QVERIFY(rect); QCOMPARE(rect->width(), 240.0); QCOMPARE(rect->height(), 120.0); +} - delete loader; +void tst_QQuickLoader::transientWindow() // QTBUG-52944 +{ + QQuickView view; + view.setSource(testFileUrl("itemLoaderWindow.qml")); + QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject()); + QVERIFY(root); + QQuickLoader *loader = root->findChild<QQuickLoader *>(); + QVERIFY(loader); + QTRY_COMPARE(loader->status(), QQuickLoader::Ready); + QQuickWindowQmlImpl *loadedWindow = qobject_cast<QQuickWindowQmlImpl *>(loader->item()); + QVERIFY(loadedWindow); + QCOMPARE(loadedWindow->visibility(), QWindow::Hidden); + + QElapsedTimer timer; + qint64 viewVisibleTime = -1; + qint64 loadedWindowVisibleTime = -1; + connect(&view, &QWindow::visibleChanged, + [&viewVisibleTime, &timer]() { viewVisibleTime = timer.elapsed(); } ); + connect(loadedWindow, &QQuickWindowQmlImpl::visibilityChanged, + [&loadedWindowVisibleTime, &timer]() { loadedWindowVisibleTime = timer.elapsed(); } ); + timer.start(); + view.show(); + + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QTRY_VERIFY(loadedWindowVisibleTime >= 0); + QVERIFY(viewVisibleTime >= 0); + + // now that we're sure they are both visible, which one became visible first? + qCDebug(lcTests) << "transient Window became visible" << (loadedWindowVisibleTime - viewVisibleTime) << "ms after the root Item"; + QVERIFY((loadedWindowVisibleTime - viewVisibleTime) >= 0); + + QWindowList windows = QGuiApplication::topLevelWindows(); + QTRY_COMPARE(windows.size(), 2); + + // TODO Ideally we would now close the outer window and make sure the transient window closes too. + // It works during manual testing because of QWindowPrivate::maybeQuitOnLastWindowClosed() + // but quitting an autotest doesn't make sense. +} + +void tst_QQuickLoader::nestedTransientWindow() // QTBUG-52944 +{ + QQuickView view; + view.setSource(testFileUrl("itemLoaderItemWindow.qml")); + QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject()); + QVERIFY(root); + QQuickLoader *loader = root->findChild<QQuickLoader *>(); + QVERIFY(loader); + QTRY_COMPARE(loader->status(), QQuickLoader::Ready); + QQuickItem *loadedItem = qobject_cast<QQuickItem *>(loader->item()); + QVERIFY(loadedItem); + QQuickWindowQmlImpl *loadedWindow = loadedItem->findChild<QQuickWindowQmlImpl *>(); + QVERIFY(loadedWindow); + QCOMPARE(loadedWindow->visibility(), QWindow::Hidden); + + QElapsedTimer timer; + qint64 viewVisibleTime = -1; + qint64 loadedWindowVisibleTime = -1; + connect(&view, &QWindow::visibleChanged, + [&viewVisibleTime, &timer]() { viewVisibleTime = timer.elapsed(); } ); + connect(loadedWindow, &QQuickWindowQmlImpl::visibilityChanged, + [&loadedWindowVisibleTime, &timer]() { loadedWindowVisibleTime = timer.elapsed(); } ); + timer.start(); + view.show(); + + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QTRY_VERIFY(loadedWindowVisibleTime >= 0); + QVERIFY(viewVisibleTime >= 0); + + // now that we're sure they are both visible, which one became visible first? + qCDebug(lcTests) << "transient Window became visible" << (loadedWindowVisibleTime - viewVisibleTime) << "ms after the root Item"; + QVERIFY((loadedWindowVisibleTime - viewVisibleTime) >= 0); + + QWindowList windows = QGuiApplication::topLevelWindows(); + QTRY_COMPARE(windows.size(), 2); + + // TODO Ideally we would now close the outer window and make sure the transient window closes too. + // It works during manual testing because of QWindowPrivate::maybeQuitOnLastWindowClosed() + // but quitting an autotest doesn't make sense. } void tst_QQuickLoader::sourceComponentGarbageCollection() { + QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("sourceComponentGarbageCollection.qml")); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); QMetaObject::invokeMethod(obj.data(), "setSourceComponent"); engine.collectGarbage(); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QSignalSpy spy(obj.data(), SIGNAL(loaded())); @@ -1220,6 +1271,176 @@ void tst_QQuickLoader::sourceComponentGarbageCollection() QCOMPARE(spy.count(), 1); } +// QTBUG-51995 +void tst_QQuickLoader::bindings() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("bindings.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QQuickItem *game = object->property("game").value<QQuickItem*>(); + QVERIFY(game); + + QQuickLoader *loader = object->property("loader").value<QQuickLoader*>(); + QVERIFY(loader); + + QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QQmlError>))); + + // Causes the Loader to become active + game->setState(QLatin1String("running")); + QTRY_VERIFY(loader->item()); + + // Causes the Loader to become inactive - should not cause binding errors + game->setState(QLatin1String("invalid")); + QTRY_VERIFY(!loader->item()); + + QString failureMessage; + if (!warningsSpy.isEmpty()) { + QDebug stream(&failureMessage); + stream << warningsSpy.first().first().value<QList<QQmlError>>(); + } + QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage)); +} + +// QTBUG-47321 +void tst_QQuickLoader::parentErrors() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("parentErrors.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QQuickLoader *loader = object->property("loader").value<QQuickLoader*>(); + QVERIFY(loader); + + QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QQmlError>))); + + // Give the loader a component + loader->setSourceComponent(object->property("component").value<QQmlComponent*>()); + QTRY_VERIFY(loader->item()); + + // Clear the loader's component; should not cause binding errors + loader->setSourceComponent(nullptr); + QTRY_VERIFY(!loader->item()); + + QString failureMessage; + if (!warningsSpy.isEmpty()) { + QDebug stream(&failureMessage); + stream << warningsSpy.first().first().value<QList<QQmlError>>(); + } + QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage)); +} + +class ObjectInRootContext: public QObject +{ + Q_OBJECT + +public: + int didIt = 0; + +public slots: + void doIt() { + didIt += 1; + } +}; + +void tst_QQuickLoader::rootContext() +{ + QQmlEngine engine; + ObjectInRootContext objectInRootContext; + engine.rootContext()->setContextProperty("objectInRootContext", &objectInRootContext); + + QQmlComponent component(&engine, testFileUrl("rootContext.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QQuickLoader *loader = object->property("loader").value<QQuickLoader*>(); + QVERIFY(loader); + + QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QQmlError>))); + + // Give the loader a component + loader->setSourceComponent(object->property("component").value<QQmlComponent*>()); + QTRY_VERIFY(loader->active()); + QTRY_VERIFY(loader->item()); + + QString failureMessage; + if (!warningsSpy.isEmpty()) { + QDebug stream(&failureMessage); + stream << warningsSpy.first().first().value<QList<QQmlError>>(); + } + QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage)); + QCOMPARE(objectInRootContext.didIt, 0); + + // Deactivate the loader, which deletes the item. + // Check that a) there are no errors, and b) the objectInRootContext can still be resolved even + // after deactivating the loader. If it cannot, a ReferenceError for objectInRootContext is + // generated (and the 'doIt' counter in objectInRootContext will be 1 for the call before + // the deactivation). + loader->item()->setProperty("trigger", true); + QTRY_VERIFY(!loader->active()); + QTRY_VERIFY(!loader->item()); + + if (!warningsSpy.isEmpty()) { + QDebug stream(&failureMessage); + stream << warningsSpy.first().first().value<QList<QQmlError>>(); + } + QVERIFY2(warningsSpy.isEmpty(), qPrintable(failureMessage)); + QCOMPARE(objectInRootContext.didIt, 2); +} + +void tst_QQuickLoader::sourceURLKeepComponent() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData(QByteArray( + "import QtQuick 2.0\n" + " Loader { id: loader\n }"), + dataDirectoryUrl()); + + QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create())); + loader->setSource(testFileUrl("/Rect120x60.qml")); + + QVERIFY(loader); + QVERIFY(loader->item()); + QVERIFY(loader->sourceComponent()); + QCOMPARE(loader->progress(), 1.0); + + const QPointer<QQmlComponent> sourceComponent = loader->sourceComponent(); + + //Ensure toggling active status does not recreate component + loader->setActive(false); + QVERIFY(!loader->item()); + QVERIFY(loader->sourceComponent()); + QCOMPARE(sourceComponent.data(), loader->sourceComponent()); + + loader->setActive(true); + QVERIFY(loader->item()); + QVERIFY(loader->sourceComponent()); + QCOMPARE(sourceComponent.data(), loader->sourceComponent()); + + loader->setActive(false); + QVERIFY(!loader->item()); + QVERIFY(loader->sourceComponent()); + QCOMPARE(sourceComponent.data(), loader->sourceComponent()); + + //Ensure changing source url causes component to be recreated when inactive + loader->setSource(testFileUrl("/BlueRect.qml")); + + loader->setActive(true); + QVERIFY(loader->item()); + QVERIFY(loader->sourceComponent()); + + const QPointer<QQmlComponent> newSourceComponent = loader->sourceComponent(); + QVERIFY(sourceComponent.data() != newSourceComponent.data()); + + //Ensure changing source url causes component to be recreated when active + loader->setSource(testFileUrl("/Rect120x60.qml")); + QVERIFY(loader->sourceComponent() != newSourceComponent.data()); + +} + QTEST_MAIN(tst_QQuickLoader) #include "tst_qquickloader.moc" diff --git a/tests/auto/quick/qquickmousearea/data/mask.qml b/tests/auto/quick/qquickmousearea/data/mask.qml new file mode 100644 index 0000000000..ec315c2a63 --- /dev/null +++ b/tests/auto/quick/qquickmousearea/data/mask.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Ford Motor Company +** 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.11 +import Test 1.0 + +Item { + id: root + property int clicked: 0 + property int pressed: 0 + property int released: 0 + + width: 200; height: 200 + + MouseArea { + id: mouseArea + width: 200; height: 200 + onPressed: { root.pressed++ } + onClicked: { root.clicked++ } + onReleased: { root.released++ } + + containmentMask: CircleMask { + radius: mouseArea.width/2 + } + } +} + diff --git a/tests/auto/quick/qquickmousearea/data/nestedSendEvent.qml b/tests/auto/quick/qquickmousearea/data/nestedSendEvent.qml new file mode 100644 index 0000000000..908a43b04e --- /dev/null +++ b/tests/auto/quick/qquickmousearea/data/nestedSendEvent.qml @@ -0,0 +1,49 @@ +import QtQuick 2.11 +import QtQuick.Window 2.11 +import Test 1.0 + +Window { + id: window + visible: true + width: 200 + height: 200 + + property EventSender sender: EventSender { } + + Item { + width: 200 + height: 200 + + MouseArea { + anchors.fill: parent + } + + Item { + width: 200 + height: 200 + + Rectangle { + width: 200 + height: 100 + color: "red" + + MouseArea { + anchors.fill: parent + onPressed: sender.sendMouseClick(window, 50, 50) + } + } + + Rectangle { + y: 100 + width: 200 + height: 100 + color: "yellow" + + MouseArea { + anchors.fill: parent + onPressed: sender.sendMouseClick(window, 50, 50) + } + } + } + } +} diff --git a/tests/auto/quick/qquickmousearea/data/twoMouseAreas.qml b/tests/auto/quick/qquickmousearea/data/twoMouseAreas.qml new file mode 100644 index 0000000000..28f48c742a --- /dev/null +++ b/tests/auto/quick/qquickmousearea/data/twoMouseAreas.qml @@ -0,0 +1,33 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 + +Rectangle { + width: 400 + height: 300 + + property bool topPressed: top.pressed + property bool bottomPressed: bottom.pressed + + MouseArea { + id: top + objectName: "top" + width: parent.width + height: parent.height / 2 - 2 + Rectangle { + anchors.fill: parent + color: parent.pressed ? "MediumSeaGreen" : "beige" + } + } + + MouseArea { + id: bottom + objectName: "bottom" + y: parent.height / 2 + width: parent.width + height: parent.height / 2 + Rectangle { + anchors.fill: parent + color: parent.pressed ? "MediumSeaGreen" : "beige" + } + } +} diff --git a/tests/auto/quick/qquickmousearea/qquickmousearea.pro b/tests/auto/quick/qquickmousearea/qquickmousearea.pro index 3a4dfa946f..ee9d6dce2b 100644 --- a/tests/auto/quick/qquickmousearea/qquickmousearea.pro +++ b/tests/auto/quick/qquickmousearea/qquickmousearea.pro @@ -6,6 +6,8 @@ HEADERS += ../../shared/testhttpserver.h SOURCES += tst_qquickmousearea.cpp \ ../../shared/testhttpserver.cpp +OTHER_FILES += $$files(data/*.qml) + include (../../shared/util.pri) include (../shared/util.pri) diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index 01bce46ccb..52d1458a53 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -43,30 +43,51 @@ #include <QtGui/QScreen> #include <qpa/qwindowsysteminterface.h> -// Initialize view, set Url, center in available geometry, move mouse away if desired -static bool initView(QQuickView &v, const QUrl &url, bool moveMouseOut, QByteArray *errorMessage) +class CircleMask : public QObject { - v.setBaseSize(QSize(240,320)); - v.setSource(url); - while (v.status() == QQuickView::Loading) - QTest::qWait(10); - if (v.status() != QQuickView::Ready) { - foreach (const QQmlError &e, v.errors()) - errorMessage->append(e.toString().toLocal8Bit() + '\n'); - return false; + Q_OBJECT + Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged) + +public: + virtual ~CircleMask() {} + qreal radius() const { return m_radius; } + void setRadius(qreal radius) + { + if (m_radius == radius) + return; + m_radius = radius; + emit radiusChanged(); } - const QRect screenGeometry = v.screen()->availableGeometry(); - const QSize size = v.size(); - const QPoint offset = QPoint(size.width() / 2, size.height() / 2); - v.setFramePosition(screenGeometry.center() - offset); -#if QT_CONFIG(cursor) // Get the cursor out of the way. - if (moveMouseOut) - QCursor::setPos(v.geometry().topRight() + QPoint(100, 100)); -#else - Q_UNUSED(moveMouseOut) -#endif - return true; -} + + Q_INVOKABLE bool contains(const QPointF &point) const + { + QPointF center(m_radius, m_radius); + QLineF line(center, point); + return line.length() <= m_radius; + } + +signals: + void radiusChanged(); + +private: + qreal m_radius; +}; + +class EventSender : public QObject { + Q_OBJECT + +public: + Q_INVOKABLE void sendMouseClick(QObject* obj ,qreal x , qreal y) { + { + QMouseEvent event(QEvent::MouseButtonPress, QPointF(x , y), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + qApp->sendEvent(obj, &event); + } + { + QMouseEvent event(QEvent::MouseButtonRelease, QPointF(x , y), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + qApp->sendEvent(obj, &event); + } + } +}; class tst_QQuickMouseArea: public QQmlDataTest { @@ -74,10 +95,13 @@ class tst_QQuickMouseArea: public QQmlDataTest public: tst_QQuickMouseArea() : device(nullptr) - {} + { + qmlRegisterType<CircleMask>("Test", 1, 0, "CircleMask"); + qmlRegisterType<EventSender>("Test", 1, 0, "EventSender"); + } private slots: - void initTestCase() Q_DECL_OVERRIDE; + void initTestCase() override; void dragProperties(); void resetDrag(); void dragging_data() { acceptedButton_data(); } @@ -130,6 +154,10 @@ private slots: void notPressedAfterStolenGrab(); void pressAndHold_data(); void pressAndHold(); + void pressOneAndTapAnother_data(); + void pressOneAndTapAnother(); + void mask(); + void nestedEventDelivery(); private: int startDragDistance() const { @@ -182,22 +210,22 @@ void tst_QQuickMouseArea::dragProperties() QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("dragproperties.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("dragproperties.qml"), true, &errorMessage), errorMessage.constData()); window.show(); - QTest::qWaitForWindowExposed(&window); - QVERIFY(window.rootObject() != 0); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); QQuickDrag *drag = mouseRegion->drag(); - QVERIFY(mouseRegion != 0); - QVERIFY(drag != 0); + QVERIFY(mouseRegion != nullptr); + QVERIFY(drag != nullptr); // target QQuickItem *blackRect = window.rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QCOMPARE(blackRect, drag->target()); QQuickItem *rootItem = qobject_cast<QQuickItem*>(window.rootObject()); - QVERIFY(rootItem != 0); + QVERIFY(rootItem != nullptr); QSignalSpy targetSpy(drag, SIGNAL(targetChanged())); drag->setTarget(rootItem); QCOMPARE(targetSpy.count(),1); @@ -280,24 +308,24 @@ void tst_QQuickMouseArea::resetDrag() QQuickView window; QByteArray errorMessage; window.rootContext()->setContextProperty("haveTarget", QVariant(true)); - QVERIFY2(initView(window, testFileUrl("dragreset.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("dragreset.qml"), true, &errorMessage), errorMessage.constData()); window.show(); - QTest::qWaitForWindowExposed(&window); - QVERIFY(window.rootObject() != 0); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); QQuickDrag *drag = mouseRegion->drag(); - QVERIFY(mouseRegion != 0); - QVERIFY(drag != 0); + QVERIFY(mouseRegion != nullptr); + QVERIFY(drag != nullptr); // target QQuickItem *blackRect = window.rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QCOMPARE(blackRect, drag->target()); QQuickItem *rootItem = qobject_cast<QQuickItem*>(window.rootObject()); - QVERIFY(rootItem != 0); + QVERIFY(rootItem != nullptr); QSignalSpy targetSpy(drag, SIGNAL(targetChanged())); - QVERIFY(drag->target() != 0); + QVERIFY(drag->target() != nullptr); window.rootContext()->setContextProperty("haveTarget", QVariant(false)); QCOMPARE(targetSpy.count(),1); QVERIFY(!drag->target()); @@ -310,28 +338,28 @@ void tst_QQuickMouseArea::dragging() QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); QQuickDrag *drag = mouseRegion->drag(); - QVERIFY(mouseRegion != 0); - QVERIFY(drag != 0); + QVERIFY(mouseRegion != nullptr); + QVERIFY(drag != nullptr); mouseRegion->setAcceptedButtons(acceptedButtons); // target QQuickItem *blackRect = window.rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QCOMPARE(blackRect, drag->target()); QVERIFY(!drag->active()); QPoint p = QPoint(100,100); - QTest::mousePress(&window, button, 0, p); + QTest::mousePress(&window, button, Qt::NoModifier, p); QVERIFY(!drag->active()); QCOMPARE(blackRect->x(), 50.0); @@ -365,7 +393,7 @@ void tst_QQuickMouseArea::dragging() QTRY_COMPARE(blackRect->x(), 61.0); QCOMPARE(blackRect->y(), 61.0); - QTest::mouseRelease(&window, button, 0, p); + QTest::mouseRelease(&window, button, Qt::NoModifier, p); QTRY_VERIFY(!drag->active()); QTRY_COMPARE(blackRect->x(), 61.0); QCOMPARE(blackRect->y(), 61.0); @@ -375,11 +403,11 @@ void tst_QQuickMouseArea::dragSmoothed() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); QQuickDrag *drag = mouseRegion->drag(); @@ -387,17 +415,17 @@ void tst_QQuickMouseArea::dragSmoothed() mouseRegion->setAcceptedButtons(Qt::LeftButton); QQuickItem *blackRect = window.rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QCOMPARE(blackRect, drag->target()); QVERIFY(!drag->active()); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QVERIFY(!drag->active()); QTest::mouseMove(&window, QPoint(100, 102), 50); QTest::mouseMove(&window, QPoint(100, 106), 50); QTest::mouseMove(&window, QPoint(100, 122), 50); QTRY_COMPARE(blackRect->x(), 50.0); QTRY_COMPARE(blackRect->y(), 66.0); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(100,122)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100,122)); // reset rect position blackRect->setX(50.0); @@ -406,14 +434,14 @@ void tst_QQuickMouseArea::dragSmoothed() // now try with smoothed disabled drag->setSmoothed(false); QVERIFY(!drag->active()); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QVERIFY(!drag->active()); QTest::mouseMove(&window, QPoint(100, 102), 50); QTest::mouseMove(&window, QPoint(100, 106), 50); QTest::mouseMove(&window, QPoint(100, 122), 50); QTRY_COMPARE(blackRect->x(), 50.0); QTRY_COMPARE(blackRect->y(), 72.0); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(100, 122)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 122)); } void tst_QQuickMouseArea::dragThreshold_data() @@ -429,11 +457,11 @@ void tst_QQuickMouseArea::dragThreshold() QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); mouseRegion->setPreventStealing(preventStealing); @@ -443,10 +471,10 @@ void tst_QQuickMouseArea::dragThreshold() mouseRegion->setAcceptedButtons(Qt::LeftButton); QQuickItem *blackRect = window.rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QCOMPARE(blackRect, drag->target()); QVERIFY(!drag->active()); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QVERIFY(!drag->active()); QCOMPARE(blackRect->x(), 50.0); QCOMPARE(blackRect->y(), 50.0); @@ -465,18 +493,18 @@ void tst_QQuickMouseArea::dragThreshold() QTRY_VERIFY(drag->active()); QTRY_COMPARE(blackRect->x(), 50.0); QTRY_COMPARE(blackRect->y(), 66.0); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(122,122)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(122,122)); QTRY_VERIFY(!drag->active()); // Immediate drag threshold drag->setThreshold(0); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QTest::mouseMove(&window, QPoint(100, 122), 50); QVERIFY(!drag->active()); QTest::mouseMove(&window, QPoint(100, 123), 50); QVERIFY(drag->active()); QTest::mouseMove(&window, QPoint(100, 124), 50); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(100, 124)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 124)); QTRY_VERIFY(!drag->active()); drag->resetThreshold(); } @@ -487,26 +515,26 @@ void tst_QQuickMouseArea::invalidDrag() QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); window.show(); - QTest::qWaitForWindowExposed(&window); - QVERIFY(window.rootObject() != 0); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); QQuickDrag *drag = mouseRegion->drag(); - QVERIFY(mouseRegion != 0); - QVERIFY(drag != 0); + QVERIFY(mouseRegion != nullptr); + QVERIFY(drag != nullptr); mouseRegion->setAcceptedButtons(acceptedButtons); // target QQuickItem *blackRect = window.rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QCOMPARE(blackRect, drag->target()); QVERIFY(!drag->active()); - QTest::mousePress(&window, button, 0, QPoint(100,100)); + QTest::mousePress(&window, button, Qt::NoModifier, QPoint(100,100)); QVERIFY(!drag->active()); QCOMPARE(blackRect->x(), 50.0); @@ -524,7 +552,7 @@ void tst_QQuickMouseArea::invalidDrag() QCOMPARE(blackRect->x(), 50.0); QCOMPARE(blackRect->y(), 50.0); - QTest::mouseRelease(&window, button, 0, QPoint(122,122)); + QTest::mouseRelease(&window, button, Qt::NoModifier, QPoint(122,122)); QTest::qWait(50); QVERIFY(!drag->active()); @@ -536,28 +564,28 @@ void tst_QQuickMouseArea::cancelDragging() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); QQuickDrag *drag = mouseRegion->drag(); - QVERIFY(mouseRegion != 0); - QVERIFY(drag != 0); + QVERIFY(mouseRegion != nullptr); + QVERIFY(drag != nullptr); mouseRegion->setAcceptedButtons(Qt::LeftButton); // target QQuickItem *blackRect = window.rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QCOMPARE(blackRect, drag->target()); QVERIFY(!drag->active()); QPoint p = QPoint(100,100); - QTest::mousePress(&window, Qt::LeftButton, 0, p); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p); QVERIFY(!drag->active()); QCOMPARE(blackRect->x(), 50.0); @@ -583,7 +611,7 @@ void tst_QQuickMouseArea::cancelDragging() QCOMPARE(blackRect->x(), 61.0); QCOMPARE(blackRect->y(), 61.0); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(122,122)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(122,122)); } // QTBUG-58347 @@ -591,7 +619,7 @@ void tst_QQuickMouseArea::availableDistanceLessThanDragThreshold() { QQuickView view; QByteArray errorMessage; - QVERIFY2(initView(view, testFileUrl("availableDistanceLessThanDragThreshold.qml"), true, &errorMessage), + QVERIFY2(QQuickTest::initView(view, testFileUrl("availableDistanceLessThanDragThreshold.qml"), true, &errorMessage), errorMessage.constData()); view.show(); view.requestActivate(); @@ -602,14 +630,14 @@ void tst_QQuickMouseArea::availableDistanceLessThanDragThreshold() QVERIFY(mouseArea); QPoint position(100, 100); - QTest::mousePress(&view, Qt::LeftButton, 0, position); + QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position); QTest::qWait(10); position.setX(301); QTest::mouseMove(&view, position); position.setX(501); QTest::mouseMove(&view, position); QVERIFY(mouseArea->drag()->active()); - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); QVERIFY(!mouseArea->drag()->active()); QCOMPARE(mouseArea->x(), 200.0); @@ -619,10 +647,10 @@ void tst_QQuickMouseArea::setDragOnPressed() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("setDragOnPressed.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("setDragOnPressed.qml"), true, &errorMessage), errorMessage.constData()); window.show(); - QTest::qWaitForWindowExposed(&window); - QVERIFY(window.rootObject() != 0); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseArea = qobject_cast<QQuickMouseArea *>(window.rootObject()); QVERIFY(mouseArea); @@ -632,7 +660,7 @@ void tst_QQuickMouseArea::setDragOnPressed() QVERIFY(target); QPoint p = QPoint(100, 100); - QTest::mousePress(&window, Qt::LeftButton, 0, p); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p); QQuickDrag *drag = mouseArea->drag(); QVERIFY(drag); @@ -653,7 +681,7 @@ void tst_QQuickMouseArea::setDragOnPressed() QTRY_COMPARE(target->x(), 61.0); QCOMPARE(target->y(), 50.0); - QTest::mouseRelease(&window, Qt::LeftButton, 0, p); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p); QTRY_VERIFY(!drag->active()); QCOMPARE(target->x(), 61.0); QCOMPARE(target->y(), 50.0); @@ -663,21 +691,21 @@ void tst_QQuickMouseArea::updateMouseAreaPosOnClick() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("updateMousePosOnClick.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("updateMousePosOnClick.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); - QVERIFY(mouseRegion != 0); + QVERIFY(mouseRegion != nullptr); QQuickRectangle *rect = window.rootObject()->findChild<QQuickRectangle*>("ball"); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(mouseRegion->mouseX(), rect->x()); QCOMPARE(mouseRegion->mouseY(), rect->y()); - QMouseEvent event(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent event(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &event); QCOMPARE(mouseRegion->mouseX(), 100.0); @@ -691,21 +719,21 @@ void tst_QQuickMouseArea::updateMouseAreaPosOnResize() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("updateMousePosOnResize.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("updateMousePosOnResize.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); - QVERIFY(mouseRegion != 0); + QVERIFY(mouseRegion != nullptr); QQuickRectangle *rect = window.rootObject()->findChild<QQuickRectangle*>("brother"); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(mouseRegion->mouseX(), 0.0); QCOMPARE(mouseRegion->mouseY(), 0.0); - QMouseEvent event(QEvent::MouseButtonPress, rect->position().toPoint(), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent event(QEvent::MouseButtonPress, rect->position().toPoint(), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &event); QVERIFY(!mouseRegion->property("emitPositionChanged").toBool()); @@ -727,14 +755,14 @@ void tst_QQuickMouseArea::noOnClickedWithPressAndHold() // We handle onPressAndHold, therefore no onClicked QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("clickandhold.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("clickandhold.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseArea = qobject_cast<QQuickMouseArea*>(window.rootObject()->children().first()); QVERIFY(mouseArea); - QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &pressEvent); QCOMPARE(mouseArea->pressedButtons(), Qt::LeftButton); @@ -748,7 +776,7 @@ void tst_QQuickMouseArea::noOnClickedWithPressAndHold() QVERIFY(!window.rootObject()->property("clicked").toBool()); QVERIFY(window.rootObject()->property("held").toBool()); - QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &releaseEvent); QTRY_VERIFY(window.rootObject()->property("held").toBool()); @@ -759,19 +787,19 @@ void tst_QQuickMouseArea::noOnClickedWithPressAndHold() // We do not handle onPressAndHold, therefore we get onClicked QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("noclickandhold.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("noclickandhold.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); - QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &pressEvent); QVERIFY(!window.rootObject()->property("clicked").toBool()); QTest::qWait(1000); - QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &releaseEvent); QVERIFY(window.rootObject()->property("clicked").toBool()); @@ -782,10 +810,10 @@ void tst_QQuickMouseArea::onMousePressRejected() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("rejectEvent.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("rejectEvent.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QVERIFY(window.rootObject()->property("enabled").toBool()); QVERIFY(!window.rootObject()->property("mr1_pressed").toBool()); @@ -795,7 +823,7 @@ void tst_QQuickMouseArea::onMousePressRejected() QVERIFY(!window.rootObject()->property("mr2_released").toBool()); QVERIFY(!window.rootObject()->property("mr2_canceled").toBool()); - QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &pressEvent); QVERIFY(window.rootObject()->property("mr1_pressed").toBool()); @@ -807,7 +835,7 @@ void tst_QQuickMouseArea::onMousePressRejected() QTest::qWait(200); - QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &releaseEvent); QVERIFY(window.rootObject()->property("mr1_released").toBool()); @@ -829,10 +857,10 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate() QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("pressedCanceled.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("pressedCanceled.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QVERIFY(!window.rootObject()->property("pressed").toBool()); QVERIFY(!window.rootObject()->property("canceled").toBool()); @@ -842,8 +870,8 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate() QCOMPARE(window.rootObject()->property("clicked").toInt(), expectedClicks); - QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); - QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &pressEvent); @@ -860,7 +888,7 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate() QCOMPARE(window.rootObject()->property("clicked").toInt(), ++expectedClicks); QGuiApplication::sendEvent(&window, &pressEvent); - QMouseEvent pressEvent2(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent pressEvent2(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &pressEvent2); QTRY_VERIFY(window.rootObject()->property("pressed").toBool()); @@ -873,7 +901,7 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate() QWindow *secondWindow = qvariant_cast<QWindow*>(window.rootObject()->property("secondWindow")); secondWindow->setProperty("visible", true); - QTest::qWaitForWindowExposed(secondWindow); + QVERIFY(QTest::qWaitForWindowExposed(secondWindow)); QTRY_VERIFY(!window.rootObject()->property("pressed").toBool()); QVERIFY(window.rootObject()->property("canceled").toBool()); @@ -902,10 +930,10 @@ void tst_QQuickMouseArea::doubleClick() QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("doubleclick.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("doubleclick.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>("mousearea"); QVERIFY(mouseArea); @@ -913,16 +941,16 @@ void tst_QQuickMouseArea::doubleClick() // The sequence for a double click is: // press, release, (click), press, double click, release - QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, 0); + QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, nullptr); QGuiApplication::sendEvent(&window, &pressEvent); - QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, 0); + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, nullptr); QGuiApplication::sendEvent(&window, &releaseEvent); QCOMPARE(window.rootObject()->property("released").toInt(), 1); QGuiApplication::sendEvent(&window, &pressEvent); - pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, 0); + pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, nullptr); QGuiApplication::sendEvent(&window, &pressEvent); QGuiApplication::sendEvent(&window, &releaseEvent); @@ -939,19 +967,19 @@ void tst_QQuickMouseArea::clickTwice() QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("clicktwice.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("clicktwice.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>("mousearea"); QVERIFY(mouseArea); mouseArea->setAcceptedButtons(acceptedButtons); - QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, 0); + QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, nullptr); QGuiApplication::sendEvent(&window, &pressEvent); - QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, 0); + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, nullptr); QGuiApplication::sendEvent(&window, &releaseEvent); QCOMPARE(window.rootObject()->property("pressed").toInt(), 1); @@ -959,7 +987,7 @@ void tst_QQuickMouseArea::clickTwice() QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); QGuiApplication::sendEvent(&window, &pressEvent); - pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, 0); + pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, nullptr); QGuiApplication::sendEvent(&window, &pressEvent); QGuiApplication::sendEvent(&window, &releaseEvent); @@ -975,10 +1003,10 @@ void tst_QQuickMouseArea::invalidClick() QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("doubleclick.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("doubleclick.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>("mousearea"); QVERIFY(mouseArea); @@ -986,16 +1014,16 @@ void tst_QQuickMouseArea::invalidClick() // The sequence for a double click is: // press, release, (click), press, double click, release - QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, 0); + QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, nullptr); QGuiApplication::sendEvent(&window, &pressEvent); - QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, 0); + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, nullptr); QGuiApplication::sendEvent(&window, &releaseEvent); QCOMPARE(window.rootObject()->property("released").toInt(), 0); QGuiApplication::sendEvent(&window, &pressEvent); - pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, 0); + pressEvent = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, nullptr); QGuiApplication::sendEvent(&window, &pressEvent); QGuiApplication::sendEvent(&window, &releaseEvent); @@ -1008,19 +1036,19 @@ void tst_QQuickMouseArea::pressedOrdering() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("pressedOrdering.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("pressedOrdering.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QCOMPARE(window.rootObject()->property("value").toString(), QLatin1String("base")); - QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &pressEvent); QCOMPARE(window.rootObject()->property("value").toString(), QLatin1String("pressed")); - QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); + QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, nullptr); QGuiApplication::sendEvent(&window, &releaseEvent); QCOMPARE(window.rootObject()->property("value").toString(), QLatin1String("toggled")); @@ -1034,21 +1062,21 @@ void tst_QQuickMouseArea::preventStealing() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("preventstealing.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("preventstealing.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window.rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea*>("mousearea"); - QVERIFY(mouseArea != 0); + QVERIFY(mouseArea != nullptr); QSignalSpy mousePositionSpy(mouseArea, SIGNAL(positionChanged(QQuickMouseEvent*))); QPoint p = QPoint(80, 80); - QTest::mousePress(&window, Qt::LeftButton, 0, p); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p); // Without preventStealing, mouse movement over MouseArea would // cause the Flickable to steal mouse and trigger content movement. @@ -1071,13 +1099,13 @@ void tst_QQuickMouseArea::preventStealing() QCOMPARE(flickable->contentX(), 0.); QCOMPARE(flickable->contentY(), 0.); - QTest::mouseRelease(&window, Qt::LeftButton, 0, p); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p); // Now allow stealing and confirm Flickable does its thing. window.rootObject()->setProperty("stealing", false); p = QPoint(80, 80); - QTest::mousePress(&window, Qt::LeftButton, 0, p); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p); // Without preventStealing, mouse movement over MouseArea would // cause the Flickable to steal mouse and trigger content movement. @@ -1100,7 +1128,7 @@ void tst_QQuickMouseArea::preventStealing() QTRY_COMPARE(flickable->contentX(), 20.); QCOMPARE(flickable->contentY(), 20.); - QTest::mouseRelease(&window, Qt::LeftButton, 0, p); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p); } void tst_QQuickMouseArea::clickThrough() @@ -1108,30 +1136,30 @@ void tst_QQuickMouseArea::clickThrough() //With no handlers defined click, doubleClick and PressAndHold should propagate to those with handlers QScopedPointer<QQuickView> window(new QQuickView); QByteArray errorMessage; - QVERIFY2(initView(*window.data(), testFileUrl("clickThrough.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(*window.data(), testFileUrl("clickThrough.qml"), true, &errorMessage), errorMessage.constData()); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); // to avoid generating a double click. const int doubleClickInterval = qApp->styleHints()->mouseDoubleClickInterval() + 10; - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QTRY_COMPARE(window->rootObject()->property("presses").toInt(), 0); QTRY_COMPARE(window->rootObject()->property("clicks").toInt(), 1); QCOMPARE(window->rootObject()->property("doubleClicks").toInt(), 0); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QTRY_COMPARE(window->rootObject()->property("presses").toInt(), 0); QTRY_COMPARE(window->rootObject()->property("clicks").toInt(), 1); QTRY_COMPARE(window->rootObject()->property("pressAndHolds").toInt(), 1); - QTest::mouseDClick(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mouseDClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QTest::qWait(100); QCOMPARE(window->rootObject()->property("presses").toInt(), 0); @@ -1142,27 +1170,27 @@ void tst_QQuickMouseArea::clickThrough() window.reset(new QQuickView); //With handlers defined click, doubleClick and PressAndHold should propagate only when explicitly ignored - QVERIFY2(initView(*window.data(), testFileUrl("clickThrough2.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(*window.data(), testFileUrl("clickThrough2.qml"), true, &errorMessage), errorMessage.constData()); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QCOMPARE(window->rootObject()->property("presses").toInt(), 0); QCOMPARE(window->rootObject()->property("clicks").toInt(), 0); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QTest::qWait(100); QCOMPARE(window->rootObject()->property("presses").toInt(), 0); QCOMPARE(window->rootObject()->property("clicks").toInt(), 0); QCOMPARE(window->rootObject()->property("pressAndHolds").toInt(), 0); - QTest::mouseDClick(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mouseDClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QTest::qWait(100); QCOMPARE(window->rootObject()->property("presses").toInt(), 0); @@ -1172,22 +1200,22 @@ void tst_QQuickMouseArea::clickThrough() window->rootObject()->setProperty("letThrough", QVariant(true)); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100), doubleClickInterval); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QCOMPARE(window->rootObject()->property("presses").toInt(), 0); QTRY_COMPARE(window->rootObject()->property("clicks").toInt(), 1); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QTest::qWait(100); QCOMPARE(window->rootObject()->property("presses").toInt(), 0); QCOMPARE(window->rootObject()->property("clicks").toInt(), 1); QCOMPARE(window->rootObject()->property("pressAndHolds").toInt(), 1); - QTest::mouseDClick(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mouseDClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QTest::qWait(100); QCOMPARE(window->rootObject()->property("presses").toInt(), 0); @@ -1197,15 +1225,15 @@ void tst_QQuickMouseArea::clickThrough() window->rootObject()->setProperty("noPropagation", QVariant(true)); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100), doubleClickInterval); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QTest::qWait(100); - QTest::mouseDClick(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mouseDClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QTest::qWait(100); QCOMPARE(window->rootObject()->property("presses").toInt(), 0); @@ -1216,21 +1244,21 @@ void tst_QQuickMouseArea::clickThrough() window.reset(new QQuickView); //QTBUG-34368 - Shouldn't propagate to disabled mouse areas - QVERIFY2(initView(*window.data(), testFileUrl("qtbug34368.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(*window.data(), testFileUrl("qtbug34368.qml"), true, &errorMessage), errorMessage.constData()); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100), doubleClickInterval); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QCOMPARE(window->rootObject()->property("clicksEnabled").toInt(), 1); QCOMPARE(window->rootObject()->property("clicksDisabled").toInt(), 1); //Not disabled yet window->rootObject()->setProperty("disableLower", QVariant(true)); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100), doubleClickInterval); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QCOMPARE(window->rootObject()->property("clicksEnabled").toInt(), 2); QCOMPARE(window->rootObject()->property("clicksDisabled").toInt(), 1); //disabled, shouldn't increment @@ -1238,24 +1266,24 @@ void tst_QQuickMouseArea::clickThrough() window.reset(new QQuickView); //QTBUG-49100 - QVERIFY2(initView(*window.data(), testFileUrl("qtbug49100.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(*window.data(), testFileUrl("qtbug49100.qml"), true, &errorMessage), errorMessage.constData()); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); } void tst_QQuickMouseArea::hoverPosition() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("hoverPosition.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("hoverPosition.qml"), true, &errorMessage), errorMessage.constData()); QQuickItem *root = window.rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QCOMPARE(root->property("mouseX").toReal(), qreal(0)); QCOMPARE(root->property("mouseY").toReal(), qreal(0)); @@ -1272,20 +1300,20 @@ void tst_QQuickMouseArea::hoverPropagation() //QTBUG-18175, to behave like GV did. QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("hoverPropagation.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("hoverPropagation.qml"), true, &errorMessage), errorMessage.constData()); QQuickItem *root = window.rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QCOMPARE(root->property("point1").toBool(), false); QCOMPARE(root->property("point2").toBool(), false); - QMouseEvent moveEvent(QEvent::MouseMove, QPoint(32, 32), Qt::NoButton, Qt::NoButton, 0); + QMouseEvent moveEvent(QEvent::MouseMove, QPoint(32, 32), Qt::NoButton, Qt::NoButton, nullptr); QGuiApplication::sendEvent(&window, &moveEvent); QCOMPARE(root->property("point1").toBool(), true); QCOMPARE(root->property("point2").toBool(), false); - QMouseEvent moveEvent2(QEvent::MouseMove, QPoint(232, 32), Qt::NoButton, Qt::NoButton, 0); + QMouseEvent moveEvent2(QEvent::MouseMove, QPoint(232, 32), Qt::NoButton, Qt::NoButton, nullptr); QGuiApplication::sendEvent(&window, &moveEvent2); QCOMPARE(root->property("point1").toBool(), false); QCOMPARE(root->property("point2").toBool(), true); @@ -1293,14 +1321,18 @@ void tst_QQuickMouseArea::hoverPropagation() void tst_QQuickMouseArea::hoverVisible() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("hoverVisible.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("hoverVisible.qml"), true, &errorMessage), errorMessage.constData()); QQuickItem *root = window.rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QQuickMouseArea *mouseTracker = window.rootObject()->findChild<QQuickMouseArea*>("mousetracker"); - QVERIFY(mouseTracker != 0); + QVERIFY(mouseTracker != nullptr); QSignalSpy enteredSpy(mouseTracker, SIGNAL(entered())); @@ -1323,12 +1355,12 @@ void tst_QQuickMouseArea::hoverAfterPress() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("hoverAfterPress.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("hoverAfterPress.qml"), true, &errorMessage), errorMessage.constData()); QQuickItem *root = window.rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea*>("mouseArea"); - QVERIFY(mouseArea != 0); + QVERIFY(mouseArea != nullptr); QTest::mouseMove(&window, QPoint(22,33)); QCOMPARE(mouseArea->hovered(), false); QTest::mouseMove(&window, QPoint(200,200)); @@ -1349,13 +1381,13 @@ void tst_QQuickMouseArea::subtreeHoverEnabled() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("qtbug54019.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("qtbug54019.qml"), true, &errorMessage), errorMessage.constData()); QQuickItem *root = window.rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QQuickMouseArea *mouseArea = root->findChild<QQuickMouseArea*>(); QQuickItemPrivate *rootPrivate = QQuickItemPrivate::get(root); - QVERIFY(mouseArea != 0); + QVERIFY(mouseArea != nullptr); QTest::mouseMove(&window, QPoint(10, 160)); QCOMPARE(mouseArea->hovered(), false); QVERIFY(rootPrivate->subtreeHoverEnabled); @@ -1369,15 +1401,15 @@ void tst_QQuickMouseArea::disableAfterPress() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); QQuickDrag *drag = mouseArea->drag(); - QVERIFY(mouseArea != 0); - QVERIFY(drag != 0); + QVERIFY(mouseArea != nullptr); + QVERIFY(drag != nullptr); QSignalSpy mousePositionSpy(mouseArea, SIGNAL(positionChanged(QQuickMouseEvent*))); QSignalSpy mousePressSpy(mouseArea, SIGNAL(pressed(QQuickMouseEvent*))); @@ -1385,12 +1417,12 @@ void tst_QQuickMouseArea::disableAfterPress() // target QQuickItem *blackRect = window.rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QCOMPARE(blackRect, drag->target()); QVERIFY(!drag->active()); QPoint p = QPoint(100,100); - QTest::mousePress(&window, Qt::LeftButton, 0, p); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p); QTRY_COMPARE(mousePressSpy.count(), 1); QVERIFY(!drag->active()); @@ -1428,7 +1460,7 @@ void tst_QQuickMouseArea::disableAfterPress() QVERIFY(mouseArea->pressed()); QVERIFY(mouseArea->hovered()); - QTest::mouseRelease(&window, Qt::LeftButton, 0, p); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p); QTRY_COMPARE(mouseReleaseSpy.count(), 1); @@ -1447,7 +1479,7 @@ void tst_QQuickMouseArea::disableAfterPress() mousePositionSpy.clear(); mouseReleaseSpy.clear(); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); QTest::qWait(50); QCOMPARE(mousePressSpy.count(), 0); @@ -1462,7 +1494,7 @@ void tst_QQuickMouseArea::disableAfterPress() QCOMPARE(blackRect->x(), 50.0); QCOMPARE(blackRect->y(), 50.0); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(122,122)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(122,122)); QTest::qWait(50); QCOMPARE(mouseReleaseSpy.count(), 0); @@ -1472,9 +1504,9 @@ void tst_QQuickMouseArea::onWheel() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("wheel.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("wheel.qml"), true, &errorMessage), errorMessage.constData()); QQuickItem *root = window.rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QWheelEvent wheelEvent(QPoint(10, 32), QPoint(10, 32), QPoint(60, 20), QPoint(0, 120), 0, Qt::Vertical,Qt::NoButton, Qt::ControlModifier); @@ -1516,13 +1548,13 @@ void tst_QQuickMouseArea::transformedMouseArea() QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("transformedMouseArea.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("transformedMouseArea.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>("mouseArea"); - QVERIFY(mouseArea != 0); + QVERIFY(mouseArea != nullptr); foreach (const QPoint &point, points) { // check hover @@ -1530,133 +1562,123 @@ void tst_QQuickMouseArea::transformedMouseArea() QTRY_COMPARE(mouseArea->property("containsMouse").toBool(), insideTarget); // check mouse press - QTest::mousePress(&window, Qt::LeftButton, 0, point); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, point); QTRY_COMPARE(mouseArea->property("pressed").toBool(), insideTarget); // check mouse release - QTest::mouseRelease(&window, Qt::LeftButton, 0, point); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, point); QTRY_COMPARE(mouseArea->property("pressed").toBool(), false); } } +struct MouseEvent { + QEvent::Type type; + Qt::MouseButton button; +}; +Q_DECLARE_METATYPE(MouseEvent) + void tst_QQuickMouseArea::pressedMultipleButtons_data() { QTest::addColumn<Qt::MouseButtons>("accepted"); - QTest::addColumn<QList<Qt::MouseButtons> >("buttons"); + QTest::addColumn<QList<MouseEvent> >("mouseEvents"); QTest::addColumn<QList<bool> >("pressed"); QTest::addColumn<QList<Qt::MouseButtons> >("pressedButtons"); QTest::addColumn<int>("changeCount"); - QList<Qt::MouseButtons> buttons; + Qt::MouseButtons accepted; + QList<MouseEvent> mouseEvents; QList<bool> pressed; QList<Qt::MouseButtons> pressedButtons; - buttons << Qt::LeftButton - << (Qt::LeftButton | Qt::RightButton) - << Qt::LeftButton - << 0; - pressed << true - << true - << true - << false; - pressedButtons << Qt::LeftButton - << Qt::LeftButton - << Qt::LeftButton - << 0; - QTest::newRow("Accept Left - Press left, Press Right, Release Right") - << Qt::MouseButtons(Qt::LeftButton) << buttons << pressed << pressedButtons << 2; - - buttons.clear(); - pressed.clear(); - pressedButtons.clear(); - buttons << Qt::LeftButton - << (Qt::LeftButton | Qt::RightButton) - << Qt::RightButton - << 0; - pressed << true - << true - << false - << false; - pressedButtons << Qt::LeftButton - << Qt::LeftButton - << 0 - << 0; - QTest::newRow("Accept Left - Press left, Press Right, Release Left") - << Qt::MouseButtons(Qt::LeftButton) << buttons << pressed << pressedButtons << 2; - - buttons.clear(); - pressed.clear(); - pressedButtons.clear(); - buttons << Qt::LeftButton - << (Qt::LeftButton | Qt::RightButton) - << Qt::LeftButton - << 0; - pressed << true - << true - << true - << false; - pressedButtons << Qt::LeftButton - << (Qt::LeftButton | Qt::RightButton) - << Qt::LeftButton - << 0; - QTest::newRow("Accept Left|Right - Press left, Press Right, Release Right") - << (Qt::LeftButton | Qt::RightButton) << buttons << pressed << pressedButtons << 4; - - buttons.clear(); - pressed.clear(); - pressedButtons.clear(); - buttons << Qt::RightButton - << (Qt::LeftButton | Qt::RightButton) - << Qt::LeftButton - << 0; - pressed << true - << true - << false - << false; - pressedButtons << Qt::RightButton - << Qt::RightButton - << 0 - << 0; - QTest::newRow("Accept Right - Press Right, Press Left, Release Right") - << Qt::MouseButtons(Qt::RightButton) << buttons << pressed << pressedButtons << 2; + int changeCount; + + MouseEvent leftPress = { QEvent::MouseButtonPress, Qt::LeftButton }; + MouseEvent leftRelease = { QEvent::MouseButtonRelease, Qt::LeftButton }; + MouseEvent rightPress = { QEvent::MouseButtonPress, Qt::RightButton }; + MouseEvent rightRelease = { QEvent::MouseButtonRelease, Qt::RightButton }; + + auto addRowWithFormattedTitleAndReset = [&]() { + QByteArray title; + title.append("Accept:"); + if (accepted & Qt::LeftButton) + title.append(" LeftButton"); + if (accepted & Qt::RightButton) + title.append(" RightButton"); + title.append(" | Events:"); + for (MouseEvent event : mouseEvents) { + title.append(event.type == QEvent::MouseButtonPress ? " Press" : " Release"); + title.append(event.button == Qt::LeftButton ? " Left," : " Right,"); + } + title.chop(1); // remove last comma + QTest::newRow(title) << accepted << mouseEvents << pressed << pressedButtons << changeCount; + + mouseEvents.clear(); + pressed.clear(); + pressedButtons.clear(); + }; + + accepted = Qt::LeftButton; + changeCount = 2; + mouseEvents << leftPress << rightPress << rightRelease << leftRelease; + pressed << true << true << true << false; + pressedButtons << Qt::LeftButton << Qt::LeftButton << Qt::LeftButton << Qt::NoButton; + addRowWithFormattedTitleAndReset(); + + accepted = Qt::LeftButton; + changeCount = 2; + mouseEvents << leftPress << rightPress << leftRelease << rightRelease; + pressed << true << true << false << false; + pressedButtons << Qt::LeftButton << Qt::LeftButton << Qt::NoButton << Qt::NoButton; + addRowWithFormattedTitleAndReset(); + + accepted = Qt::LeftButton | Qt::RightButton; + changeCount = 4; + mouseEvents << leftPress << rightPress << rightRelease << leftRelease; + pressed << true << true << true << false; + pressedButtons << Qt::LeftButton << (Qt::LeftButton | Qt::RightButton) << Qt::LeftButton + << Qt::NoButton; + addRowWithFormattedTitleAndReset(); + + accepted = Qt::RightButton; + changeCount = 2; + mouseEvents << rightPress << leftPress << rightRelease << leftRelease; + pressed << true << true << false << false; + pressedButtons << Qt::RightButton << Qt::RightButton << Qt::NoButton << Qt::NoButton; + addRowWithFormattedTitleAndReset(); } void tst_QQuickMouseArea::pressedMultipleButtons() { QFETCH(Qt::MouseButtons, accepted); - QFETCH(QList<Qt::MouseButtons>, buttons); + QFETCH(QList<MouseEvent>, mouseEvents); QFETCH(QList<bool>, pressed); QFETCH(QList<Qt::MouseButtons>, pressedButtons); QFETCH(int, changeCount); QQuickView view; QByteArray errorMessage; - QVERIFY2(initView(view, testFileUrl("simple.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(view, testFileUrl("simple.qml"), true, &errorMessage), errorMessage.constData()); view.show(); - QTest::qWaitForWindowExposed(&view); - QVERIFY(view.rootObject() != 0); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QVERIFY(view.rootObject() != nullptr); QQuickMouseArea *mouseArea = view.rootObject()->findChild<QQuickMouseArea *>("mousearea"); - QVERIFY(mouseArea != 0); + QVERIFY(mouseArea != nullptr); QSignalSpy pressedSpy(mouseArea, SIGNAL(pressedChanged())); QSignalSpy pressedButtonsSpy(mouseArea, SIGNAL(pressedButtonsChanged())); mouseArea->setAcceptedMouseButtons(accepted); - QPoint point(10,10); - - for (int i = 0; i < buttons.count(); ++i) { - int btns = buttons.at(i); - - // The windowsysteminterface takes care of sending releases - QTest::mousePress(&view, (Qt::MouseButton)btns, 0, point); - + QPoint point(10, 10); + for (int i = 0; i < mouseEvents.count(); ++i) { + const MouseEvent mouseEvent = mouseEvents.at(i); + if (mouseEvent.type == QEvent::MouseButtonPress) + QTest::mousePress(&view, mouseEvent.button, Qt::NoModifier, point); + else + QTest::mouseRelease(&view, mouseEvent.button, Qt::NoModifier, point); QCOMPARE(mouseArea->pressed(), pressed.at(i)); QCOMPARE(mouseArea->pressedButtons(), pressedButtons.at(i)); } - QTest::mousePress(&view, Qt::NoButton, 0, point); - QCOMPARE(mouseArea->pressed(), false); - QCOMPARE(pressedSpy.count(), 2); QCOMPARE(pressedButtonsSpy.count(), changeCount); } @@ -1665,28 +1687,28 @@ void tst_QQuickMouseArea::changeAxis() { QQuickView view; QByteArray errorMessage; - QVERIFY2(initView(view, testFileUrl("changeAxis.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(view, testFileUrl("changeAxis.qml"), true, &errorMessage), errorMessage.constData()); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - QTRY_VERIFY(view.rootObject() != 0); + QTRY_VERIFY(view.rootObject() != nullptr); QQuickMouseArea *mouseRegion = view.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); QQuickDrag *drag = mouseRegion->drag(); - QVERIFY(mouseRegion != 0); - QVERIFY(drag != 0); + QVERIFY(mouseRegion != nullptr); + QVERIFY(drag != nullptr); mouseRegion->setAcceptedButtons(Qt::LeftButton); // target QQuickItem *blackRect = view.rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QCOMPARE(blackRect, drag->target()); QVERIFY(!drag->active()); // Start a diagonal drag QPoint p = QPoint(100, 100); - QTest::mousePress(&view, Qt::LeftButton, 0, p); + QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, p); QVERIFY(!drag->active()); QCOMPARE(blackRect->x(), 50.0); @@ -1717,7 +1739,7 @@ void tst_QQuickMouseArea::changeAxis() QTRY_COMPARE(blackRect->y(), 94.0); QCOMPARE(blackRect->x(), 83.0); - QTest::mouseRelease(&view, Qt::LeftButton, 0, p); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, p); QTRY_VERIFY(!drag->active()); QCOMPARE(blackRect->x(), 83.0); @@ -1758,14 +1780,14 @@ void tst_QQuickMouseArea::moveAndReleaseWithoutPress() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("moveAndReleaseWithoutPress.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("moveAndReleaseWithoutPress.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); QObject *root = window.rootObject(); QVERIFY(root); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); // the press was not accepted, make sure there is no move or release event QTest::mouseMove(&window, QPoint(110,110), 50); @@ -1775,7 +1797,7 @@ void tst_QQuickMouseArea::moveAndReleaseWithoutPress() QTest::qWait(100); QCOMPARE(root->property("hadMove").toBool(), false); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(110,110)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(110,110)); QTest::qWait(100); QCOMPARE(root->property("hadRelease").toBool(), false); } @@ -1798,7 +1820,7 @@ void tst_QQuickMouseArea::nestedStopAtBounds() QQuickView view; QByteArray errorMessage; - QVERIFY2(initView(view, testFileUrl("nestedStopAtBounds.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(view, testFileUrl("nestedStopAtBounds.qml"), true, &errorMessage), errorMessage.constData()); view.show(); view.requestActivate(); QVERIFY(QTest::qWaitForWindowExposed(&view)); @@ -1819,7 +1841,7 @@ void tst_QQuickMouseArea::nestedStopAtBounds() int &axis = transpose ? position.ry() : position.rx(); // drag toward the aligned boundary. Outer mouse area dragged. - QTest::mousePress(&view, Qt::LeftButton, 0, position); + QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position); QTest::qWait(10); axis += invert ? threshold * 2 : -threshold * 2; QTest::mouseMove(&view, position); @@ -1827,7 +1849,7 @@ void tst_QQuickMouseArea::nestedStopAtBounds() QTest::mouseMove(&view, position); QCOMPARE(outer->drag()->active(), true); QCOMPARE(inner->drag()->active(), false); - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); QVERIFY(!outer->drag()->active()); @@ -1836,7 +1858,7 @@ void tst_QQuickMouseArea::nestedStopAtBounds() outer->setY(50); // drag away from the aligned boundary. Inner mouse area dragged. - QTest::mousePress(&view, Qt::LeftButton, 0, position); + QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position); QTest::qWait(10); axis += invert ? -threshold * 2 : threshold * 2; QTest::mouseMove(&view, position); @@ -1844,14 +1866,14 @@ void tst_QQuickMouseArea::nestedStopAtBounds() QTest::mouseMove(&view, position); QTRY_COMPARE(outer->drag()->active(), false); QTRY_COMPARE(inner->drag()->active(), true); - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); } void tst_QQuickMouseArea::nestedFlickableStopAtBounds() { QQuickView view; QByteArray errorMessage; - QVERIFY2(initView(view, testFileUrl("nestedFlickableStopAtBounds.qml"), false, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(view, testFileUrl("nestedFlickableStopAtBounds.qml"), false, &errorMessage), errorMessage.constData()); view.show(); view.requestActivate(); QVERIFY(QTest::qWaitForWindowExposed(&view)); @@ -1869,7 +1891,7 @@ void tst_QQuickMouseArea::nestedFlickableStopAtBounds() int &pos = position.ry(); // Drag up - should move the Flickable to end - QTest::mousePress(&view, Qt::LeftButton, 0, position); + QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position); QTest::qWait(10); pos -= threshold * 2; QTest::mouseMove(&view, position); @@ -1881,7 +1903,7 @@ void tst_QQuickMouseArea::nestedFlickableStopAtBounds() QVERIFY(flickable->isDragging()); QVERIFY(!mouseArea->drag()->active()); QCOMPARE(flickable->isAtYEnd(), true); - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); QTRY_VERIFY(!flickable->isMoving()); @@ -1889,7 +1911,7 @@ void tst_QQuickMouseArea::nestedFlickableStopAtBounds() // Drag up again - should activate MouseArea drag QVERIFY(!mouseArea->drag()->active()); - QTest::mousePress(&view, Qt::LeftButton, 0, position); + QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position); QTest::qWait(10); pos -= threshold * 2; QTest::mouseMove(&view, position); @@ -1901,12 +1923,12 @@ void tst_QQuickMouseArea::nestedFlickableStopAtBounds() QVERIFY(mouseArea->drag()->active()); QCOMPARE(flickable->isAtYEnd(), true); QVERIFY(!flickable->isDragging()); - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); // Drag to the top and verify that the MouseArea doesn't steal the grab when we drag back (QTBUG-56036) pos = 50; - QTest::mousePress(&view, Qt::LeftButton, 0, position); + QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position); QTest::qWait(10); pos += threshold; QTest::mouseMove(&view, position); @@ -1918,14 +1940,14 @@ void tst_QQuickMouseArea::nestedFlickableStopAtBounds() QVERIFY(flickable->isDragging()); QVERIFY(!mouseArea->drag()->active()); QCOMPARE(flickable->isAtYBeginning(), true); - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); QTRY_VERIFY(!flickable->isMoving()); pos = 280; // Drag up again - should not activate MouseArea drag - QTest::mousePress(&view, Qt::LeftButton, 0, position); + QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, position); QTest::qWait(10); pos -= threshold; QTest::mouseMove(&view, position); @@ -1936,7 +1958,7 @@ void tst_QQuickMouseArea::nestedFlickableStopAtBounds() QTest::mouseMove(&view, position); QVERIFY(flickable->isDragging()); QVERIFY(!mouseArea->drag()->active()); - QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, position); } void tst_QQuickMouseArea::containsPress_data() @@ -1953,15 +1975,15 @@ void tst_QQuickMouseArea::containsPress() QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("containsPress.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("containsPress.qml"), true, &errorMessage), errorMessage.constData()); window.show(); window.requestActivate(); QVERIFY(QTest::qWaitForWindowExposed(&window)); QQuickItem *root = window.rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea*>("mouseArea"); - QVERIFY(mouseArea != 0); + QVERIFY(mouseArea != nullptr); QSignalSpy containsPressSpy(mouseArea, SIGNAL(containsPressChanged())); @@ -2006,7 +2028,7 @@ void tst_QQuickMouseArea::ignoreBySource() { QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("ignoreBySource.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("ignoreBySource.qml"), true, &errorMessage), errorMessage.constData()); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); QVERIFY(window.rootObject()); @@ -2022,7 +2044,7 @@ void tst_QQuickMouseArea::ignoreBySource() // MouseArea should grab the press because it's interested in non-synthesized mouse events QPoint p = QPoint(80, 80); - QTest::mousePress(&window, Qt::LeftButton, 0, p); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p); QCOMPARE(window.mouseGrabberItem(), mouseArea); // That was a real mouse event QCOMPARE(root->property("lastEventSource").toInt(), int(Qt::MouseEventNotSynthesized)); @@ -2037,7 +2059,7 @@ void tst_QQuickMouseArea::ignoreBySource() QCOMPARE(flickable->contentX(), 0.); QCOMPARE(flickable->contentY(), 0.); - QTest::mouseRelease(&window, Qt::LeftButton, 0, p); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p); QCOMPARE(window.mouseGrabberItem(), nullptr); // Now try touch events and confirm that MouseArea ignores them, while Flickable does its thing @@ -2073,7 +2095,7 @@ void tst_QQuickMouseArea::ignoreBySource() // MouseArea should ignore the press because it's interested in synthesized mouse events p = QPoint(80, 80); - QTest::mousePress(&window, Qt::LeftButton, 0, p); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p); QVERIFY(window.mouseGrabberItem() != mouseArea); // That was a real mouse event QVERIFY(root->property("lastEventSource").toInt() == Qt::MouseEventNotSynthesized); @@ -2088,7 +2110,7 @@ void tst_QQuickMouseArea::ignoreBySource() QTRY_VERIFY(flickable->contentX() > 1); QVERIFY(flickable->contentY() > 1); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(47, 47)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(47, 47)); flickable->setContentX(0); flickable->setContentY(0); @@ -2118,7 +2140,7 @@ void tst_QQuickMouseArea::notPressedAfterStolenGrab() QQuickWindow window; window.resize(200, 200); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); QQuickMouseArea *ma = new QQuickMouseArea(window.contentItem()); ma->setSize(window.size()); @@ -2147,15 +2169,15 @@ void tst_QQuickMouseArea::pressAndHold() QQuickView window; QByteArray errorMessage; - QVERIFY2(initView(window, testFileUrl("pressAndHold.qml"), true, &errorMessage), errorMessage.constData()); + QVERIFY2(QQuickTest::initView(window, testFileUrl("pressAndHold.qml"), true, &errorMessage), errorMessage.constData()); window.show(); window.requestActivate(); QVERIFY(QTest::qWaitForWindowExposed(&window)); QQuickItem *root = window.rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea*>("mouseArea"); - QVERIFY(mouseArea != 0); + QVERIFY(mouseArea != nullptr); QSignalSpy pressAndHoldSpy(mouseArea, &QQuickMouseArea::pressAndHold); @@ -2173,6 +2195,117 @@ void tst_QQuickMouseArea::pressAndHold() QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(50, 50)); } +void tst_QQuickMouseArea::pressOneAndTapAnother_data() +{ + QTest::addColumn<bool>("pressMouseFirst"); + QTest::addColumn<bool>("releaseMouseFirst"); + + QTest::newRow("press mouse, tap touch, release mouse") << true << false; // QTBUG-64249 as written + QTest::newRow("press touch, press mouse, release touch, release mouse") << false << false; + QTest::newRow("press mouse, press touch, release mouse, release touch") << true << true; + // TODO fix in a separate patch after the 5.9->5.10 merge + // QTest::newRow("press touch, click mouse, release touch") << false << true; +} + +void tst_QQuickMouseArea::pressOneAndTapAnother() +{ + QFETCH(bool, pressMouseFirst); + QFETCH(bool, releaseMouseFirst); + + QQuickView window; + QByteArray errorMessage; + QVERIFY2(QQuickTest::initView(window, testFileUrl("twoMouseAreas.qml"), true, &errorMessage), errorMessage.constData()); + window.show(); + window.requestActivate(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QQuickItem *root = window.rootObject(); + QVERIFY(root); + QQuickMouseArea *bottomMA = window.rootObject()->findChild<QQuickMouseArea*>("bottom"); + QVERIFY(bottomMA); + QQuickMouseArea *topMA = window.rootObject()->findChild<QQuickMouseArea*>("top"); + QVERIFY(topMA); + + QPoint upper(32, 32); + QPoint lower(32, window.height() - 32); + + // press them both + if (pressMouseFirst) { + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, lower); + QTRY_COMPARE(bottomMA->pressed(), true); + + QTest::touchEvent(&window, device).press(0, lower, &window); + QQuickTouchUtils::flush(&window); + QTRY_COMPARE(bottomMA->pressed(), true); + } else { + QTest::touchEvent(&window, device).press(0, lower, &window); + QQuickTouchUtils::flush(&window); + QTRY_COMPARE(bottomMA->pressed(), true); + + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, lower); + QTRY_COMPARE(bottomMA->pressed(), true); + } + + // release them both and make sure neither one gets stuck + if (releaseMouseFirst) { + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, lower); + QTRY_COMPARE(bottomMA->pressed(), false); + + QTest::touchEvent(&window, device).release(0, upper, &window); + QQuickTouchUtils::flush(&window); + QTRY_COMPARE(topMA->pressed(), false); + } else { + QTest::touchEvent(&window, device).release(0, upper, &window); + QQuickTouchUtils::flush(&window); + + QTRY_COMPARE(topMA->pressed(), false); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, lower); + QTRY_COMPARE(bottomMA->pressed(), false); + } +} + +void tst_QQuickMouseArea::mask() +{ + QQuickView window; + QByteArray errorMessage; + QVERIFY2(QQuickTest::initView(window, testFileUrl("mask.qml"), true, &errorMessage), errorMessage.constData()); + window.show(); + window.requestActivate(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QQuickItem *root = window.rootObject(); + QVERIFY(root != nullptr); + + // click inside the mask, and verify it registers + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100,100)); + + QCOMPARE(window.rootObject()->property("pressed").toInt(), 1); + QCOMPARE(window.rootObject()->property("released").toInt(), 1); + QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); + + // click outside the mask (but inside the MouseArea), and verify it doesn't register + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(10,10)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(10,10)); + + QCOMPARE(window.rootObject()->property("pressed").toInt(), 1); + QCOMPARE(window.rootObject()->property("released").toInt(), 1); + QCOMPARE(window.rootObject()->property("clicked").toInt(), 1); +} + +void tst_QQuickMouseArea::nestedEventDelivery() // QTBUG-70898 +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("nestedSendEvent.qml")); + QScopedPointer<QQuickWindow> window(qmlobject_cast<QQuickWindow *>(c.create())); + QVERIFY(window.data()); + + // Click each MouseArea and verify that it doesn't crash + QByteArray message = "event went missing during delivery! (nested sendEvent() is not allowed)"; + QTest::ignoreMessage(QtWarningMsg, message); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50,50)); + QTest::ignoreMessage(QtWarningMsg, message); // twice though, actually + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50,150)); +} + QTEST_MAIN(tst_QQuickMouseArea) #include "tst_qquickmousearea.moc" 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/qquickmultipointtoucharea/data/mouse.qml b/tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml index 0abcc76f7c..b0410dac4a 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml +++ b/tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml @@ -6,6 +6,9 @@ MultiPointTouchArea { property int touchCount: 0 property int cancelCount: 0 + property int gestureStartedX: 0 + property int gestureStartedY: 0 + property bool grabGesture: false minimumTouchPoints: 1 maximumTouchPoints: 4 @@ -17,6 +20,12 @@ MultiPointTouchArea { onPressed: { touchCount = touchPoints.length } onTouchUpdated: { touchCount = touchPoints.length } onCanceled: { cancelCount = touchPoints.length } + onGestureStarted: { + gestureStartedX = gesture.touchPoints[0].startX + gestureStartedY = gesture.touchPoints[0].startY + if (grabGesture) + gesture.grab() + } Rectangle { color: "red" diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml index 039607e26c..027f90c7f4 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml +++ b/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml @@ -11,9 +11,21 @@ Rectangle { maximumTouchPoints: 2 onGestureStarted: gesture.grab() touchPoints: [ - TouchPoint { objectName: "point11" }, - TouchPoint { objectName: "point12" } + TouchPoint { id: point11; objectName: "point11" }, + TouchPoint { id: point12; objectName: "point12" } ] + Rectangle { + color: "red" + width: 10; height: 10; radius: 5 + x: point11.x - radius; y: point11.y - radius + visible: point11.pressed + } + Rectangle { + color: "tomato" + width: 10; height: 10; radius: 5 + x: point12.x - radius; y: point12.y - radius + visible: point12.pressed + } } MultiPointTouchArea { @@ -24,9 +36,27 @@ Rectangle { maximumTouchPoints: 3 onGestureStarted: gesture.grab() touchPoints: [ - TouchPoint { objectName: "point21" }, - TouchPoint { objectName: "point22" }, - TouchPoint { objectName: "point23" } + TouchPoint { id: point21; objectName: "point21" }, + TouchPoint { id: point22; objectName: "point22" }, + TouchPoint { id: point23; objectName: "point23" } ] + Rectangle { + color: "lightgreen" + width: 10; height: 10; radius: 5 + x: point21.x - radius; y: point21.y - radius + visible: point21.pressed + } + Rectangle { + color: "green" + width: 10; height: 10; radius: 5 + x: point22.x - radius; y: point22.y - radius + visible: point22.pressed + } + Rectangle { + color: "darkgreen" + width: 10; height: 10; radius: 5 + x: point23.x - radius; y: point23.y - radius + visible: point23.pressed + } } } diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp index 87acd67f6a..d4ad282701 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp +++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -41,7 +41,7 @@ class tst_QQuickMultiPointTouchArea : public QQmlDataTest { Q_OBJECT public: - tst_QQuickMultiPointTouchArea() : device(0) { } + tst_QQuickMultiPointTouchArea() { } private slots: void initTestCase() { @@ -69,20 +69,22 @@ private slots: void transformedTouchArea(); void mouseInteraction(); void mouseInteraction_data(); + void mouseGestureStarted_data(); + void mouseGestureStarted(); void cancel(); private: QQuickView *createAndShowView(const QString &file); - QTouchDevice *device; + QTouchDevice *device = nullptr; }; void tst_QQuickMultiPointTouchArea::properties() { QScopedPointer<QQuickView> window(createAndShowView("properties.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(window->rootObject()); - QVERIFY(area != 0); + QVERIFY(area != nullptr); QCOMPARE(area->minimumTouchPoints(), 2); QCOMPARE(area->maximumTouchPoints(), 4); @@ -94,10 +96,10 @@ void tst_QQuickMultiPointTouchArea::properties() void tst_QQuickMultiPointTouchArea::signalTest() { QScopedPointer<QQuickView> window(createAndShowView("signalTest.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(window->rootObject()); - QVERIFY(area != 0); + QVERIFY(area != nullptr); QPoint p1(20,100); QPoint p2(40,100); @@ -161,7 +163,7 @@ void tst_QQuickMultiPointTouchArea::signalTest() void tst_QQuickMultiPointTouchArea::release() { QScopedPointer<QQuickView> window(createAndShowView("basic.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickTouchPoint *point1 = window->rootObject()->findChild<QQuickTouchPoint*>("point1"); @@ -197,7 +199,7 @@ void tst_QQuickMultiPointTouchArea::release() void tst_QQuickMultiPointTouchArea::reuse() { QScopedPointer<QQuickView> window(createAndShowView("basic.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickTouchPoint *point1 = window->rootObject()->findChild<QQuickTouchPoint*>("point1"); QQuickTouchPoint *point2 = window->rootObject()->findChild<QQuickTouchPoint*>("point2"); @@ -264,7 +266,7 @@ void tst_QQuickMultiPointTouchArea::reuse() void tst_QQuickMultiPointTouchArea::nonOverlapping() { QScopedPointer<QQuickView> window(createAndShowView("nonOverlapping.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickTouchPoint *point11 = window->rootObject()->findChild<QQuickTouchPoint*>("point11"); QQuickTouchPoint *point12 = window->rootObject()->findChild<QQuickTouchPoint*>("point12"); @@ -378,7 +380,7 @@ void tst_QQuickMultiPointTouchArea::nonOverlapping() void tst_QQuickMultiPointTouchArea::nested() { QScopedPointer<QQuickView> window(createAndShowView("nested.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickTouchPoint *point11 = window->rootObject()->findChild<QQuickTouchPoint*>("point11"); QQuickTouchPoint *point12 = window->rootObject()->findChild<QQuickTouchPoint*>("point12"); @@ -574,13 +576,13 @@ void tst_QQuickMultiPointTouchArea::nested() void tst_QQuickMultiPointTouchArea::inFlickable() { QScopedPointer<QQuickView> window(createAndShowView("inFlickable.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>(); - QVERIFY(mpta != 0); + QVERIFY(mpta != nullptr); QQuickTouchPoint *point11 = window->rootObject()->findChild<QQuickTouchPoint*>("point1"); QQuickTouchPoint *point12 = window->rootObject()->findChild<QQuickTouchPoint*>("point2"); @@ -623,7 +625,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable() //moving two points vertically p1 = QPoint(20,100); QTest::touchEvent(window.data(), device).press(0, p1).press(1, p2); - QTest::mousePress(window.data(), Qt::LeftButton, 0, p1); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, p1); QQuickTouchUtils::flush(window.data()); QCOMPARE(point11->pressed(), true); @@ -658,7 +660,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable() QCOMPARE(flickable->property("touchCount").toInt(), 0); QTest::touchEvent(window.data(), device).release(0, p1).release(1, p2); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, p1); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, p1); QQuickTouchUtils::flush(window.data()); QTRY_VERIFY(!flickable->isMoving()); @@ -670,7 +672,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable() QQuickTouchUtils::flush(window.data()); // ensure that mouse events do not fall through to the Flickable mpta->setMaximumTouchPoints(3); - QTest::mousePress(window.data(), Qt::LeftButton, 0, p1); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(point11->pressed(), true); QCOMPARE(point12->pressed(), true); @@ -720,7 +722,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable() QCOMPARE(point12->pressed(), true); QTest::touchEvent(window.data(), device).release(0, p1).release(1, p2); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, p1); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, p1); QQuickTouchUtils::flush(window.data()); } @@ -728,10 +730,10 @@ void tst_QQuickMultiPointTouchArea::inFlickable() void tst_QQuickMultiPointTouchArea::inFlickable2() { QScopedPointer<QQuickView> window(createAndShowView("inFlickable2.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable"); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); QQuickTouchPoint *point11 = window->rootObject()->findChild<QQuickTouchPoint*>("point1"); QVERIFY(point11); @@ -743,7 +745,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable2() // move point horizontally, out of Flickable area QTest::touchEvent(window.data(), device).press(0, p1); QQuickTouchUtils::flush(window.data()); - QTest::mousePress(window.data(), Qt::LeftButton, 0, p1); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, p1); p1 += QPoint(15,0); QTest::touchEvent(window.data(), device).move(0, p1); @@ -770,7 +772,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable2() QTest::touchEvent(window.data(), device).release(0, p1); QQuickTouchUtils::flush(window.data()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, p1); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, p1); QTest::qWait(50); QTRY_VERIFY(!flickable->isMoving()); @@ -813,13 +815,13 @@ void tst_QQuickMultiPointTouchArea::inFlickable2() void tst_QQuickMultiPointTouchArea::inMouseArea() { QScopedPointer<QQuickView> window(createAndShowView("inMouseArea.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickMouseArea *mouseArea = qobject_cast<QQuickMouseArea *>(window->rootObject()); - QVERIFY(mouseArea != 0); + QVERIFY(mouseArea != nullptr); QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>("mpta"); - QVERIFY(mpta != 0); + QVERIFY(mpta != nullptr); QPoint innerPoint(40,100); QPoint outerPoint(10,100); @@ -829,15 +831,15 @@ void tst_QQuickMultiPointTouchArea::inMouseArea() QTest::touchEvent(window.data(), device).release(0, innerPoint); QVERIFY(!mpta->property("pressed").toBool()); - QTest::mousePress(window.data(), Qt::LeftButton, 0, outerPoint); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, outerPoint); QVERIFY(mouseArea->property("pressed").toBool()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, outerPoint); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, outerPoint); QVERIFY(!mouseArea->property("pressed").toBool()); - QTest::mousePress(window.data(), Qt::LeftButton, 0, innerPoint); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, innerPoint); QVERIFY(mpta->property("pressed").toBool()); QVERIFY(!mouseArea->property("pressed").toBool()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, innerPoint); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, innerPoint); QVERIFY(!mpta->property("pressed").toBool()); QVERIFY(!mouseArea->property("pressed").toBool()); @@ -854,10 +856,10 @@ void tst_QQuickMultiPointTouchArea::inMouseArea() QVERIFY(!mpta->property("pressed").toBool()); // Right click should pass through - QTest::mousePress(window.data(), Qt::RightButton, 0, innerPoint); + QTest::mousePress(window.data(), Qt::RightButton, Qt::NoModifier, innerPoint); QVERIFY(mouseArea->property("pressed").toBool()); QVERIFY(!mpta->property("pressed").toBool()); - QTest::mouseRelease(window.data(), Qt::RightButton, 0, innerPoint); + QTest::mouseRelease(window.data(), Qt::RightButton, Qt::NoModifier, innerPoint); mpta->setProperty("mouseEnabled", false); @@ -868,15 +870,15 @@ void tst_QQuickMultiPointTouchArea::inMouseArea() QVERIFY(!mpta->property("pressed").toBool()); QVERIFY(!mouseArea->property("pressed").toBool()); - QTest::mousePress(window.data(), Qt::LeftButton, 0, outerPoint); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, outerPoint); QVERIFY(mouseArea->property("pressed").toBool()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, outerPoint); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, outerPoint); QVERIFY(!mouseArea->property("pressed").toBool()); - QTest::mousePress(window.data(), Qt::LeftButton, 0, innerPoint); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, innerPoint); QVERIFY(!mpta->property("pressed").toBool()); QVERIFY(mouseArea->property("pressed").toBool()); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, innerPoint); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, innerPoint); QVERIFY(!mpta->property("pressed").toBool()); QVERIFY(!mouseArea->property("pressed").toBool()); @@ -896,10 +898,10 @@ void tst_QQuickMultiPointTouchArea::inMouseArea() void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() { QScopedPointer<QQuickView> window(createAndShowView("dualGestures.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickMultiPointTouchArea *dualmpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>("dualTouchArea"); - QVERIFY(dualmpta != 0); + QVERIFY(dualmpta != nullptr); QQuickItem *touch1rect = window->rootObject()->findChild<QQuickItem*>("touch1rect"); QQuickItem *touch2rect = window->rootObject()->findChild<QQuickItem*>("touch2rect"); @@ -923,18 +925,18 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); QTest::touchEvent(window.data(), device).release(1, touch1).move(2, touch2); touch1.setY(20); - QTest::mousePress(window.data(), Qt::LeftButton, 0, touch1); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, touch1); QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); QTest::touchEvent(window.data(), device).release(2, touch2); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, touch1); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, touch1); QQuickTouchUtils::flush(window.data()); // Start with mouse, move it, touch second point, move it - QTest::mousePress(window.data(), Qt::LeftButton, 0, touch1); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, touch1); touch1.setX(60); QTest::mouseMove(window.data(), touch1); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); @@ -963,7 +965,7 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); // Release all - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, touch1); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, touch1); QTest::touchEvent(window.data(), device).release(3, touch2); QQuickTouchUtils::flush(window.data()); QTest::touchEvent(window.data(), device).release(4, touch3); @@ -982,7 +984,7 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() QPoint touch3(340,100); QPoint touch4(540,10); - QTest::mousePress(window.data(), Qt::LeftButton, 0, mouse1); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, mouse1); QCOMPARE(touch1rect->property("x").toInt(), mouse1.x()); QCOMPARE(touch1rect->property("y").toInt(), mouse1.y()); QTest::touchEvent(window.data(), device).press(1, touch1); @@ -1006,7 +1008,7 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() QCOMPARE(touch5rect->property("y").toInt(), touch4.y()); // Release all - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, mouse1); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, mouse1); QTest::touchEvent(window.data(), device).release(1, touch1).release(2, touch2).release(3, touch3).release(4, touch4); QQuickTouchUtils::flush(window.data()); } @@ -1024,7 +1026,7 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() // Start with mouse, move it, touch a point, move it, touch another. // Mouse is ignored, both touch points are heeded. - QTest::mousePress(window.data(), Qt::LeftButton, 0, mouse1); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, mouse1); mouse1.setX(60); QTest::mouseMove(window.data(), mouse1); QCOMPARE(touch1rect->property("x").toInt(), 10); @@ -1047,7 +1049,7 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); // Release all - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, mouse1); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, mouse1); QTest::touchEvent(window.data(), device).release(1, touch1); QQuickTouchUtils::flush(window.data()); QTest::touchEvent(window.data(), device).release(2, touch2); @@ -1063,10 +1065,10 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() void tst_QQuickMultiPointTouchArea::invisible() { QScopedPointer<QQuickView> window(createAndShowView("signalTest.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(window->rootObject()); - QVERIFY(area != 0); + QVERIFY(area != nullptr); area->setVisible(false); @@ -1124,10 +1126,10 @@ void tst_QQuickMultiPointTouchArea::transformedTouchArea() QScopedPointer<QQuickView> view(createAndShowView("transformedMultiPointTouchArea.qml")); - QVERIFY(view->rootObject() != 0); + QVERIFY(view->rootObject() != nullptr); QQuickMultiPointTouchArea *area = view->rootObject()->findChild<QQuickMultiPointTouchArea *>("touchArea"); - QVERIFY(area != 0); + QVERIFY(area != nullptr); QTest::QTouchEventSequence sequence = QTest::touchEvent(view.data(), device); @@ -1143,7 +1145,7 @@ void tst_QQuickMultiPointTouchArea::transformedTouchArea() QQuickView *tst_QQuickMultiPointTouchArea::createAndShowView(const QString &file) { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl(file)); const QRect screenGeometry = window->screen()->availableGeometry(); const QSize size = window->size(); @@ -1171,16 +1173,16 @@ void tst_QQuickMultiPointTouchArea::mouseInteraction() QFETCH(int, accept); QScopedPointer<QQuickView> view(createAndShowView("mouse.qml")); - QVERIFY(view->rootObject() != 0); + QVERIFY(view->rootObject() != nullptr); QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(view->rootObject()); - QVERIFY(area != 0); + QVERIFY(area != nullptr); QQuickTouchPoint *point1 = view->rootObject()->findChild<QQuickTouchPoint*>("point1"); QCOMPARE(point1->pressed(), false); QCOMPARE(area->property("touchCount").toInt(), 0); QPoint p1 = QPoint(100, 100); - QTest::mousePress(view.data(), (Qt::MouseButton) buttons, 0, p1); + QTest::mousePress(view.data(), (Qt::MouseButton) buttons, Qt::NoModifier, p1); QCOMPARE(area->property("touchCount").toInt(), accept); QCOMPARE(point1->pressed(), accept != 0); p1 += QPoint(10, 10); @@ -1196,10 +1198,61 @@ void tst_QQuickMultiPointTouchArea::mouseInteraction() QCOMPARE(area->property("touchCount").toInt(), 0); } +void tst_QQuickMultiPointTouchArea::mouseGestureStarted_data() +{ + QTest::addColumn<bool>("grabGesture"); + QTest::addColumn<int>("distanceFromOrigin"); + + QTest::newRow("near origin, don't grab") << false << 4; + QTest::newRow("near origin, grab") << true << 4; + QTest::newRow("away from origin, don't grab") << false << 100; + QTest::newRow("away from origin, grab") << true << 100; +} + +void tst_QQuickMultiPointTouchArea::mouseGestureStarted() // QTBUG-70258 +{ + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + QFETCH(bool, grabGesture); + QFETCH(int, distanceFromOrigin); + + QScopedPointer<QQuickView> view(createAndShowView("mouse.qml")); + QVERIFY(view->rootObject() != nullptr); + + QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(view->rootObject()); + QVERIFY(area); + area->setProperty("grabGesture", grabGesture); + QQuickTouchPoint *point1 = view->rootObject()->findChild<QQuickTouchPoint*>("point1"); + QCOMPARE(point1->pressed(), false); + QSignalSpy gestureStartedSpy(area, SIGNAL(gestureStarted(QQuickGrabGestureEvent *))); + + QPoint p1 = QPoint(distanceFromOrigin, distanceFromOrigin); + QTest::mousePress(view.data(), Qt::LeftButton, Qt::NoModifier, p1); + QCOMPARE(gestureStartedSpy.count(), 0); + + p1 += QPoint(dragThreshold, dragThreshold); + QTest::mouseMove(view.data(), p1); + QCOMPARE(gestureStartedSpy.count(), 0); + + p1 += QPoint(1, 1); + QTest::mouseMove(view.data(), p1); + QTRY_COMPARE(gestureStartedSpy.count(), 1); + QTRY_COMPARE(area->property("gestureStartedX").toInt(), distanceFromOrigin); + QCOMPARE(area->property("gestureStartedY").toInt(), distanceFromOrigin); + + p1 += QPoint(10, 10); + QTest::mouseMove(view.data(), p1); + // if nobody called gesteure->grab(), gestureStarted will keep happening + QTRY_COMPARE(gestureStartedSpy.count(), grabGesture ? 1 : 2); + QCOMPARE(area->property("gestureStartedX").toInt(), distanceFromOrigin); + QCOMPARE(area->property("gestureStartedY").toInt(), distanceFromOrigin); + + QTest::mouseRelease(view.data(), Qt::LeftButton); +} + void tst_QQuickMultiPointTouchArea::cancel() { QScopedPointer<QQuickView> window(createAndShowView("cancel.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(window->rootObject()); QTest::QTouchEventSequence sequence = QTest::touchEvent(window.data(), device); diff --git a/tests/auto/quick/qquickopenglinfo/BLACKLIST b/tests/auto/quick/qquickopenglinfo/BLACKLIST new file mode 100644 index 0000000000..7ac31e1cd0 --- /dev/null +++ b/tests/auto/quick/qquickopenglinfo/BLACKLIST @@ -0,0 +1,3 @@ +# QTBUG-65615 +[testProperties] +b2qt diff --git a/tests/auto/quick/qquickpainteditem/BLACKLIST b/tests/auto/quick/qquickpainteditem/BLACKLIST new file mode 100644 index 0000000000..9b58325f6c --- /dev/null +++ b/tests/auto/quick/qquickpainteditem/BLACKLIST @@ -0,0 +1,27 @@ +# QTBUG-63053 +[opaquePainting] +b2qt + +# QTBUG-63053 +[antialiasing] +b2qt + +# QTBUG-63053 +[mipmap] +b2qt + +# QTBUG-63053 +[performanceHints] +b2qt + +# QTBUG-63053 +[contentScale] +b2qt + +# QTBUG-63053 +[contentsBoundingRect] +b2qt + +# QTBUG-63053 +[fillColor] +b2qt diff --git a/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp b/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp index 1716bdeafb..2661762669 100644 --- a/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp +++ b/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp @@ -61,9 +61,9 @@ class TestPaintedItem : public QQuickPaintedItem { Q_OBJECT public: - TestPaintedItem(QQuickItem *parent = 0) + TestPaintedItem(QQuickItem *parent = nullptr) : QQuickPaintedItem(parent) - , paintNode(0) + , paintNode(nullptr) , paintRequests(0) { } diff --git a/tests/auto/quick/qquickpath/data/anglearc.qml b/tests/auto/quick/qquickpath/data/anglearc.qml new file mode 100644 index 0000000000..cbe41c1ac8 --- /dev/null +++ b/tests/auto/quick/qquickpath/data/anglearc.qml @@ -0,0 +1,12 @@ +import QtQuick 2.11 + +Path { + PathAngleArc { + centerX: 100 + centerY: 100 + radiusX: 50 + radiusY: 50 + startAngle: 45 + sweepAngle: 90 + } +} diff --git a/tests/auto/quick/qquickpath/tst_qquickpath.cpp b/tests/auto/quick/qquickpath/tst_qquickpath.cpp index 2ec95840e1..12a8c673b0 100644 --- a/tests/auto/quick/qquickpath/tst_qquickpath.cpp +++ b/tests/auto/quick/qquickpath/tst_qquickpath.cpp @@ -41,6 +41,7 @@ public: private slots: void arc(); + void angleArc(); void catmullromCurve(); void closedCatmullromCurve(); void svg(); @@ -52,7 +53,7 @@ void tst_QuickPath::arc() QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("arc.qml")); QQuickPath *obj = qobject_cast<QQuickPath*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->startX(), 0.); QCOMPARE(obj->startY(), 0.); @@ -61,7 +62,7 @@ void tst_QuickPath::arc() QCOMPARE(list.count(), 1); QQuickPathArc* arc = qobject_cast<QQuickPathArc*>(list.at(0)); - QVERIFY(arc != 0); + QVERIFY(arc != nullptr); QCOMPARE(arc->x(), 100.); QCOMPARE(arc->y(), 100.); QCOMPARE(arc->radiusX(), 100.); @@ -82,12 +83,51 @@ void tst_QuickPath::arc() QCOMPARE(pos, QPointF(100,100)); } +void tst_QuickPath::angleArc() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("anglearc.qml")); + QQuickPath *obj = qobject_cast<QQuickPath*>(c.create()); + QVERIFY(obj != nullptr); + + QQmlListReference list(obj, "pathElements"); + QCOMPARE(list.count(), 1); + + QQuickPathAngleArc* arc = qobject_cast<QQuickPathAngleArc*>(list.at(0)); + QVERIFY(arc != nullptr); + QCOMPARE(arc->centerX(), 100.); + QCOMPARE(arc->centerY(), 100.); + QCOMPARE(arc->radiusX(), 50.); + QCOMPARE(arc->radiusY(), 50.); + QCOMPARE(arc->startAngle(), 45.); + QCOMPARE(arc->sweepAngle(), 90.); + QCOMPARE(arc->moveToStart(), true); + + QPainterPath path = obj->path(); + QVERIFY(path != QPainterPath()); + + // using QPoint to do fuzzy compare + QPointF pos = obj->pointAt(0); + QCOMPARE(pos.toPoint(), QPoint(135,135)); + pos = obj->pointAt(.25); + QCOMPARE(pos.toPoint(), QPoint(119,146)); + pos = obj->pointAt(.75); + QCOMPARE(pos.toPoint(), QPoint(81,146)); + pos = obj->pointAt(1); + QCOMPARE(pos.toPoint(), QPoint(65,135)); + + // if moveToStart is false, we should have a line starting from startX/Y + arc->setMoveToStart(false); + pos = obj->pointAt(0); + QCOMPARE(pos, QPointF(0,0)); +} + void tst_QuickPath::catmullromCurve() { QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("curve.qml")); QQuickPath *obj = qobject_cast<QQuickPath*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->startX(), 0.); QCOMPARE(obj->startY(), 0.); @@ -96,12 +136,12 @@ void tst_QuickPath::catmullromCurve() QCOMPARE(list.count(), 3); QQuickPathCatmullRomCurve* curve = qobject_cast<QQuickPathCatmullRomCurve*>(list.at(0)); - QVERIFY(curve != 0); + QVERIFY(curve != nullptr); QCOMPARE(curve->x(), 100.); QCOMPARE(curve->y(), 50.); curve = qobject_cast<QQuickPathCatmullRomCurve*>(list.at(2)); - QVERIFY(curve != 0); + QVERIFY(curve != nullptr); QCOMPARE(curve->x(), 100.); QCOMPARE(curve->y(), 150.); @@ -123,7 +163,7 @@ void tst_QuickPath::closedCatmullromCurve() QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("closedcurve.qml")); QQuickPath *obj = qobject_cast<QQuickPath*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->startX(), 50.); QCOMPARE(obj->startY(), 50.); @@ -132,7 +172,7 @@ void tst_QuickPath::closedCatmullromCurve() QCOMPARE(list.count(), 3); QQuickPathCatmullRomCurve* curve = qobject_cast<QQuickPathCatmullRomCurve*>(list.at(2)); - QVERIFY(curve != 0); + QVERIFY(curve != nullptr); QCOMPARE(curve->x(), 50.); QCOMPARE(curve->y(), 50.); @@ -156,7 +196,7 @@ void tst_QuickPath::svg() QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("svg.qml")); QQuickPath *obj = qobject_cast<QQuickPath*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->startX(), 0.); QCOMPARE(obj->startY(), 0.); @@ -165,7 +205,7 @@ void tst_QuickPath::svg() QCOMPARE(list.count(), 1); QQuickPathSvg* svg = qobject_cast<QQuickPathSvg*>(list.at(0)); - QVERIFY(svg != 0); + QVERIFY(svg != nullptr); QCOMPARE(svg->path(), QLatin1String("M200,300 Q400,50 600,300 T1000,300")); QPainterPath path = obj->path(); diff --git a/tests/auto/quick/qquickpathview/data/flickableDelegate.qml b/tests/auto/quick/qquickpathview/data/flickableDelegate.qml index df9cb1d547..0304efaa31 100644 --- a/tests/auto/quick/qquickpathview/data/flickableDelegate.qml +++ b/tests/auto/quick/qquickpathview/data/flickableDelegate.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquickpathview/data/nestedInFlickable.qml b/tests/auto/quick/qquickpathview/data/nestedInFlickable.qml index ec1f3235c3..216a25b8e2 100644 --- a/tests/auto/quick/qquickpathview/data/nestedInFlickable.qml +++ b/tests/auto/quick/qquickpathview/data/nestedInFlickable.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquickpathview/data/objectModelMove.qml b/tests/auto/quick/qquickpathview/data/objectModelMove.qml new file mode 100644 index 0000000000..d5fa510d69 --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/objectModelMove.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:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQml.Models 2.11 +import QtQuick 2.11 + +Item { + id: root + width: 400 + height: 400 + visible: true + + property Item pathViewItem + + function destroyView() { + if (pathViewItem) + pathViewItem.destroy() + } + + function newView() { + pathViewItem = pathViewComponent.createObject(root) + } + + function move() { + objectModel.move(0, 1) + } + + Component { + id: pathViewComponent + + PathView { + id: pathView + objectName: "PathView" + width: 32 * 3 + height: 32 + model: objectModel + + interactive: false + snapMode: PathView.SnapToItem + movementDirection: PathView.Positive + highlightMoveDuration: 100 + + path: Path { + startX: 16 + startY: 16 + PathLine { + x: 16 + (32 * 3) + y: 16 + } + } + } + } + + ObjectModel { + id: objectModel + + Rectangle { + objectName: "red" + width: 32 + height: 32 + color: "red" + } + Rectangle { + objectName: "green" + width: 32 + height: 32 + color: "green" + } + Rectangle { + objectName: "blue" + width: 32 + height: 32 + color: "blue" + } + } +} diff --git a/tests/auto/quick/qquickpathview/data/panels.qml b/tests/auto/quick/qquickpathview/data/panels.qml index a111e45736..08e4636dca 100644 --- a/tests/auto/quick/qquickpathview/data/panels.qml +++ b/tests/auto/quick/qquickpathview/data/panels.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 Item { id: root @@ -6,7 +7,7 @@ Item { property bool enforceRange: false width: 320; height: 480 - VisualItemModel { + ObjectModel { id: itemModel Rectangle { diff --git a/tests/auto/quick/qquickpathview/data/pathview_package.qml b/tests/auto/quick/qquickpathview/data/pathview_package.qml index 2af57e6bb1..34d4ee73ba 100644 --- a/tests/auto/quick/qquickpathview/data/pathview_package.qml +++ b/tests/auto/quick/qquickpathview/data/pathview_package.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 Item { width: 800; height: 600 @@ -37,7 +38,7 @@ Item { ListElement { lColor: "brown" } ListElement { lColor: "thistle" } } - VisualDataModel { id: visualModel; model: rssModel; delegate: photoDelegate } + DelegateModel { id: visualModel; model: rssModel; delegate: photoDelegate } PathView { id: photoPathView diff --git a/tests/auto/quick/qquickpathview/data/qtbug37815.qml b/tests/auto/quick/qquickpathview/data/qtbug37815.qml index 3fd4daca63..28affbac38 100644 --- a/tests/auto/quick/qquickpathview/data/qtbug37815.qml +++ b/tests/auto/quick/qquickpathview/data/qtbug37815.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** ** Copyright (C) 2016 Netris -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquickpathview/data/qtbug53464.qml b/tests/auto/quick/qquickpathview/data/qtbug53464.qml index d30d404e68..123cafb04c 100644 --- a/tests/auto/quick/qquickpathview/data/qtbug53464.qml +++ b/tests/auto/quick/qquickpathview/data/qtbug53464.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** ** Copyright (C) 2016 Netris -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquickpathview/data/removePath.qml b/tests/auto/quick/qquickpathview/data/removePath.qml index 85029f3eaf..36343adaaf 100644 --- a/tests/auto/quick/qquickpathview/data/removePath.qml +++ b/tests/auto/quick/qquickpathview/data/removePath.qml @@ -6,7 +6,7 @@ PathView { path: myPath - delegate: Text { text: value } + delegate: Text { text: modelData } model: 10 Path { diff --git a/tests/auto/quick/qquickpathview/data/treemodel.qml b/tests/auto/quick/qquickpathview/data/treemodel.qml index fcf6922d00..b1e06f47d2 100644 --- a/tests/auto/quick/qquickpathview/data/treemodel.qml +++ b/tests/auto/quick/qquickpathview/data/treemodel.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 PathView { width: 320 @@ -6,7 +7,7 @@ PathView { function setRoot(index) { vdm.rootIndex = vdm.modelIndex(index); } - model: VisualDataModel { + model: DelegateModel { id: vdm model: myModel delegate: Text { objectName: "wrapper"; text: display } diff --git a/tests/auto/quick/qquickpathview/data/vdm.qml b/tests/auto/quick/qquickpathview/data/vdm.qml index 839393d9bd..f24837b7a6 100644 --- a/tests/auto/quick/qquickpathview/data/vdm.qml +++ b/tests/auto/quick/qquickpathview/data/vdm.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 PathView { id: pathView @@ -20,7 +21,7 @@ PathView { ListElement { value: "three" } } - model: VisualDataModel { + model: DelegateModel { delegate: Text { text: model.value } model : mo } diff --git a/tests/auto/quick/qquickpathview/qquickpathview.pro b/tests/auto/quick/qquickpathview/qquickpathview.pro index 90c1eb0c67..f21fb64fa4 100644 --- a/tests/auto/quick/qquickpathview/qquickpathview.pro +++ b/tests/auto/quick/qquickpathview/qquickpathview.pro @@ -9,5 +9,5 @@ include (../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private qml-private quick-private testlib +QT += core-private gui-private qml-private quick-private testlib qmltest qtHaveModule(widgets): QT += widgets diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index b01d0c3cec..bf38d2d926 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -38,6 +38,7 @@ #include <QtQuick/private/qquickpath_p.h> #include <QtQuick/private/qquicktext_p.h> #include <QtQuick/private/qquickrectangle_p.h> +#include <QtQuickTest/QtQuickTest> #include <QtQml/private/qqmllistmodel_p.h> #include <QtQml/private/qqmlvaluetype_p.h> #include <QtGui/qstandarditemmodel.h> @@ -48,6 +49,10 @@ #include "../shared/viewtestutil.h" #include "../shared/visualtestutil.h" +#include <math.h> + +Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") + using namespace QQuickViewTestUtil; using namespace QQuickVisualTestUtil; @@ -142,6 +147,7 @@ private slots: void movementDirection_data(); void movementDirection(); void removePath(); + void objectModelMove(); }; class TestObject : public QObject @@ -184,7 +190,7 @@ void tst_QQuickPathView::initValues() QQmlComponent c(&engine, testFileUrl("pathview1.qml")); QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QVERIFY(!obj->path()); QVERIFY(!obj->delegate()); QCOMPARE(obj->model(), QVariant()); @@ -215,7 +221,7 @@ void tst_QQuickPathView::items() qApp->processEvents(); QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QCOMPARE(pathview->count(), model.count()); QCOMPARE(window->rootObject()->property("count").toInt(), model.count()); @@ -223,10 +229,10 @@ void tst_QQuickPathView::items() for (int i = 0; i < model.count(); ++i) { QQuickText *name = findItem<QQuickText>(pathview, "textName", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QCOMPARE(name->text(), model.name(i)); QQuickText *number = findItem<QQuickText>(pathview, "textNumber", i); - QVERIFY(number != 0); + QVERIFY(number != nullptr); QCOMPARE(number->text(), model.number(i)); } @@ -257,7 +263,7 @@ void tst_QQuickPathView::initialCurrentItem() qApp->processEvents(); QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QVERIFY(pathview->currentIndex() != -1); QVERIFY(!window->rootObject()->property("currentItemIsNull").toBool()); } @@ -268,9 +274,9 @@ void tst_QQuickPathView::pathview2() QQmlComponent c(&engine, testFileUrl("pathview2.qml")); QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create()); - QVERIFY(obj != 0); - QVERIFY(obj->path() != 0); - QVERIFY(obj->delegate() != 0); + QVERIFY(obj != nullptr); + QVERIFY(obj->path() != nullptr); + QVERIFY(obj->delegate() != nullptr); QVERIFY(obj->model() != QVariant()); QCOMPARE(obj->currentIndex(), 0); QCOMPARE(obj->offset(), 0.); @@ -288,9 +294,9 @@ void tst_QQuickPathView::pathview3() QQmlComponent c(&engine, testFileUrl("pathview3.qml")); QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create()); - QVERIFY(obj != 0); - QVERIFY(obj->path() != 0); - QVERIFY(obj->delegate() != 0); + QVERIFY(obj != nullptr); + QVERIFY(obj->path() != nullptr); + QVERIFY(obj->delegate() != nullptr); QVERIFY(obj->model() != QVariant()); QCOMPARE(obj->currentIndex(), 7); QCOMPARE(obj->offset(), 1.0); @@ -308,9 +314,9 @@ void tst_QQuickPathView::initialCurrentIndex() QQmlComponent c(&engine, testFileUrl("initialCurrentIndex.qml")); QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create()); - QVERIFY(obj != 0); - QVERIFY(obj->path() != 0); - QVERIFY(obj->delegate() != 0); + QVERIFY(obj != nullptr); + QVERIFY(obj->path() != nullptr); + QVERIFY(obj->delegate() != nullptr); QVERIFY(obj->model() != QVariant()); QCOMPARE(obj->currentIndex(), 3); QCOMPARE(obj->offset(), 5.0); @@ -364,6 +370,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); @@ -390,7 +400,7 @@ void tst_QQuickPathView::insertModel() qApp->processEvents(); QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode); @@ -483,7 +493,7 @@ void tst_QQuickPathView::removeModel() qApp->processEvents(); QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode); @@ -576,7 +586,7 @@ void tst_QQuickPathView::moveModel() qApp->processEvents(); QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); pathview->setHighlightRangeMode((QQuickPathView::HighlightRangeMode)mode); @@ -675,7 +685,7 @@ void tst_QQuickPathView::consecutiveModelChanges() qApp->processEvents(); QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); pathview->setHighlightRangeMode(mode); @@ -705,13 +715,13 @@ void tst_QQuickPathView::consecutiveModelChanges() pathview->setCurrentIndex(changes[i].index); break; case ListChange::Polish: - QQUICK_VERIFY_POLISH(pathview); + QQuickTest::qWaitForItemPolished(pathview); break; default: continue; } } - QQUICK_VERIFY_POLISH(pathview); + QQuickTest::qWaitForItemPolished(pathview); QCOMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), count); QCOMPARE(pathview->count(), count); @@ -727,7 +737,7 @@ void tst_QQuickPathView::path() QQmlComponent c(&engine, testFileUrl("pathtest.qml")); QQuickPath *obj = qobject_cast<QQuickPath*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->startX(), 120.); QCOMPARE(obj->startY(), 100.); QVERIFY(obj->path() != QPainterPath()); @@ -736,28 +746,28 @@ void tst_QQuickPathView::path() QCOMPARE(list.count(), 5); QQuickPathAttribute* attr = qobject_cast<QQuickPathAttribute*>(list.at(0)); - QVERIFY(attr != 0); + QVERIFY(attr != nullptr); QCOMPARE(attr->name(), QString("scale")); QCOMPARE(attr->value(), 1.0); QQuickPathQuad* quad = qobject_cast<QQuickPathQuad*>(list.at(1)); - QVERIFY(quad != 0); + QVERIFY(quad != nullptr); QCOMPARE(quad->x(), 120.); QCOMPARE(quad->y(), 25.); QCOMPARE(quad->controlX(), 260.); QCOMPARE(quad->controlY(), 75.); QQuickPathPercent* perc = qobject_cast<QQuickPathPercent*>(list.at(2)); - QVERIFY(perc != 0); + QVERIFY(perc != nullptr); QCOMPARE(perc->value(), 0.3); QQuickPathLine* line = qobject_cast<QQuickPathLine*>(list.at(3)); - QVERIFY(line != 0); + QVERIFY(line != nullptr); QCOMPARE(line->x(), 120.); QCOMPARE(line->y(), 100.); QQuickPathCubic* cubic = qobject_cast<QQuickPathCubic*>(list.at(4)); - QVERIFY(cubic != 0); + QVERIFY(cubic != nullptr); QCOMPARE(cubic->x(), 180.); QCOMPARE(cubic->y(), 0.); QCOMPARE(cubic->control1X(), -10.); @@ -770,6 +780,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(); @@ -798,7 +812,7 @@ void tst_QQuickPathView::dataModel() qApp->processEvents(); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QMetaObject::invokeMethod(window->rootObject(), "checkProperties"); QVERIFY(!testObject->error()); @@ -835,7 +849,7 @@ void tst_QQuickPathView::dataModel() QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5); QQuickRectangle *testItem = findItem<QQuickRectangle>(pathview, "wrapper", 4); - QVERIFY(testItem != 0); + QVERIFY(testItem != nullptr); testItem = findItem<QQuickRectangle>(pathview, "wrapper", 5); QVERIFY(!testItem); @@ -898,7 +912,7 @@ void tst_QQuickPathView::pathMoved() qApp->processEvents(); QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0); QVERIFY(firstItem); @@ -986,7 +1000,7 @@ void tst_QQuickPathView::setCurrentIndex() qApp->processEvents(); QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QQuickRectangle *firstItem = findItem<QQuickRectangle>(pathview, "wrapper", 0); QVERIFY(firstItem); @@ -1139,13 +1153,13 @@ void tst_QQuickPathView::resetModel() qApp->processEvents(); QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QCOMPARE(pathview->count(), model.rowCount()); for (int i = 0; i < model.rowCount(); ++i) { QQuickText *display = findItem<QQuickText>(pathview, "displayText", i); - QVERIFY(display != 0); + QVERIFY(display != nullptr); QCOMPARE(display->text(), strings.at(i)); } @@ -1157,7 +1171,7 @@ void tst_QQuickPathView::resetModel() for (int i = 0; i < model.rowCount(); ++i) { QQuickText *display = findItem<QQuickText>(pathview, "displayText", i); - QVERIFY(display != 0); + QVERIFY(display != nullptr); QCOMPARE(display->text(), strings.at(i)); } @@ -1358,6 +1372,7 @@ void tst_QQuickPathView::package() QSKIP("QTBUG-27170 view does not reliably receive polish without a running animation"); #endif + QQuickTest::qWaitForItemPolished(pathView); QQuickItem *item = findItem<QQuickItem>(pathView, "pathItem"); QVERIFY(item); QVERIFY(item->scale() != 1.0); @@ -1378,7 +1393,7 @@ void tst_QQuickPathView::emptyModel() qApp->processEvents(); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QCOMPARE(pathview->offset(), qreal(0.0)); @@ -1392,7 +1407,7 @@ void tst_QQuickPathView::emptyPath() qApp->processEvents(); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); delete window; } @@ -1440,7 +1455,7 @@ void tst_QQuickPathView::visualDataModel() QQmlComponent c(&engine, testFileUrl("vdm.qml")); QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->count(), 3); @@ -1463,7 +1478,7 @@ void tst_QQuickPathView::undefinedPath() QQmlComponent c(&engine, testFileUrl("undefinedpath.qml")); QQuickPathView *obj = qobject_cast<QQuickPathView*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->count(), 3); @@ -1481,7 +1496,7 @@ void tst_QQuickPathView::mouseDrag() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QSignalSpy movingSpy(pathview, SIGNAL(movingChanged())); QSignalSpy moveStartedSpy(pathview, SIGNAL(movementStarted())); @@ -1492,7 +1507,7 @@ void tst_QQuickPathView::mouseDrag() int current = pathview->currentIndex(); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(10,100)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(10,100)); QTest::qWait(100); { @@ -1529,7 +1544,7 @@ void tst_QQuickPathView::mouseDrag() QVERIFY(pathview->currentIndex() != current); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(40,100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(40,100)); QVERIFY(!pathview->isDragging()); QCOMPARE(draggingSpy.count(), 2); QCOMPARE(dragStartedSpy.count(), 1); @@ -1552,7 +1567,7 @@ void tst_QQuickPathView::nestedMouseAreaDrag() QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); // Dragging the child mouse area should move it and not animate the PathView flick(window.data(), QPoint(200,200), QPoint(400,200), 200); @@ -1575,7 +1590,7 @@ void tst_QQuickPathView::treeModel() window->setSource(testFileUrl("treemodel.qml")); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QCOMPARE(pathview->count(), 3); QQuickText *item = findItem<QQuickText>(pathview, "wrapper", 0); @@ -1601,7 +1616,7 @@ void tst_QQuickPathView::changePreferredHighlight() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); int current = pathview->currentIndex(); QCOMPARE(current, 0); @@ -1654,7 +1669,7 @@ void tst_QQuickPathView::currentOffsetOnInsertion() qApp->processEvents(); QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); pathview->setPreferredHighlightBegin(0.5); pathview->setPreferredHighlightEnd(0.5); @@ -1665,7 +1680,7 @@ void tst_QQuickPathView::currentOffsetOnInsertion() QCOMPARE(pathview->count(), model.count()); - QQuickRectangle *item = 0; + QQuickRectangle *item = nullptr; QTRY_VERIFY(item = findItem<QQuickRectangle>(pathview, "wrapper", 0)); QQuickPath *path = qobject_cast<QQuickPath*>(pathview->path()); @@ -1732,7 +1747,7 @@ void tst_QQuickPathView::asynchronous() QQuickItem *rootObject = qobject_cast<QQuickItem*>(window->rootObject()); QVERIFY(rootObject); - QQuickPathView *pathview = 0; + QQuickPathView *pathview = nullptr; while (!pathview) { bool b = false; controller.incubateWhile(&b); @@ -1741,8 +1756,8 @@ void tst_QQuickPathView::asynchronous() // items will be created one at a time for (int i = 0; i < 5; ++i) { - QVERIFY(findItem<QQuickItem>(pathview, "wrapper", i) == 0); - QQuickItem *item = 0; + QVERIFY(findItem<QQuickItem>(pathview, "wrapper", i) == nullptr); + QQuickItem *item = nullptr; while (!item) { bool b = false; controller.incubateWhile(&b); @@ -1804,14 +1819,14 @@ void tst_QQuickPathView::cancelDrag() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QSignalSpy draggingSpy(pathview, SIGNAL(draggingChanged())); QSignalSpy dragStartedSpy(pathview, SIGNAL(dragStarted())); QSignalSpy dragEndedSpy(pathview, SIGNAL(dragEnded())); // drag between snap points - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(10,100)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(10,100)); QTest::qWait(100); QTest::mouseMove(window.data(), QPoint(80, 100)); QTest::mouseMove(window.data(), QPoint(130, 100)); @@ -1835,7 +1850,7 @@ void tst_QQuickPathView::cancelDrag() QCOMPARE(dragStartedSpy.count(), 1); QCOMPARE(dragEndedSpy.count(), 1); - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(40,100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(40,100)); } @@ -1850,7 +1865,7 @@ void tst_QQuickPathView::maximumFlickVelocity() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); pathview->setMaximumFlickVelocity(700); flick(window.data(), QPoint(200,10), QPoint(10,10), 180); @@ -1897,7 +1912,7 @@ void tst_QQuickPathView::snapToItem() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathview = window->rootObject()->findChild<QQuickPathView*>("view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); window->rootObject()->setProperty("enforceRange", enforceRange); QTRY_VERIFY(!pathview->isMoving()); // ensure stable @@ -1941,7 +1956,7 @@ void tst_QQuickPathView::snapOneItem() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathview = window->rootObject()->findChild<QQuickPathView*>("view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); window->rootObject()->setProperty("enforceRange", enforceRange); @@ -1994,7 +2009,7 @@ void tst_QQuickPathView::positionViewAtIndex() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); window->rootObject()->setProperty("enforceRange", enforceRange); if (pathItemCount == -1) @@ -2057,9 +2072,9 @@ void tst_QQuickPathView::indexAt_itemAt() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); - QQuickItem *item = 0; + QQuickItem *item = nullptr; if (index >= 0) { item = findItem<QQuickItem>(pathview, "wrapper", index); QVERIFY(item); @@ -2091,7 +2106,7 @@ void tst_QQuickPathView::cacheItemCount() qApp->processEvents(); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QMetaObject::invokeMethod(pathview, "addColor", Q_ARG(QVariant, QString("orange"))); QMetaObject::invokeMethod(pathview, "addColor", Q_ARG(QVariant, QString("lightsteelblue"))); @@ -2117,8 +2132,8 @@ void tst_QQuickPathView::cacheItemCount() int i = 0; while (cached[i] >= 0) { // items will be created one at a time - QVERIFY(findItem<QQuickItem>(pathview, "wrapper", cached[i]) == 0); - QQuickItem *item = 0; + QVERIFY(findItem<QQuickItem>(pathview, "wrapper", cached[i]) == nullptr); + QQuickItem *item = nullptr; while (!item) { bool b = false; controller.incubateWhile(&b); @@ -2145,8 +2160,8 @@ void tst_QQuickPathView::cacheItemCount() QVERIFY(findItem<QQuickItem>(pathview, "wrapper", 11)); // one item prepended async. - QVERIFY(findItem<QQuickItem>(pathview, "wrapper", 5) == 0); - QQuickItem *item = 0; + QVERIFY(findItem<QQuickItem>(pathview, "wrapper", 5) == nullptr); + QQuickItem *item = nullptr; while (!item) { bool b = false; controller.incubateWhile(&b); @@ -2182,7 +2197,7 @@ void tst_QQuickPathView::changePathDuringRefill() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathView = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathView != 0); + QVERIFY(pathView != nullptr); testCurrentIndexChange(pathView, QStringList() << "delegateC" << "delegateA" << "delegateB"); @@ -2210,10 +2225,10 @@ void tst_QQuickPathView::nestedinFlickable() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "pathView"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); QSignalSpy movingSpy(pathview, SIGNAL(movingChanged())); QSignalSpy moveStartedSpy(pathview, SIGNAL(movementStarted())); @@ -2225,7 +2240,7 @@ void tst_QQuickPathView::nestedinFlickable() int waitInterval = 5; - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(23,218)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(23,218)); QTest::mouseMove(window.data(), QPoint(25,218), waitInterval); QTest::mouseMove(window.data(), QPoint(26,218), waitInterval); @@ -2244,7 +2259,7 @@ void tst_QQuickPathView::nestedinFlickable() QCOMPARE(fflickEndedSpy.count(), 0); // no further moves after the initial move beyond threshold - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(73,219)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(73,219)); QTRY_COMPARE(movingSpy.count(), 2); QTRY_COMPARE(moveEndedSpy.count(), 1); QCOMPARE(moveStartedSpy.count(), 1); @@ -2252,6 +2267,59 @@ void tst_QQuickPathView::nestedinFlickable() QCOMPARE(fflickingSpy.count(), 0); QCOMPARE(fflickStartedSpy.count(), 0); QCOMPARE(fflickEndedSpy.count(), 0); + + // now test that two quick flicks are both handled by the pathview + movingSpy.clear(); + moveStartedSpy.clear(); + moveEndedSpy.clear(); + fflickingSpy.clear(); + fflickStartedSpy.clear(); + fflickEndedSpy.clear(); + int shortInterval = 2; + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(23,216)); + QTest::mouseMove(window.data(), QPoint(48,216), shortInterval); + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(73,217)); + QVERIFY(pathview->isMoving()); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(21,216)); + QTest::mouseMove(window.data(), QPoint(46,216), shortInterval); + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(71,217)); + QVERIFY(pathview->isMoving()); + // moveEndedSpy.count() and moveStartedSpy.count() should be exactly 1 + // but in CI we sometimes see a scheduling issue being hit which + // causes the main thread to be stalled while the animation thread + // continues, allowing the animation timer to finish after the first + // call to QVERIFY(pathview->isMoving()) in the code above, prior to + // the detected beginning of the second flick, which can cause both of + // those signal counts to be 2 rather than 1. + // Note that this is not a true problem (this scheduling quirk just + // means that the unit test is not testing the enforced behavior + // as strictly as it would otherwise); it is only a bug if it results + // in the Flickable handling one or more of the flicks, and that + // is unconditionally tested below. + // To avoid false positive test failure in the scheduling quirk case + // we allow the multiple signal count case, rather than simply: + // QTRY_COMPARE(moveEndedSpy.count(), 1); + // QCOMPARE(moveStartedSpy.count(), 1); + QTRY_VERIFY(moveEndedSpy.count() > 0); + qCDebug(lcTests) << "After receiving moveEnded signal:" + << "moveEndedSpy.count():" << moveEndedSpy.count() + << "moveStartedSpy.count():" << moveStartedSpy.count() + << "fflickingSpy.count():" << fflickingSpy.count() + << "fflickStartedSpy.count():" << fflickStartedSpy.count() + << "fflickEndedSpy.count():" << fflickEndedSpy.count(); + QTRY_COMPARE(moveStartedSpy.count(), moveEndedSpy.count()); + qCDebug(lcTests) << "After receiving matched moveEnded signal(s):" + << "moveEndedSpy.count():" << moveEndedSpy.count() + << "moveStartedSpy.count():" << moveStartedSpy.count() + << "fflickingSpy.count():" << fflickingSpy.count() + << "fflickStartedSpy.count():" << fflickStartedSpy.count() + << "fflickEndedSpy.count():" << fflickEndedSpy.count(); + QVERIFY(moveStartedSpy.count() <= 2); + // Flickable should not handle this + QCOMPARE(fflickingSpy.count(), 0); + QCOMPARE(fflickStartedSpy.count(), 0); + QCOMPARE(fflickEndedSpy.count(), 0); + } void tst_QQuickPathView::flickableDelegate() @@ -2265,10 +2333,10 @@ void tst_QQuickPathView::flickableDelegate() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(pathview->currentItem()); - QVERIFY(flickable != 0); + QVERIFY(flickable != nullptr); QSignalSpy movingSpy(pathview, SIGNAL(movingChanged())); QSignalSpy moveStartedSpy(pathview, SIGNAL(movementStarted())); @@ -2280,7 +2348,7 @@ void tst_QQuickPathView::flickableDelegate() int waitInterval = 5; - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(23,100)); + QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(23,100)); QTest::mouseMove(window.data(), QPoint(25,100), waitInterval); QTest::mouseMove(window.data(), QPoint(26,100), waitInterval); @@ -2299,7 +2367,7 @@ void tst_QQuickPathView::flickableDelegate() QCOMPARE(fflickEndedSpy.count(), 0); // no further moves after the initial move beyond threshold - QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(53,100)); + QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(53,100)); QTRY_COMPARE(fflickingSpy.count(), 2); QTRY_COMPARE(fflickStartedSpy.count(), 1); QCOMPARE(fflickEndedSpy.count(), 1); @@ -2349,7 +2417,7 @@ void tst_QQuickPathView::qtbug37815() QTest::qWait(1000); QQuickPathView *pathView = findItem<QQuickPathView>(window->rootObject(), "pathView"); - QVERIFY(pathView != Q_NULLPTR); + QVERIFY(pathView != nullptr); const int pathItemCount = pathView->pathItemCount(); const int cacheItemCount = pathView->cacheItemCount(); @@ -2377,7 +2445,7 @@ void tst_QQuickPathView::qtbug42716() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathView = findItem<QQuickPathView>(window->rootObject(), "pathView"); - QVERIFY(pathView != 0); + QVERIFY(pathView != nullptr); int order1[] = {5,6,7,0,1,2,3}; int missing1 = 4; @@ -2419,7 +2487,7 @@ void tst_QQuickPathView::qtbug53464() QVERIFY(QTest::qWaitForWindowActive(window.data())); QQuickPathView *pathView = findItem<QQuickPathView>(window->rootObject(), "pathView"); - QVERIFY(pathView != Q_NULLPTR); + QVERIFY(pathView != nullptr); const int currentIndex = pathView->currentIndex(); QCOMPARE(currentIndex, 8); @@ -2460,9 +2528,11 @@ static void verify_offsets(QQuickPathView *pathview, int toidx, qreal fromoffset QTest::qWait(100); first = pathview->offset(); while (1) { + if (first == 0) + first = pathview->offset(); QTest::qWait(10); // highlightMoveDuration: 1000 second = pathview->offset(); - if (!started && second != first) { // animation started + if (!started && first != 0 && second != first) { // animation started started = true; break; } @@ -2496,7 +2566,7 @@ void tst_QQuickPathView::movementDirection() QCOMPARE(window.data(), qGuiApp->focusWindow()); QQuickPathView *pathview = window->rootObject()->findChild<QQuickPathView*>("view"); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QVERIFY(pathview->offset() == 0.0); QVERIFY(pathview->currentIndex() == 0); pathview->setMovementDirection(movementdirection); @@ -2512,12 +2582,59 @@ void tst_QQuickPathView::removePath() window->show(); QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject()); - QVERIFY(pathview != 0); + QVERIFY(pathview != nullptr); QVERIFY(QMetaObject::invokeMethod(pathview, "removePath")); QVERIFY(QMetaObject::invokeMethod(pathview, "setPath")); } +/* + Tests that moving items in an ObjectModel and then deleting the view + doesn't cause heap-use-after-free when run through ASAN. + + The test case is based on a Qt Quick Controls 2 test where the issue was + discovered. +*/ +void tst_QQuickPathView::objectModelMove() +{ + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("objectModelMove.qml")); + window->show(); + + // Create the view. + QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "newView")); + QPointer<QQuickPathView> pathView = window->rootObject()->property("pathViewItem").value<QQuickPathView*>(); + QVERIFY(pathView); + QCOMPARE(pathView->count(), 3); + pathView->highlightItem()->setObjectName("highlight"); + + // Move an item from index 0 to 1. + QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "move")); + QCOMPARE(pathView->count(), 3); + + // Keep track of the amount of listeners + QVector<QString> itemObjectNames; + itemObjectNames << QLatin1String("red") << QLatin1String("green") << QLatin1String("blue"); + QVector<QQuickItem*> childItems; + for (const QString itemObjectName : qAsConst(itemObjectNames)) { + QQuickItem *childItem = findItem<QQuickItem>(pathView, itemObjectName); + QVERIFY(childItem); + childItems.append(childItem); + } + + // Destroy the view (via destroy()). + QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "destroyView")); + // Ensure that the view has been destroyed. This check is also necessary in order for + // ASAN to complain (it will complain after the test function has finished). + QTRY_VERIFY(pathView.isNull()); + // By this point, all of its cached items should have been released, + // which means none of the items should have any listeners. + for (const auto childItem : qAsConst(childItems)) { + const QQuickItemPrivate *childItemPrivate = QQuickItemPrivate::get(childItem); + QCOMPARE(childItemPrivate->changeListeners.size(), 0); + } +} + QTEST_MAIN(tst_QQuickPathView) #include "tst_qquickpathview.moc" diff --git a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp index c1a51fd659..5b7108d96b 100644 --- a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp +++ b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 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. @@ -41,7 +41,7 @@ class tst_QQuickPinchArea: public QQmlDataTest { Q_OBJECT public: - tst_QQuickPinchArea() : device(0) { } + tst_QQuickPinchArea() { } private slots: void initTestCase(); void cleanupTestCase(); @@ -55,7 +55,7 @@ private slots: private: QQuickView *createView(); - QTouchDevice *device; + QTouchDevice *device = nullptr; }; void tst_QQuickPinchArea::initTestCase() { @@ -76,19 +76,19 @@ void tst_QQuickPinchArea::pinchProperties() QScopedPointer<QQuickView> window(createView()); window->setSource(testFileUrl("pinchproperties.qml")); window->show(); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); QQuickPinch *pinch = pinchArea->pinch(); - QVERIFY(pinchArea != 0); - QVERIFY(pinch != 0); + QVERIFY(pinchArea != nullptr); + QVERIFY(pinch != nullptr); // target QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QCOMPARE(blackRect, pinch->target()); QQuickItem *rootItem = qobject_cast<QQuickItem*>(window->rootObject()); - QVERIFY(rootItem != 0); + QVERIFY(rootItem != nullptr); QSignalSpy targetSpy(pinch, SIGNAL(targetChanged())); pinch->setTarget(rootItem); QCOMPARE(targetSpy.count(),1); @@ -201,20 +201,20 @@ void tst_QQuickPinchArea::scale() window->setSource(testFileUrl("pinchproperties.qml")); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window)); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); qApp->processEvents(); QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); QQuickPinch *pinch = pinchArea->pinch(); - QVERIFY(pinchArea != 0); - QVERIFY(pinch != 0); + QVERIFY(pinchArea != nullptr); + QVERIFY(pinch != nullptr); QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); - QVERIFY(root != 0); + QVERIFY(root != nullptr); // target QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QPoint p1(80, 80); QPoint p2(100, 100); @@ -268,20 +268,20 @@ void tst_QQuickPinchArea::pan() window->setSource(testFileUrl("pinchproperties.qml")); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window)); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); qApp->processEvents(); QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); QQuickPinch *pinch = pinchArea->pinch(); - QVERIFY(pinchArea != 0); - QVERIFY(pinch != 0); + QVERIFY(pinchArea != nullptr); + QVERIFY(pinch != nullptr); QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); - QVERIFY(root != 0); + QVERIFY(root != nullptr); // target QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QPoint p1(80, 80); QPoint p2(100, 100); @@ -374,23 +374,23 @@ void tst_QQuickPinchArea::retouch() window->setSource(testFileUrl("pinchproperties.qml")); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window)); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); qApp->processEvents(); QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); QQuickPinch *pinch = pinchArea->pinch(); - QVERIFY(pinchArea != 0); - QVERIFY(pinch != 0); + QVERIFY(pinchArea != nullptr); + QVERIFY(pinch != nullptr); QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QSignalSpy startedSpy(pinchArea, SIGNAL(pinchStarted(QQuickPinchEvent*))); QSignalSpy finishedSpy(pinchArea, SIGNAL(pinchFinished(QQuickPinchEvent*))); // target QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QPoint p1(80, 80); QPoint p2(100, 100); @@ -465,20 +465,20 @@ void tst_QQuickPinchArea::cancel() window->setSource(testFileUrl("pinchproperties.qml")); window->show(); QVERIFY(QTest::qWaitForWindowExposed(window)); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); qApp->processEvents(); QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); QQuickPinch *pinch = pinchArea->pinch(); - QVERIFY(pinchArea != 0); - QVERIFY(pinch != 0); + QVERIFY(pinchArea != nullptr); + QVERIFY(pinch != nullptr); QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject()); - QVERIFY(root != 0); + QVERIFY(root != nullptr); // target QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect"); - QVERIFY(blackRect != 0); + QVERIFY(blackRect != nullptr); QPoint p1(80, 80); QPoint p2(100, 100); @@ -558,11 +558,11 @@ void tst_QQuickPinchArea::transformedPinchArea() view->setSource(testFileUrl("transformedPinchArea.qml")); view->show(); QVERIFY(QTest::qWaitForWindowExposed(view)); - QVERIFY(view->rootObject() != 0); + QVERIFY(view->rootObject() != nullptr); qApp->processEvents(); QQuickPinchArea *pinchArea = view->rootObject()->findChild<QQuickPinchArea*>("pinchArea"); - QVERIFY(pinchArea != 0); + QVERIFY(pinchArea != nullptr); const int threshold = qApp->styleHints()->startDragDistance(); @@ -588,7 +588,7 @@ void tst_QQuickPinchArea::transformedPinchArea() QQuickView *tst_QQuickPinchArea::createView() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setGeometry(0,0,240,320); return window; diff --git a/tests/auto/quick/qquickpixmapcache/qquickpixmapcache.pro b/tests/auto/quick/qquickpixmapcache/qquickpixmapcache.pro index 185eb2c213..52b798e829 100644 --- a/tests/auto/quick/qquickpixmapcache/qquickpixmapcache.pro +++ b/tests/auto/quick/qquickpixmapcache/qquickpixmapcache.pro @@ -5,7 +5,6 @@ macx:CONFIG -= app_bundle SOURCES += tst_qquickpixmapcache.cpp \ ../../shared/testhttpserver.cpp HEADERS += ../../shared/testhttpserver.h -INCLUDEPATH += ../../shared/ include (../../shared/util.pri) diff --git a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp index e854a109a1..bffaaf7c6e 100644 --- a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp +++ b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp @@ -431,7 +431,7 @@ void tst_qquickpixmapcache::uncached() QUrl url("image://mypixmaps/mypix"); { QQuickPixmap p; - p.load(&engine, url, 0); + p.load(&engine, url, nullptr); QImage img = p.image(); QCOMPARE(img.pixel(0,0), qRgb(255, 0, 0)); } @@ -440,7 +440,7 @@ void tst_qquickpixmapcache::uncached() MyPixmapProvider::fillColor = qRgb(0, 255, 0); { QQuickPixmap p; - p.load(&engine, url, 0); + p.load(&engine, url, nullptr); QImage img = p.image(); QCOMPARE(img.pixel(0,0), qRgb(0, 255, 0)); } @@ -458,7 +458,7 @@ void tst_qquickpixmapcache::uncached() MyPixmapProvider::fillColor = qRgb(255, 0, 255); { QQuickPixmap p; - p.load(&engine, url, 0); + p.load(&engine, url, nullptr); QImage img = p.image(); QCOMPARE(img.pixel(0,0), qRgb(255, 0, 255)); } diff --git a/tests/auto/quick/qquickpositioners/qquickpositioners.pro b/tests/auto/quick/qquickpositioners/qquickpositioners.pro index 6e85ba9db8..d1547df189 100644 --- a/tests/auto/quick/qquickpositioners/qquickpositioners.pro +++ b/tests/auto/quick/qquickpositioners/qquickpositioners.pro @@ -9,4 +9,4 @@ macx:CONFIG -= app_bundle TESTDATA = data/* -QT += testlib +QT += testlib qmltest diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp index 1b3939401a..80be25d1b0 100644 --- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp +++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp @@ -31,6 +31,7 @@ #include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickpositioners_p.h> #include <QtQuick/private/qquicktransition_p.h> +#include <QtQuickTest/QtQuickTest> #include <private/qquickitem_p.h> #include <qqmlexpression.h> #include "../shared/viewtestutil.h" @@ -40,6 +41,8 @@ using namespace QQuickViewTestUtil; using namespace QQuickVisualTestUtil; +Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") + class tst_qquickpositioners : public QQmlDataTest { Q_OBJECT @@ -313,13 +316,13 @@ void tst_qquickpositioners::test_horizontal() window->rootObject()->setProperty("testRightToLeft", false); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -357,13 +360,13 @@ void tst_qquickpositioners::test_horizontal_padding() window->rootObject()->setProperty("testRightToLeft", false); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -377,7 +380,7 @@ void tst_qquickpositioners::test_horizontal_padding() QCOMPARE(row->height(), 50.0); QQuickRow *obj = qobject_cast<QQuickRow*>(row); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(row->property("padding").toDouble(), 0.0); QCOMPARE(row->property("topPadding").toDouble(), 0.0); @@ -519,13 +522,13 @@ void tst_qquickpositioners::test_horizontal_rtl() window->rootObject()->setProperty("testRightToLeft", true); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(one->x(), 60.0); QCOMPARE(one->y(), 0.0); @@ -598,13 +601,13 @@ void tst_qquickpositioners::test_horizontal_spacing() window->rootObject()->setProperty("testRightToLeft", false); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -642,13 +645,13 @@ void tst_qquickpositioners::test_horizontal_spacing_rightToLeft() window->rootObject()->setProperty("testRightToLeft", true); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(one->x(), 80.0); QCOMPARE(one->y(), 0.0); @@ -686,13 +689,13 @@ void tst_qquickpositioners::test_horizontal_animated() window->rootObject()->setProperty("testRightToLeft", false); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); //Note that they animate in QCOMPARE(one->x(), -100.0); @@ -739,13 +742,13 @@ void tst_qquickpositioners::test_horizontal_animated_padding() window->rootObject()->setProperty("testRightToLeft", false); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); //Note that they animate in QCOMPARE(one->x(), -100.0); @@ -803,13 +806,13 @@ void tst_qquickpositioners::test_horizontal_animated_rightToLeft() window->rootObject()->setProperty("testRightToLeft", true); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); //Note that they animate in QCOMPARE(one->x(), -100.0); @@ -858,13 +861,13 @@ void tst_qquickpositioners::test_horizontal_animated_rightToLeft_padding() window->rootObject()->setProperty("testRightToLeft", true); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); //Note that they animate in QCOMPARE(one->x(), -100.0); @@ -922,13 +925,13 @@ void tst_qquickpositioners::test_horizontal_animated_disabled() QScopedPointer<QQuickView> window(createView(testFile("horizontal-animated-disabled.qml"))); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row"); QVERIFY(row); @@ -970,13 +973,13 @@ void tst_qquickpositioners::test_horizontal_animated_disabled_padding() QScopedPointer<QQuickView> window(createView(testFile("horizontal-animated-disabled.qml"))); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row"); QVERIFY(row); @@ -1037,7 +1040,7 @@ void tst_qquickpositioners::populateTransitions(const QString &positionerObjectN QQuickItem *positioner = window->rootObject()->findChild<QQuickItem*>(positionerObjectName); QVERIFY(positioner); window->show(); - QTest::qWaitForWindowExposed(window.data()); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); qApp->processEvents(); if (!dynamicallyPopulate && usePopulateTransition) { @@ -1060,7 +1063,7 @@ void tst_qquickpositioners::populateTransitions(const QString &positionerObjectN QTRY_COMPARE(window->rootObject()->property("populateTransitionsDone").toInt(), 0); QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), model.count()); } else { - QTRY_COMPARE(QQuickItemPrivate::get(positioner)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(positioner)); QTRY_COMPARE(window->rootObject()->property("populateTransitionsDone").toInt(), 0); QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), 0); } @@ -1120,13 +1123,13 @@ void tst_qquickpositioners::addTransitions(const QString &positionerObjectName) ctxt->setContextProperty("testedPositioner", QString()); window->setSource(testFileUrl(qmlFile)); window->show(); - QTest::qWaitForWindowExposed(window.data()); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); qApp->processEvents(); QQuickItem *positioner = window->rootObject()->findChild<QQuickItem*>(positionerObjectName); QVERIFY(positioner); positioner->findChild<QQuickItem*>("repeater")->setProperty("model", QVariant::fromValue(&model)); - QTRY_COMPARE(QQuickItemPrivate::get(positioner)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(positioner)); for (int i = 0; i < initialItemCount; i++) model.addItem("Original item" + QString::number(i), ""); @@ -1243,7 +1246,7 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName) ctxt->setContextProperty("testedPositioner", QString()); window->setSource(testFileUrl(qmlFile)); window->show(); - QTest::qWaitForWindowExposed(window.data()); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); qApp->processEvents(); QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); @@ -1251,7 +1254,7 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName) QQuickItem *positioner = window->rootObject()->findChild<QQuickItem*>(positionerObjectName); QVERIFY(positioner); positioner->findChild<QQuickItem*>("repeater")->setProperty("model", QVariant::fromValue(&model)); - QTRY_COMPARE(QQuickItemPrivate::get(positioner)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(positioner)); switch (change.type) { case ListChange::Removed: @@ -1260,7 +1263,7 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName) break; case ListChange::Moved: model.moveItems(change.index, change.to, change.count); - QTRY_COMPARE(QQuickItemPrivate::get(positioner)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(positioner)); break; case ListChange::Inserted: case ListChange::SetCurrent: @@ -1390,7 +1393,7 @@ void tst_qquickpositioners::checkItemPositions(QQuickItem *positioner, QaimModel QVERIFY2(false, "Unknown positioner type"); } QQuickText *name = findItem<QQuickText>(positioner, "name", i); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QTRY_COMPARE(name->text(), model->name(i)); padding += i * incrementalSize; @@ -1403,13 +1406,13 @@ void tst_qquickpositioners::test_vertical() QScopedPointer<QQuickView> window(createView(testFile("vertical.qml"))); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -1446,13 +1449,13 @@ void tst_qquickpositioners::test_vertical_padding() QScopedPointer<QQuickView> window(createView(testFile("vertical.qml"))); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -1467,7 +1470,7 @@ void tst_qquickpositioners::test_vertical_padding() QCOMPARE(column->width(), 50.0); QQuickColumn *obj = qobject_cast<QQuickColumn*>(column); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(column->property("padding").toDouble(), 0.0); QCOMPARE(column->property("topPadding").toDouble(), 0.0); @@ -1607,13 +1610,13 @@ void tst_qquickpositioners::test_vertical_spacing() QScopedPointer<QQuickView> window(createView(testFile("vertical-spacing.qml"))); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -1650,15 +1653,15 @@ void tst_qquickpositioners::test_vertical_animated() //Note that they animate in QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QCOMPARE(one->y(), -100.0); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QCOMPARE(two->y(), -100.0); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(three->y(), -100.0); QVERIFY(QTest::qWaitForWindowExposed(window.data())); //It may not relayout until the next frame, so it needs to be drawn @@ -1699,15 +1702,15 @@ void tst_qquickpositioners::test_vertical_animated_padding() //Note that they animate in QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QCOMPARE(one->y(), -100.0); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QCOMPARE(two->y(), -100.0); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(three->y(), -100.0); QVERIFY(QTest::qWaitForWindowExposed(window.data())); //It may not relayout until the next frame, so it needs to be drawn @@ -1758,15 +1761,15 @@ void tst_qquickpositioners::test_grid() QScopedPointer<QQuickView> window(createView(testFile("gridtest.qml"))); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -1811,15 +1814,15 @@ void tst_qquickpositioners::test_grid_padding() QScopedPointer<QQuickView> window(createView(testFile("gridtest.qml"))); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -1999,15 +2002,15 @@ void tst_qquickpositioners::test_grid_topToBottom() QScopedPointer<QQuickView> window(createView(testFile("grid-toptobottom.qml"))); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -2054,15 +2057,15 @@ void tst_qquickpositioners::test_grid_rightToLeft() window->rootObject()->setProperty("testRightToLeft", true); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 50.0); QCOMPARE(one->y(), 0.0); @@ -2154,15 +2157,15 @@ void tst_qquickpositioners::test_grid_spacing() QScopedPointer<QQuickView> window(createView(testFile("grid-spacing.qml"))); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -2206,15 +2209,15 @@ void tst_qquickpositioners::test_grid_row_column_spacing() QScopedPointer<QQuickView> window(createView(testFile("grid-row-column-spacing.qml"))); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -2261,27 +2264,27 @@ void tst_qquickpositioners::test_grid_animated() //Note that all animate in QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QCOMPARE(one->x(), -100.0); QCOMPARE(one->y(), -100.0); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QCOMPARE(two->x(), -100.0); QCOMPARE(two->y(), -100.0); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(three->x(), -100.0); QCOMPARE(three->y(), -100.0); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QCOMPARE(four->x(), -100.0); QCOMPARE(four->y(), -100.0); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(five->x(), -100.0); QCOMPARE(five->y(), -100.0); @@ -2345,27 +2348,27 @@ void tst_qquickpositioners::test_grid_animated_padding() //Note that all animate in QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QCOMPARE(one->x(), -100.0); QCOMPARE(one->y(), -100.0); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QCOMPARE(two->x(), -100.0); QCOMPARE(two->y(), -100.0); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(three->x(), -100.0); QCOMPARE(three->y(), -100.0); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QCOMPARE(four->x(), -100.0); QCOMPARE(four->y(), -100.0); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(five->x(), -100.0); QCOMPARE(five->y(), -100.0); @@ -2439,27 +2442,27 @@ void tst_qquickpositioners::test_grid_animated_rightToLeft() //Note that all animate in QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QCOMPARE(one->x(), -100.0); QCOMPARE(one->y(), -100.0); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QCOMPARE(two->x(), -100.0); QCOMPARE(two->y(), -100.0); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(three->x(), -100.0); QCOMPARE(three->y(), -100.0); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QCOMPARE(four->x(), -100.0); QCOMPARE(four->y(), -100.0); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(five->x(), -100.0); QCOMPARE(five->y(), -100.0); @@ -2523,27 +2526,27 @@ void tst_qquickpositioners::test_grid_animated_rightToLeft_padding() //Note that all animate in QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QCOMPARE(one->x(), -100.0); QCOMPARE(one->y(), -100.0); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QCOMPARE(two->x(), -100.0); QCOMPARE(two->y(), -100.0); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(three->x(), -100.0); QCOMPARE(three->y(), -100.0); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QCOMPARE(four->x(), -100.0); QCOMPARE(four->y(), -100.0); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(five->x(), -100.0); QCOMPARE(five->y(), -100.0); @@ -2614,15 +2617,15 @@ void tst_qquickpositioners::test_grid_zero_columns() QScopedPointer<QQuickView> window(createView(testFile("gridzerocolumns.qml"))); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -2668,15 +2671,15 @@ void tst_qquickpositioners::test_grid_H_alignment() window->rootObject()->setProperty("testHAlignment", QQuickGrid::AlignHCenter); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -2747,15 +2750,15 @@ void tst_qquickpositioners::test_grid_H_alignment_padding() window->rootObject()->setProperty("testHAlignment", QQuickGrid::AlignHCenter); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -2836,15 +2839,15 @@ void tst_qquickpositioners::test_grid_V_alignment() window->rootObject()->setProperty("testVAlignment", QQuickGrid::AlignVCenter); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -2879,15 +2882,15 @@ void tst_qquickpositioners::test_grid_V_alignment_padding() window->rootObject()->setProperty("testVAlignment", QQuickGrid::AlignVCenter); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QQuickItem *grid = window->rootObject()->findChild<QQuickItem*>("grid"); QCOMPARE(grid->width(), 100.0); @@ -2934,7 +2937,7 @@ void tst_qquickpositioners::test_propertychanges() QScopedPointer<QQuickView> window(createView(testFile("propertychangestest.qml"))); QQuickGrid *grid = qobject_cast<QQuickGrid*>(window->rootObject()); - QVERIFY(grid != 0); + QVERIFY(grid != nullptr); QQuickTransition *rowTransition = window->rootObject()->findChild<QQuickTransition*>("rowTransition"); QQuickTransition *columnTransition = window->rootObject()->findChild<QQuickTransition*>("columnTransition"); @@ -2963,8 +2966,8 @@ void tst_qquickpositioners::test_propertychanges() QCOMPARE(addSpy.count(),1); QCOMPARE(moveSpy.count(),1); - grid->setAdd(0); - grid->setMove(0); + grid->setAdd(nullptr); + grid->setMove(nullptr); QCOMPARE(addSpy.count(),2); QCOMPARE(moveSpy.count(),2); @@ -2992,13 +2995,13 @@ void tst_qquickpositioners::test_repeater() QScopedPointer<QQuickView> window(createView(testFile("repeatertest.qml"))); QQuickRectangle *one = findItem<QQuickRectangle>(window->contentItem(), "one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = findItem<QQuickRectangle>(window->contentItem(), "two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = findItem<QQuickRectangle>(window->contentItem(), "three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -3014,13 +3017,13 @@ void tst_qquickpositioners::test_repeater_padding() QScopedPointer<QQuickView> window(createView(testFile("repeatertest-padding.qml"))); QQuickRectangle *one = findItem<QQuickRectangle>(window->contentItem(), "one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = findItem<QQuickRectangle>(window->contentItem(), "two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = findItem<QQuickRectangle>(window->contentItem(), "three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QCOMPARE(one->x(), 3.0); QCOMPARE(one->y(), 2.0); @@ -3038,15 +3041,15 @@ void tst_qquickpositioners::test_flow() window->rootObject()->setProperty("testRightToLeft", false); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -3093,15 +3096,15 @@ void tst_qquickpositioners::test_flow_padding() window->rootObject()->setProperty("testRightToLeft", false); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -3120,7 +3123,7 @@ void tst_qquickpositioners::test_flow_padding() QCOMPARE(flow->height(), 120.0); QQuickFlow *obj = qobject_cast<QQuickFlow*>(flow); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(flow->property("padding").toDouble(), 0.0); QCOMPARE(flow->property("topPadding").toDouble(), 0.0); @@ -3286,15 +3289,15 @@ void tst_qquickpositioners::test_flow_rightToLeft() window->rootObject()->setProperty("testRightToLeft", true); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 40.0); QCOMPARE(one->y(), 0.0); @@ -3341,15 +3344,15 @@ void tst_qquickpositioners::test_flow_topToBottom() window->rootObject()->setProperty("testRightToLeft", false); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -3393,15 +3396,15 @@ void tst_qquickpositioners::test_flow_topToBottom_padding() window->rootObject()->setProperty("testRightToLeft", false); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 0.0); QCOMPARE(one->y(), 0.0); @@ -3469,15 +3472,15 @@ void tst_qquickpositioners::test_flow_resize() root->setProperty("testRightToLeft", false); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QTRY_COMPARE(one->x(), 0.0); QTRY_COMPARE(one->y(), 0.0); @@ -3502,15 +3505,15 @@ void tst_qquickpositioners::test_flow_resize_padding() root->setProperty("testRightToLeft", false); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QVERIFY(one != 0); + QVERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QTRY_COMPARE(one->x(), 3.0); QTRY_COMPARE(one->y(), 2.0); @@ -3535,15 +3538,15 @@ void tst_qquickpositioners::test_flow_resize_rightToLeft() root->setProperty("testRightToLeft", true); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QTRY_VERIFY(one != 0); + QTRY_VERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 75.0); QCOMPARE(one->y(), 0.0); @@ -3568,15 +3571,15 @@ void tst_qquickpositioners::test_flow_resize_rightToLeft_padding() root->setProperty("testRightToLeft", true); QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one"); - QTRY_VERIFY(one != 0); + QTRY_VERIFY(one != nullptr); QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two"); - QVERIFY(two != 0); + QVERIFY(two != nullptr); QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three"); - QVERIFY(three != 0); + QVERIFY(three != nullptr); QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four"); - QVERIFY(four != 0); + QVERIFY(four != nullptr); QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five"); - QVERIFY(five != 0); + QVERIFY(five != nullptr); QCOMPARE(one->x(), 71.0); QCOMPARE(one->y(), 2.0); @@ -3594,10 +3597,10 @@ void tst_qquickpositioners::test_flow_resize_rightToLeft_padding() void tst_qquickpositioners::test_flow_implicit_resize() { QScopedPointer<QQuickView> window(createView(testFile("flow-testimplicitsize.qml"))); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlow *flow = window->rootObject()->findChild<QQuickFlow*>("flow"); - QVERIFY(flow != 0); + QVERIFY(flow != nullptr); QCOMPARE(flow->width(), 100.0); QCOMPARE(flow->height(), 120.0); @@ -3622,10 +3625,10 @@ void tst_qquickpositioners::test_flow_implicit_resize() void tst_qquickpositioners::test_flow_implicit_resize_padding() { QScopedPointer<QQuickView> window(createView(testFile("flow-testimplicitsize.qml"))); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlow *flow = window->rootObject()->findChild<QQuickFlow*>("flow"); - QVERIFY(flow != 0); + QVERIFY(flow != nullptr); QCOMPARE(flow->width(), 100.0); QCOMPARE(flow->height(), 120.0); @@ -3813,7 +3816,7 @@ void tst_qquickpositioners::test_mirroring() QQuickItem *positionerB = itemB->parentItem(); positionerA->setWidth(positionerA->width() * 2); positionerB->setWidth(positionerB->width() * 2); - QTRY_VERIFY(!QQuickItemPrivate::get(positionerA)->polishScheduled && !QQuickItemPrivate::get(positionerB)->polishScheduled); + QVERIFY(QQuickTest::qWaitForItemPolished(positionerA) && QQuickTest::qWaitForItemPolished(positionerB)); QTRY_COMPARE(itemA->x(), itemB->x()); } @@ -3841,7 +3844,7 @@ void tst_qquickpositioners::test_allInvisible() QVERIFY(root); QQuickRow *row = window->rootObject()->findChild<QQuickRow*>("row"); - QVERIFY(row != 0); + QVERIFY(row != nullptr); QCOMPARE(row->width(), qreal(0)); QCOMPARE(row->height(), qreal(0)); @@ -3856,7 +3859,7 @@ void tst_qquickpositioners::test_allInvisible() QCOMPARE(row->width(), 7.0); QQuickColumn *column = window->rootObject()->findChild<QQuickColumn*>("column"); - QVERIFY(column != 0); + QVERIFY(column != nullptr); QCOMPARE(column->width(), qreal(0)); QCOMPARE(column->height(), qreal(0)); @@ -3871,7 +3874,7 @@ void tst_qquickpositioners::test_allInvisible() QCOMPARE(column->width(), 7.0); QQuickGrid *grid = window->rootObject()->findChild<QQuickGrid*>("grid"); - QVERIFY(grid != 0); + QVERIFY(grid != nullptr); QCOMPARE(grid->width(), qreal(0)); QCOMPARE(grid->height(), qreal(0)); @@ -3886,7 +3889,7 @@ void tst_qquickpositioners::test_allInvisible() QCOMPARE(grid->width(), 7.0); QQuickFlow *flow = window->rootObject()->findChild<QQuickFlow*>("flow"); - QVERIFY(flow != 0); + QVERIFY(flow != nullptr); QCOMPARE(flow->width(), qreal(0)); QCOMPARE(flow->height(), qreal(0)); @@ -3906,10 +3909,10 @@ void tst_qquickpositioners::test_attachedproperties() QFETCH(QString, filename); QScopedPointer<QQuickView> window(createView(filename)); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickRectangle *greenRect = window->rootObject()->findChild<QQuickRectangle *>("greenRect"); - QVERIFY(greenRect != 0); + QVERIFY(greenRect != nullptr); int posIndex = greenRect->property("posIndex").toInt(); QCOMPARE(posIndex, 0); @@ -3919,7 +3922,7 @@ void tst_qquickpositioners::test_attachedproperties() QVERIFY(!isLast); QQuickRectangle *yellowRect = window->rootObject()->findChild<QQuickRectangle *>("yellowRect"); - QVERIFY(yellowRect != 0); + QVERIFY(yellowRect != nullptr); posIndex = yellowRect->property("posIndex").toInt(); QCOMPARE(posIndex, -1); @@ -3952,13 +3955,13 @@ void tst_qquickpositioners::test_attachedproperties_data() void tst_qquickpositioners::test_attachedproperties_dynamic() { QScopedPointer<QQuickView> window(createView(testFile("attachedproperties-dynamic.qml"))); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickRow *row = window->rootObject()->findChild<QQuickRow *>("pos"); - QVERIFY(row != 0); + QVERIFY(row != nullptr); QQuickRectangle *rect0 = window->rootObject()->findChild<QQuickRectangle *>("rect0"); - QVERIFY(rect0 != 0); + QVERIFY(rect0 != nullptr); int posIndex = rect0->property("index").toInt(); QCOMPARE(posIndex, 0); @@ -3968,7 +3971,7 @@ void tst_qquickpositioners::test_attachedproperties_dynamic() QVERIFY(!isLast); QQuickRectangle *rect1 = window->rootObject()->findChild<QQuickRectangle *>("rect1"); - QVERIFY(rect1 != 0); + QVERIFY(rect1 != nullptr); posIndex = rect1->property("index").toInt(); QCOMPARE(posIndex, 1); @@ -3984,7 +3987,7 @@ void tst_qquickpositioners::test_attachedproperties_dynamic() QTRY_VERIFY(!rect1->property("lastItem").toBool()); QQuickRectangle *rect2 = window->rootObject()->findChild<QQuickRectangle *>("rect2"); - QVERIFY(rect2 != 0); + QVERIFY(rect2 != nullptr); posIndex = rect2->property("index").toInt(); QCOMPARE(posIndex, 2); @@ -3995,7 +3998,7 @@ void tst_qquickpositioners::test_attachedproperties_dynamic() row->metaObject()->invokeMethod(row, "destroySubRect"); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QCoreApplication::processEvents(); QTRY_COMPARE(rect1->property("index").toInt(), 1); @@ -4006,16 +4009,20 @@ void tst_qquickpositioners::test_attachedproperties_dynamic() QQuickView *tst_qquickpositioners::createView(const QString &filename, bool wait) { - QQuickView *window = new QQuickView(0); - qDebug() << "1"; + QQuickView *window = new QQuickView(nullptr); + 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 0d79592e37..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: @@ -70,6 +71,10 @@ void tst_qquickrectangle::color() QVERIFY(QTest::qWaitForWindowExposed(&view)); + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort); + QImage image = view.grabWindow(); QVERIFY(image.pixel(0,0) == QColor("#020202").rgba()); } @@ -80,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(); @@ -99,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; @@ -170,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/asynchronousMove.qml b/tests/auto/quick/qquickrepeater/data/asynchronousMove.qml new file mode 100644 index 0000000000..02499c8531 --- /dev/null +++ b/tests/auto/quick/qquickrepeater/data/asynchronousMove.qml @@ -0,0 +1,51 @@ +import QtQuick 2.3 +import QtQuick.Window 2.2 + +Item { + property bool finished: loader.status === Loader.Ready && loader.progress === 1 + + ListModel { + id: listModel + ListElement { i:0 } + ListElement { i:1 } + ListElement { i:2 } + ListElement { i:3 } + } + + Timer { + running: true + interval: 1 + repeat: count < 5 + property int count : 0 + + onTriggered: { + listModel.move(listModel.count - 1, listModel.count - 2, 1) + ++count + } + } + + Loader { + id: loader + asynchronous: true + sourceComponent: Row { + spacing: 4 + Repeater { + model: listModel + delegate: Column { + spacing: 4 + Repeater { + model: 4 + delegate: Rectangle { + width: 30 + height: 30 + color: "blue" + Component.onCompleted: { + ctrl.wait() + } + } + } + } + } + } + } +} diff --git a/tests/auto/quick/qquickrepeater/data/itemlist.qml b/tests/auto/quick/qquickrepeater/data/itemlist.qml index 174bfd4d18..12470f9fd9 100644 --- a/tests/auto/quick/qquickrepeater/data/itemlist.qml +++ b/tests/auto/quick/qquickrepeater/data/itemlist.qml @@ -1,7 +1,8 @@ // This example demonstrates placing items in a view using -// a VisualItemModel +// an ObjectModel import QtQuick 2.0 +import QtQml.Models 2.12 Rectangle { id: root @@ -22,38 +23,38 @@ Rectangle { root.itemModel = itemModel2 } - VisualItemModel { + ObjectModel { id: itemModel1 objectName: "itemModel1" Rectangle { objectName: "item1" height: 50; width: 100; color: "#FFFEF0" - Text { objectName: "text1"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text1"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } Rectangle { objectName: "item2" height: 50; width: 100; color: "#F0FFF7" - Text { objectName: "text2"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text2"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } Rectangle { objectName: "item3" height: 50; width: 100; color: "#F4F0FF" - Text { objectName: "text3"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text3"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } } - VisualItemModel { + ObjectModel { id: itemModel2 objectName: "itemModel2" Rectangle { objectName: "item4" height: 50; width: 100; color: "#FFFEF0" - Text { objectName: "text4"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text4"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } Rectangle { objectName: "item5" height: 50; width: 100; color: "#F0FFF7" - Text { objectName: "text5"; text: "index: " + parent.VisualItemModel.index; font.bold: true; anchors.centerIn: parent } + Text { objectName: "text5"; text: "index: " + parent.ObjectModel.index; font.bold: true; anchors.centerIn: parent } } } 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/data/visualitemmodel.qml b/tests/auto/quick/qquickrepeater/data/visualitemmodel.qml index b1b7b97881..0fb930449a 100644 --- a/tests/auto/quick/qquickrepeater/data/visualitemmodel.qml +++ b/tests/auto/quick/qquickrepeater/data/visualitemmodel.qml @@ -1,10 +1,11 @@ import QtQuick 2.0 +import QtQml.Models 2.12 Rectangle { width: 360 height: 360 - VisualItemModel { + ObjectModel { id: visItemModel Rectangle { width: 20 diff --git a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp index f7b04e9a30..e4b427f6ec 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" @@ -75,6 +76,9 @@ private slots: void destroyCount(); void stackingOrder(); void objectModel(); + void QTBUG54859_asynchronousMove(); + void package(); + void ownership(); }; class TestObject : public QObject @@ -118,7 +122,7 @@ void tst_QQuickRepeater::numberModel() qApp->processEvents(); QQuickRepeater *repeater = findItem<QQuickRepeater>(window->rootObject(), "repeater"); - QVERIFY(repeater != 0); + QVERIFY(repeater != nullptr); QCOMPARE(repeater->parentItem()->childItems().count(), 5+1); QVERIFY(!repeater->itemAt(-1)); @@ -129,6 +133,12 @@ void tst_QQuickRepeater::numberModel() QMetaObject::invokeMethod(window->rootObject(), "checkProperties"); QVERIFY(!testObject->error()); + ctxt->setContextProperty("testData", std::numeric_limits<int>::max()); + QCOMPARE(repeater->parentItem()->childItems().count(), 1); + + ctxt->setContextProperty("testData", -1234); + QCOMPARE(repeater->parentItem()->childItems().count(), 1); + delete testObject; delete window; } @@ -159,7 +169,7 @@ void tst_QQuickRepeater::objectList() qApp->processEvents(); QQuickRepeater *repeater = findItem<QQuickRepeater>(window->rootObject(), "repeater"); - QVERIFY(repeater != 0); + QVERIFY(repeater != nullptr); QCOMPARE(repeater->property("errors").toInt(), 0);//If this fails either they are out of order or can't find the object's data QCOMPARE(repeater->property("instantiated").toInt(), 100); @@ -200,10 +210,10 @@ void tst_QQuickRepeater::stringList() qApp->processEvents(); QQuickRepeater *repeater = findItem<QQuickRepeater>(window->rootObject(), "repeater"); - QVERIFY(repeater != 0); + QVERIFY(repeater != nullptr); QQuickItem *container = findItem<QQuickItem>(window->rootObject(), "container"); - QVERIFY(container != 0); + QVERIFY(container != nullptr); QCOMPARE(container->childItems().count(), data.count() + 3); @@ -212,7 +222,7 @@ void tst_QQuickRepeater::stringList() if (i == 0) { QQuickText *name = qobject_cast<QQuickText*>(container->childItems().at(i)); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QCOMPARE(name->text(), QLatin1String("Zero")); } else if (i == container->childItems().count() - 2) { // The repeater itself @@ -222,11 +232,11 @@ void tst_QQuickRepeater::stringList() continue; } else if (i == container->childItems().count() - 1) { QQuickText *name = qobject_cast<QQuickText*>(container->childItems().at(i)); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QCOMPARE(name->text(), QLatin1String("Last")); } else { QQuickText *name = qobject_cast<QQuickText*>(container->childItems().at(i)); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QCOMPARE(name->text(), data.at(i-1)); } } @@ -248,9 +258,9 @@ void tst_QQuickRepeater::dataModel_adding() qApp->processEvents(); QQuickRepeater *repeater = findItem<QQuickRepeater>(window->rootObject(), "repeater"); - QVERIFY(repeater != 0); + QVERIFY(repeater != nullptr); QQuickItem *container = findItem<QQuickItem>(window->rootObject(), "container"); - QVERIFY(container != 0); + QVERIFY(container != nullptr); QVERIFY(!repeater->itemAt(0)); @@ -330,9 +340,9 @@ void tst_QQuickRepeater::dataModel_removing() qApp->processEvents(); QQuickRepeater *repeater = findItem<QQuickRepeater>(window->rootObject(), "repeater"); - QVERIFY(repeater != 0); + QVERIFY(repeater != nullptr); QQuickItem *container = findItem<QQuickItem>(window->rootObject(), "container"); - QVERIFY(container != 0); + QVERIFY(container != nullptr); QCOMPARE(container->childItems().count(), repeater->count()+1); QSignalSpy countSpy(repeater, SIGNAL(countChanged())); @@ -396,9 +406,9 @@ void tst_QQuickRepeater::dataModel_changes() qApp->processEvents(); QQuickRepeater *repeater = findItem<QQuickRepeater>(window->rootObject(), "repeater"); - QVERIFY(repeater != 0); + QVERIFY(repeater != nullptr); QQuickItem *container = findItem<QQuickItem>(window->rootObject(), "container"); - QVERIFY(container != 0); + QVERIFY(container != nullptr); QCOMPARE(container->childItems().count(), repeater->count()+1); // Check that model changes are propagated @@ -430,10 +440,10 @@ void tst_QQuickRepeater::itemModel() qApp->processEvents(); QQuickRepeater *repeater = findItem<QQuickRepeater>(window->rootObject(), "repeater"); - QVERIFY(repeater != 0); + QVERIFY(repeater != nullptr); QQuickItem *container = findItem<QQuickItem>(window->rootObject(), "container"); - QVERIFY(container != 0); + QVERIFY(container != nullptr); QCOMPARE(container->childItems().count(), 1); @@ -473,9 +483,9 @@ void tst_QQuickRepeater::resetModel() window->setSource(testFileUrl("repeater1.qml")); qApp->processEvents(); QQuickRepeater *repeater = findItem<QQuickRepeater>(window->rootObject(), "repeater"); - QVERIFY(repeater != 0); + QVERIFY(repeater != nullptr); QQuickItem *container = findItem<QQuickItem>(window->rootObject(), "container"); - QVERIFY(container != 0); + QVERIFY(container != nullptr); QCOMPARE(repeater->count(), dataA.count()); for (int i=0; i<repeater->count(); i++) @@ -566,9 +576,9 @@ void tst_QQuickRepeater::modelReset() QVERIFY(rootItem); QQuickRepeater *repeater = findItem<QQuickRepeater>(rootItem, "repeater"); - QVERIFY(repeater != 0); + QVERIFY(repeater != nullptr); QQuickItem *container = findItem<QQuickItem>(rootItem, "container"); - QVERIFY(container != 0); + QVERIFY(container != nullptr); QCOMPARE(repeater->count(), 0); @@ -700,7 +710,7 @@ void tst_QQuickRepeater::asynchronous() container = findItem<QQuickItem>(rootObject, "container"); } - QQuickRepeater *repeater = 0; + QQuickRepeater *repeater = nullptr; while (!repeater) { bool b = false; controller.incubateWhile(&b); @@ -712,8 +722,8 @@ void tst_QQuickRepeater::asynchronous() for (int i = 9; i >= 0; --i) { QString name("delegate"); name += QString::number(i); - QVERIFY(findItem<QQuickItem>(container, name) == 0); - QQuickItem *item = 0; + QVERIFY(findItem<QQuickItem>(container, name) == nullptr); + QQuickItem *item = nullptr; while (!item) { bool b = false; controller.incubateWhile(&b); @@ -803,7 +813,7 @@ void tst_QQuickRepeater::invalidContextCrash() // deleted first and then the repeater. During deletion the QML context // has been deleted already and is invalid. model->setParent(root.data()); - repeater->setParent(0); + repeater->setParent(nullptr); repeater->setParent(root.data()); QCOMPARE(root->children().count(), 2); @@ -812,7 +822,7 @@ void tst_QQuickRepeater::invalidContextCrash() // Delete the root object, which will invalidate/delete the QML context // and then delete the child QObjects, which may try to access the context. - root.reset(0); + root.reset(nullptr); } void tst_QQuickRepeater::jsArrayChange() @@ -989,6 +999,115 @@ void tst_QQuickRepeater::objectModel() delete positioner; } +class Ctrl : public QObject +{ + Q_OBJECT +public: + + Q_INVOKABLE void wait() + { + QTest::qWait(200); + } +}; + +void tst_QQuickRepeater::QTBUG54859_asynchronousMove() +{ + Ctrl ctrl; + QQuickView* view = createView(); + view->rootContext()->setContextProperty("ctrl", &ctrl); + view->setSource(testFileUrl("asynchronousMove.qml")); + view->show(); + QQuickItem* item = view->rootObject(); + + + 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/qquickshadereffect/data/MyIcon.qml b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml index b83da321f2..eb788fce7a 100644 --- a/tests/auto/quick/qquickshadereffect/data/MyIcon.qml +++ b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** ** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies). -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml index d1292f74b8..46d81f2106 100644 --- a/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml +++ b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml @@ -1,12 +1,22 @@ /**************************************************************************** ** ** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies). -** Contact: http://www.qt.io/licensing/ +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are diff --git a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp index fe33dbd4d8..a57b7d4c1f 100644 --- a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp +++ b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp @@ -46,14 +46,18 @@ class TestShaderEffect : public QQuickShaderEffect Q_PROPERTY(QMatrix4x4 mat4x4 READ mat4x4Read NOTIFY dummyChanged) public: + TestShaderEffect(QQuickItem* parent = nullptr) : QQuickShaderEffect(parent) + { + } + QMatrix4x4 mat4x4Read() const { return QMatrix4x4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1); } QVariant dummyRead() const { return QVariant(); } int signalsConnected = 0; protected: - void connectNotify(const QMetaMethod &) { ++signalsConnected; } - void disconnectNotify(const QMetaMethod &) { --signalsConnected; } + void connectNotify(const QMetaMethod &) override { ++signalsConnected; } + void disconnectNotify(const QMetaMethod &) override { --signalsConnected; } signals: void dummyChanged(); @@ -79,6 +83,8 @@ private slots: void deleteShaderEffectSource(); void twoImagesOneShaderEffect(); + void withoutQmlEngine(); + private: enum PresenceFlags { VertexPresent = 0x01, @@ -257,7 +263,7 @@ void tst_qquickshadereffect::lookThroughShaderCode() QQmlComponent component(&engine); component.setData("import QtQuick 2.0\nimport ShaderEffectTest 1.0\nTestShaderEffect {}", QUrl()); QScopedPointer<TestShaderEffect> item(qobject_cast<TestShaderEffect*>(component.create())); - QCOMPARE(item->signalsConnected, 1); + QCOMPARE(item->signalsConnected, 0); QString expected; if ((presenceFlags & VertexPresent) == 0) @@ -274,13 +280,13 @@ void tst_qquickshadereffect::lookThroughShaderCode() QCOMPARE(item->parseLog(), expected); // If the uniform was successfully parsed, the notify signal has been connected to an update slot. - QCOMPARE(item->signalsConnected, (presenceFlags & SourcePresent) ? 2 : 1); + QCOMPARE(item->signalsConnected, (presenceFlags & SourcePresent) ? 1 : 0); } void tst_qquickshadereffect::deleteSourceItem() { // purely to ensure that deleting the sourceItem of a shader doesn't cause a crash - QQuickView *view = new QQuickView(0); + QQuickView *view = new QQuickView(nullptr); view->setSource(QUrl::fromLocalFile(testFile("deleteSourceItem.qml"))); view->show(); QVERIFY(QTest::qWaitForWindowExposed(view)); @@ -295,7 +301,7 @@ void tst_qquickshadereffect::deleteSourceItem() void tst_qquickshadereffect::deleteShaderEffectSource() { // purely to ensure that deleting the sourceItem of a shader doesn't cause a crash - QQuickView *view = new QQuickView(0); + QQuickView *view = new QQuickView(nullptr); view->setSource(QUrl::fromLocalFile(testFile("deleteShaderEffectSource.qml"))); view->show(); QVERIFY(QTest::qWaitForWindowExposed(view)); @@ -310,7 +316,7 @@ void tst_qquickshadereffect::deleteShaderEffectSource() void tst_qquickshadereffect::twoImagesOneShaderEffect() { // purely to ensure that deleting the sourceItem of a shader doesn't cause a crash - QQuickView *view = new QQuickView(0); + QQuickView *view = new QQuickView(nullptr); view->setSource(QUrl::fromLocalFile(testFile("twoImagesOneShaderEffect.qml"))); view->show(); QVERIFY(QTest::qWaitForWindowExposed(view)); @@ -320,6 +326,16 @@ void tst_qquickshadereffect::twoImagesOneShaderEffect() delete view; } +void tst_qquickshadereffect::withoutQmlEngine() +{ + // using a shader without QML engine used to crash + auto window = new QQuickWindow; + auto shaderEffect = new TestShaderEffect(window->contentItem()); + shaderEffect->setVertexShader(""); + QVERIFY(shaderEffect->isComponentComplete()); + delete window; +} + QTEST_MAIN(tst_qquickshadereffect) #include "tst_qquickshadereffect.moc" diff --git a/tests/auto/quick/qquickshape/BLACKLIST b/tests/auto/quick/qquickshape/BLACKLIST new file mode 100644 index 0000000000..d0ebc2f505 --- /dev/null +++ b/tests/auto/quick/qquickshape/BLACKLIST @@ -0,0 +1,8 @@ +[render] +osx ci +[renderWithMultipleSp] +osx ci +[radialGrad] +osx ci +[conicalGrad] +osx ci diff --git a/tests/auto/quick/qquickshape/data/pathitem5.png b/tests/auto/quick/qquickshape/data/pathitem5.png Binary files differnew file mode 100644 index 0000000000..cb5cfd25dc --- /dev/null +++ b/tests/auto/quick/qquickshape/data/pathitem5.png diff --git a/tests/auto/quick/qquickshape/data/pathitem5.qml b/tests/auto/quick/qquickshape/data/pathitem5.qml new file mode 100644 index 0000000000..1bd465d5c0 --- /dev/null +++ b/tests/auto/quick/qquickshape/data/pathitem5.qml @@ -0,0 +1,37 @@ +import QtQuick 2.9 +import tst_qquickpathitem 1.0 + +Item { + width: 200 + height: 150 + + Shape { + vendorExtensionsEnabled: false + objectName: "pathItem" + anchors.fill: parent + + ShapePath { + strokeWidth: 4 + strokeColor: "red" + fillGradient: RadialGradient { + centerX: 100; centerY: 100; centerRadius: 100 + focalX: 100; focalY: 100; focalRadius: 10 + GradientStop { position: 0; color: "#ffffff" } + GradientStop { position: 0.11; color: "#f9ffa0" } + GradientStop { position: 0.13; color: "#f9ff99" } + GradientStop { position: 0.14; color: "#f3ff86" } + GradientStop { position: 0.49; color: "#93b353" } + GradientStop { position: 0.87; color: "#264619" } + GradientStop { position: 0.96; color: "#0c1306" } + GradientStop { position: 1; color: "#000000" } + } + fillColor: "blue" // ignored with the gradient set + strokeStyle: ShapePath.DashLine + dashPattern: [ 1, 4 ] + startX: 20; startY: 20 + PathLine { x: 180; y: 130 } + PathLine { x: 20; y: 130 } + PathLine { x: 20; y: 20 } + } + } +} diff --git a/tests/auto/quick/qquickshape/data/pathitem6.png b/tests/auto/quick/qquickshape/data/pathitem6.png Binary files differnew file mode 100644 index 0000000000..d9e53d6c00 --- /dev/null +++ b/tests/auto/quick/qquickshape/data/pathitem6.png diff --git a/tests/auto/quick/qquickshape/data/pathitem6.qml b/tests/auto/quick/qquickshape/data/pathitem6.qml new file mode 100644 index 0000000000..fafcc48196 --- /dev/null +++ b/tests/auto/quick/qquickshape/data/pathitem6.qml @@ -0,0 +1,35 @@ +import QtQuick 2.9 +import tst_qquickpathitem 1.0 + +Item { + width: 200 + height: 150 + + Shape { + vendorExtensionsEnabled: false + objectName: "pathItem" + anchors.fill: parent + + ShapePath { + strokeWidth: 4 + strokeColor: "red" + fillGradient: ConicalGradient { + centerX: 100; centerY: 100; angle: 45 + GradientStop { position: 0; color: "#00000000" } + GradientStop { position: 0.10; color: "#ffe0cc73" } + GradientStop { position: 0.17; color: "#ffc6a006" } + GradientStop { position: 0.46; color: "#ff600659" } + GradientStop { position: 0.72; color: "#ff0680ac" } + GradientStop { position: 0.92; color: "#ffb9d9e6" } + GradientStop { position: 1.00; color: "#00000000" } + } + fillColor: "blue" // ignored with the gradient set + strokeStyle: ShapePath.DashLine + dashPattern: [ 1, 4 ] + startX: 20; startY: 20 + PathLine { x: 180; y: 130 } + PathLine { x: 20; y: 130 } + PathLine { x: 20; y: 20 } + } + } +} 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 dcc79e6599..61fb260612 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" @@ -55,6 +55,8 @@ private slots: void changeSignals(); void render(); void renderWithMultipleSp(); + void radialGrad(); + void conicalGrad(); }; tst_QQuickShape::tst_QQuickShape() @@ -67,6 +69,8 @@ tst_QQuickShape::tst_QQuickShape() qmlRegisterType<QQuickShapePath>(uri, 1, 0, "ShapePath"); qmlRegisterUncreatableType<QQuickShapeGradient>(uri, 1, 0, "ShapeGradient", QQuickShapeGradient::tr("ShapeGradient is an abstract base class")); qmlRegisterType<QQuickShapeLinearGradient>(uri, 1, 0, "LinearGradient"); + qmlRegisterType<QQuickShapeRadialGradient>(uri, 1, 0, "RadialGradient"); + qmlRegisterType<QQuickShapeConicalGradient>(uri, 1, 0, "ConicalGradient"); } void tst_QQuickShape::initValues() @@ -78,7 +82,7 @@ void tst_QQuickShape::initValues() QVERIFY(obj != nullptr); QVERIFY(obj->rendererType() == QQuickShape::UnknownRenderer); QVERIFY(!obj->asynchronous()); - QVERIFY(obj->vendorExtensionsEnabled()); + QVERIFY(!obj->vendorExtensionsEnabled()); QVERIFY(obj->status() == QQuickShape::Null); auto vps = obj->data(); QVERIFY(vps.count(&vps) == 0); @@ -95,7 +99,7 @@ void tst_QQuickShape::vpInitValues() QVERIFY(obj != nullptr); QVERIFY(obj->rendererType() == QQuickShape::UnknownRenderer); QVERIFY(!obj->asynchronous()); - QVERIFY(obj->vendorExtensionsEnabled()); + QVERIFY(!obj->vendorExtensionsEnabled()); QVERIFY(obj->status() == QQuickShape::Null); auto vps = obj->data(); QVERIFY(vps.count(&vps) == 2); @@ -219,13 +223,20 @@ void tst_QQuickShape::render() window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort); + QImage img = window->grabWindow(); QVERIFY(!img.isNull()); QImage refImg(testFileUrl("pathitem3.png").toLocalFile()); QVERIFY(!refImg.isNull()); - QVERIFY(QQuickVisualTestUtil::compareImages(img.convertToFormat(refImg.format()), refImg)); + QString errorMessage; + const QImage actualImg = img.convertToFormat(refImg.format()); + QVERIFY2(QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage), + qPrintable(errorMessage)); } void tst_QQuickShape::renderWithMultipleSp() @@ -236,13 +247,68 @@ void tst_QQuickShape::renderWithMultipleSp() window->show(); QVERIFY(QTest::qWaitForWindowExposed(window.data())); + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort); + QImage img = window->grabWindow(); QVERIFY(!img.isNull()); QImage refImg(testFileUrl("pathitem4.png").toLocalFile()); QVERIFY(!refImg.isNull()); - QVERIFY(QQuickVisualTestUtil::compareImages(img.convertToFormat(refImg.format()), refImg)); + QString errorMessage; + const QImage actualImg = img.convertToFormat(refImg.format()); + QVERIFY2(QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage), + qPrintable(errorMessage)); +} + +void tst_QQuickShape::radialGrad() +{ + QScopedPointer<QQuickView> window(createView()); + + window->setSource(testFileUrl("pathitem5.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort); + + QImage img = window->grabWindow(); + QVERIFY(!img.isNull()); + + QImage refImg(testFileUrl("pathitem5.png").toLocalFile()); + QVERIFY(!refImg.isNull()); + + QString errorMessage; + const QImage actualImg = img.convertToFormat(refImg.format()); + QVERIFY2(QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage), + qPrintable(errorMessage)); +} + +void tst_QQuickShape::conicalGrad() +{ + QScopedPointer<QQuickView> window(createView()); + + window->setSource(testFileUrl("pathitem6.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort); + + QImage img = window->grabWindow(); + QVERIFY(!img.isNull()); + + QImage refImg(testFileUrl("pathitem6.png").toLocalFile()); + QVERIFY(!refImg.isNull()); + + QString errorMessage; + const QImage actualImg = img.convertToFormat(refImg.format()); + QVERIFY2(QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage), + qPrintable(errorMessage)); } QTEST_MAIN(tst_QQuickShape) diff --git a/tests/auto/quick/qquickshortcut/BLACKLIST b/tests/auto/quick/qquickshortcut/BLACKLIST new file mode 100644 index 0000000000..ba7871dc2d --- /dev/null +++ b/tests/auto/quick/qquickshortcut/BLACKLIST @@ -0,0 +1,7 @@ +# QTBUG-74050 +[shortcuts] +opensuse-42.3 + +# QTBUG-74050 +[multiple] +opensuse-42.3 diff --git a/tests/auto/quick/qquickshortcut/data/shortcutsRect.qml b/tests/auto/quick/qquickshortcut/data/shortcutsRect.qml new file mode 100644 index 0000000000..9aced4e530 --- /dev/null +++ b/tests/auto/quick/qquickshortcut/data/shortcutsRect.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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: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.5 + +Rectangle { + width: 300 + height: 300 + + property string activatedShortcut + property string ambiguousShortcut + + property alias shortcuts: repeater.model + + Repeater { + id: repeater + + Item { + Shortcut { + sequence: modelData.sequence + enabled: modelData.enabled + autoRepeat: modelData.autoRepeat + context: modelData.context + onActivated: activatedShortcut = sequence + onActivatedAmbiguously: ambiguousShortcut = sequence + } + } + } +} diff --git a/tests/auto/quick/qquickshortcut/qquickshortcut.pro b/tests/auto/quick/qquickshortcut/qquickshortcut.pro index d780d9061a..018bb91594 100644 --- a/tests/auto/quick/qquickshortcut/qquickshortcut.pro +++ b/tests/auto/quick/qquickshortcut/qquickshortcut.pro @@ -8,3 +8,6 @@ include (../../shared/util.pri) TESTDATA = data/* QT += core gui qml quick testlib +qtHaveModule(widgets) { + QT += quickwidgets +} diff --git a/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp b/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp index 75ccf26af9..4962690796 100644 --- a/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp +++ b/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp @@ -29,6 +29,11 @@ #include <QtTest/qtest.h> #include <QtQuick/qquickwindow.h> #include <QtQml/qqmlapplicationengine.h> +#include <QtQuick/qquickitem.h> +#include <QtTest/qsignalspy.h> +#ifdef QT_QUICKWIDGETS_LIB +#include <QtQuickWidgets/qquickwidget.h> +#endif #include "../../shared/util.h" @@ -47,6 +52,10 @@ private slots: void matcher(); void multiple_data(); void multiple(); +#ifdef QT_QUICKWIDGETS_LIB + void renderControlShortcuts_data(); + void renderControlShortcuts(); +#endif }; Q_DECLARE_METATYPE(Qt::Key) @@ -453,6 +462,121 @@ void tst_QQuickShortcut::multiple() QCOMPARE(window->property("activated").toBool(), activated); } +#ifdef QT_QUICKWIDGETS_LIB +void tst_QQuickShortcut::renderControlShortcuts_data() +{ + QTest::addColumn<QVariantList>("shortcuts"); + QTest::addColumn<Qt::Key>("key"); + QTest::addColumn<Qt::KeyboardModifiers>("modifiers"); + QTest::addColumn<QString>("activatedShortcut"); + QTest::addColumn<QString>("ambiguousShortcut"); + + QVariantList shortcuts; + shortcuts << shortcutMap("M") + << shortcutMap("Alt+M") + << shortcutMap("Ctrl+M") + << shortcutMap("Shift+M") + << shortcutMap("Ctrl+Alt+M") + << shortcutMap("+") + << shortcutMap("F1") + << shortcutMap("Shift+F1"); + + QTest::newRow("M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "M" << ""; + QTest::newRow("Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "Alt+M" << ""; + QTest::newRow("Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "Ctrl+M" << ""; + QTest::newRow("Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+M" << ""; + QTest::newRow("Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "Ctrl+Alt+M" << ""; + QTest::newRow("+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "+" << ""; + QTest::newRow("F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "F1" << ""; + QTest::newRow("Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+F1" << ""; + + // ambiguous + shortcuts << shortcutMap("M") + << shortcutMap("Alt+M") + << shortcutMap("Ctrl+M") + << shortcutMap("Shift+M") + << shortcutMap("Ctrl+Alt+M") + << shortcutMap("+") + << shortcutMap("F1") + << shortcutMap("Shift+F1"); + + QTest::newRow("?M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "M"; + QTest::newRow("?Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "" << "Alt+M"; + QTest::newRow("?Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "" << "Ctrl+M"; + QTest::newRow("?Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << "Shift+M"; + QTest::newRow("?Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "" << "Ctrl+Alt+M"; + QTest::newRow("?+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "+"; + QTest::newRow("?F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "" << "F1"; + QTest::newRow("?Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << "Shift+F1"; + + // disabled + shortcuts.clear(); + shortcuts << shortcutMap("M", DisabledShortcut) + << shortcutMap("Alt+M", DisabledShortcut) + << shortcutMap("Ctrl+M", DisabledShortcut) + << shortcutMap("Shift+M", DisabledShortcut) + << shortcutMap("Ctrl+Alt+M", DisabledShortcut) + << shortcutMap("+", DisabledShortcut) + << shortcutMap("F1", DisabledShortcut) + << shortcutMap("Shift+F1", DisabledShortcut); + + QTest::newRow("!M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "" << ""; + QTest::newRow("!Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "" << ""; + QTest::newRow("!Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "" << ""; + QTest::newRow("!Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << ""; + QTest::newRow("!Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "" << ""; + QTest::newRow("!+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "" << ""; + QTest::newRow("!F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "" << ""; + QTest::newRow("!Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "" << ""; + + // unambigous because others disabled + shortcuts << shortcutMap("M") + << shortcutMap("Alt+M") + << shortcutMap("Ctrl+M") + << shortcutMap("Shift+M") + << shortcutMap("Ctrl+Alt+M") + << shortcutMap("+") + << shortcutMap("F1") + << shortcutMap("Shift+F1"); + + QTest::newRow("/M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::NoModifier) << "M" << ""; + QTest::newRow("/Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::AltModifier) << "Alt+M" << ""; + QTest::newRow("/Ctrl+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier) << "Ctrl+M" << ""; + QTest::newRow("/Shift+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+M" << ""; + QTest::newRow("/Ctrl+Alt+M") << shortcuts << Qt::Key_M << Qt::KeyboardModifiers(Qt::ControlModifier|Qt::AltModifier) << "Ctrl+Alt+M" << ""; + QTest::newRow("/+") << shortcuts << Qt::Key_Plus << Qt::KeyboardModifiers(Qt::NoModifier) << "+" << ""; + QTest::newRow("/F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::NoModifier) << "F1" << ""; + QTest::newRow("/Shift+F1") << shortcuts << Qt::Key_F1 << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Shift+F1" << ""; +} + +void tst_QQuickShortcut::renderControlShortcuts() +{ + QFETCH(QVariantList, shortcuts); + QFETCH(Qt::Key, key); + QFETCH(Qt::KeyboardModifiers, modifiers); + QFETCH(QString, activatedShortcut); + QFETCH(QString, ambiguousShortcut); + + QScopedPointer<QQuickWidget> quickWidget(new QQuickWidget); + quickWidget->resize(300,300); + + QSignalSpy spy(qApp, &QGuiApplication::focusObjectChanged); + + quickWidget->setSource(testFileUrl("shortcutsRect.qml")); + quickWidget->show(); + + spy.wait(); + + QVERIFY(qobject_cast<QQuickWidget*>(qApp->focusObject()) == quickWidget.data()); + + QQuickItem* item = quickWidget->rootObject(); + item->setProperty("shortcuts", shortcuts); + QTest::keyPress(quickWidget->quickWindow(), key, modifiers, 1500); + QCOMPARE(item->property("activatedShortcut").toString(), activatedShortcut); + QCOMPARE(item->property("ambiguousShortcut").toString(), ambiguousShortcut); +} +#endif // QT_QUICKWIDGETS_LIB + QTEST_MAIN(tst_QQuickShortcut) #include "tst_qquickshortcut.moc" diff --git a/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp b/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp index d78a38a662..14d2e858e8 100644 --- a/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp +++ b/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp @@ -64,7 +64,7 @@ void tst_qquicksmoothedanimation::defaultValues() QQmlComponent c(&engine, testFileUrl("smoothedanimation1.qml")); QQuickSmoothedAnimation *obj = qobject_cast<QQuickSmoothedAnimation*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->to(), 0.); QCOMPARE(obj->velocity(), 200.); @@ -81,7 +81,7 @@ void tst_qquicksmoothedanimation::values() QQmlComponent c(&engine, testFileUrl("smoothedanimation2.qml")); QQuickSmoothedAnimation *obj = qobject_cast<QQuickSmoothedAnimation*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->to(), 10.); QCOMPARE(obj->velocity(), 200.); @@ -98,7 +98,7 @@ void tst_qquicksmoothedanimation::disabled() QQmlComponent c(&engine, testFileUrl("smoothedanimation3.qml")); QQuickSmoothedAnimation *obj = qobject_cast<QQuickSmoothedAnimation*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->to(), 10.); QCOMPARE(obj->velocity(), 250.); @@ -259,7 +259,7 @@ void tst_qquicksmoothedanimation::noStart() QQmlComponent c(&engine, testFileUrl("smoothedanimation1.qml")); QQuickSmoothedAnimation *obj = qobject_cast<QQuickSmoothedAnimation*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); obj->start(); QCOMPARE(obj->isRunning(), false); diff --git a/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp b/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp index b4184ba1d3..9042e94c75 100644 --- a/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp +++ b/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp @@ -59,7 +59,7 @@ void tst_qquickspringanimation::defaultValues() QQmlComponent c(&engine, testFileUrl("springanimation1.qml")); QQuickSpringAnimation *obj = qobject_cast<QQuickSpringAnimation*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->to(), 0.); QCOMPARE(obj->velocity(), 0.); @@ -81,7 +81,7 @@ void tst_qquickspringanimation::values() QQuickSpringAnimation *obj = root->findChild<QQuickSpringAnimation*>(); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->to(), 1.44); QCOMPARE(obj->velocity(), 0.9); @@ -103,7 +103,7 @@ void tst_qquickspringanimation::disabled() QQmlComponent c(&engine, testFileUrl("springanimation3.qml")); QQuickSpringAnimation *obj = qobject_cast<QQuickSpringAnimation*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->to(), 1.44); QCOMPARE(obj->velocity(), 0.9); diff --git a/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp b/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp index 08674c528a..e5d55a6871 100644 --- a/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp +++ b/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp @@ -47,7 +47,7 @@ private slots: void tst_qquickspritesequence::test_properties() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("basic.qml")); window->show(); @@ -75,7 +75,7 @@ void tst_qquickspritesequence::test_huge() The large allocations of memory involved and separate codepath does make a doesn't crash test worthwhile. */ - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("huge.qml")); window->show(); @@ -90,7 +90,7 @@ void tst_qquickspritesequence::test_huge() void tst_qquickspritesequence::test_framerateAdvance() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("advance.qml")); window->show(); @@ -106,7 +106,7 @@ void tst_qquickspritesequence::test_framerateAdvance() void tst_qquickspritesequence::test_jumpToCrash() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("crashonstart.qml")); window->show(); @@ -118,7 +118,7 @@ void tst_qquickspritesequence::test_jumpToCrash() void tst_qquickspritesequence::test_spriteBeforeGoal() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("spritebeforegoal.qml")); window->show(); @@ -130,7 +130,7 @@ void tst_qquickspritesequence::test_spriteBeforeGoal() void tst_qquickspritesequence::test_spriteAfterGoal() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(testFileUrl("spriteaftergoal.qml")); window->show(); diff --git a/tests/auto/quick/qquickstates/data/duplicateStateName.qml b/tests/auto/quick/qquickstates/data/duplicateStateName.qml new file mode 100644 index 0000000000..7bfafbef1b --- /dev/null +++ b/tests/auto/quick/qquickstates/data/duplicateStateName.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Rectangle { + property bool condition1: false + property bool condition2: false + property bool condition3: false + + states: [ + State { name: "state1"; when: condition1 }, + State { name: "state2"; when: condition2 }, + State { name: "state1"; when: condition3 } + ] +} diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp index 9b152b0676..50554f6333 100644 --- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp +++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp @@ -137,6 +137,7 @@ private slots: void revertListBug(); void QTBUG_38492(); void revertListMemoryLeak(); + void duplicateStateName(); }; void tst_qquickstates::initTestCase() @@ -158,7 +159,7 @@ void tst_qquickstates::basicChanges() QQmlComponent rectComponent(&engine, testFileUrl("basicChanges.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("red")); @@ -173,7 +174,7 @@ void tst_qquickstates::basicChanges() QQmlComponent rectComponent(&engine, testFileUrl("basicChanges2.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("red")); @@ -194,7 +195,7 @@ void tst_qquickstates::basicChanges() QQmlComponent rectComponent(&engine, testFileUrl("basicChanges3.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("red")); QCOMPARE(rect->border()->width(),1.0); @@ -231,7 +232,7 @@ void tst_qquickstates::basicChanges() QVERIFY(component.isReady()); MyRect *rect = qobject_cast<MyRect*>(component.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QMetaProperty prop = rect->metaObject()->property(rect->metaObject()->indexOfProperty("propertyWithNotify")); QVERIFY(prop.hasNotifySignal()); @@ -253,7 +254,7 @@ void tst_qquickstates::attachedPropertyChanges() QVERIFY(component.isReady()); QQuickItem *item = qobject_cast<QQuickItem*>(component.create()); - QVERIFY(item != 0); + QVERIFY(item != nullptr); QCOMPARE(item->width(), 50.0); // Ensure attached property has been changed @@ -274,7 +275,7 @@ void tst_qquickstates::basicExtension() QQmlComponent rectComponent(&engine, testFileUrl("basicExtension.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("red")); QCOMPARE(rect->border()->width(),1.0); @@ -308,7 +309,7 @@ void tst_qquickstates::basicExtension() QQmlComponent rectComponent(&engine, testFileUrl("fakeExtension.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("red")); @@ -340,7 +341,7 @@ void tst_qquickstates::basicBinding() QQmlComponent rectComponent(&engine, testFileUrl("basicBinding.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("red")); @@ -368,7 +369,7 @@ void tst_qquickstates::basicBinding() QQmlComponent rectComponent(&engine, testFileUrl("basicBinding2.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("red")); @@ -399,7 +400,7 @@ void tst_qquickstates::basicBinding() QQmlComponent rectComponent(&engine, testFileUrl("basicBinding3.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("red")); rect->setProperty("sourceColor", QColor("green")); @@ -424,7 +425,7 @@ void tst_qquickstates::basicBinding() QQmlComponent rectComponent(&engine, testFileUrl("basicBinding4.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("red")); @@ -456,7 +457,7 @@ void tst_qquickstates::signalOverride() { QQmlComponent rectComponent(&engine, testFileUrl("signalOverride.qml")); MyRect *rect = qobject_cast<MyRect*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("red")); rect->doSomething(); @@ -472,7 +473,7 @@ void tst_qquickstates::signalOverride() { QQmlComponent rectComponent(&engine, testFileUrl("signalOverride2.qml")); MyRect *rect = qobject_cast<MyRect*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("white")); rect->doSomething(); @@ -495,7 +496,7 @@ void tst_qquickstates::signalOverrideCrash() QQmlComponent rectComponent(&engine, testFileUrl("signalOverrideCrash.qml")); MyRect *rect = qobject_cast<MyRect*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate::get(rect)->setState("overridden"); rect->doSomething(); @@ -507,7 +508,7 @@ void tst_qquickstates::signalOverrideCrash2() QQmlComponent rectComponent(&engine, testFileUrl("signalOverrideCrash2.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate::get(rect)->setState("state1"); QQuickItemPrivate::get(rect)->setState("state2"); @@ -522,7 +523,7 @@ void tst_qquickstates::signalOverrideCrash3() QQmlComponent rectComponent(&engine, testFileUrl("signalOverrideCrash3.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate::get(rect)->setState("state1"); QQuickItemPrivate::get(rect)->setState(""); @@ -537,7 +538,7 @@ void tst_qquickstates::signalOverrideCrash4() QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("signalOverrideCrash4.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); @@ -557,20 +558,20 @@ void tst_qquickstates::parentChange() { QQmlComponent rectComponent(&engine, testFileUrl("parentChange1.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); QQmlListReference list(rect, "states"); QQuickState *state = qobject_cast<QQuickState*>(list.at(0)); - QVERIFY(state != 0); + QVERIFY(state != nullptr); qmlExecuteDeferred(state); QQuickParentChange *pChange = qobject_cast<QQuickParentChange*>(state->operationAt(0)); - QVERIFY(pChange != 0); + QVERIFY(pChange != nullptr); QQuickItem *nParent = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("NewParent")); - QVERIFY(nParent != 0); + QVERIFY(nParent != nullptr); QCOMPARE(pChange->parent(), nParent); @@ -584,10 +585,10 @@ void tst_qquickstates::parentChange() { QQmlComponent rectComponent(&engine, testFileUrl("parentChange2.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); rectPrivate->setState("reparented"); QCOMPARE(innerRect->rotation(), qreal(15)); @@ -599,10 +600,10 @@ void tst_qquickstates::parentChange() { QQmlComponent rectComponent(&engine, testFileUrl("parentChange3.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); rectPrivate->setState("reparented"); QCOMPARE(innerRect->rotation(), qreal(-37)); @@ -621,10 +622,10 @@ void tst_qquickstates::parentChange() { QQmlComponent rectComponent(&engine, testFileUrl("parentChange6.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); QQuickItemPrivate::get(rect)->setState("reparented"); QCOMPARE(innerRect->rotation(), qreal(180)); @@ -641,10 +642,10 @@ void tst_qquickstates::parentChangeErrors() { QQmlComponent rectComponent(&engine, testFileUrl("parentChange4.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); QTest::ignoreMessage(QtWarningMsg, fullDataPath("parentChange4.qml") + ":25:9: QML ParentChange: Unable to preserve appearance under non-uniform scale"); QQuickItemPrivate::get(rect)->setState("reparented"); @@ -657,10 +658,10 @@ void tst_qquickstates::parentChangeErrors() { QQmlComponent rectComponent(&engine, testFileUrl("parentChange5.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); QTest::ignoreMessage(QtWarningMsg, fullDataPath("parentChange5.qml") + ":25:9: QML ParentChange: Unable to preserve appearance under complex transform"); QQuickItemPrivate::get(rect)->setState("reparented"); @@ -677,19 +678,19 @@ void tst_qquickstates::anchorChanges() QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges1.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); QQmlListReference list(rect, "states"); QQuickState *state = qobject_cast<QQuickState*>(list.at(0)); - QVERIFY(state != 0); + QVERIFY(state != nullptr); qmlExecuteDeferred(state); QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0)); - QVERIFY(aChanges != 0); + QVERIFY(aChanges != nullptr); QCOMPARE(aChanges->anchors()->left().isUndefinedLiteral(), true); QVERIFY(!aChanges->anchors()->left().isEmpty()); @@ -714,11 +715,11 @@ void tst_qquickstates::anchorChanges2() QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges2.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); rectPrivate->setState("right"); QCOMPARE(innerRect->x(), qreal(150)); @@ -735,25 +736,25 @@ void tst_qquickstates::anchorChanges3() QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges3.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); QQuickItem *leftGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("LeftGuideline")); - QVERIFY(leftGuideline != 0); + QVERIFY(leftGuideline != nullptr); QQuickItem *bottomGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("BottomGuideline")); - QVERIFY(bottomGuideline != 0); + QVERIFY(bottomGuideline != nullptr); QQmlListReference list(rect, "states"); QQuickState *state = qobject_cast<QQuickState*>(list.at(0)); - QVERIFY(state != 0); + QVERIFY(state != nullptr); qmlExecuteDeferred(state); QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0)); - QVERIFY(aChanges != 0); + QVERIFY(aChanges != nullptr); QVERIFY(!aChanges->anchors()->top().isEmpty()); QVERIFY(!aChanges->anchors()->bottom().isEmpty()); @@ -789,24 +790,24 @@ void tst_qquickstates::anchorChanges4() QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges4.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); QQuickItem *leftGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("LeftGuideline")); - QVERIFY(leftGuideline != 0); + QVERIFY(leftGuideline != nullptr); QQuickItem *bottomGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("BottomGuideline")); - QVERIFY(bottomGuideline != 0); + QVERIFY(bottomGuideline != nullptr); QQmlListReference list(rect, "states"); QQuickState *state = qobject_cast<QQuickState*>(list.at(0)); - QVERIFY(state != 0); + QVERIFY(state != nullptr); qmlExecuteDeferred(state); QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0)); - QVERIFY(aChanges != 0); + QVERIFY(aChanges != nullptr); QVERIFY(!aChanges->anchors()->horizontalCenter().isEmpty()); QVERIFY(!aChanges->anchors()->verticalCenter().isEmpty()); @@ -827,24 +828,24 @@ void tst_qquickstates::anchorChanges5() QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges5.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); QQuickItem *leftGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("LeftGuideline")); - QVERIFY(leftGuideline != 0); + QVERIFY(leftGuideline != nullptr); QQuickItem *bottomGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("BottomGuideline")); - QVERIFY(bottomGuideline != 0); + QVERIFY(bottomGuideline != nullptr); QQmlListReference list(rect, "states"); QQuickState *state = qobject_cast<QQuickState*>(list.at(0)); - QVERIFY(state != 0); + QVERIFY(state != nullptr); qmlExecuteDeferred(state); QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0)); - QVERIFY(aChanges != 0); + QVERIFY(aChanges != nullptr); QVERIFY(!aChanges->anchors()->baseline().isEmpty()); @@ -873,20 +874,20 @@ void tst_qquickstates::anchorChangesRTL() QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges1.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); mirrorAnchors(innerRect); QQmlListReference list(rect, "states"); QQuickState *state = qobject_cast<QQuickState*>(list.at(0)); - QVERIFY(state != 0); + QVERIFY(state != nullptr); qmlExecuteDeferred(state); QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0)); - QVERIFY(aChanges != 0); + QVERIFY(aChanges != nullptr); rectPrivate->setState("right"); QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(150)); @@ -907,11 +908,11 @@ void tst_qquickstates::anchorChangesRTL2() QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges2.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); mirrorAnchors(innerRect); rectPrivate->setState("right"); @@ -929,26 +930,26 @@ void tst_qquickstates::anchorChangesRTL3() QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges3.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect")); - QVERIFY(innerRect != 0); + QVERIFY(innerRect != nullptr); mirrorAnchors(innerRect); QQuickItem *leftGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("LeftGuideline")); - QVERIFY(leftGuideline != 0); + QVERIFY(leftGuideline != nullptr); QQuickItem *bottomGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("BottomGuideline")); - QVERIFY(bottomGuideline != 0); + QVERIFY(bottomGuideline != nullptr); QQmlListReference list(rect, "states"); QQuickState *state = qobject_cast<QQuickState*>(list.at(0)); - QVERIFY(state != 0); + QVERIFY(state != nullptr); qmlExecuteDeferred(state); QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0)); - QVERIFY(aChanges != 0); + QVERIFY(aChanges != nullptr); rectPrivate->setState("reanchored"); QCOMPARE(aChanges->object(), qobject_cast<QQuickItem*>(innerRect)); @@ -984,7 +985,7 @@ void tst_qquickstates::anchorChangesCrash() QQmlComponent rectComponent(&engine, testFileUrl("anchorChangesCrash.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate::get(rect)->setState("reanchored"); @@ -1002,11 +1003,11 @@ void tst_qquickstates::anchorRewindBug() QVERIFY(QTest::qWaitForWindowExposed(view)); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(view->rootObject()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItem * column = rect->findChild<QQuickItem*>("column"); - QVERIFY(column != 0); + QVERIFY(column != nullptr); QVERIFY(!QQuickItemPrivate::get(column)->heightValid); QVERIFY(!QQuickItemPrivate::get(column)->widthValid); QCOMPARE(column->height(), 200.0); @@ -1036,11 +1037,11 @@ void tst_qquickstates::anchorRewindBug2() QQmlComponent rectComponent(&engine, testFileUrl("anchorRewindBug2.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickRectangle *mover = rect->findChild<QQuickRectangle*>("mover"); - QVERIFY(mover != 0); + QVERIFY(mover != nullptr); QCOMPARE(mover->y(), qreal(0.0)); QCOMPARE(mover->width(), qreal(50.0)); @@ -1062,7 +1063,7 @@ void tst_qquickstates::script() { QQmlComponent rectComponent(&engine, testFileUrl("script.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QCOMPARE(rect->color(),QColor("red")); @@ -1080,7 +1081,7 @@ void tst_qquickstates::restoreEntryValues() QQmlComponent rectComponent(&engine, testFileUrl("restoreEntryValues.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QCOMPARE(rect->color(),QColor("red")); @@ -1097,15 +1098,15 @@ void tst_qquickstates::explicitChanges() QQmlComponent rectComponent(&engine, testFileUrl("explicit.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQmlListReference list(rect, "states"); QQuickState *state = qobject_cast<QQuickState*>(list.at(0)); - QVERIFY(state != 0); + QVERIFY(state != nullptr); qmlExecuteDeferred(state); QQuickPropertyChanges *changes = qobject_cast<QQuickPropertyChanges*>(rect->findChild<QQuickPropertyChanges*>("changes")); - QVERIFY(changes != 0); + QVERIFY(changes != nullptr); QVERIFY(changes->isExplicit()); QCOMPARE(rect->color(),QColor("red")); @@ -1130,7 +1131,7 @@ void tst_qquickstates::propertyErrors() QQmlEngine engine; QQmlComponent rectComponent(&engine, testFileUrl("propertyErrors.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QCOMPARE(rect->color(),QColor("red")); @@ -1145,7 +1146,7 @@ void tst_qquickstates::incorrectRestoreBug() QQmlComponent rectComponent(&engine, testFileUrl("basicChanges.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QCOMPARE(rect->color(),QColor("red")); @@ -1172,7 +1173,7 @@ void tst_qquickstates::autoStateAtStartupRestoreBug() QQmlComponent component(&engine, testFileUrl("autoStateAtStartupRestoreBug.qml")); QObject *obj = component.create(); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QCOMPARE(obj->property("test").toInt(), 3); obj->setProperty("input", 2); @@ -1188,7 +1189,7 @@ void tst_qquickstates::deletingChange() QQmlComponent rectComponent(&engine, testFileUrl("deleting.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); rectPrivate->setState("blue"); QCOMPARE(rect->color(),QColor("blue")); @@ -1199,11 +1200,11 @@ void tst_qquickstates::deletingChange() QCOMPARE(rect->radius(),qreal(0)); QQuickPropertyChanges *pc = rect->findChild<QQuickPropertyChanges*>("pc1"); - QVERIFY(pc != 0); + QVERIFY(pc != nullptr); delete pc; QQuickState *state = rect->findChild<QQuickState*>(); - QVERIFY(state != 0); + QVERIFY(state != nullptr); qmlExecuteDeferred(state); QCOMPARE(state->operationCount(), 1); @@ -1220,11 +1221,11 @@ void tst_qquickstates::deletingState() QQmlComponent rectComponent(&engine, testFileUrl("deletingState.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickStateGroup *sg = rect->findChild<QQuickStateGroup*>(); - QVERIFY(sg != 0); - QVERIFY(sg->findState("blue") != 0); + QVERIFY(sg != nullptr); + QVERIFY(sg->findState("blue") != nullptr); sg->setState("blue"); QCOMPARE(rect->color(),QColor("blue")); @@ -1233,7 +1234,7 @@ void tst_qquickstates::deletingState() QCOMPARE(rect->color(),QColor("red")); QQuickState *state = rect->findChild<QQuickState*>(); - QVERIFY(state != 0); + QVERIFY(state != nullptr); delete state; QVERIFY(!sg->findState("blue")); @@ -1251,7 +1252,7 @@ void tst_qquickstates::tempState() QQmlComponent rectComponent(&engine, testFileUrl("legalTempState.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QTest::ignoreMessage(QtDebugMsg, "entering placed"); QTest::ignoreMessage(QtDebugMsg, "entering idle"); @@ -1265,7 +1266,7 @@ void tst_qquickstates::illegalTempState() QQmlComponent rectComponent(&engine, testFileUrl("illegalTempState.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML StateGroup: Can't apply a state change as part of a state definition."); rectPrivate->setState("placed"); @@ -1278,7 +1279,7 @@ void tst_qquickstates::nonExistantProperty() QQmlComponent rectComponent(&engine, testFileUrl("nonExistantProp.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QTest::ignoreMessage(QtWarningMsg, fullDataPath("nonExistantProp.qml") + ":9:9: QML PropertyChanges: Cannot assign to non-existent property \"colr\""); rectPrivate->setState("blue"); @@ -1291,10 +1292,10 @@ void tst_qquickstates::reset() QQmlComponent c(&engine, testFileUrl("reset.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickImage *image = rect->findChild<QQuickImage*>(); - QVERIFY(image != 0); + QVERIFY(image != nullptr); QCOMPARE(image->width(), qreal(40.)); QCOMPARE(image->height(), qreal(20.)); @@ -1325,7 +1326,7 @@ void tst_qquickstates::whenOrdering() QQmlComponent c(&engine, testFileUrl("whenOrdering.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QCOMPARE(rectPrivate->state(), QLatin1String("")); @@ -1348,13 +1349,13 @@ void tst_qquickstates::urlResolution() QQmlComponent c(&engine, testFileUrl("urlResolution.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItem *myType = rect->findChild<QQuickItem*>("MyType"); QQuickImage *image1 = rect->findChild<QQuickImage*>("image1"); QQuickImage *image2 = rect->findChild<QQuickImage*>("image2"); QQuickImage *image3 = rect->findChild<QQuickImage*>("image3"); - QVERIFY(myType != 0 && image1 != 0 && image2 != 0 && image3 != 0); + QVERIFY(myType != nullptr && image1 != nullptr && image2 != nullptr && image3 != nullptr); QQuickItemPrivate::get(myType)->setState("SetImageState"); QUrl resolved = testFileUrl("Implementation/images/qt-logo.png"); @@ -1371,7 +1372,7 @@ void tst_qquickstates::unnamedWhen() QQmlComponent c(&engine, testFileUrl("unnamedWhen.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QCOMPARE(rectPrivate->state(), QLatin1String("")); @@ -1390,7 +1391,7 @@ void tst_qquickstates::returnToBase() QQmlComponent c(&engine, testFileUrl("returnToBase.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QCOMPARE(rectPrivate->state(), QLatin1String("")); @@ -1410,7 +1411,7 @@ void tst_qquickstates::extendsBug() QQmlComponent c(&engine, testFileUrl("extendsBug.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQuickRectangle *greenRect = rect->findChild<QQuickRectangle*>("greenRect"); @@ -1425,30 +1426,30 @@ void tst_qquickstates::editProperties() QQmlComponent c(&engine, testFileUrl("editProperties.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); QQuickStateGroup *stateGroup = rectPrivate->_states(); - QVERIFY(stateGroup != 0); + QVERIFY(stateGroup != nullptr); qmlExecuteDeferred(stateGroup); QQuickState *blueState = stateGroup->findState("blue"); - QVERIFY(blueState != 0); + QVERIFY(blueState != nullptr); qmlExecuteDeferred(blueState); QQuickPropertyChanges *propertyChangesBlue = qobject_cast<QQuickPropertyChanges*>(blueState->operationAt(0)); - QVERIFY(propertyChangesBlue != 0); + QVERIFY(propertyChangesBlue != nullptr); QQuickState *greenState = stateGroup->findState("green"); - QVERIFY(greenState != 0); + QVERIFY(greenState != nullptr); qmlExecuteDeferred(greenState); QQuickPropertyChanges *propertyChangesGreen = qobject_cast<QQuickPropertyChanges*>(greenState->operationAt(0)); - QVERIFY(propertyChangesGreen != 0); + QVERIFY(propertyChangesGreen != nullptr); QQuickRectangle *childRect = rect->findChild<QQuickRectangle*>("rect2"); - QVERIFY(childRect != 0); + QVERIFY(childRect != nullptr); QCOMPARE(childRect->width(), qreal(402)); QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width"))); QCOMPARE(childRect->height(), qreal(200)); @@ -1553,7 +1554,7 @@ void tst_qquickstates::QTBUG_14830() QQmlComponent c(&engine, testFileUrl("QTBUG-14830.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItem *item = rect->findChild<QQuickItem*>("area"); QCOMPARE(item->width(), qreal(170)); @@ -1566,7 +1567,7 @@ void tst_qquickstates::avoidFastForward() //shouldn't fast forward if there isn't a transition QQmlComponent c(&engine, testFileUrl("avoidFastForward.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect); rectPrivate->setState("a"); @@ -1580,7 +1581,7 @@ void tst_qquickstates::revertListBug() QQmlComponent c(&engine, testFileUrl("revertListBug.qml")); QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create()); - QVERIFY(rect != 0); + QVERIFY(rect != nullptr); QQuickRectangle *rect1 = rect->findChild<QQuickRectangle*>("rect1"); QQuickRectangle *rect2 = rect->findChild<QQuickRectangle*>("rect2"); @@ -1621,7 +1622,7 @@ void tst_qquickstates::QTBUG_38492() QQmlComponent rectComponent(&engine, testFileUrl("QTBUG-38492.qml")); QQuickItem *item = qobject_cast<QQuickItem*>(rectComponent.create()); - QVERIFY(item != 0); + QVERIFY(item != nullptr); QQuickItemPrivate::get(item)->setState("apply"); @@ -1654,6 +1655,17 @@ void tst_qquickstates::revertListMemoryLeak() QVERIFY(bindingPtr->ref == 1); } +void tst_qquickstates::duplicateStateName() +{ + QQmlEngine engine; + + QQmlComponent c(&engine, testFileUrl("duplicateStateName.qml")); + QTest::ignoreMessage(QtWarningMsg, fullDataPath("duplicateStateName.qml") + ":3:1: QML Rectangle: Found duplicate state name: state1"); + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem *>(c.create())); + QVERIFY(!item.isNull()); +} + + QTEST_MAIN(tst_qquickstates) #include "tst_qquickstates.moc" diff --git a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp index 045029c3b6..88b0e95e0a 100644 --- a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp +++ b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp @@ -44,7 +44,8 @@ public: Bold = 0x01, Underline = 0x02, Italic = 0x04, - Anchor = 0x08 + Anchor = 0x08, + StrikeOut = 0x10 }; Format(int t, int s, int l) : type(t), start(s), length(l) {} @@ -92,6 +93,10 @@ void tst_qquickstyledtext::textOutput_data() QTest::newRow("underline") << "<u>underline</u>" << "underline" << (FormatList() << Format(Format::Underline, 0, 9)) << false; QTest::newRow("strong") << "<strong>strong</strong>" << "strong" << (FormatList() << Format(Format::Bold, 0, 6)) << false; QTest::newRow("underline") << "<u>underline</u>" << "underline" << (FormatList() << Format(Format::Underline, 0, 9)) << false; + QTest::newRow("strike out s") << "<s>strike out</s>" << "strike out" << (FormatList() << Format(Format::StrikeOut, 0, 10)) << false; + QTest::newRow("strike out del") << "<del>strike out</del>" << "strike out" << (FormatList() << Format(Format::StrikeOut, 0, 10)) << false; + QTest::newRow("strike out not s") << "this is <s>not</s> a test" << "this is not a test" << (FormatList() << Format(Format::StrikeOut, 8, 3)) << false; + QTest::newRow("strike out not del") << "this is <del>not</del> a test" << "this is not a test" << (FormatList() << Format(Format::StrikeOut, 8, 3)) << false; QTest::newRow("missing >") << "<b>text</b" << "text" << (FormatList() << Format(Format::Bold, 0, 4)) << false; QTest::newRow("missing b>") << "<b>text</" << "text" << (FormatList() << Format(Format::Bold, 0, 4)) << false; QTest::newRow("missing /b>") << "<b>text<" << "text" << (FormatList() << Format(Format::Bold, 0, 4)) << false; @@ -162,7 +167,7 @@ void tst_qquickstyledtext::textOutput() QTextLayout layout; QList<QQuickStyledTextImgTag*> imgTags; bool fontSizeModified = false; - QQuickStyledText::parse(input, layout, imgTags, QUrl(), 0, false, &fontSizeModified); + QQuickStyledText::parse(input, layout, imgTags, QUrl(), nullptr, false, &fontSizeModified); QCOMPARE(layout.text(), output); @@ -178,6 +183,7 @@ void tst_qquickstyledtext::textOutput() QCOMPARE(layoutFormats.at(i).format.fontWeight(), int(QFont::Normal)); QVERIFY(layoutFormats.at(i).format.fontItalic() == bool(formats.at(i).type & Format::Italic)); QVERIFY(layoutFormats.at(i).format.fontUnderline() == bool(formats.at(i).type & Format::Underline)); + QVERIFY(layoutFormats.at(i).format.fontStrikeOut() == bool(formats.at(i).type & Format::StrikeOut)); } QCOMPARE(fontSizeModified, modifiesFontSize); } @@ -191,7 +197,7 @@ void tst_qquickstyledtext::anchors() QTextLayout layout; QList<QQuickStyledTextImgTag*> imgTags; bool fontSizeModified = false; - QQuickStyledText::parse(input, layout, imgTags, QUrl(), 0, false, &fontSizeModified); + QQuickStyledText::parse(input, layout, imgTags, QUrl(), nullptr, false, &fontSizeModified); QCOMPARE(layout.text(), output); @@ -229,11 +235,11 @@ void tst_qquickstyledtext::longString() bool fontSizeModified = false; QString input(9999999, QChar('.')); - QQuickStyledText::parse(input, layout, imgTags, QUrl(), 0, false, &fontSizeModified); + QQuickStyledText::parse(input, layout, imgTags, QUrl(), nullptr, false, &fontSizeModified); QCOMPARE(layout.text(), input); input = QString(9999999, QChar('\t')); // whitespace - QQuickStyledText::parse(input, layout, imgTags, QUrl(), 0, false, &fontSizeModified); + QQuickStyledText::parse(input, layout, imgTags, QUrl(), nullptr, false, &fontSizeModified); QCOMPARE(layout.text(), QString("")); } diff --git a/tests/auto/quick/qquicksystempalette/tst_qquicksystempalette.cpp b/tests/auto/quick/qquicksystempalette/tst_qquicksystempalette.cpp index 136cfa9a80..071dcafc97 100644 --- a/tests/auto/quick/qquicksystempalette/tst_qquicksystempalette.cpp +++ b/tests/auto/quick/qquicksystempalette/tst_qquicksystempalette.cpp @@ -62,7 +62,7 @@ void tst_qquicksystempalette::activePalette() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickSystemPalette *object = qobject_cast<QQuickSystemPalette*>(component.create()); - QVERIFY(object != 0); + QVERIFY(object != nullptr); QPalette palette; palette.setCurrentColorGroup(QPalette::Active); @@ -91,7 +91,7 @@ void tst_qquicksystempalette::inactivePalette() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickSystemPalette *object = qobject_cast<QQuickSystemPalette*>(component.create()); - QVERIFY(object != 0); + QVERIFY(object != nullptr); QCOMPARE(object->colorGroup(), QQuickSystemPalette::Inactive); QPalette palette; @@ -121,7 +121,7 @@ void tst_qquicksystempalette::disabledPalette() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickSystemPalette *object = qobject_cast<QQuickSystemPalette*>(component.create()); - QVERIFY(object != 0); + QVERIFY(object != nullptr); QCOMPARE(object->colorGroup(), QQuickSystemPalette::Disabled); QPalette palette; @@ -152,7 +152,7 @@ void tst_qquicksystempalette::paletteChanged() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickSystemPalette *object = qobject_cast<QQuickSystemPalette*>(component.create()); - QVERIFY(object != 0); + QVERIFY(object != nullptr); QPalette p; p.setCurrentColorGroup(QPalette::Active); diff --git a/tests/auto/quick/qquicktableview/data/alternatingrowheightcolumnwidth.qml b/tests/auto/quick/qquicktableview/data/alternatingrowheightcolumnwidth.qml new file mode 100644 index 0000000000..e6cf9bf2a4 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/alternatingrowheightcolumnwidth.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + property Component delegate: tableViewDelegate + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + columnSpacing: 1 + rowSpacing: 1 + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + implicitWidth: column % 2 ? 40 : 30 + implicitHeight: row % 2 ? 40 : 20 + color: "lightgray" + border.width: 1 + Text { + anchors.centerIn: parent + text: modelData + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/asyncloader.qml b/tests/auto/quick/qquicktableview/data/asyncloader.qml new file mode 100644 index 0000000000..ba99430416 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/asyncloader.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias loader: loader + property TableView tableView: loader.item ? loader.item.tableView : null + property string loaderSource: "" + + Loader { + id: loader + anchors.fill: parent + source: Qt.resolvedUrl(loaderSource) + asynchronous: true + } +} diff --git a/tests/auto/quick/qquicktableview/data/asyncplain.qml b/tests/auto/quick/qquicktableview/data/asyncplain.qml new file mode 100644 index 0000000000..df09d3e276 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/asyncplain.qml @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 TestModel 0.1 + +Item { + id: root + width: 640 + height: 450 + + property alias tableView: tableView + property Loader loader: parent + + property int statusWhenDelegate0_0Created: Loader.Null + property int statusWhenDelegate5_5Created: Loader.Null + + property real tableViewWidthWhileBuilding: -1 + property real tableViewHeightWhileBuilding: -1 + + TableView { + id: tableView + anchors.fill: parent + clip: true + delegate: tableViewDelegate + columnSpacing: 1 + rowSpacing: 1 + model: TestModel { + rowCount: 100 + columnCount: 100 + } + } + + Component { + id: tableViewDelegate + Rectangle { + implicitWidth: 100 + implicitHeight: 50 + color: "lightgray" + border.width: 1 + + Text { + anchors.centerIn: parent + text: modelData + } + + Component.onCompleted: { + if (row === 0 && column === 0) { + statusWhenDelegate0_0Created = loader.status + tableViewWidthWhileBuilding = tableView.width + tableViewHeightWhileBuilding = tableView.height + } + else if (row === 5 && column === 5) + statusWhenDelegate5_5Created = loader.status + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/changemodelfromdelegate.qml b/tests/auto/quick/qquicktableview/data/changemodelfromdelegate.qml new file mode 100644 index 0000000000..79a8e4351a --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/changemodelfromdelegate.qml @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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 TestModel 0.1 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + property bool addRowFromDelegate: false + + onAddRowFromDelegateChanged: { + if (!addRowFromDelegate) + return; + tableModel.addRow(0); + tableView.forceLayout(); + } + + TestModel { + id: tableModel + rowCount: 1 + columnCount: 4 + } + + TableView { + id: tableView + width: 600 + height: 400 + clip: true + model: tableModel + delegate: tableViewDelegate + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + implicitWidth: 100 + implicitHeight: 100 + color: "lightgray" + border.width: 1 + + Text { + anchors.centerIn: parent + text: modelData + } + + Component.onCompleted: { + if (!addRowFromDelegate) + return; + addRowFromDelegate = false; + tableModel.addRow(0); + } + } + } + +} + diff --git a/tests/auto/quick/qquicktableview/data/changemodelordelegateduringupdate.qml b/tests/auto/quick/qquicktableview/data/changemodelordelegateduringupdate.qml new file mode 100644 index 0000000000..de404be63d --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/changemodelordelegateduringupdate.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + property bool changeDelegate: false + property bool changeModel: false + + TableView { + id: tableView + width: 600 + height: 400 + clip: true + delegate: tableViewDelegate + } + + Component { + id: tableViewDelegate + Rectangle { + implicitWidth: 100 + implicitHeight: 100 + color: "lightgray" + border.width: 1 + + Text { + anchors.centerIn: parent + text: modelData + } + + Component.onCompleted: { + if (changeDelegate) + TableView.view.delegate = null + if (changeModel) + TableView.view.model = null + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/checkmodelpropertyrevision.qml b/tests/auto/quick/qquicktableview/data/checkmodelpropertyrevision.qml new file mode 100644 index 0000000000..0550f20bac --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/checkmodelpropertyrevision.qml @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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.12 + +Item { + id: root + width: 640 + height: 480 + + property alias tableView: tableView + + property int row: 42 + property int column: 42 + + property int resolvedDelegateRow: 0 + property int resolvedDelegateColumn: 0 + + TableView { + id: tableView + // Dummy tableView, to let the auto test follow the + // same pattern for loading qml files as other tests. + } + + Item { + width: 100 + height: parent.height; + Repeater { + model: 1 + delegate: Component { + Rectangle { + color: "blue" + height: 100 + width: 100 + Component.onCompleted: { + // row and column should be resolved to be the ones + // found in the root item, and not in the delegate + // items context. The context properties are revisioned, + // and require that the QQmlDelegateModel has an import + // version set (which is not the case when using a + // Repeater, only when using a TableView). + resolvedDelegateRow = row + resolvedDelegateColumn = column + } + } + } + } + } +} + diff --git a/tests/auto/quick/qquicktableview/data/checkrowandcolumnnotchanged.qml b/tests/auto/quick/qquicktableview/data/checkrowandcolumnnotchanged.qml new file mode 100644 index 0000000000..bef0df2501 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/checkrowandcolumnnotchanged.qml @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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.qmlmodels 1.0 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + + TableView { + id: tableView + width: 600 + height: 400 + delegate: DelegateChooser { + DelegateChoice { + row: 0 + column: 0 + delegate: maskDelegate + } + DelegateChoice { + row: 1 + column: 1 + delegate: maskDelegate + } + DelegateChoice { + delegate: tableViewDelegate + } + } + } + + Component { + // Add this mask delegate, to force QQmlTableInstanceModel to + // reuse the precise cells that we want to swap in the test + id: maskDelegate + Rectangle { + implicitWidth: 100 + implicitHeight: 50 + color: "green" + } + } + + Component { + id: tableViewDelegate + Rectangle { + implicitWidth: 100 + implicitHeight: 50 + Text { + anchors.fill: parent + text: column + "," + row + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/contentwidthheight.qml b/tests/auto/quick/qquicktableview/data/contentwidthheight.qml new file mode 100644 index 0000000000..6b15e8dd21 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/contentwidthheight.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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + property Component delegate: tableViewDelegate + + TableView { + id: tableView + width: 500 + height: 500 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + columnSpacing: 1 + rowSpacing: 1 + leftMargin: 10 + rightMargin: 10 + topMargin: 10 + bottomMargin: 10 + columnWidthProvider: function(column) { return column < 20 ? 100 : 200 } + rowHeightProvider: function(row) { return row < 20 ? 100 : 200 } + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + color: "lightgray" + border.width: 1 + Text { + anchors.centerIn: parent + text: column + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/countingtableview.qml b/tests/auto/quick/qquicktableview/data/countingtableview.qml new file mode 100644 index 0000000000..ecd4ca3cc7 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/countingtableview.qml @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** 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 + +Item { + id: root + width: 640 + height: 450 + + property alias tableView: tableView + + // currentDelegateCount is the number of currently visible items + property int currentDelegateCount: 0 + // maxDelegateCount is the largest number of items that has ever been visible at the same time + property int maxDelegateCount: 0 + // delegatesCreatedCount is the number of items created during the lifetime of the test + property int delegatesCreatedCount: 0 + + property real delegateWidth: 100 + property real delegateHeight: 50 + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + implicitWidth: delegateWidth + implicitHeight: delegateHeight + color: "lightgray" + border.width: 1 + + property int pooledCount: 0 + property int reusedCount: 0 + TableView.onPooled: pooledCount++; + TableView.onReused: reusedCount++; + + Text { + anchors.centerIn: parent + text: column + } + Component.onCompleted: { + delegatesCreatedCount++; + currentDelegateCount++; + maxDelegateCount = Math.max(maxDelegateCount, currentDelegateCount); + } + Component.onDestruction: { + currentDelegateCount--; + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/delegatewithanchors.qml b/tests/auto/quick/qquicktableview/data/delegatewithanchors.qml new file mode 100644 index 0000000000..0b549f09a4 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/delegatewithanchors.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + + TableView { + id: tableView + width: 600 + height: 400 + delegate: tableViewDelegate + } + + Component { + id: tableViewDelegate + Rectangle { + anchors.fill: parent + implicitWidth: 100 + implicitHeight: 100 + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/forcelayout.qml b/tests/auto/quick/qquicktableview/data/forcelayout.qml new file mode 100644 index 0000000000..f03dc2f25b --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/forcelayout.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + property real columnWidths: 80 + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + delegate: tableViewDelegate + columnSpacing: 1 + rowSpacing: 1 + + columnWidthProvider: function(c) { return columnWidths; } + } + + Component { + id: tableViewDelegate + Rectangle { + color: "lightgray" + border.width: 1 + implicitHeight: 100 + + Text { + anchors.centerIn: parent + text: modelData + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/hiderowsandcolumns.qml b/tests/auto/quick/qquicktableview/data/hiderowsandcolumns.qml new file mode 100644 index 0000000000..b11cb1476c --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/hiderowsandcolumns.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + property var rowsToHide + property var columnsToHide + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + columnSpacing: 1 + rowSpacing: 1 + columnWidthProvider: function(column) { + if (columnsToHide.includes(column)) + return 0; + } + rowHeightProvider: function(row) { + if (rowsToHide.includes(row)) + return 0; + } + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + color: "lightgray" + border.width: 1 + implicitWidth: 50 + implicitHeight: 50 + Text { + anchors.centerIn: parent + text: column + "," + row + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/plaintableview.qml b/tests/auto/quick/qquicktableview/data/plaintableview.qml new file mode 100644 index 0000000000..90271eda71 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/plaintableview.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + property real delegateWidth: 100 + property real delegateHeight: 50 + property Component delegate: tableViewDelegate + property bool delegateParentSetBeforeCompleted: false + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + columnSpacing: 1 + rowSpacing: 1 + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + implicitWidth: delegateWidth + implicitHeight: delegateHeight + color: "lightgray" + border.width: 1 + + property string modelDataBinding: modelData + + Text { + anchors.centerIn: parent + text: modelData + } + + Component.onCompleted: { + delegateParentSetBeforeCompleted = parent != null; + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/qqmllistpropertymodel.qml b/tests/auto/quick/qquicktableview/data/qqmllistpropertymodel.qml new file mode 100644 index 0000000000..38fca2c5cb --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/qqmllistpropertymodel.qml @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 + +Item { + id: root + width: 640 + height: 450 + + property alias tableView: tableView + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + } + + Item { + Repeater { + model: 100 + Item { property string someCustomProperty: index } + } + Component.onCompleted: tableView.model = children + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + implicitWidth: 100 + implicitHeight: 50 + color: "lightgray" + border.width: 1 + + Text { + anchors.centerIn: parent + text: column + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/setcontentpos.qml b/tests/auto/quick/qquicktableview/data/setcontentpos.qml new file mode 100644 index 0000000000..fa040d3959 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/setcontentpos.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + + TableView { + id: tableView + width: 400 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + contentX: (contentWidth - width) / 2; + contentY: (contentHeight - height) / 2; + } + + Component { + id: tableViewDelegate + Rectangle { + implicitWidth: 100 + implicitHeight: 100 + color: "lightgray" + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/tableviewdefaultspacing.qml b/tests/auto/quick/qquicktableview/data/tableviewdefaultspacing.qml new file mode 100644 index 0000000000..f4a3094dd2 --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/tableviewdefaultspacing.qml @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + delegate: tableViewDelegate + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + color: "lightgray" + border.width: 1 + implicitWidth: 15 + implicitHeight: 10 + Text { + anchors.centerIn: parent + text: modelData + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/tableviewfocus.qml b/tests/auto/quick/qquicktableview/data/tableviewfocus.qml new file mode 100644 index 0000000000..c388e2c8de --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/tableviewfocus.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + + TableView { + id: tableView + width: 600 + height: 400 + clip: true + delegate: tableViewDelegate + } + + Component { + id: tableViewDelegate + Item { + id: delegate + implicitWidth: 100 + implicitHeight: 50 + focus: true + + property alias delegateRoot: delegate + property alias delegateChild: textInput + + TextInput { + id: textInput + width: parent.width + height: parent.height + text: "TextInput" + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml b/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml new file mode 100644 index 0000000000..425b950fce --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + 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/data/usechooserwithoutdefault.qml b/tests/auto/quick/qquicktableview/data/usechooserwithoutdefault.qml new file mode 100644 index 0000000000..847500d71f --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/usechooserwithoutdefault.qml @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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.qmlmodels 1.0 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + + TableView { + id: tableView + width: 600 + height: 400 + delegate: DelegateChooser { + DelegateChoice { + row: 0 + delegate: Item { + implicitWidth: 100 + implicitHeight: 100 + } + } + } + } +} diff --git a/tests/auto/quick/qquicktableview/data/usefaultyrowcolumnprovider.qml b/tests/auto/quick/qquicktableview/data/usefaultyrowcolumnprovider.qml new file mode 100644 index 0000000000..1e35d65bcd --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/usefaultyrowcolumnprovider.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + property Component delegate: tableViewDelegate + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + columnSpacing: 1 + rowSpacing: 1 + columnWidthProvider: function(column) { return "notAValidValue" } + rowHeightProvider: function(row) { return "notAValidValue" } + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + color: "lightgray" + border.width: 1 + Text { + anchors.centerIn: parent + text: modelData + } + } + } + +} diff --git a/tests/auto/quick/qquicktableview/data/userowcolumnprovider.qml b/tests/auto/quick/qquicktableview/data/userowcolumnprovider.qml new file mode 100644 index 0000000000..e9f01b6abf --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/userowcolumnprovider.qml @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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 + +Item { + width: 640 + height: 450 + + property alias tableView: tableView + property Component delegate: tableViewDelegate + property bool returnNegativeColumnWidth: false + property bool returnNegativeRowHeight: false + + TableView { + id: tableView + width: 600 + height: 400 + anchors.margins: 1 + clip: true + delegate: tableViewDelegate + columnSpacing: 1 + rowSpacing: 1 + columnWidthProvider: function(column) { + if (returnNegativeColumnWidth) + return -1 + return column + 10 + } + rowHeightProvider: function(row) { + if (returnNegativeRowHeight) + return -1 + return row + 10 + } + } + + Component { + id: tableViewDelegate + Rectangle { + objectName: "tableViewDelegate" + implicitWidth: 20 + implicitHeight: 20 + color: "lightgray" + border.width: 1 + 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..cf831ed5b5 --- /dev/null +++ b/tests/auto/quick/qquicktableview/qquicktableview.pro @@ -0,0 +1,15 @@ +CONFIG += testcase +QT += qmltest +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..50f434019e --- /dev/null +++ b/tests/auto/quick/qquicktableview/testmodel.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** 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 serializedIndex = index.row() + (index.column() * m_columns); + if (modelData.contains(serializedIndex)) + return modelData.value(serializedIndex); + return QStringLiteral("%1").arg(index.row()); + } + + QHash<int, QByteArray> roleNames() const override + { + return { {Qt::DisplayRole, "display"} }; + } + + Q_INVOKABLE void setModelData(const QPoint &cell, const QSize &span, const QString &string) + { + for (int c = 0; c < span.width(); ++c) { + for (int r = 0; r < span.height(); ++r) { + const int changedRow = cell.y() + r; + const int changedColumn = cell.x() + c; + const int serializedIndex = changedRow + (changedColumn * m_rows); + modelData.insert(serializedIndex, string); + } + } + + const auto topLeftIndex = createIndex(cell.y(), cell.x(), nullptr); + const auto bottomRightIndex = createIndex(cell.y() + span.height() - 1, cell.x() + span.width() - 1, nullptr); + emit dataChanged(topLeftIndex, bottomRightIndex); + } + + bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override + { + if (row < 0 || count <= 0) + return false; + + beginInsertRows(parent, row, row + count - 1); + m_rows += count; + endInsertRows(); + return true; + } + + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override + { + if (!checkIndex(createIndex(row, 0)) || !checkIndex(createIndex(row + count - 1, 0))) + return false; + + beginRemoveRows(parent, row, row + count - 1); + m_rows -= count; + endRemoveRows(); + return true; + } + + bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override + { + if (column < 0 || count <= 0) + return false; + + beginInsertColumns(parent, column, column + count - 1); + m_columns += count; + endInsertColumns(); + return true; + } + + bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex()) override + { + if (!checkIndex(createIndex(0, column)) || !checkIndex(createIndex(0, column + count - 1))) + return false; + + beginRemoveColumns(parent, column, column + count - 1); + m_columns -= count; + endRemoveColumns(); + return true; + } + + void swapRows(int row1, int row2) + { + layoutAboutToBeChanged(); + Q_ASSERT(modelData.contains(row1)); + Q_ASSERT(modelData.contains(row2)); + const QString tmp = modelData[row1]; + modelData[row1] = modelData[row2]; + modelData[row2] = tmp; + layoutChanged(); + } + + void clear() { + beginResetModel(); + m_rows = 0; + m_columns = 0; + modelData.clear(); + endResetModel(); + } + + Q_INVOKABLE void addRow(int row) + { + insertRow(row, QModelIndex()); + } + +signals: + void rowCountChanged(); + void columnCountChanged(); + +private: + int m_rows = 0; + int m_columns = 0; + QHash<int, QString> modelData; +}; + +#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..60d48bb59f --- /dev/null +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -0,0 +1,2157 @@ +/**************************************************************************** +** +** 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 <QtQuickTest/quicktest.h> + +#include <QtQuick/qquickview.h> +#include <QtQuick/private/qquicktableview_p.h> +#include <QtQuick/private/qquicktableview_p_p.h> +#include <QtQuick/private/qquickloader_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 "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"; +static const char *kDelegatesCreatedCountProp = "delegatesCreatedCount"; +static const char *kModelDataBindingProp = "modelDataBinding"; + +Q_DECLARE_METATYPE(QMarginsF); + +#define DECLARE_TABLEVIEW_VARIABLES \ + auto tableView = view->rootObject()->property(kTableViewPropName).value<QQuickTableView *>(); \ + QVERIFY(tableView); \ + auto tableViewPrivate = QQuickTableViewPrivate::get(tableView); \ + Q_UNUSED(tableViewPrivate) + +#define LOAD_TABLEVIEW(fileName) \ + view->setSource(testFileUrl(fileName)); \ + view->show(); \ + QVERIFY(QTest::qWaitForWindowActive(view)); \ + DECLARE_TABLEVIEW_VARIABLES + +#define LOAD_TABLEVIEW_ASYNC(fileName) \ + view->setSource(testFileUrl("asyncloader.qml")); \ + view->show(); \ + QVERIFY(QTest::qWaitForWindowActive(view)); \ + auto loader = view->rootObject()->property("loader").value<QQuickLoader *>(); \ + loader->setSource(QUrl::fromLocalFile("data/" fileName)); \ + QTRY_VERIFY(loader->item()); \ + QCOMPARE(loader->status(), QQuickLoader::Status::Ready); \ + DECLARE_TABLEVIEW_VARIABLES + +#define WAIT_UNTIL_POLISHED \ + QVERIFY(QQuickTest::qIsPolishScheduled(tableView)); \ + QVERIFY(QQuickTest::qWaitForItemPolished(tableView)) + +class tst_QQuickTableView : public QQmlDataTest +{ + Q_OBJECT +public: + tst_QQuickTableView(); + + QQuickTableViewAttached *getAttachedObject(const QObject *object) const; + QPoint getContextRowAndColumn(const QQuickItem *item) const; + +private: + QQuickView *view = nullptr; + +private slots: + void initTestCase() override; + void cleanupTestCase(); + + void setAndGetModel_data(); + void setAndGetModel(); + void emptyModel_data(); + void emptyModel(); + void checkPreload_data(); + void checkPreload(); + void checkZeroSizedDelegate(); + void checkImplicitSizeDelegate(); + void checkColumnWidthWithoutProvider(); + void checkDelegateWithAnchors(); + void checkColumnWidthProvider(); + void checkColumnWidthProviderInvalidReturnValues(); + void checkColumnWidthProviderNegativeReturnValue(); + void checkColumnWidthProviderNotCallable(); + void checkRowHeightWithoutProvider(); + void checkRowHeightProvider(); + void checkRowHeightProviderInvalidReturnValues(); + void checkRowHeightProviderNegativeReturnValue(); + void checkRowHeightProviderNotCallable(); + void checkForceLayoutFunction(); + void checkContentWidthAndHeight(); + void checkPageFlicking(); + void checkExplicitContentWidthAndHeight(); + void checkContentXY(); + void noDelegate(); + void changeDelegateDuringUpdate(); + void changeModelDuringUpdate(); + void countDelegateItems_data(); + void countDelegateItems(); + void checkLayoutOfEqualSizedDelegateItems_data(); + void checkLayoutOfEqualSizedDelegateItems(); + void checkFocusRemoved_data(); + void checkFocusRemoved(); + void fillTableViewButNothingMore_data(); + void fillTableViewButNothingMore(); + void checkInitialAttachedProperties_data(); + void checkInitialAttachedProperties(); + void checkSpacingValues(); + void checkDelegateParent(); + void flick_data(); + void flick(); + void flickOvershoot_data(); + void flickOvershoot(); + void checkRowColumnCount(); + void modelSignals(); + void checkModelSignalsUpdateLayout(); + void dataChangedSignal(); + void checkThatPoolIsDrainedWhenReuseIsFalse(); + void checkIfDelegatesAreReused_data(); + void checkIfDelegatesAreReused(); + void checkIfDelegatesAreReusedAsymmetricTableSize(); + void checkContextProperties_data(); + void checkContextProperties(); + void checkContextPropertiesQQmlListProperyModel_data(); + void checkContextPropertiesQQmlListProperyModel(); + void checkRowAndColumnChangedButNotIndex(); + void checkChangingModelFromDelegate(); + void checkRebuildViewportOnly(); + void useDelegateChooserWithoutDefault(); + void checkTableviewInsideAsyncLoader(); + void hideRowsAndColumns_data(); + void hideRowsAndColumns(); + void checkThatRevisionedPropertiesCannotBeUsedInOldImports(); +}; + +tst_QQuickTableView::tst_QQuickTableView() +{ +} + +void tst_QQuickTableView::initTestCase() +{ + QQmlDataTest::initTestCase(); + qmlRegisterType<TestModel>("TestModel", 0, 1, "TestModel"); + view = createView(); +} + +void tst_QQuickTableView::cleanupTestCase() +{ + delete view; +} + +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::checkPreload_data() +{ + QTest::addColumn<bool>("reuseItems"); + + QTest::newRow("reuse") << true; + QTest::newRow("not reuse") << false; +} + +void tst_QQuickTableView::checkPreload() +{ + // Check that the reuse pool is filled up with one extra row and + // column (pluss corner) after rebuilding the table, but only if we reuse items. + QFETCH(bool, reuseItems); + LOAD_TABLEVIEW("plaintableview.qml"); + + auto model = TestModelAsVariant(100, 100); + tableView->setModel(model); + tableView->setReuseItems(reuseItems); + + WAIT_UNTIL_POLISHED; + + if (reuseItems) { + const int rowCount = tableViewPrivate->loadedRows.count(); + const int columnCount = tableViewPrivate->loadedColumns.count(); + const int expectedPoolSize = rowCount + columnCount + 1; + QCOMPARE(tableViewPrivate->tableModel->poolSize(), expectedPoolSize); + } else { + QCOMPARE(tableViewPrivate->tableModel->poolSize(), 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); + + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*implicit")); + + 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 implicitWidth/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::checkColumnWidthWithoutProvider() +{ + // Checks that a function isn't assigned to the columnWidthProvider property + // and that the column width is then equal to sizeHintForColumn. + LOAD_TABLEVIEW("alternatingrowheightcolumnwidth.qml"); + + auto model = TestModelAsVariant(10, 10); + + tableView->setModel(model); + QVERIFY(tableView->columnWidthProvider().isUndefined()); + + WAIT_UNTIL_POLISHED; + + for (const int column : tableViewPrivate->loadedColumns.keys()) { + const qreal expectedColumnWidth = tableViewPrivate->sizeHintForColumn(column); + for (const int row : tableViewPrivate->loadedRows.keys()) { + const auto item = tableViewPrivate->loadedTableItem(QPoint(column, row))->item; + QCOMPARE(item->width(), expectedColumnWidth); + } + } +} + +void tst_QQuickTableView::checkDelegateWithAnchors() +{ + // Checks that we issue a warning if the delegate has anchors + LOAD_TABLEVIEW("delegatewithanchors.qml"); + + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*anchors")); + + auto model = TestModelAsVariant(1, 1); + tableView->setModel(model); + WAIT_UNTIL_POLISHED; +} + +void tst_QQuickTableView::checkColumnWidthProvider() +{ + // Check that you can assign a function to the columnWidthProvider property, and + // that it's used to control (and override) the width of the columns. + LOAD_TABLEVIEW("userowcolumnprovider.qml"); + + auto model = TestModelAsVariant(10, 10); + + tableView->setModel(model); + QVERIFY(tableView->columnWidthProvider().isCallable()); + + WAIT_UNTIL_POLISHED; + + for (auto fxItem : tableViewPrivate->loadedItems) { + // expectedWidth mirrors the expected return value of the assigned javascript function + qreal expectedWidth = fxItem->cell.x() + 10; + QCOMPARE(fxItem->item->width(), expectedWidth); + } +} + +void tst_QQuickTableView::checkColumnWidthProviderInvalidReturnValues() +{ + // Check that we fall back to use default columns widths, if you + // assign a function to columnWidthProvider that returns invalid values. + LOAD_TABLEVIEW("usefaultyrowcolumnprovider.qml"); + + auto model = TestModelAsVariant(10, 10); + + tableView->setModel(model); + + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*implicitHeight.*zero")); + + WAIT_UNTIL_POLISHED; + + for (auto fxItem : tableViewPrivate->loadedItems) + QCOMPARE(fxItem->item->width(), kDefaultColumnWidth); +} + +void tst_QQuickTableView::checkColumnWidthProviderNegativeReturnValue() +{ + // Check that we fall back to use the implicit width of the delegate + // items if the columnWidthProvider return a negative number. + LOAD_TABLEVIEW("userowcolumnprovider.qml"); + + auto model = TestModelAsVariant(10, 10); + view->rootObject()->setProperty("returnNegativeColumnWidth", true); + + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + for (auto fxItem : tableViewPrivate->loadedItems) + QCOMPARE(fxItem->item->width(), 20); +} + +void tst_QQuickTableView::checkColumnWidthProviderNotCallable() +{ + // Check that we fall back to use default columns widths, if you + // assign something to columnWidthProvider that is not callable. + LOAD_TABLEVIEW("usefaultyrowcolumnprovider.qml"); + + auto model = TestModelAsVariant(10, 10); + + tableView->setModel(model); + tableView->setRowHeightProvider(QJSValue()); + tableView->setColumnWidthProvider(QJSValue(10)); + + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".Provider.*function")); + + WAIT_UNTIL_POLISHED; + + for (auto fxItem : tableViewPrivate->loadedItems) + QCOMPARE(fxItem->item->width(), kDefaultColumnWidth); +} + +void tst_QQuickTableView::checkRowHeightWithoutProvider() +{ + // Checks that a function isn't assigned to the rowHeightProvider property + // and that the row height is then equal to sizeHintForRow. + LOAD_TABLEVIEW("alternatingrowheightcolumnwidth.qml"); + + auto model = TestModelAsVariant(10, 10); + QVERIFY(tableView->rowHeightProvider().isUndefined()); + + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + for (const int row : tableViewPrivate->loadedRows.keys()) { + const qreal expectedRowHeight = tableViewPrivate->sizeHintForRow(row); + for (const int column : tableViewPrivate->loadedColumns.keys()) { + const auto item = tableViewPrivate->loadedTableItem(QPoint(column, row))->item; + QCOMPARE(item->height(), expectedRowHeight); + } + } +} + +void tst_QQuickTableView::checkRowHeightProvider() +{ + // Check that you can assign a function to the columnWidthProvider property, and + // that it's used to control (and override) the width of the columns. + LOAD_TABLEVIEW("userowcolumnprovider.qml"); + + auto model = TestModelAsVariant(10, 10); + + tableView->setModel(model); + QVERIFY(tableView->rowHeightProvider().isCallable()); + + WAIT_UNTIL_POLISHED; + + for (auto fxItem : tableViewPrivate->loadedItems) { + // expectedWidth mirrors the expected return value of the assigned javascript function + qreal expectedHeight = fxItem->cell.y() + 10; + QCOMPARE(fxItem->item->height(), expectedHeight); + } +} + +void tst_QQuickTableView::checkRowHeightProviderInvalidReturnValues() +{ + // Check that we fall back to use default row heights, if you + // assign a function to rowHeightProvider that returns invalid values. + LOAD_TABLEVIEW("usefaultyrowcolumnprovider.qml"); + + auto model = TestModelAsVariant(10, 10); + + tableView->setModel(model); + + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*implicitHeight.*zero")); + + WAIT_UNTIL_POLISHED; + + for (auto fxItem : tableViewPrivate->loadedItems) + QCOMPARE(fxItem->item->height(), kDefaultRowHeight); +} + +void tst_QQuickTableView::checkRowHeightProviderNegativeReturnValue() +{ + // Check that we fall back to use the implicit height of the delegate + // items if the rowHeightProvider return a negative number. + LOAD_TABLEVIEW("userowcolumnprovider.qml"); + + auto model = TestModelAsVariant(10, 10); + view->rootObject()->setProperty("returnNegativeRowHeight", true); + + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + for (auto fxItem : tableViewPrivate->loadedItems) + QCOMPARE(fxItem->item->height(), 20); +} + +void tst_QQuickTableView::checkRowHeightProviderNotCallable() +{ + // Check that we fall back to use default row heights, if you + // assign something to rowHeightProvider that is not callable. + LOAD_TABLEVIEW("usefaultyrowcolumnprovider.qml"); + + auto model = TestModelAsVariant(10, 10); + + tableView->setModel(model); + + tableView->setColumnWidthProvider(QJSValue()); + tableView->setRowHeightProvider(QJSValue(10)); + + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Provider.*function")); + + WAIT_UNTIL_POLISHED; + + for (auto fxItem : tableViewPrivate->loadedItems) + QCOMPARE(fxItem->item->height(), kDefaultRowHeight); +} + +void tst_QQuickTableView::checkForceLayoutFunction() +{ + // When we set the 'columnWidths' property in the test file, the + // columnWidthProvider should return other values than it did during + // start-up. Check that this takes effect after a call to the 'forceLayout()' function. + LOAD_TABLEVIEW("forcelayout.qml"); + + const char *propertyName = "columnWidths"; + auto model = TestModelAsVariant(10, 10); + + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + // Check that the initial column widths are as specified in the QML file + const qreal initialColumnWidth = view->rootObject()->property(propertyName).toReal(); + for (auto fxItem : tableViewPrivate->loadedItems) + QCOMPARE(fxItem->item->width(), initialColumnWidth); + + // Change the return value from the columnWidthProvider to something else + const qreal newColumnWidth = 100; + view->rootObject()->setProperty(propertyName, newColumnWidth); + tableView->forceLayout(); + // We don't have to polish; The re-layout happens immediately + + for (auto fxItem : tableViewPrivate->loadedItems) + QCOMPARE(fxItem->item->width(), newColumnWidth); +} + +void tst_QQuickTableView::checkContentWidthAndHeight() +{ + // Check that contentWidth/Height reports the correct size of the the + // table, based on knowledge of the rows and columns that has been loaded. + LOAD_TABLEVIEW("contentwidthheight.qml"); + + // Vertical and horizontal properties should be mirrored, so we only have + // to do the calculations once, and use them for both axis, below. + QCOMPARE(tableView->width(), tableView->height()); + QCOMPARE(tableView->rowSpacing(), tableView->columnSpacing()); + + const int tableSize = 100; + const int cellSizeSmall = 100; + const int cellSizeLarge = 200; + const int spacing = 1; + const int smallCellCount = 20; + const int largeCellCount = tableSize - smallCellCount; + const qreal accumulatedSpacing = ((tableSize - 1) * spacing); + auto model = TestModelAsVariant(tableSize, tableSize); + + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + const qreal expectedSizeInit = (tableSize * cellSizeSmall) + ((tableSize - 1) * spacing); + QCOMPARE(tableView->contentWidth(), expectedSizeInit); + QCOMPARE(tableView->contentHeight(), expectedSizeInit); + QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellSizeSmall); + QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellSizeSmall); + + // Flick in 5 more rows and columns, but not so far that we start loading in + // the ones that are bigger. Loading in more rows and columns of the same + // size as the initial ones should not change the first prediction. + qreal flickTo = ((cellSizeSmall + spacing) * 5); + tableView->setContentX(flickTo); + tableView->setContentY(flickTo); + + QCOMPARE(tableView->contentWidth(), expectedSizeInit); + QCOMPARE(tableView->contentHeight(), expectedSizeInit); + QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellSizeSmall); + QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellSizeSmall); + + // Flick to row and column 20 (smallCellCount), since there the row and + // column sizes increases with 100. Check that TableView then adjusts + // contentWidth and contentHeight accordingly. + flickTo = ((cellSizeSmall + spacing) * smallCellCount) - spacing; + tableView->setContentX(flickTo); + tableView->setContentY(flickTo); + + // Since we move the viewport more than a page, tableview + // will jump to the new position and do a rebuild. + QVERIFY(tableViewPrivate->polishScheduled); + QVERIFY(tableViewPrivate->rebuildScheduled); + WAIT_UNTIL_POLISHED; + + // Check that the average cell size is now matching the + // large cells since they fill up the whole view. + QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellSizeLarge); + QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellSizeLarge); + + const int largeSizeCellCountInView = qCeil(tableView->width() / cellSizeLarge); + const int columnCount = smallCellCount + largeSizeCellCountInView; + QCOMPARE(tableViewPrivate->leftColumn(), smallCellCount); + QCOMPARE(tableViewPrivate->rightColumn(), columnCount - 1); + + const qreal firstHalfLength = smallCellCount * cellSizeSmall; + const qreal secondHalfOneScreenLength = largeSizeCellCountInView * cellSizeLarge; + const qreal lengthAfterFlick = firstHalfLength + secondHalfOneScreenLength; + + // Check that loadedTableOuterRect has been calculated correct thus far + const qreal spacingAfterFlick = (smallCellCount + largeSizeCellCountInView - 1) * spacing; + QCOMPARE(tableViewPrivate->loadedTableOuterRect.left(), flickTo + spacing); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.right(), lengthAfterFlick + spacingAfterFlick); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.top(), flickTo + spacing); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.bottom(), lengthAfterFlick + spacingAfterFlick); + + // At this point, we should have the exact content width/height set, because + // TableView knows where the large cells start in the viewport, and how many + // columns that remain in the model. It will assume that the rest of the the + // columns have the same average size as the ones currently inside the viewport. + const qreal expectedContentSize = (smallCellCount * cellSizeSmall) + (largeCellCount * cellSizeLarge) + accumulatedSpacing; + QCOMPARE(tableView->contentWidth(), expectedContentSize); + QCOMPARE(tableView->contentHeight(), expectedContentSize); + + // Flick to the end (row/column 100, and overshoot a bit), and + // check that we then end up with the exact content width/height. + const qreal secondHalfLength = largeCellCount * cellSizeLarge; + const qreal expectedFullSize = (firstHalfLength + secondHalfLength) + accumulatedSpacing; + const qreal overshoot = 100; + const qreal endPosX = expectedFullSize - tableView->width() + overshoot; + const qreal endPosY = expectedFullSize - tableView->height() + overshoot; + tableView->setContentX(endPosX); + tableView->setContentY(endPosY); + + QCOMPARE(tableView->contentWidth(), expectedFullSize); + QCOMPARE(tableView->contentHeight(), expectedFullSize); + + // Flick back to start + tableView->setContentX(0); + tableView->setContentY(0); + + // Since we move the viewport more than a page, tableview + // will jump to the new position and do a rebuild. + QVERIFY(tableViewPrivate->polishScheduled); + QVERIFY(tableViewPrivate->rebuildScheduled); + WAIT_UNTIL_POLISHED; + + // We should now have the same content width/height as when we started + QCOMPARE(tableView->contentWidth(), expectedSizeInit); + QCOMPARE(tableView->contentHeight(), expectedSizeInit); +} + +void tst_QQuickTableView::checkPageFlicking() +{ + // Check that we rebuild the table instead of refilling edges, if the viewport moves + // more than a page (the size of TableView). + LOAD_TABLEVIEW("plaintableview.qml"); + + const int cellWidth = 100; + const int cellHeight = 50; + auto model = TestModelAsVariant(10000, 10000); + const auto &loadedRows = tableViewPrivate->loadedRows; + const auto &loadedColumns = tableViewPrivate->loadedColumns; + + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + // Sanity check startup table + QCOMPARE(tableViewPrivate->topRow(), 0); + QCOMPARE(tableViewPrivate->leftColumn(), 0); + QCOMPARE(loadedRows.count(), tableView->height() / cellHeight); + QCOMPARE(loadedColumns.count(), tableView->width() / cellWidth); + + // Since all cells have the same size, the average row/column + // size found by TableView should be exactly equal to this. + QCOMPARE(tableViewPrivate->averageEdgeSize.width(), cellWidth); + QCOMPARE(tableViewPrivate->averageEdgeSize.height(), cellHeight); + + QVERIFY(!tableViewPrivate->rebuildScheduled); + QCOMPARE(tableViewPrivate->scheduledRebuildOptions, QQuickTableViewPrivate::RebuildOption::None); + + // Flick 5000 columns to the right, and check that this triggers a + // rebuild, and that we end up at the expected top-left. + const int flickToColumn = 5000; + const qreal columnSpacing = tableView->columnSpacing(); + const qreal flickToColumnInPixels = ((cellWidth + columnSpacing) * flickToColumn) - columnSpacing; + tableView->setContentX(flickToColumnInPixels); + + QVERIFY(tableViewPrivate->rebuildScheduled); + QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::ViewportOnly); + QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn); + QVERIFY(!(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow)); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->topRow(), 0); + QCOMPARE(tableViewPrivate->leftColumn(), flickToColumn); + QCOMPARE(loadedColumns.count(), tableView->width() / cellWidth); + QCOMPARE(loadedRows.count(), tableView->height() / cellHeight); + + // Flick 5000 rows down as well. Since flicking down should only calculate a new row (but + // keep the current column), we deliberatly change the average width to check that it's + // actually ignored by the rebuild, and that the column stays the same. + tableViewPrivate->averageEdgeSize.rwidth() /= 2; + + const int flickToRow = 5000; + const qreal rowSpacing = tableView->rowSpacing(); + const qreal flickToRowInPixels = ((cellHeight + rowSpacing) * flickToRow) - rowSpacing; + tableView->setContentY(flickToRowInPixels); + + QVERIFY(tableViewPrivate->rebuildScheduled); + QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::ViewportOnly); + QVERIFY(!(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn)); + QVERIFY(tableViewPrivate->scheduledRebuildOptions & QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->topRow(), flickToColumn); + QCOMPARE(tableViewPrivate->leftColumn(), flickToRow); + QCOMPARE(loadedRows.count(), tableView->height() / cellHeight); + QCOMPARE(loadedColumns.count(), tableView->width() / cellWidth); +} + +void tst_QQuickTableView::checkExplicitContentWidthAndHeight() +{ + // Check that you can set a custom contentWidth/Height, and that + // TableView doesn't override it while loading more rows and columns. + LOAD_TABLEVIEW("contentwidthheight.qml"); + + tableView->setContentWidth(1000); + tableView->setContentHeight(1000); + QCOMPARE(tableView->contentWidth(), 1000); + QCOMPARE(tableView->contentHeight(), 1000); + + auto model = TestModelAsVariant(100, 100); + tableView->setModel(model); + WAIT_UNTIL_POLISHED; + + // Flick somewhere. It should not affect the contentWidth/Height + tableView->setContentX(500); + tableView->setContentY(500); + QCOMPARE(tableView->contentWidth(), 1000); + QCOMPARE(tableView->contentHeight(), 1000); +} + +void tst_QQuickTableView::checkContentXY() +{ + // Check that you can bind contentX and contentY to + // e.g show the center of the table at start-up + LOAD_TABLEVIEW("setcontentpos.qml"); + + auto model = TestModelAsVariant(10, 10); + tableView->setModel(model); + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableView->width(), 400); + QCOMPARE(tableView->height(), 400); + QCOMPARE(tableView->contentWidth(), 1000); + QCOMPARE(tableView->contentHeight(), 1000); + + // Check that the content item is positioned according + // to the binding in the QML file (which will set the + // viewport to be at the center of the table). + const qreal expectedXY = (tableView->contentWidth() - tableView->width()) / 2; + QCOMPARE(tableView->contentX(), expectedXY); + QCOMPARE(tableView->contentY(), expectedXY); + + // Check that we end up at the correct top-left cell: + const qreal delegateWidth = tableViewPrivate->loadedItems.values().first()->item->width(); + const int expectedCellXY = qCeil(expectedXY / delegateWidth); + QCOMPARE(tableViewPrivate->leftColumn(), expectedCellXY); + QCOMPARE(tableViewPrivate->topRow(), expectedCellXY); +} + +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::changeDelegateDuringUpdate() +{ + // Check that you can change the delegate (set it to null) + // while the TableView is busy loading the table. + LOAD_TABLEVIEW("changemodelordelegateduringupdate.qml"); + + auto model = TestModelAsVariant(1, 1); + tableView->setModel(model); + view->rootObject()->setProperty("changeDelegate", true); + + WAIT_UNTIL_POLISHED; + + // We should no longer have a delegate, and no + // items should therefore be loaded. + QCOMPARE(tableView->delegate(), nullptr); + QCOMPARE(tableViewPrivate->loadedItems.size(), 0); + + // Even if the delegate is missing, we still report + // the correct size of the model + QCOMPARE(tableView->rows(), 1); + QCOMPARE(tableView->columns(), 1); +}; + +void tst_QQuickTableView::changeModelDuringUpdate() +{ + // Check that you can change the model (set it to null) + // while the TableView is buzy loading the table. + LOAD_TABLEVIEW("changemodelordelegateduringupdate.qml"); + + auto model = TestModelAsVariant(1, 1); + tableView->setModel(model); + view->rootObject()->setProperty("changeModel", true); + + WAIT_UNTIL_POLISHED; + + // We should no longer have a model, and the no + // items should therefore be loaded. + QVERIFY(tableView->model().isNull()); + QCOMPARE(tableViewPrivate->loadedItems.size(), 0); + + // The empty model has no rows or columns + QCOMPARE(tableView->rows(), 0); + QCOMPARE(tableView->columns(), 0); +}; + +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()); + + // Setting margins on Flickable should not affect the layout of the + // delegate items, since the margins is "transparent" to the TableView. + 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 = cell.x() * (expectedItemWidth + spacing.width()); + qreal expectedY = cell.y() * (expectedItemHeight + spacing.height()); + QCOMPARE(item->x(), expectedX); + QCOMPARE(item->y(), expectedY); + QCOMPARE(item->z(), 1); + QCOMPARE(item->width(), expectedItemWidth); + QCOMPARE(item->height(), expectedItemHeight); + } +} + +void tst_QQuickTableView::checkFocusRemoved_data() +{ + QTest::addColumn<QString>("focusedItemProp"); + + QTest::newRow("delegate root") << QStringLiteral("delegateRoot"); + QTest::newRow("delegate child") << QStringLiteral("delegateChild"); +} + +void tst_QQuickTableView::checkFocusRemoved() +{ + // Check that we clear the focus of a delegate item when + // a child of the delegate item has focus, and the cell is + // flicked out of view. + QFETCH(QString, focusedItemProp); + LOAD_TABLEVIEW("tableviewfocus.qml"); + + auto model = TestModelAsVariant(100, 100); + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + auto const item = tableViewPrivate->loadedTableItem(QPoint(0, 0))->item; + auto const focusedItem = qvariant_cast<QQuickItem *>(item->property(focusedItemProp.toUtf8().data())); + QVERIFY(focusedItem); + QCOMPARE(tableView->hasActiveFocus(), false); + QCOMPARE(focusedItem->hasActiveFocus(), false); + + focusedItem->forceActiveFocus(); + QCOMPARE(tableView->hasActiveFocus(), true); + QCOMPARE(focusedItem->hasActiveFocus(), true); + + // Flick the focused cell out, and check that none of the + // items in the table has focus (which means that the reused + // item lost focus when it was flicked out). But the tableview + // itself will maintain active focus. + tableView->setContentX(500); + QCOMPARE(tableView->hasActiveFocus(), true); + for (auto fxItem : tableViewPrivate->loadedItems) { + auto const focusedItem2 = qvariant_cast<QQuickItem *>(fxItem->item->property(focusedItemProp.toUtf8().data())); + QCOMPARE(focusedItem2->hasActiveFocus(), false); + } +} + +void tst_QQuickTableView::fillTableViewButNothingMore_data() +{ + QTest::addColumn<QSizeF>("spacing"); + + QTest::newRow("0 0,0 0") << QSizeF(0, 0); + QTest::newRow("0 10,10 0") << QSizeF(10, 10); + QTest::newRow("100 10,10 0") << QSizeF(10, 10); + QTest::newRow("0 0,0 100") << QSizeF(0, 0); + QTest::newRow("0 10,10 100") << QSizeF(10, 10); + QTest::newRow("100 10,10 100") << QSizeF(10, 10); +} + +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); + 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()); + + WAIT_UNTIL_POLISHED; + + auto const topLeftFxItem = tableViewPrivate->loadedTableItem(QPoint(0, 0)); + auto const topLeftItem = topLeftFxItem->item; + + auto const bottomRightLoadedCell = QPoint(tableViewPrivate->rightColumn(), tableViewPrivate->bottomRow()); + auto const bottomRightFxItem = tableViewPrivate->loadedTableItem(bottomRightLoadedCell); + 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(); + int expectedColumns = qCeil(tableView->width() / 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(); + int expectedRows = qCeil(tableView->height() / 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(); + + QCOMPARE(contextCell.y(), cell.y()); + QCOMPARE(contextCell.x(), cell.x()); + QCOMPARE(contextIndex, index); + QCOMPARE(contextModelData, QStringLiteral("%1").arg(cell.y())); + QCOMPARE(getAttachedObject(item)->view(), tableView); + } +} + +void tst_QQuickTableView::checkSpacingValues() +{ + LOAD_TABLEVIEW("tableviewdefaultspacing.qml"); + + int rowCount = 9; + int columnCount = 9; + int delegateWidth = 15; + int delegateHeight = 10; + auto model = TestModelAsVariant(rowCount, columnCount); + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + // Default spacing : 0 + QCOMPARE(tableView->rowSpacing(), 0); + QCOMPARE(tableView->columnSpacing(), 0); + + tableView->polish(); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->contentWidth(), columnCount * (delegateWidth + tableView->columnSpacing()) - tableView->columnSpacing()); + QCOMPARE(tableView->contentHeight(), rowCount * (delegateHeight + tableView->rowSpacing()) - tableView->rowSpacing()); + + // Valid spacing assignment + tableView->setRowSpacing(42); + tableView->setColumnSpacing(12); + QCOMPARE(tableView->rowSpacing(), 42); + QCOMPARE(tableView->columnSpacing(), 12); + + tableView->polish(); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->contentWidth(), columnCount * (delegateWidth + tableView->columnSpacing()) - tableView->columnSpacing()); + QCOMPARE(tableView->contentHeight(), rowCount * (delegateHeight + tableView->rowSpacing()) - tableView->rowSpacing()); + + // Invalid assignments (should ignore) + tableView->setRowSpacing(-1); + tableView->setColumnSpacing(-5); + tableView->setRowSpacing(INFINITY); + tableView->setColumnSpacing(INFINITY); + tableView->setRowSpacing(NAN); + tableView->setColumnSpacing(NAN); + QCOMPARE(tableView->rowSpacing(), 42); + QCOMPARE(tableView->columnSpacing(), 12); +} + +void tst_QQuickTableView::checkDelegateParent() +{ + // Check that TableView sets the delegate parent before + // bindings are evaluated, so that the app can bind to it. + LOAD_TABLEVIEW("plaintableview.qml"); + + auto model = TestModelAsVariant(100, 100); + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + QVERIFY(view->rootObject()->property("delegateParentSetBeforeCompleted").toBool()); +} + +void tst_QQuickTableView::flick_data() +{ + QTest::addColumn<QSizeF>("spacing"); + QTest::addColumn<QMarginsF>("margins"); + QTest::addColumn<bool>("reuseItems"); + + QTest::newRow("s:0 m:0 reuse") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0) << true; + QTest::newRow("s:5 m:0 reuse") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0) << true; + QTest::newRow("s:0 m:20 reuse") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20) << true; + QTest::newRow("s:5 m:20 reuse") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20) << true; + QTest::newRow("s:0 m:0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0) << false; + QTest::newRow("s:5 m:0") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0) << false; + QTest::newRow("s:0 m:20") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20) << false; + QTest::newRow("s:5 m:20") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20) << false; +} + +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); + QFETCH(bool, reuseItems); + 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->setReuseItems(reuseItems); + 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 int expectedTableLeft = int(cellsToFlick - int((margins.left() + spacing.width()) / cellWidth)); + const int expectedTableTop = int(cellsToFlick - int((margins.top() + spacing.height()) / cellHeight)); + + QCOMPARE(tableViewPrivate->leftColumn(), expectedTableLeft); + QCOMPARE(tableViewPrivate->rightColumn(), expectedTableLeft + visualColumnCount); + QCOMPARE(tableViewPrivate->topRow(), expectedTableTop); + QCOMPARE(tableViewPrivate->bottomRow(), expectedTableTop + visualRowCount); + } +} + +void tst_QQuickTableView::flickOvershoot_data() +{ + QTest::addColumn<QSizeF>("spacing"); + QTest::addColumn<QMarginsF>("margins"); + QTest::addColumn<bool>("reuseItems"); + + QTest::newRow("s:0 m:0 reuse") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0) << true; + QTest::newRow("s:5 m:0 reuse") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0) << true; + QTest::newRow("s:0 m:20 reuse") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20) << true; + QTest::newRow("s:5 m:20 reuse") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20) << true; + QTest::newRow("s:0 m:0") << QSizeF(0, 0) << QMarginsF(0, 0, 0, 0) << false; + QTest::newRow("s:5 m:0") << QSizeF(5, 5) << QMarginsF(0, 0, 0, 0) << false; + QTest::newRow("s:0 m:20") << QSizeF(0, 0) << QMarginsF(20, 20, 20, 20) << false; + QTest::newRow("s:5 m:20") << QSizeF(5, 5) << QMarginsF(20, 20, 20, 20) << false; +} + +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); + QFETCH(bool, reuseItems); + 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->setReuseItems(reuseItems); + 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->leftColumn(), 0); + QCOMPARE(tableViewPrivate->rightColumn(), 0); + QCOMPARE(tableViewPrivate->topRow(), 0); + QCOMPARE(tableViewPrivate->bottomRow(), rowCount - 1); + + // Flick table out of view right + tableView->setContentX(tableWidth + outsideMargin); + tableView->setContentY(0); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->leftColumn(), columnCount - 1); + QCOMPARE(tableViewPrivate->rightColumn(), columnCount - 1); + QCOMPARE(tableViewPrivate->topRow(), 0); + QCOMPARE(tableViewPrivate->bottomRow(), rowCount - 1); + + // Flick table out of view on top + tableView->setContentX(0); + tableView->setContentY(-tableView->height() - outsideMargin); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->leftColumn(), 0); + QCOMPARE(tableViewPrivate->rightColumn(), columnCount - 1); + QCOMPARE(tableViewPrivate->topRow(), 0); + QCOMPARE(tableViewPrivate->bottomRow(), 0); + + // Flick table out of view at the bottom + tableView->setContentX(0); + tableView->setContentY(tableHeight + outsideMargin); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->leftColumn(), 0); + QCOMPARE(tableViewPrivate->rightColumn(), columnCount - 1); + QCOMPARE(tableViewPrivate->topRow(), rowCount - 1); + QCOMPARE(tableViewPrivate->bottomRow(), 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->leftColumn(), 0); + QCOMPARE(tableViewPrivate->rightColumn(), 0); + QCOMPARE(tableViewPrivate->topRow(), 0); + QCOMPARE(tableViewPrivate->bottomRow(), 0); + + // Flick table back to origo + tableView->setContentX(0); + tableView->setContentY(0); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->leftColumn(), 0); + QCOMPARE(tableViewPrivate->rightColumn(), columnCount - 1); + QCOMPARE(tableViewPrivate->topRow(), 0); + QCOMPARE(tableViewPrivate->bottomRow(), 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->leftColumn(), columnCount - 1); + QCOMPARE(tableViewPrivate->rightColumn(), columnCount - 1); + QCOMPARE(tableViewPrivate->topRow(), rowCount - 1); + QCOMPARE(tableViewPrivate->bottomRow(), rowCount - 1); + + // Flick table back to origo + tableView->setContentX(0); + tableView->setContentY(0); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableViewPrivate->leftColumn(), 0); + QCOMPARE(tableViewPrivate->rightColumn(), columnCount - 1); + QCOMPARE(tableViewPrivate->topRow(), 0); + QCOMPARE(tableViewPrivate->bottomRow(), 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"; + const qreal delegateWidth = 100; + const qreal delegateHeight = 50; + auto model = TestModelAsVariant(100, 100); + const auto &loadedRows = tableViewPrivate->loadedRows; + const auto &loadedColumns = tableViewPrivate->loadedColumns; + + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + // We expect that the number of created items after start-up should match + //the size of the visible table, pluss one extra preloaded row and column. + const int qmlCountAfterInit = view->rootObject()->property(maxDelegateCountProp).toInt(); + const int expectedCount = (loadedColumns.count() + 1) * (loadedRows.count() + 1); + QCOMPARE(qmlCountAfterInit, expectedCount); + + // This test will keep track of the maximum number of delegate items TableView + // had to show at any point while flicking (in countingtableview.qml). Because + // of the geometries chosen for TableView and the delegate, only complete columns + // will be shown at start-up. + QVERIFY(loadedRows.count() > loadedColumns.count()); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.width(), tableView->width()); + QCOMPARE(tableViewPrivate->loadedTableOuterRect.height(), tableView->height()); + + // Flick half an item to the left+up, to force one extra column and row to load before we + // start. By doing so, we end up showing the maximum number of rows and columns that will + // ever be shown in the view. This will make things less complicated below, when checking + // how many items that end up visible while flicking. + tableView->setContentX(delegateWidth / 2); + tableView->setContentY(delegateHeight / 2); + const int qmlCountAfterFirstFlick = view->rootObject()->property(maxDelegateCountProp).toInt(); + + // Flick a long distance right + tableView->setContentX(tableView->width() * 2); + + const int qmlCountAfterLongFlick = view->rootObject()->property(maxDelegateCountProp).toInt(); + QCOMPARE(qmlCountAfterLongFlick, qmlCountAfterFirstFlick); + + // Flick a long distance down + tableView->setContentX(tableView->height() * 2); + + const int qmlCountAfterDownFlick = view->rootObject()->property(maxDelegateCountProp).toInt(); + QCOMPARE(qmlCountAfterDownFlick, qmlCountAfterFirstFlick); + + // Flick a long distance left + tableView->setContentX(0); + + const int qmlCountAfterLeftFlick = view->rootObject()->property(maxDelegateCountProp).toInt(); + QCOMPARE(qmlCountAfterLeftFlick, qmlCountAfterFirstFlick); + + // Flick a long distance up + tableView->setContentY(0); + + const int qmlCountAfterUpFlick = view->rootObject()->property(maxDelegateCountProp).toInt(); + QCOMPARE(qmlCountAfterUpFlick, qmlCountAfterFirstFlick); +} + +void tst_QQuickTableView::modelSignals() +{ + LOAD_TABLEVIEW("plaintableview.qml"); + + TestModel model(1, 1); + tableView->setModel(QVariant::fromValue(&model)); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 1); + QCOMPARE(tableView->columns(), 1); + + QVERIFY(model.insertRows(0, 1)); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 2); + QCOMPARE(tableView->columns(), 1); + + QVERIFY(model.removeRows(1, 1)); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 1); + QCOMPARE(tableView->columns(), 1); + + model.insertColumns(1, 1); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 1); + QCOMPARE(tableView->columns(), 2); + + model.removeColumns(1, 1); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 1); + QCOMPARE(tableView->columns(), 1); + + model.setRowCount(10); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 10); + QCOMPARE(tableView->columns(), 1); + + model.setColumnCount(10); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 10); + QCOMPARE(tableView->columns(), 10); + + model.setRowCount(0); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 0); + QCOMPARE(tableView->columns(), 10); + + model.setColumnCount(1); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 0); + QCOMPARE(tableView->columns(), 1); + + model.setRowCount(10); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 10); + QCOMPARE(tableView->columns(), 1); + + model.setColumnCount(10); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 10); + QCOMPARE(tableView->columns(), 10); + + model.clear(); + model.setColumnCount(1); + WAIT_UNTIL_POLISHED; + QCOMPARE(tableView->rows(), 0); + QCOMPARE(tableView->columns(), 1); +} + +void tst_QQuickTableView::checkModelSignalsUpdateLayout() +{ + // Check that if the model rearranges rows and emit the + // 'layoutChanged' signal, TableView will be updated correctly. + LOAD_TABLEVIEW("plaintableview.qml"); + + TestModel model(0, 1); + tableView->setModel(QVariant::fromValue(&model)); + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableView->rows(), 0); + QCOMPARE(tableView->columns(), 1); + + QString modelRow1Text = QStringLiteral("firstRow"); + QString modelRow2Text = QStringLiteral("secondRow"); + model.insertRow(0); + model.insertRow(0); + model.setModelData(QPoint(0, 0), QSize(1, 1), modelRow1Text); + model.setModelData(QPoint(0, 1), QSize(1, 1), modelRow2Text); + WAIT_UNTIL_POLISHED; + + QCOMPARE(tableView->rows(), 2); + QCOMPARE(tableView->columns(), 1); + + QString delegate1text = tableViewPrivate->loadedTableItem(QPoint(0, 0))->item->property("modelDataBinding").toString(); + QString delegate2text = tableViewPrivate->loadedTableItem(QPoint(0, 1))->item->property("modelDataBinding").toString(); + QCOMPARE(delegate1text, modelRow1Text); + QCOMPARE(delegate2text, modelRow2Text); + + model.swapRows(0, 1); + WAIT_UNTIL_POLISHED; + + delegate1text = tableViewPrivate->loadedTableItem(QPoint(0, 0))->item->property("modelDataBinding").toString(); + delegate2text = tableViewPrivate->loadedTableItem(QPoint(0, 1))->item->property("modelDataBinding").toString(); + QCOMPARE(delegate1text, modelRow2Text); + QCOMPARE(delegate2text, modelRow1Text); +} + +void tst_QQuickTableView::dataChangedSignal() +{ + // Check that bindings to the model inside a delegate gets updated + // when the model item they bind to changes. + LOAD_TABLEVIEW("plaintableview.qml"); + + const QString prefix(QStringLiteral("changed")); + + TestModel model(10, 10); + tableView->setModel(QVariant::fromValue(&model)); + + WAIT_UNTIL_POLISHED; + + for (auto fxItem : tableViewPrivate->loadedItems) { + const auto item = tableViewPrivate->loadedTableItem(fxItem->cell)->item; + const QString modelDataBindingProperty = item->property(kModelDataBindingProp).toString(); + QString expectedModelData = QString::number(fxItem->cell.y()); + QCOMPARE(modelDataBindingProperty, expectedModelData); + } + + // Change one cell in the model + model.setModelData(QPoint(0, 0), QSize(1, 1), prefix); + + for (auto fxItem : tableViewPrivate->loadedItems) { + const QPoint cell = fxItem->cell; + const auto modelIndex = model.index(cell.y(), cell.x()); + QString expectedModelData = model.data(modelIndex, Qt::DisplayRole).toString(); + + const auto item = tableViewPrivate->loadedTableItem(fxItem->cell)->item; + const QString modelDataBindingProperty = item->property(kModelDataBindingProp).toString(); + + QCOMPARE(modelDataBindingProperty, expectedModelData); + } + + // Change four cells in one go + model.setModelData(QPoint(1, 0), QSize(2, 2), prefix); + + for (auto fxItem : tableViewPrivate->loadedItems) { + const QPoint cell = fxItem->cell; + const auto modelIndex = model.index(cell.y(), cell.x()); + QString expectedModelData = model.data(modelIndex, Qt::DisplayRole).toString(); + + const auto item = tableViewPrivate->loadedTableItem(fxItem->cell)->item; + const QString modelDataBindingProperty = item->property(kModelDataBindingProp).toString(); + + QCOMPARE(modelDataBindingProperty, expectedModelData); + } +} + +void tst_QQuickTableView::checkThatPoolIsDrainedWhenReuseIsFalse() +{ + // Check that the reuse pool is drained + // immediately when setting reuseItems to false. + LOAD_TABLEVIEW("countingtableview.qml"); + + auto model = TestModelAsVariant(100, 100); + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + // The pool should now contain preloaded items + QVERIFY(tableViewPrivate->tableModel->poolSize() > 0); + tableView->setReuseItems(false); + // The pool should now be empty + QCOMPARE(tableViewPrivate->tableModel->poolSize(), 0); +} + +void tst_QQuickTableView::checkIfDelegatesAreReused_data() +{ + QTest::addColumn<bool>("reuseItems"); + + QTest::newRow("reuse = true") << true; + QTest::newRow("reuse = false") << false; +} + +void tst_QQuickTableView::checkIfDelegatesAreReused() +{ + // Check that we end up reusing delegate items while flicking if + // TableView has reuseItems set to true, but otherwise not. + QFETCH(bool, reuseItems); + LOAD_TABLEVIEW("countingtableview.qml"); + + const qreal delegateWidth = 100; + const qreal delegateHeight = 50; + const int pageFlickCount = 4; + + auto model = TestModelAsVariant(100, 100); + tableView->setModel(model); + tableView->setReuseItems(reuseItems); + + WAIT_UNTIL_POLISHED; + + // Flick half an item to the side, to force one extra row and column to load before we start. + // This will make things less complicated below, when checking how many times the items + // have been reused (all items will then report the same number). + tableView->setContentX(delegateWidth / 2); + tableView->setContentY(delegateHeight / 2); + QCOMPARE(tableViewPrivate->tableModel->poolSize(), 0); + + // Some items have already been pooled and reused after we moved the content view, because + // we preload one extra row and column at start-up. So reset the count-properties back to 0 + // before we continue. + for (auto fxItem : tableViewPrivate->loadedItems) { + fxItem->item->setProperty("pooledCount", 0); + fxItem->item->setProperty("reusedCount", 0); + } + + const int visibleColumnCount = tableViewPrivate->loadedColumns.count(); + const int visibleRowCount = tableViewPrivate->loadedRows.count(); + const int delegateCountAfterInit = view->rootObject()->property(kDelegatesCreatedCountProp).toInt(); + + for (int column = 1; column <= (visibleColumnCount * pageFlickCount); ++column) { + // Flick columns to the left (and add one pixel to ensure the left column is completely out) + tableView->setContentX((delegateWidth * column) + 1); + // Check that the number of delegate items created so far is what we expect. + const int delegatesCreatedCount = view->rootObject()->property(kDelegatesCreatedCountProp).toInt(); + int expectedCount = delegateCountAfterInit + (reuseItems ? 0 : visibleRowCount * column); + QCOMPARE(delegatesCreatedCount, expectedCount); + } + + // Check that each delegate item has been reused as many times + // as we have flicked pages (if reuse is enabled). + for (auto fxItem : tableViewPrivate->loadedItems) { + int pooledCount = fxItem->item->property("pooledCount").toInt(); + int reusedCount = fxItem->item->property("reusedCount").toInt(); + if (reuseItems) { + QCOMPARE(pooledCount, pageFlickCount); + QCOMPARE(reusedCount, pageFlickCount); + } else { + QCOMPARE(pooledCount, 0); + QCOMPARE(reusedCount, 0); + } + } +} + +void tst_QQuickTableView::checkIfDelegatesAreReusedAsymmetricTableSize() +{ + // Check that we end up reusing all delegate items while flicking, also if the table contain + // more columns than rows. In that case, if we flick out a whole row, we'll move a lot of + // items into the pool. And if we then start flicking in columns, we'll only reuse a few of + // them for each column. Still, we don't want the pool to release the superfluous items after + // each load, since they are still in circulation and will be needed once we flick in a new + // row at the end of the test. + LOAD_TABLEVIEW("countingtableview.qml"); + + const int columnCount = 20; + const int rowCount = 2; + const qreal delegateWidth = tableView->width() / columnCount; + const qreal delegateHeight = (tableView->height() / rowCount) + 10; + + auto model = TestModelAsVariant(100, 100); + tableView->setModel(model); + + // Let the height of each row be much bigger than the width of each column. + view->rootObject()->setProperty("delegateWidth", delegateWidth); + view->rootObject()->setProperty("delegateHeight", delegateHeight); + + WAIT_UNTIL_POLISHED; + + auto initialTopLeftItem = tableViewPrivate->loadedTableItem(QPoint(0, 0))->item; + QVERIFY(initialTopLeftItem); + int pooledCount = initialTopLeftItem->property("pooledCount").toInt(); + int reusedCount = initialTopLeftItem->property("reusedCount").toInt(); + QCOMPARE(pooledCount, 0); + QCOMPARE(reusedCount, 0); + + // Flick half an item left+down, to force one extra row and column to load. By doing + // so, we force the maximum number of rows and columns to show before we start the test. + // This will make things less complicated below, when checking how many + // times the items have been reused (all items will then report the same number). + tableView->setContentX(delegateWidth * 0.5); + tableView->setContentY(delegateHeight * 0.5); + + // Since we have flicked half a delegate to the left, the number of visible + // columns is now one more than the column count were when we started the test. + const int visibleColumnCount = tableViewPrivate->loadedColumns.count(); + QCOMPARE(visibleColumnCount, columnCount + 1); + + // We expect no items to have been pooled so far + pooledCount = initialTopLeftItem->property("pooledCount").toInt(); + reusedCount = initialTopLeftItem->property("reusedCount").toInt(); + QCOMPARE(pooledCount, 0); + QCOMPARE(reusedCount, 0); + QCOMPARE(tableViewPrivate->tableModel->poolSize(), 0); + + // Flick one row out of view. This will move one whole row of items into the + // pool without reusing them, since no new row is exposed at the bottom. + tableView->setContentY(delegateHeight + 1); + pooledCount = initialTopLeftItem->property("pooledCount").toInt(); + reusedCount = initialTopLeftItem->property("reusedCount").toInt(); + QCOMPARE(pooledCount, 1); + QCOMPARE(reusedCount, 0); + QCOMPARE(tableViewPrivate->tableModel->poolSize(), visibleColumnCount); + + const int delegateCountAfterInit = view->rootObject()->property(kDelegatesCreatedCountProp).toInt(); + + // Start flicking in a lot of columns, and check that the created count stays the same + for (int column = 1; column <= 10; ++column) { + tableView->setContentX((delegateWidth * column) + 10); + const int delegatesCreatedCount = view->rootObject()->property(kDelegatesCreatedCountProp).toInt(); + // Since we reuse items while flicking, the created count should stay the same + QCOMPARE(delegatesCreatedCount, delegateCountAfterInit); + // Since we flick out just as many columns as we flick in, the pool size should stay the same + QCOMPARE(tableViewPrivate->tableModel->poolSize(), visibleColumnCount); + } + + // Finally, flick one row back into view (but without flicking so far that we push the third + // row out and into the pool). The pool should still contain the exact amount of items that + // we had after we flicked the first row out. And this should be exactly the amount of items + // needed to load the row back again. And this also means that the pool count should then return + // back to 0. + tableView->setContentY(delegateHeight - 1); + const int delegatesCreatedCount = view->rootObject()->property(kDelegatesCreatedCountProp).toInt(); + QCOMPARE(delegatesCreatedCount, delegateCountAfterInit); + QCOMPARE(tableViewPrivate->tableModel->poolSize(), 0); +} + +void tst_QQuickTableView::checkContextProperties_data() +{ + QTest::addColumn<QVariant>("model"); + QTest::addColumn<bool>("reuseItems"); + + auto stringList = QStringList(); + for (int i = 0; i < 100; ++i) + stringList.append(QString::number(i)); + + QTest::newRow("QAIM, reuse=false") << TestModelAsVariant(100, 100) << false; + QTest::newRow("QAIM, reuse=true") << TestModelAsVariant(100, 100) << true; + QTest::newRow("Number model, reuse=false") << QVariant::fromValue(100) << false; + QTest::newRow("Number model, reuse=true") << QVariant::fromValue(100) << true; + QTest::newRow("QStringList, reuse=false") << QVariant::fromValue(stringList) << false; + QTest::newRow("QStringList, reuse=true") << QVariant::fromValue(stringList) << true; +} + +void tst_QQuickTableView::checkContextProperties() +{ + // Check that the context properties of the delegate items + // are what we expect while flicking, with or without item recycling. + QFETCH(QVariant, model); + QFETCH(bool, reuseItems); + LOAD_TABLEVIEW("countingtableview.qml"); + + const qreal delegateWidth = 100; + const qreal delegateHeight = 50; + const int rowCount = 100; + const int pageFlickCount = 3; + + tableView->setModel(model); + tableView->setReuseItems(reuseItems); + + WAIT_UNTIL_POLISHED; + + const int visibleRowCount = qMin(tableView->rows(), qCeil(tableView->height() / delegateHeight)); + const int visibleColumnCount = qMin(tableView->columns(), qCeil(tableView->width() / delegateWidth)); + + for (int row = 1; row <= (visibleRowCount * pageFlickCount); ++row) { + // Flick rows up + tableView->setContentY((delegateHeight * row) + (delegateHeight / 2)); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + for (int col = 0; col < visibleColumnCount; ++col) { + const auto item = tableViewPrivate->loadedTableItem(QPoint(col, row))->item; + const auto context = qmlContext(item.data()); + const int contextIndex = context->contextProperty("index").toInt(); + const int contextRow = context->contextProperty("row").toInt(); + const int contextColumn = context->contextProperty("column").toInt(); + const QString contextModelData = context->contextProperty("modelData").toString(); + + QCOMPARE(contextIndex, row + (col * rowCount)); + QCOMPARE(contextRow, row); + QCOMPARE(contextColumn, col); + QCOMPARE(contextModelData, QStringLiteral("%1").arg(row)); + } + } +} + +void tst_QQuickTableView::checkContextPropertiesQQmlListProperyModel_data() +{ + QTest::addColumn<bool>("reuseItems"); + + QTest::newRow("reuse=false") << false; + QTest::newRow("reuse=true") << true; +} + +void tst_QQuickTableView::checkContextPropertiesQQmlListProperyModel() +{ + // Check that the context properties of the delegate items + // are what we expect while flicking, with or without item recycling. + // This test hard-codes the model to be a QQmlListPropertyModel from + // within the qml file. + QFETCH(bool, reuseItems); + LOAD_TABLEVIEW("qqmllistpropertymodel.qml"); + + const qreal delegateWidth = 100; + const qreal delegateHeight = 50; + const int rowCount = 100; + const int pageFlickCount = 3; + + tableView->setReuseItems(reuseItems); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + const int visibleRowCount = qMin(tableView->rows(), qCeil(tableView->height() / delegateHeight)); + const int visibleColumnCount = qMin(tableView->columns(), qCeil(tableView->width() / delegateWidth)); + + for (int row = 1; row <= (visibleRowCount * pageFlickCount); ++row) { + // Flick rows up + tableView->setContentY((delegateHeight * row) + (delegateHeight / 2)); + tableView->polish(); + + WAIT_UNTIL_POLISHED; + + for (int col = 0; col < visibleColumnCount; ++col) { + const auto item = tableViewPrivate->loadedTableItem(QPoint(col, row))->item; + const auto context = qmlContext(item.data()); + const int contextIndex = context->contextProperty("index").toInt(); + const int contextRow = context->contextProperty("row").toInt(); + const int contextColumn = context->contextProperty("column").toInt(); + const QObject *contextModelData = qvariant_cast<QObject *>(context->contextProperty("modelData")); + const QString modelDataProperty = contextModelData->property("someCustomProperty").toString(); + + QCOMPARE(contextIndex, row + (col * rowCount)); + QCOMPARE(contextRow, row); + QCOMPARE(contextColumn, col); + QCOMPARE(modelDataProperty, QStringLiteral("%1").arg(row)); + } + } +} + +void tst_QQuickTableView::checkRowAndColumnChangedButNotIndex() +{ + // Check that context row and column changes even if the index stays the + // same when the item is reused. This can happen in rare cases if the item + // is first used at e.g (row 1, col 0), but then reused at (row 0, col 1) + // while the model has changed row count in-between. + LOAD_TABLEVIEW("checkrowandcolumnnotchanged.qml"); + + TestModel model(2, 1); + tableView->setModel(QVariant::fromValue(&model)); + + WAIT_UNTIL_POLISHED; + + model.removeRow(1); + model.insertColumn(1); + tableView->forceLayout(); + + const auto item = tableViewPrivate->loadedTableItem(QPoint(1, 0))->item; + const auto context = qmlContext(item.data()); + const int contextIndex = context->contextProperty("index").toInt(); + const int contextRow = context->contextProperty("row").toInt(); + const int contextColumn = context->contextProperty("column").toInt(); + + QCOMPARE(contextIndex, 1); + QCOMPARE(contextRow, 0); + QCOMPARE(contextColumn, 1); +} + +void tst_QQuickTableView::checkChangingModelFromDelegate() +{ + // Check that we don't restart a rebuild of the table + // while we're in the middle of rebuilding it from before + LOAD_TABLEVIEW("changemodelfromdelegate.qml"); + + // Set addRowFromDelegate. This will trigger the QML code to add a new + // row and call forceLayout(). When TableView instantiates the first + // delegate in the new row, the Component.onCompleted handler will try to + // add a new row. But since we're currently rebuilding, this should be + // scheduled for later. + view->rootObject()->setProperty("addRowFromDelegate", true); + + // We now expect two rows in the table, one more than initially + QCOMPARE(tableViewPrivate->tableSize.height(), 2); + QCOMPARE(tableViewPrivate->loadedRows.count(), 2); + + // And since the QML code tried to add another row as well, we + // expect rebuildScheduled to be true, and a polish event to be pending. + QCOMPARE(tableViewPrivate->rebuildScheduled, true); + QCOMPARE(tableViewPrivate->polishScheduled, true); + WAIT_UNTIL_POLISHED; + + // After handling the polish event, we expect also the third row to now be added + QCOMPARE(tableViewPrivate->tableSize.height(), 3); + QCOMPARE(tableViewPrivate->loadedRows.count(), 3); +} + +void tst_QQuickTableView::checkRebuildViewportOnly() +{ + // Check that we only rebuild from the current top-left cell + // when you add or remove rows and columns. There should be + // no need to do a rebuild from scratch in such cases. + LOAD_TABLEVIEW("countingtableview.qml"); + + const char *propName = "delegatesCreatedCount"; + const qreal delegateWidth = 100; + const qreal delegateHeight = 50; + + TestModel model(100, 100); + tableView->setModel(QVariant::fromValue(&model)); + + WAIT_UNTIL_POLISHED; + + // Flick to row/column 50, 50 + tableView->setContentX(delegateWidth * 50); + tableView->setContentY(delegateHeight * 50); + + // Set reuse items to false, just to make it easier to + // check the number of items created during a rebuild. + tableView->setReuseItems(false); + const int itemCountBeforeRebuild = tableViewPrivate->loadedItems.count(); + + // Since all cells have the same size, we expect that we end up creating + // the same amount of items that were already showing before, even after + // adding or removing rows and columns. + view->rootObject()->setProperty(propName, 0); + model.insertRow(51); + WAIT_UNTIL_POLISHED; + int countAfterRebuild = view->rootObject()->property(propName).toInt(); + QCOMPARE(countAfterRebuild, itemCountBeforeRebuild); + + view->rootObject()->setProperty(propName, 0); + model.removeRow(51); + WAIT_UNTIL_POLISHED; + countAfterRebuild = view->rootObject()->property(propName).toInt(); + QCOMPARE(countAfterRebuild, itemCountBeforeRebuild); + + view->rootObject()->setProperty(propName, 0); + model.insertColumn(51); + WAIT_UNTIL_POLISHED; + countAfterRebuild = view->rootObject()->property(propName).toInt(); + QCOMPARE(countAfterRebuild, itemCountBeforeRebuild); + + view->rootObject()->setProperty(propName, 0); + model.removeColumn(51); + WAIT_UNTIL_POLISHED; + countAfterRebuild = view->rootObject()->property(propName).toInt(); + QCOMPARE(countAfterRebuild, itemCountBeforeRebuild); +} + +void tst_QQuickTableView::useDelegateChooserWithoutDefault() +{ + // Check that the application issues a warning (but doesn't e.g + // crash) if the delegate chooser doesn't cover all cells + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*failed")); + LOAD_TABLEVIEW("usechooserwithoutdefault.qml"); + auto model = TestModelAsVariant(2, 1); + tableView->setModel(model); + WAIT_UNTIL_POLISHED; +}; + +void tst_QQuickTableView::checkTableviewInsideAsyncLoader() +{ + // Check that you can put a TableView inside an async Loader, and + // that the delegate items are created before the loader is ready. + LOAD_TABLEVIEW_ASYNC("asyncplain.qml"); + + // At this point the Loader has finished + QCOMPARE(loader->status(), QQuickLoader::Ready); + + // Check that TableView has finished building + QCOMPARE(tableViewPrivate->rebuildScheduled, false); + QCOMPARE(tableViewPrivate->rebuildState, QQuickTableViewPrivate::RebuildState::Done); + + // Check that all expected delegate items have been loaded + const qreal delegateWidth = 100; + const qreal delegateHeight = 50; + int expectedColumns = qCeil(tableView->width() / delegateWidth); + int expectedRows = qCeil(tableView->height() / delegateHeight); + QCOMPARE(tableViewPrivate->loadedColumns.count(), expectedColumns); + QCOMPARE(tableViewPrivate->loadedRows.count(), expectedRows); + + // Check that the loader was still in a loading state while TableView was creating + // delegate items. If we delayed creating delegate items until we got the first + // updatePolish() callback in QQuickTableView, this would not be the case. + auto statusWhenDelegate0_0Completed = qvariant_cast<QQuickLoader::Status>( + loader->item()->property("statusWhenDelegate0_0Created")); + auto statusWhenDelegate5_5Completed = qvariant_cast<QQuickLoader::Status>( + loader->item()->property("statusWhenDelegate5_5Created")); + QCOMPARE(statusWhenDelegate0_0Completed, QQuickLoader::Loading); + QCOMPARE(statusWhenDelegate5_5Completed, QQuickLoader::Loading); + + // Check that TableView had a valid geometry when we started to build. If the build + // was started too early (e.g upon QQuickTableView::componentComplete), width and + // height would still be 0 since the bindings would not have been evaluated yet. + qreal width = loader->item()->property("tableViewWidthWhileBuilding").toReal(); + qreal height = loader->item()->property("tableViewHeightWhileBuilding").toReal(); + QVERIFY(width > 0); + QVERIFY(height > 0); +}; + +#define INT_LIST(indices) QVariant::fromValue(QList<int>() << indices) + +void tst_QQuickTableView::hideRowsAndColumns_data() +{ + QTest::addColumn<QVariant>("rowsToHide"); + QTest::addColumn<QVariant>("columnsToHide"); + + const auto emptyList = QVariant::fromValue(QList<int>()); + + // Hide rows + QTest::newRow("first") << INT_LIST(0) << emptyList; + QTest::newRow("middle 1") << INT_LIST(1) << emptyList; + QTest::newRow("middle 3") << INT_LIST(3) << emptyList; + QTest::newRow("last") << INT_LIST(4) << emptyList; + + QTest::newRow("subsequent 0,1") << INT_LIST(0 << 1) << emptyList; + QTest::newRow("subsequent 1,2") << INT_LIST(1 << 2) << emptyList; + QTest::newRow("subsequent 3,4") << INT_LIST(3 << 4) << emptyList; + + QTest::newRow("all but first") << INT_LIST(1 << 2 << 3 << 4) << emptyList; + QTest::newRow("all but last") << INT_LIST(0 << 1 << 2 << 3) << emptyList; + QTest::newRow("all but middle") << INT_LIST(0 << 1 << 3 << 4) << emptyList; + + // Hide columns + QTest::newRow("first") << emptyList << INT_LIST(0); + QTest::newRow("middle 1") << emptyList << INT_LIST(1); + QTest::newRow("middle 3") << emptyList << INT_LIST(3); + QTest::newRow("last") << emptyList << INT_LIST(4); + + QTest::newRow("subsequent 0,1") << emptyList << INT_LIST(0 << 1); + QTest::newRow("subsequent 1,2") << emptyList << INT_LIST(1 << 2); + QTest::newRow("subsequent 3,4") << emptyList << INT_LIST(3 << 4); + + QTest::newRow("all but first") << emptyList << INT_LIST(1 << 2 << 3 << 4); + QTest::newRow("all but last") << emptyList << INT_LIST(0 << 1 << 2 << 3); + QTest::newRow("all but middle") << emptyList << INT_LIST(0 << 1 << 3 << 4); + + // Hide both rows and columns at the same time + QTest::newRow("first") << INT_LIST(0) << INT_LIST(0); + QTest::newRow("middle 1") << INT_LIST(1) << INT_LIST(1); + QTest::newRow("middle 3") << INT_LIST(3) << INT_LIST(3); + QTest::newRow("last") << INT_LIST(4) << INT_LIST(4); + + QTest::newRow("subsequent 0,1") << INT_LIST(0 << 1) << INT_LIST(0 << 1); + QTest::newRow("subsequent 1,2") << INT_LIST(1 << 2) << INT_LIST(1 << 2); + QTest::newRow("subsequent 3,4") << INT_LIST(3 << 4) << INT_LIST(3 << 4); + + QTest::newRow("all but first") << INT_LIST(1 << 2 << 3 << 4) << INT_LIST(1 << 2 << 3 << 4); + QTest::newRow("all but last") << INT_LIST(0 << 1 << 2 << 3) << INT_LIST(0 << 1 << 2 << 3); + QTest::newRow("all but middle") << INT_LIST(0 << 1 << 3 << 4) << INT_LIST(0 << 1 << 3 << 4); + + // Hide all rows and columns + QTest::newRow("all") << INT_LIST(0 << 1 << 2 << 3 << 4) << INT_LIST(0 << 1 << 2 << 3 << 4); +} + +void tst_QQuickTableView::hideRowsAndColumns() +{ + // Check that you can hide the first row (corner case) + // and that we load the other columns as expected. + QFETCH(QVariant, rowsToHide); + QFETCH(QVariant, columnsToHide); + LOAD_TABLEVIEW("hiderowsandcolumns.qml"); + + const QList<int> rowsToHideList = qvariant_cast<QList<int>>(rowsToHide); + const QList<int> columnsToHideList = qvariant_cast<QList<int>>(columnsToHide); + const int modelSize = 5; + auto model = TestModelAsVariant(modelSize, modelSize); + view->rootObject()->setProperty("rowsToHide", rowsToHide); + view->rootObject()->setProperty("columnsToHide", columnsToHide); + + tableView->setModel(model); + + WAIT_UNTIL_POLISHED; + + const int expectedRowCount = modelSize - rowsToHideList.count(); + const int expectedColumnCount = modelSize - columnsToHideList.count(); + QCOMPARE(tableViewPrivate->loadedRows.count(), expectedRowCount); + QCOMPARE(tableViewPrivate->loadedColumns.count(), expectedColumnCount); + + for (const int row : tableViewPrivate->loadedRows.keys()) + QVERIFY(!rowsToHideList.contains(row)); + + for (const int column : tableViewPrivate->loadedColumns.keys()) + QVERIFY(!columnsToHideList.contains(column)); +} + +void tst_QQuickTableView::checkThatRevisionedPropertiesCannotBeUsedInOldImports() +{ + // Check that if you use a QQmlAdaptorModel together with a Repeater, the + // revisioned context properties 'row' and 'column' are not accessible. + LOAD_TABLEVIEW("checkmodelpropertyrevision.qml"); + const int resolvedRow = view->rootObject()->property("resolvedDelegateRow").toInt(); + const int resolvedColumn = view->rootObject()->property("resolvedDelegateColumn").toInt(); + QCOMPARE(resolvedRow, 42); + QCOMPARE(resolvedColumn, 42); +} + +QTEST_MAIN(tst_QQuickTableView) + +#include "tst_qquicktableview.moc" diff --git a/tests/auto/quick/qquicktext/data/contentHeight.qml b/tests/auto/quick/qquicktext/data/contentHeight.qml new file mode 100644 index 0000000000..472e97078e --- /dev/null +++ b/tests/auto/quick/qquicktext/data/contentHeight.qml @@ -0,0 +1,7 @@ +import QtQuick 2.9 + +Text{ + width: 200 + height: contentHeight + text: '' +} diff --git a/tests/auto/quick/qquicktext/data/elideParentChanged.qml b/tests/auto/quick/qquicktext/data/elideParentChanged.qml new file mode 100644 index 0000000000..f605cf58f1 --- /dev/null +++ b/tests/auto/quick/qquicktext/data/elideParentChanged.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Item { + width: 100 + height: 30 + + Text { + width: parent ? parent.width : 0 + height: parent ? parent.height : 0 + elide: Text.ElideRight + text: "wot" + } +} 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/qquicktext.pro b/tests/auto/quick/qquicktext/qquicktext.pro index 4f4b77ed7b..fdea9dcddd 100644 --- a/tests/auto/quick/qquicktext/qquicktext.pro +++ b/tests/auto/quick/qquicktext/qquicktext.pro @@ -4,7 +4,6 @@ macx:CONFIG -= app_bundle SOURCES += tst_qquicktext.cpp -INCLUDEPATH += ../../shared/ HEADERS += ../../shared/testhttpserver.h SOURCES += ../../shared/testhttpserver.cpp @@ -12,4 +11,4 @@ include (../../shared/util.pri) TESTDATA = data/* -QT += core-private gui-private qml-private quick-private network testlib +QT += core-private gui-private qml-private quick-private network testlib qmltest diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index f741062d42..fd0ba0f49b 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -32,12 +32,14 @@ #include <QtQml/qqmlcomponent.h> #include <QtQuick/private/qquicktext_p.h> #include <QtQuick/private/qquickmousearea_p.h> +#include <QtQuickTest/QtQuickTest> #include <private/qquicktext_p_p.h> #include <private/qquicktextdocument_p.h> #include <private/qquickvaluetypes_p.h> #include <QFontMetrics> #include <qmath.h> #include <QtQuick/QQuickView> +#include <QtQuick/qquickitemgrabresult.h> #include <private/qguiapplication_p.h> #include <limits.h> #include <QtGui/QMouseEvent> @@ -64,6 +66,7 @@ private slots: void width(); void wrap(); void elide(); + void elideParentChanged(); void multilineElide_data(); void multilineElide(); void implicitElide_data(); @@ -103,6 +106,7 @@ private slots: void implicitSize_data(); void implicitSize(); + void implicitSizeChangeRewrap(); void dependentImplicitSizes(); void contentSize(); void implicitSizeBinding_data(); @@ -156,6 +160,8 @@ private slots: void fontInfo(); + void initialContentHeight(); + private: QStringList standard; QStringList richText; @@ -238,7 +244,7 @@ tst_qquicktext::tst_qquicktext() QQuickView *tst_qquicktext::createView(const QString &filename) { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setSource(QUrl::fromLocalFile(filename)); return window; @@ -251,7 +257,7 @@ void tst_qquicktext::text() textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->text(), QString("")); QCOMPARE(textObject->width(), qreal(0)); @@ -266,7 +272,7 @@ void tst_qquicktext::text() QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->text(), standard.at(i)); QVERIFY(textObject->width() > 0); @@ -280,7 +286,7 @@ void tst_qquicktext::text() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QString expected = richText.at(i); QCOMPARE(textObject->text(), expected.replace("\\\"", "\"")); QVERIFY(textObject->width() > 0); @@ -297,7 +303,7 @@ void tst_qquicktext::width() textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->width(), 0.); delete textObject; @@ -336,7 +342,7 @@ void tst_qquicktext::width() metricWidth = layout.boundingRect().width(); } else { QFontMetricsF fm(f); - metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width(); + metricWidth = fm.size(Qt::TextExpandTabs | Qt::TextShowMnemonic, standard.at(i)).width(); } QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }"; @@ -344,7 +350,7 @@ void tst_qquicktext::width() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QVERIFY(textObject->boundingRect().width() > 0); QCOMPARE(textObject->width(), qreal(metricWidth)); QVERIFY(textObject->textFormat() == QQuickText::AutoText); // setting text doesn't change format @@ -360,14 +366,14 @@ void tst_qquicktext::width() QQmlComponent textComponent(&engine); textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QVERIFY(textPrivate->extra.isAllocated()); QTextDocument *doc = textPrivate->extra->doc; - QVERIFY(doc != 0); + QVERIFY(doc != nullptr); QCOMPARE(int(textObject->width()), int(doc->idealWidth())); QCOMPARE(textObject->textFormat(), QQuickText::RichText); @@ -386,7 +392,7 @@ void tst_qquicktext::wrap() QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); textHeight = textObject->height(); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->wrapMode(), QQuickText::WordWrap); QCOMPARE(textObject->width(), 300.); @@ -400,7 +406,7 @@ void tst_qquicktext::wrap() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->width(), 30.); QVERIFY(textObject->height() > textHeight); @@ -418,7 +424,7 @@ void tst_qquicktext::wrap() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->width(), 30.); QVERIFY(textObject->height() > textHeight); @@ -437,16 +443,16 @@ void tst_qquicktext::wrap() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->width(), 30.); QVERIFY(textObject->height() > textHeight); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QVERIFY(textPrivate->extra.isAllocated()); QTextDocument *doc = textPrivate->extra->doc; - QVERIFY(doc != 0); + QVERIFY(doc != nullptr); textObject->setWidth(doc->idealWidth()); QCOMPARE(textObject->width(), doc->idealWidth()); QVERIFY(textObject->height() > textHeight); @@ -466,7 +472,7 @@ void tst_qquicktext::wrap() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->width(), 30.); QVERIFY(textObject->implicitHeight() > textHeight); @@ -554,6 +560,45 @@ void tst_qquicktext::elide() } } +// QTBUG-60328 +// Tests that text with elide set is rendered after +// having its parent cleared and then set again. +void tst_qquicktext::elideParentChanged() +{ + QQuickView window; + window.setSource(testFileUrl("elideParentChanged.qml")); + QTRY_COMPARE(window.status(), QQuickView::Ready); + + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + QQuickItem *root = window.rootObject(); + QVERIFY(root); + QCOMPARE(root->childItems().size(), 1); + + // Store a snapshot of the scene so that we can compare it later. + QSharedPointer<QQuickItemGrabResult> grabResult = root->grabToImage(); + QTRY_VERIFY(!grabResult->image().isNull()); + const QImage expectedItemImageGrab(grabResult->image()); + + // Clear the text's parent. It shouldn't render anything. + QQuickItem *text = root->childItems().first(); + text->setParentItem(nullptr); + QCOMPARE(text->width(), 0.0); + QCOMPARE(text->height(), 0.0); + + // Set the parent back to what it was. The text should + // be rendered identically to how it was before. + text->setParentItem(root); + QCOMPARE(text->width(), 100.0); + QCOMPARE(text->height(), 30.0); + + grabResult = root->grabToImage(); + QTRY_VERIFY(!grabResult->image().isNull()); + const QImage actualItemImageGrab(grabResult->image()); + QCOMPARE(actualItemImageGrab, expectedItemImageGrab); +} + void tst_qquicktext::multilineElide_data() { QTest::addColumn<QQuickText::TextFormat>("format"); @@ -567,7 +612,7 @@ void tst_qquicktext::multilineElide() QScopedPointer<QQuickView> window(createView(testFile("multilineelide.qml"))); QQuickText *myText = qobject_cast<QQuickText*>(window->rootObject()); - QVERIFY(myText != 0); + QVERIFY(myText != nullptr); myText->setTextFormat(format); QCOMPARE(myText->lineCount(), 3); @@ -667,11 +712,11 @@ void tst_qquicktext::textFormat() textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->textFormat(), QQuickText::RichText); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QVERIFY(textPrivate->richText); delete textObject; @@ -681,11 +726,11 @@ void tst_qquicktext::textFormat() textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\" }", QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->textFormat(), QQuickText::AutoText); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QVERIFY(textPrivate->styledText); delete textObject; @@ -695,7 +740,7 @@ void tst_qquicktext::textFormat() textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->textFormat(), QQuickText::PlainText); delete textObject; @@ -723,6 +768,61 @@ void tst_qquicktext::textFormat() QCOMPARE(text->textFormat(), QQuickText::AutoText); QCOMPARE(spy.count(), 2); } + + { + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\n Text { text: \"<b>Hello</b>\" }", QUrl()); + QScopedPointer<QObject> object(component.create()); + QQuickText *text = qobject_cast<QQuickText *>(object.data()); + QVERIFY(text); + QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text); + QVERIFY(textPrivate); + + QCOMPARE(text->textFormat(), QQuickText::AutoText); + QVERIFY(!textPrivate->layout.formats().isEmpty()); + + text->setTextFormat(QQuickText::StyledText); + QVERIFY(!textPrivate->layout.formats().isEmpty()); + + text->setTextFormat(QQuickText::PlainText); + QVERIFY(textPrivate->layout.formats().isEmpty()); + + text->setTextFormat(QQuickText::AutoText); + QVERIFY(!textPrivate->layout.formats().isEmpty()); + } + + { + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nText { text: \"Hello\"; elide: Text.ElideRight }", QUrl::fromLocalFile("")); + QScopedPointer<QObject> object(component.create()); + QQuickText *text = qobject_cast<QQuickText *>(object.data()); + QVERIFY(text); + QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text); + QVERIFY(textPrivate); + + // underline a mnemonic + QVector<QTextLayout::FormatRange> formats; + QTextLayout::FormatRange range; + range.start = 0; + range.length = 1; + range.format.setFontUnderline(true); + formats << range; + + // the mnemonic format should be retained + textPrivate->layout.setFormats(formats); + text->forceLayout(); + QCOMPARE(textPrivate->layout.formats(), formats); + + // and carried over to the elide layout + text->setWidth(text->implicitWidth() - 1); + QVERIFY(textPrivate->elideLayout); + QCOMPARE(textPrivate->elideLayout->formats(), formats); + + // but cleared when the text changes + text->setText("Changed"); + QVERIFY(textPrivate->elideLayout); + QVERIFY(textPrivate->layout.formats().isEmpty()); + } } //the alignment tests may be trivial o.oa @@ -766,11 +866,11 @@ void tst_qquicktext::horizontalAlignment_RightToLeft() { QScopedPointer<QQuickView> window(createView(testFile("horizontalAlignment_RightToLeft.qml"))); QQuickText *text = window->rootObject()->findChild<QQuickText*>("text"); - QVERIFY(text != 0); + QVERIFY(text != nullptr); window->showNormal(); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QTRY_VERIFY(textPrivate->layout.lineCount()); @@ -903,17 +1003,17 @@ static inline QByteArray msgNotLessThan(int n1, int n2) void tst_qquicktext::hAlignImplicitWidth() { -#if defined(QT_OPENGL_ES_2_ANGLE) && _MSC_VER==1600 - QSKIP("QTBUG-40658"); +#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 != 0); + QVERIFY(text != nullptr); // Try to check whether alignment works by checking the number of black // pixels in the thirds of the grabbed image. @@ -929,6 +1029,10 @@ void tst_qquicktext::hAlignImplicitWidth() const int centeredSection3End = centeredSection3 + sectionWidth; { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort); + // Left Align QImage image = view.grabWindow(); const int left = numberOfNonWhitePixels(centeredSection1, centeredSection2, image); @@ -976,7 +1080,7 @@ void tst_qquicktext::verticalAlignment() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j)); delete textObject; @@ -992,7 +1096,7 @@ void tst_qquicktext::verticalAlignment() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j)); delete textObject; @@ -1388,7 +1492,7 @@ void tst_qquicktext::weight() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Normal); delete textObject; @@ -1399,7 +1503,7 @@ void tst_qquicktext::weight() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Bold); delete textObject; @@ -1413,7 +1517,7 @@ void tst_qquicktext::underline() view.requestActivate(); QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->font().overline(), false); QCOMPARE(textObject->font().underline(), true); QCOMPARE(textObject->font().strikeOut(), false); @@ -1426,7 +1530,7 @@ void tst_qquicktext::overline() view.requestActivate(); QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->font().overline(), true); QCOMPARE(textObject->font().underline(), false); QCOMPARE(textObject->font().strikeOut(), false); @@ -1439,7 +1543,7 @@ void tst_qquicktext::strikeout() view.requestActivate(); QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->font().overline(), false); QCOMPARE(textObject->font().underline(), false); QCOMPARE(textObject->font().strikeOut(), true); @@ -1453,7 +1557,7 @@ void tst_qquicktext::capitalization() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::MixedCase); delete textObject; @@ -1464,7 +1568,7 @@ void tst_qquicktext::capitalization() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllUppercase); delete textObject; @@ -1475,7 +1579,7 @@ void tst_qquicktext::capitalization() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllLowercase); delete textObject; @@ -1486,7 +1590,7 @@ void tst_qquicktext::capitalization() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::SmallCaps); delete textObject; @@ -1497,7 +1601,7 @@ void tst_qquicktext::capitalization() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::Capitalize); delete textObject; @@ -1512,7 +1616,7 @@ void tst_qquicktext::letterSpacing() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->font().letterSpacing(), 0.0); delete textObject; @@ -1523,7 +1627,7 @@ void tst_qquicktext::letterSpacing() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->font().letterSpacing(), -2.); delete textObject; @@ -1534,7 +1638,7 @@ void tst_qquicktext::letterSpacing() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->font().letterSpacing(), 3.); delete textObject; @@ -1549,7 +1653,7 @@ void tst_qquicktext::wordSpacing() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->font().wordSpacing(), 0.0); delete textObject; @@ -1560,7 +1664,7 @@ void tst_qquicktext::wordSpacing() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->font().wordSpacing(), -50.); delete textObject; @@ -1571,7 +1675,7 @@ void tst_qquicktext::wordSpacing() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->font().wordSpacing(), 200.); delete textObject; @@ -1968,7 +2072,7 @@ void tst_qquicktext::linkInteraction() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); LinkTest test; QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString))); @@ -2090,7 +2194,7 @@ void tst_qquicktext::embeddedImages() QVERIFY(QTest::qWaitForWindowActive(view)); QQuickText *textObject = qobject_cast<QQuickText*>(view->rootObject()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QTRY_COMPARE(textObject->resourcesLoading(), 0); QPixmap pm(testFile("http/exists.png")); @@ -2111,7 +2215,7 @@ void tst_qquicktext::lineCount() QScopedPointer<QQuickView> window(createView(testFile("lineCount.qml"))); QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(myText != 0); + QVERIFY(myText != nullptr); QVERIFY(myText->lineCount() > 1); QVERIFY(!myText->truncated()); @@ -2138,7 +2242,7 @@ void tst_qquicktext::lineHeight() QScopedPointer<QQuickView> window(createView(testFile("lineHeight.qml"))); QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(myText != 0); + QVERIFY(myText != nullptr); QCOMPARE(myText->lineHeight(), qreal(1)); QCOMPARE(myText->lineHeightMode(), QQuickText::ProportionalHeight); @@ -2283,23 +2387,31 @@ void tst_qquicktext::contentSize() QScopedPointer<QObject> object(textComponent.create()); QQuickText *textObject = qobject_cast<QQuickText *>(object.data()); - QSignalSpy spy(textObject, SIGNAL(contentSizeChanged())); + QSignalSpy spySize(textObject, SIGNAL(contentSizeChanged())); + QSignalSpy spyWidth(textObject, SIGNAL(contentWidthChanged(qreal))); + QSignalSpy spyHeight(textObject, SIGNAL(contentHeightChanged(qreal))); textObject->setText("The quick red fox jumped over the lazy brown dog"); QVERIFY(textObject->contentWidth() > textObject->width()); QVERIFY(textObject->contentHeight() < textObject->height()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spySize.count(), 1); + QCOMPARE(spyWidth.count(), 1); + QCOMPARE(spyHeight.count(), 0); textObject->setWrapMode(QQuickText::WordWrap); QVERIFY(textObject->contentWidth() <= textObject->width()); QVERIFY(textObject->contentHeight() > textObject->height()); - QCOMPARE(spy.count(), 2); + QCOMPARE(spySize.count(), 2); + QCOMPARE(spyWidth.count(), 2); + QCOMPARE(spyHeight.count(), 1); textObject->setElideMode(QQuickText::ElideRight); QVERIFY(textObject->contentWidth() <= textObject->width()); QVERIFY(textObject->contentHeight() < textObject->height()); - QCOMPARE(spy.count(), 3); + QCOMPARE(spySize.count(), 3); + QCOMPARE(spyWidth.count(), 3); + QCOMPARE(spyHeight.count(), 2); int spyCount = 3; qreal elidedWidth = textObject->contentWidth(); @@ -2308,14 +2420,16 @@ void tst_qquicktext::contentSize() QVERIFY(textObject->contentHeight() < textObject->height()); // this text probably won't have the same elided width, but it's not guaranteed. if (textObject->contentWidth() != elidedWidth) - QCOMPARE(spy.count(), ++spyCount); + QCOMPARE(spySize.count(), ++spyCount); else - QCOMPARE(spy.count(), spyCount); + QCOMPARE(spySize.count(), spyCount); textObject->setElideMode(QQuickText::ElideNone); QVERIFY(textObject->contentWidth() > textObject->width()); QVERIFY(textObject->contentHeight() > textObject->height()); - QCOMPARE(spy.count(), ++spyCount); + QCOMPARE(spySize.count(), ++spyCount); + QCOMPARE(spyWidth.count(), spyCount); + QCOMPARE(spyHeight.count(), 3); } void tst_qquicktext::geometryChanged() @@ -2736,10 +2850,10 @@ void tst_qquicktext::lineLaidOut() QScopedPointer<QQuickView> window(createView(testFile("lineLayout.qml"))); QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(myText != 0); + QVERIFY(myText != nullptr); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QVERIFY(!textPrivate->extra.isAllocated()); @@ -2764,10 +2878,10 @@ void tst_qquicktext::lineLaidOutRelayout() QVERIFY(QTest::qWaitForWindowActive(window.data())); QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(myText != 0); + QVERIFY(myText != nullptr); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QVERIFY(!textPrivate->extra.isAllocated()); @@ -2792,10 +2906,10 @@ void tst_qquicktext::lineLaidOutHAlign() QScopedPointer<QQuickView> window(createView(testFile("lineLayoutHAlign.qml"))); QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(myText != 0); + QVERIFY(myText != nullptr); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QCOMPARE(textPrivate->layout.lineCount(), 1); @@ -2922,11 +3036,11 @@ void tst_qquicktext::imgTagsAlign() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(".")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->height(), qreal(imgHeight)); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QRectF br = textPrivate->layout.boundingRect(); if (align == "bottom") @@ -2947,11 +3061,11 @@ void tst_qquicktext::imgTagsMultipleImages() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(".")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->height(), qreal(85)); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QCOMPARE(textPrivate->extra->visibleImgTags.count(), 2); delete textObject; @@ -2961,10 +3075,10 @@ void tst_qquicktext::imgTagsElide() { QScopedPointer<QQuickView> window(createView(testFile("imgTagsElide.qml"))); QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(myText != 0); + QVERIFY(myText != nullptr); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QCOMPARE(textPrivate->extra->visibleImgTags.count(), 0); myText->setMaximumLineCount(20); QTRY_COMPARE(textPrivate->extra->visibleImgTags.count(), 1); @@ -2976,12 +3090,12 @@ void tst_qquicktext::imgTagsUpdates() { QScopedPointer<QQuickView> window(createView(testFile("imgTagsUpdates.qml"))); QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(myText != 0); + QVERIFY(myText != nullptr); QSignalSpy spy(myText, SIGNAL(contentSizeChanged())); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); myText->setText("This is a heart<img src=\"images/heart200.png\">."); QCOMPARE(textPrivate->extra->visibleImgTags.count(), 1); @@ -3007,7 +3121,7 @@ void tst_qquicktext::imgTagsError() textComponent.setData(componentStr.toLatin1(), QUrl("file:")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); delete textObject; } @@ -3026,10 +3140,10 @@ void tst_qquicktext::fontSizeMode() window->show(); QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(myText != 0); + QVERIFY(myText != nullptr); myText->setText(text); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); qreal originalWidth = myText->contentWidth(); qreal originalHeight = myText->contentHeight(); @@ -3043,7 +3157,7 @@ void tst_qquicktext::fontSizeMode() myText->setFont(font); myText->setFontSizeMode(QQuickText::HorizontalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // Font size reduced to fit within the width of the item. qreal horizontalFitWidth = myText->contentWidth(); qreal horizontalFitHeight = myText->contentHeight(); @@ -3052,28 +3166,28 @@ void tst_qquicktext::fontSizeMode() // Elide won't affect the size with HorizontalFit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), horizontalFitWidth); QCOMPARE(myText->contentHeight(), horizontalFitHeight); myText->setElideMode(QQuickText::ElideLeft); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), horizontalFitWidth); QCOMPARE(myText->contentHeight(), horizontalFitHeight); myText->setElideMode(QQuickText::ElideMiddle); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), horizontalFitWidth); QCOMPARE(myText->contentHeight(), horizontalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::VerticalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // Font size increased to fill the height of the item. qreal verticalFitHeight = myText->contentHeight(); QVERIFY(myText->contentWidth() > myText->width()); @@ -3082,57 +3196,57 @@ void tst_qquicktext::fontSizeMode() // Elide won't affect the height of a single line with VerticalFit but will crop the width. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(myText->truncated()); QVERIFY(myText->contentWidth() <= myText->width() + 2); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideLeft); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(myText->truncated()); QVERIFY(myText->contentWidth() <= myText->width() + 2); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideMiddle); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(myText->truncated()); QVERIFY(myText->contentWidth() <= myText->width() + 2); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::Fit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // Should be the same as HorizontalFit with no wrapping. QCOMPARE(myText->contentWidth(), horizontalFitWidth); QCOMPARE(myText->contentHeight(), horizontalFitHeight); // Elide won't affect the size with Fit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), horizontalFitWidth); QCOMPARE(myText->contentHeight(), horizontalFitHeight); myText->setElideMode(QQuickText::ElideLeft); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), horizontalFitWidth); QCOMPARE(myText->contentHeight(), horizontalFitHeight); myText->setElideMode(QQuickText::ElideMiddle); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), horizontalFitWidth); QCOMPARE(myText->contentHeight(), horizontalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::FixedSize); myText->setWrapMode(QQuickText::Wrap); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); originalWidth = myText->contentWidth(); originalHeight = myText->contentHeight(); @@ -3142,7 +3256,7 @@ void tst_qquicktext::fontSizeMode() QVERIFY(originalHeight > myText->height()); myText->setFontSizeMode(QQuickText::HorizontalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the // same size as without text wrapping. QCOMPARE(myText->contentWidth(), horizontalFitWidth); @@ -3150,16 +3264,16 @@ void tst_qquicktext::fontSizeMode() // Elide won't affect the size with HorizontalFit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), horizontalFitWidth); QCOMPARE(myText->contentHeight(), horizontalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::VerticalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // VerticalFit should reduce the size to the wrapped text within the vertical height. verticalFitHeight = myText->contentHeight(); qreal verticalFitWidth = myText->contentWidth(); @@ -3169,40 +3283,40 @@ void tst_qquicktext::fontSizeMode() // Elide won't affect the height or width of a wrapped text with VerticalFit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::Fit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // Should be the same as VerticalFit with wrapping. QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); // Elide won't affect the size with Fit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::FixedSize); myText->setMaximumLineCount(2); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // The original text wrapped should exceed the height of the item. QVERIFY(originalWidth <= myText->width() + 2); QVERIFY(originalHeight > myText->height()); myText->setFontSizeMode(QQuickText::HorizontalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the // same size as without text wrapping. QCOMPARE(myText->contentWidth(), horizontalFitWidth); @@ -3210,16 +3324,16 @@ void tst_qquicktext::fontSizeMode() // Elide won't affect the size with HorizontalFit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), horizontalFitWidth); QCOMPARE(myText->contentHeight(), horizontalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::VerticalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // VerticalFit should reduce the size to the wrapped text within the vertical height. verticalFitHeight = myText->contentHeight(); verticalFitWidth = myText->contentWidth(); @@ -3229,29 +3343,29 @@ void tst_qquicktext::fontSizeMode() // Elide won't affect the height or width of a wrapped text with VerticalFit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::Fit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // Should be the same as VerticalFit with wrapping. QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); // Elide won't affect the size with Fit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); } void tst_qquicktext::fontSizeModeMultiline_data() @@ -3269,10 +3383,10 @@ void tst_qquicktext::fontSizeModeMultiline() window->show(); QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(myText != 0); + QVERIFY(myText != nullptr); myText->setText(text); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); qreal originalWidth = myText->contentWidth(); qreal originalHeight = myText->contentHeight(); @@ -3287,7 +3401,7 @@ void tst_qquicktext::fontSizeModeMultiline() myText->setFont(font); myText->setFontSizeMode(QQuickText::HorizontalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // Font size reduced to fit within the width of the item. QCOMPARE(myText->lineCount(), 2); qreal horizontalFitWidth = myText->contentWidth(); @@ -3297,7 +3411,7 @@ void tst_qquicktext::fontSizeModeMultiline() // Right eliding will remove the last line myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(myText->truncated()); QCOMPARE(myText->lineCount(), 1); QVERIFY(myText->contentWidth() <= myText->width() + 2); @@ -3305,22 +3419,22 @@ void tst_qquicktext::fontSizeModeMultiline() // Left or middle eliding wont have any effect. myText->setElideMode(QQuickText::ElideLeft); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), horizontalFitWidth); QCOMPARE(myText->contentHeight(), horizontalFitHeight); myText->setElideMode(QQuickText::ElideMiddle); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), horizontalFitWidth); QCOMPARE(myText->contentHeight(), horizontalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::VerticalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // Font size reduced to fit within the height of the item. qreal verticalFitWidth = myText->contentWidth(); qreal verticalFitHeight = myText->contentHeight(); @@ -3329,58 +3443,58 @@ void tst_qquicktext::fontSizeModeMultiline() // Elide will have no effect. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QVERIFY(myText->contentWidth() <= myText->width() + 2); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideLeft); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideMiddle); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::Fit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // Should be the same as VerticalFit with no wrapping. QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); // Elide won't affect the size with Fit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideLeft); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideMiddle); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::FixedSize); myText->setWrapMode(QQuickText::Wrap); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); originalWidth = myText->contentWidth(); originalHeight = myText->contentHeight(); @@ -3390,7 +3504,7 @@ void tst_qquicktext::fontSizeModeMultiline() QVERIFY(originalHeight > myText->height()); myText->setFontSizeMode(QQuickText::HorizontalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the // same size as without text wrapping. QCOMPARE(myText->contentWidth(), horizontalFitWidth); @@ -3398,16 +3512,16 @@ void tst_qquicktext::fontSizeModeMultiline() // Text will be elided vertically with HorizontalFit myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(myText->truncated()); QVERIFY(myText->contentWidth() <= myText->width() + 2); QVERIFY(myText->contentHeight() <= myText->height() + 2); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::VerticalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // VerticalFit should reduce the size to the wrapped text within the vertical height. verticalFitHeight = myText->contentHeight(); verticalFitWidth = myText->contentWidth(); @@ -3417,40 +3531,40 @@ void tst_qquicktext::fontSizeModeMultiline() // Elide won't affect the height or width of a wrapped text with VerticalFit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::Fit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // Should be the same as VerticalFit with wrapping. QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); // Elide won't affect the size with Fit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::FixedSize); myText->setMaximumLineCount(2); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // The original text wrapped should exceed the height of the item. QVERIFY(originalWidth <= myText->width() + 2); QVERIFY(originalHeight > myText->height()); myText->setFontSizeMode(QQuickText::HorizontalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the // same size as without text wrapping. QCOMPARE(myText->contentWidth(), horizontalFitWidth); @@ -3458,16 +3572,16 @@ void tst_qquicktext::fontSizeModeMultiline() // Elide won't affect the size with HorizontalFit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(myText->truncated()); QVERIFY(myText->contentWidth() <= myText->width() + 2); QVERIFY(myText->contentHeight() <= myText->height() + 2); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::VerticalFit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // VerticalFit should reduce the size to the wrapped text within the vertical height. verticalFitHeight = myText->contentHeight(); verticalFitWidth = myText->contentWidth(); @@ -3477,29 +3591,29 @@ void tst_qquicktext::fontSizeModeMultiline() // Elide won't affect the height or width of a wrapped text with VerticalFit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); myText->setFontSizeMode(QQuickText::Fit); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); // Should be the same as VerticalFit with wrapping. QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); // Elide won't affect the size with Fit. myText->setElideMode(QQuickText::ElideRight); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QVERIFY(!myText->truncated()); QCOMPARE(myText->contentWidth(), verticalFitWidth); QCOMPARE(myText->contentHeight(), verticalFitHeight); myText->setElideMode(QQuickText::ElideNone); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); } void tst_qquicktext::multilengthStrings_data() @@ -3517,24 +3631,24 @@ void tst_qquicktext::multilengthStrings() window->show(); QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText"); - QVERIFY(myText != 0); + QVERIFY(myText != nullptr); const QString longText = "the quick brown fox jumped over the lazy dog"; const QString mediumText = "the brown fox jumped over the dog"; const QString shortText = "fox jumped dog"; myText->setText(longText); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); const qreal longWidth = myText->contentWidth(); const qreal longHeight = myText->contentHeight(); myText->setText(mediumText); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); const qreal mediumWidth = myText->contentWidth(); const qreal mediumHeight = myText->contentHeight(); myText->setText(shortText); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); const qreal shortWidth = myText->contentWidth(); const qreal shortHeight = myText->contentHeight(); @@ -3542,21 +3656,21 @@ void tst_qquicktext::multilengthStrings() myText->setText(longText + QLatin1Char('\x9c') + mediumText + QLatin1Char('\x9c') + shortText); myText->setSize(QSizeF(longWidth, longHeight)); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QCOMPARE(myText->contentWidth(), longWidth); QCOMPARE(myText->contentHeight(), longHeight); QCOMPARE(myText->truncated(), false); myText->setSize(QSizeF(mediumWidth, mediumHeight)); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QCOMPARE(myText->contentWidth(), mediumWidth); QCOMPARE(myText->contentHeight(), mediumHeight); QCOMPARE(myText->truncated(), true); myText->setSize(QSizeF(shortWidth, shortHeight)); - QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false); + QVERIFY(QQuickTest::qWaitForItemPolished(myText)); QCOMPARE(myText->contentWidth(), shortWidth); QCOMPARE(myText->contentHeight(), shortHeight); @@ -3597,8 +3711,8 @@ void tst_qquicktext::fontFormatSizes() QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text"); QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag"); - QVERIFY(qtext != 0); - QVERIFY(qtextWithTag != 0); + QVERIFY(qtext != nullptr); + QVERIFY(qtextWithTag != nullptr); qtext->setText(text); qtextWithTag->setText(textWithTag); @@ -3616,8 +3730,8 @@ void tst_qquicktext::fontFormatSizes() view->setSource(testFileUrl("pixelFontSizes.qml")); QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text"); QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag"); - QVERIFY(qtext != 0); - QVERIFY(qtextWithTag != 0); + QVERIFY(qtext != nullptr); + QVERIFY(qtextWithTag != nullptr); qtext->setText(text); qtextWithTag->setText(textWithTag); @@ -3983,10 +4097,10 @@ void tst_qquicktext::htmlLists() QQuickText *textObject = view->rootObject()->findChild<QQuickText*>("myText"); QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject); - QVERIFY(textPrivate != 0); + QVERIFY(textPrivate != nullptr); QVERIFY(textPrivate->extra.isAllocated()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); textObject->setText(text); view->show(); @@ -4083,7 +4197,7 @@ void tst_qquicktext::padding() QQuickItem *root = window->rootObject(); QVERIFY(root); QQuickText *obj = qobject_cast<QQuickText*>(root); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); qreal cw = obj->contentWidth(); qreal ch = obj->contentHeight(); @@ -4171,7 +4285,7 @@ void tst_qquicktext::hintingPreference() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE((int)textObject->font().hintingPreference(), (int)QFont::PreferDefaultHinting); delete textObject; @@ -4182,7 +4296,7 @@ void tst_qquicktext::hintingPreference() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE((int)textObject->font().hintingPreference(), (int)QFont::PreferNoHinting); delete textObject; @@ -4272,6 +4386,35 @@ void tst_qquicktext::fontInfo() QVERIFY(copy->font().pixelSize() < 1000); } +void tst_qquicktext::initialContentHeight() +{ + QQmlComponent component(&engine, testFile("contentHeight.qml")); + QVERIFY(component.isReady()); + QScopedPointer<QObject> object(component.create()); + QObject *root = object.data(); + QVERIFY(root); + QQuickText *text = qobject_cast<QQuickText *>(root); + QVERIFY(text); + QCOMPARE(text->height(), text->contentHeight()); +} + +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/qquicktextdocument/tst_qquicktextdocument.cpp b/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp index 7507938589..e9c699db6a 100644 --- a/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp +++ b/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp @@ -58,7 +58,7 @@ void tst_qquicktextdocument::textDocumentWriter() QVERIFY(edit); QQuickTextDocument* quickDocument = qobject_cast<QQuickTextDocument*>(edit->property("textDocument").value<QObject*>()); - QVERIFY(quickDocument->textDocument() != 0); + QVERIFY(quickDocument->textDocument() != nullptr); QBuffer output; output.open(QBuffer::ReadWrite); @@ -73,7 +73,7 @@ void tst_qquicktextdocument::textDocumentWriter() void tst_qquicktextdocument::textDocumentWithImage() { - QQuickTextDocumentWithImageResources document(0); + QQuickTextDocumentWithImageResources document(nullptr); QImage image(1, 1, QImage::Format_Mono); image.fill(1); diff --git a/tests/auto/quick/qquicktextedit/data/keys_shortcutoverride.qml b/tests/auto/quick/qquicktextedit/data/keys_shortcutoverride.qml new file mode 100644 index 0000000000..24bd434830 --- /dev/null +++ b/tests/auto/quick/qquicktextedit/data/keys_shortcutoverride.qml @@ -0,0 +1,34 @@ +import QtQuick 2.10 + +Item { + width: 320 + height: 200 + property string who : "nobody" + + Shortcut { + sequence: "Esc" + onActivated: who = "Shortcut" + } + + TextEdit { + id: txt + x: 100 + text: "enter text" + Keys.onShortcutOverride: { + who = "TextEdit" + event.accepted = (event.key === Qt.Key_Escape) + } + } + + Rectangle { + objectName: "rectangle" + width: 90 + height: width + focus: true + color: focus ? "red" : "gray" + Keys.onShortcutOverride: { + who = "Rectangle" + event.accepted = (event.key === Qt.Key_Escape) + } + } +} diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index ac57a05176..ce2a8eb257 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -36,6 +36,7 @@ #include <QtQml/qqmlexpression.h> #include <QtQml/qqmlcomponent.h> #include <QtGui/qguiapplication.h> +#include <private/qquickrectangle_p.h> #include <private/qquicktextedit_p.h> #include <private/qquicktextedit_p_p.h> #include <private/qquicktext_p.h> @@ -158,6 +159,7 @@ private slots: #endif void implicitSize_data(); void implicitSize(); + void implicitSize_QTBUG_63153(); void contentSize(); void boundingRect(); void clipRect(); @@ -204,12 +206,13 @@ private slots: void padding(); void QTBUG_51115_readOnlyResetsSelection(); + void keys_shortcutoverride(); private: void simulateKeys(QWindow *window, const QList<Key> &keys); void simulateKeys(QWindow *window, const QKeySequence &sequence); - void simulateKey(QWindow *, int key, Qt::KeyboardModifiers modifiers = 0); + void simulateKey(QWindow *, int key, Qt::KeyboardModifiers modifiers = nullptr); QStringList standard; QStringList richText; @@ -335,7 +338,7 @@ void tst_qquicktextedit::cleanup() { // ensure not even skipped tests with custom input context leave it dangling QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); - inputMethodPrivate->testContext = 0; + inputMethodPrivate->testContext = nullptr; } void tst_qquicktextedit::text() @@ -345,7 +348,7 @@ void tst_qquicktextedit::text() texteditComponent.setData("import QtQuick 2.0\nTextEdit { text: \"\" }", QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->text(), QString("")); QCOMPARE(textEditObject->length(), 0); } @@ -357,7 +360,7 @@ void tst_qquicktextedit::text() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->text(), standard.at(i)); QCOMPARE(textEditObject->length(), standard.at(i).length()); } @@ -370,7 +373,7 @@ void tst_qquicktextedit::text() QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QString expected = richText.at(i); expected.replace(QRegExp("\\\\(.)"),"\\1"); @@ -385,7 +388,7 @@ void tst_qquicktextedit::text() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QString actual = textEditObject->text(); QString expected = standard.at(i); @@ -403,7 +406,7 @@ void tst_qquicktextedit::text() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QString actual = textEditObject->text(); QString expected = richText.at(i); actual.replace(QRegExp(".*<body[^>]*>"),""); @@ -422,7 +425,7 @@ void tst_qquicktextedit::text() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->text(), standard.at(i)); QCOMPARE(textEditObject->length(), standard.at(i).length()); } @@ -434,7 +437,7 @@ void tst_qquicktextedit::text() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QString actual = textEditObject->text(); QString expected = richText.at(i); actual.replace(QRegExp(".*<body[^>]*>"),""); @@ -455,7 +458,7 @@ void tst_qquicktextedit::width() texteditComponent.setData("import QtQuick 2.0\nTextEdit { text: \"\" }", QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->width(), 0.0); } @@ -491,7 +494,7 @@ void tst_qquicktextedit::width() qreal metricWidth = layout.boundingRect().width(); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->width(), metricWidth); } @@ -510,7 +513,7 @@ void tst_qquicktextedit::width() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->width(), documentWidth); } } @@ -523,7 +526,7 @@ void tst_qquicktextedit::wrap() texteditComponent.setData("import QtQuick 2.0\nTextEdit { text: \"\"; wrapMode: TextEdit.WordWrap; width: 300 }", QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->width(), 300.); } @@ -534,7 +537,7 @@ void tst_qquicktextedit::wrap() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->width(), 300.); } @@ -545,7 +548,7 @@ void tst_qquicktextedit::wrap() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->width(), 300.); } { @@ -580,7 +583,7 @@ void tst_qquicktextedit::textFormat() textComponent.setData("import QtQuick 2.0\nTextEdit { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile("")); QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->textFormat(), QQuickTextEdit::RichText); } { @@ -588,7 +591,7 @@ void tst_qquicktextedit::textFormat() textComponent.setData("import QtQuick 2.0\nTextEdit { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile("")); QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->textFormat(), QQuickTextEdit::PlainText); } { @@ -678,7 +681,7 @@ void tst_qquicktextedit::hAlign() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j)); } } @@ -692,7 +695,7 @@ void tst_qquicktextedit::hAlign() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE((int)textEditObject->hAlign(), (int)hAlignments.at(j)); } } @@ -707,7 +710,7 @@ void tst_qquicktextedit::hAlign_RightToLeft() QQuickView window(testFileUrl("horizontalAlignment_RightToLeft.qml")); QQuickTextEdit *textEdit = window.rootObject()->findChild<QQuickTextEdit*>("text"); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); window.showNormal(); const QString rtlText = textEdit->text(); @@ -789,7 +792,7 @@ void tst_qquicktextedit::hAlign_RightToLeft() QVERIFY(textEdit->positionToRectangle(0).x() < window.width()/2); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textEdit->hasActiveFocus()); textEdit->setText(QString()); @@ -852,7 +855,7 @@ void tst_qquicktextedit::hAlign_RightToLeft() // make sure editor doesn't rely on input for updating size QQuickTextEdit *emptyEdit = window.rootObject()->findChild<QQuickTextEdit*>("emptyTextEdit"); - QVERIFY(emptyEdit != 0); + QVERIFY(emptyEdit != nullptr); platformInputContext.setInputDirection(Qt::RightToLeft); emptyEdit->setFocus(true); QCOMPARE(emptyEdit->hAlign(), QQuickTextEdit::AlignRight); @@ -890,7 +893,7 @@ void tst_qquicktextedit::hAlignVisual() QVERIFY(QTest::qWaitForWindowExposed(&view)); QQuickText *text = view.rootObject()->findChild<QQuickText*>("textItem"); - QVERIFY(text != 0); + QVERIFY(text != nullptr); // Try to check whether alignment works by checking the number of black // pixels in the thirds of the grabbed image. @@ -904,6 +907,10 @@ void tst_qquicktextedit::hAlignVisual() const int centeredSection3End = centeredSection3 + sectionWidth; { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort); + // Left Align QImage image = view.grabWindow(); const int left = numberOfNonWhitePixels(centeredSection1, centeredSection2, image); @@ -982,7 +989,7 @@ void tst_qquicktextedit::vAlign() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j)); } } @@ -996,7 +1003,7 @@ void tst_qquicktextedit::vAlign() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE((int)textEditObject->vAlign(), (int)vAlignments.at(j)); } } @@ -1007,7 +1014,7 @@ void tst_qquicktextedit::vAlign() "TextEdit { width: 100; height: 100; text: \"Hello World\" }", QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->vAlign(), QQuickTextEdit::AlignTop); QVERIFY(textEditObject->cursorRectangle().bottom() < 50); @@ -1050,7 +1057,7 @@ void tst_qquicktextedit::font() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->font().pointSize(), 40); QCOMPARE(textEditObject->font().bold(), false); QCOMPARE(textEditObject->font().italic(), false); @@ -1062,7 +1069,7 @@ void tst_qquicktextedit::font() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->font().bold(), true); QCOMPARE(textEditObject->font().italic(), false); } @@ -1073,7 +1080,7 @@ void tst_qquicktextedit::font() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->font().italic(), true); QCOMPARE(textEditObject->font().bold(), false); } @@ -1084,7 +1091,7 @@ void tst_qquicktextedit::font() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->font().family(), QString("Helvetica")); QCOMPARE(textEditObject->font().bold(), false); QCOMPARE(textEditObject->font().italic(), false); @@ -1096,7 +1103,7 @@ void tst_qquicktextedit::font() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->font().family(), QString("")); } } @@ -1161,7 +1168,7 @@ void tst_qquicktextedit::color() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); //qDebug() << "textEditObject: " << textEditObject->color() << "vs. " << QColor(colorStrings.at(i)); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->color(), QColor(colorStrings.at(i))); } @@ -1172,7 +1179,7 @@ void tst_qquicktextedit::color() QQmlComponent texteditComponent(&engine); texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->selectionColor(), QColor(colorStrings.at(i))); } @@ -1183,7 +1190,7 @@ void tst_qquicktextedit::color() QQmlComponent texteditComponent(&engine); texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->selectedTextColor(), QColor(colorStrings.at(i))); } @@ -1197,7 +1204,7 @@ void tst_qquicktextedit::color() texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->color(), testColor); } } @@ -1209,7 +1216,7 @@ void tst_qquicktextedit::textMargin() QQmlComponent texteditComponent(&engine); texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->textMargin(), i); } } @@ -1219,7 +1226,7 @@ void tst_qquicktextedit::persistentSelection() QQuickView window(testFileUrl("persistentSelection.qml")); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(window.rootObject()); QVERIFY(edit); @@ -1255,6 +1262,34 @@ void tst_qquicktextedit::persistentSelection() edit->setFocus(true); QCOMPARE(edit->property("selected").toString(), QLatin1String("ell")); + // QTBUG-50587 (persistentSelection with readOnly) + edit->setReadOnly(true); + + edit->setPersistentSelection(false); + QCOMPARE(edit->persistentSelection(), false); + QCOMPARE(spy.count(), 2); + + edit->select(1, 4); + QCOMPARE(edit->property("selected").toString(), QLatin1String("ell")); + + edit->setFocus(false); + QCOMPARE(edit->property("selected").toString(), QString()); + + edit->setFocus(true); + QCOMPARE(edit->property("selected").toString(), QString()); + + edit->setPersistentSelection(true); + QCOMPARE(edit->persistentSelection(), true); + QCOMPARE(spy.count(), 3); + + edit->select(1, 4); + QCOMPARE(edit->property("selected").toString(), QLatin1String("ell")); + + edit->setFocus(false); + QCOMPARE(edit->property("selected").toString(), QLatin1String("ell")); + + edit->setFocus(true); + QCOMPARE(edit->property("selected").toString(), QLatin1String("ell")); } void tst_qquicktextedit::selectionOnFocusOut() @@ -1262,7 +1297,7 @@ void tst_qquicktextedit::selectionOnFocusOut() QQuickView window(testFileUrl("focusOutSelection.qml")); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QPoint p1(25, 35); QPoint p2(25, 85); @@ -1270,14 +1305,14 @@ void tst_qquicktextedit::selectionOnFocusOut() QQuickTextEdit *edit1 = window.rootObject()->findChild<QQuickTextEdit*>("text1"); QQuickTextEdit *edit2 = window.rootObject()->findChild<QQuickTextEdit*>("text2"); - QTest::mouseClick(&window, Qt::LeftButton, 0, p1); + QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, p1); QVERIFY(edit1->hasActiveFocus()); QVERIFY(!edit2->hasActiveFocus()); edit1->selectAll(); QCOMPARE(edit1->selectedText(), QLatin1String("text 1")); - QTest::mouseClick(&window, Qt::LeftButton, 0, p2); + QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, p2); QCOMPARE(edit1->selectedText(), QLatin1String("")); QVERIFY(!edit1->hasActiveFocus()); @@ -1313,7 +1348,7 @@ void tst_qquicktextedit::focusOnPress() QQmlComponent texteditComponent(&engine); texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QCOMPARE(textEditObject->focusOnPress(), true); QCOMPARE(textEditObject->hasFocus(), false); @@ -1330,13 +1365,13 @@ void tst_qquicktextedit::focusOnPress() textEditObject->setParentItem(window.contentItem()); window.showNormal(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QCOMPARE(textEditObject->hasFocus(), false); QCOMPARE(textEditObject->hasActiveFocus(), false); QPoint centerPoint(window.width()/2, window.height()/2); - Qt::KeyboardModifiers noModifiers = 0; + Qt::KeyboardModifiers noModifiers = nullptr; QTest::mousePress(&window, Qt::LeftButton, noModifiers, centerPoint); QGuiApplication::processEvents(); QCOMPARE(textEditObject->hasFocus(), true); @@ -1391,7 +1426,7 @@ void tst_qquicktextedit::selection() QQmlComponent texteditComponent(&engine); texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); //Test selection follows cursor @@ -1474,7 +1509,7 @@ void tst_qquicktextedit::overwriteMode() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); QSignalSpy spy(textEdit, SIGNAL(overwriteModeChanged(bool))); @@ -1482,7 +1517,7 @@ void tst_qquicktextedit::overwriteMode() textEdit->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textEdit->hasActiveFocus()); @@ -1598,13 +1633,13 @@ void tst_qquicktextedit::keySelection() QQuickView window(testFileUrl("navigation.qml")); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextEdit *input = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window.rootObject()->property("myInput"))); - QVERIFY(input != 0); + QVERIFY(input != nullptr); QVERIFY(input->hasActiveFocus()); QSignalSpy spy(input, SIGNAL(selectedTextChanged())); @@ -1800,7 +1835,7 @@ void tst_qquicktextedit::moveCursorSelection() QQmlComponent textinputComponent(&engine); textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit*>(textinputComponent.create()); - QVERIFY(texteditObject != 0); + QVERIFY(texteditObject != nullptr); texteditObject->setCursorPosition(cursorPosition); texteditObject->moveCursorSelection(movePosition, mode); @@ -1959,7 +1994,7 @@ void tst_qquicktextedit::moveCursorSelectionSequence() QQmlComponent texteditComponent(&engine); texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit*>(texteditComponent.create()); - QVERIFY(texteditObject != 0); + QVERIFY(texteditObject != nullptr); texteditObject->setCursorPosition(cursorPosition); @@ -2055,11 +2090,11 @@ void tst_qquicktextedit::mouseSelection() window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(window.rootObject()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); textEditObject->setFocus(focus); textEditObject->setFocusOnPress(focusOnPress); @@ -2102,19 +2137,19 @@ void tst_qquicktextedit::dragMouseSelection() window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(window.rootObject()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); // press-and-drag-and-release from x1 to x2 int x1 = 10; int x2 = 70; int y = QFontMetrics(textEditObject->font()).height() / 2; - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(x1,y)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x1,y)); QTest::mouseMove(&window, QPoint(x2, y)); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(x2,y)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x2,y)); QTest::qWait(300); QString str1; QTRY_VERIFY((str1 = textEditObject->selectedText()).length() > 3); @@ -2122,9 +2157,9 @@ void tst_qquicktextedit::dragMouseSelection() // press and drag the current selection. x1 = 40; x2 = 100; - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(x1,y)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x1,y)); QTest::mouseMove(&window, QPoint(x2, y)); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(x2,y)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x2,y)); QTest::qWait(300); QString str2; QTRY_VERIFY((str2 = textEditObject->selectedText()).length() > 3); @@ -2155,19 +2190,19 @@ void tst_qquicktextedit::mouseSelectionMode() window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(window.rootObject()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); // press-and-drag-and-release from x1 to x2 int x1 = 10; int x2 = 70; int y = textEditObject->height()/2; - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(x1,y)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x1,y)); QTest::mouseMove(&window, QPoint(x2, y)); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(x2,y)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x2,y)); QString str = textEditObject->selectedText(); if (selectWords) { QTRY_COMPARE(textEditObject->selectedText(), text); @@ -2340,7 +2375,7 @@ void tst_qquicktextedit::keyboardSelection() edit->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(edit->hasActiveFocus()); simulateKeys(&window, standardKey); @@ -2378,9 +2413,9 @@ void tst_qquicktextedit::inputMethodHints() window.show(); window.requestActivate(); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(window.rootObject()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); QVERIFY(textEditObject->inputMethodHints() & Qt::ImhNoPredictiveText); QSignalSpy inputMethodHintSpy(textEditObject, SIGNAL(inputMethodHintsChanged())); textEditObject->setInputMethodHints(Qt::ImhUppercaseOnly); @@ -2414,13 +2449,13 @@ void tst_qquicktextedit::positionAt() QFETCH(QQuickTextEdit::VAlignment, verticalAlignment); QQuickView window(testFileUrl("positionAt.qml")); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit *>(window.rootObject()); - QVERIFY(texteditObject != 0); + QVERIFY(texteditObject != nullptr); texteditObject->setHAlign(horizontalAlignment); texteditObject->setVAlign(verticalAlignment); @@ -2504,13 +2539,13 @@ void tst_qquicktextedit::positionAt() void tst_qquicktextedit::linkInteraction() { QQuickView window(testFileUrl("linkInteraction.qml")); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit *>(window.rootObject()); - QVERIFY(texteditObject != 0); + QVERIFY(texteditObject != nullptr); QSignalSpy spy(texteditObject, SIGNAL(linkActivated(QString))); QSignalSpy hover(texteditObject, SIGNAL(linkHovered(QString))); @@ -2520,7 +2555,7 @@ void tst_qquicktextedit::linkInteraction() const QPointF linkPos = texteditObject->positionToRectangle(7).center(); const QPointF textPos = texteditObject->positionToRectangle(2).center(); - QTest::mouseClick(&window, Qt::LeftButton, 0, linkPos.toPoint()); + QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, linkPos.toPoint()); QTRY_COMPARE(spy.count(), 1); QTRY_COMPARE(hover.count(), 1); QCOMPARE(spy.last()[0].toString(), link); @@ -2528,7 +2563,7 @@ void tst_qquicktextedit::linkInteraction() QCOMPARE(texteditObject->hoveredLink(), link); QCOMPARE(texteditObject->linkAt(linkPos.x(), linkPos.y()), link); - QTest::mouseClick(&window, Qt::LeftButton, 0, textPos.toPoint()); + QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, textPos.toPoint()); QTRY_COMPARE(spy.count(), 1); QTRY_COMPARE(hover.count(), 2); QCOMPARE(hover.last()[0].toString(), QString()); @@ -2537,7 +2572,7 @@ void tst_qquicktextedit::linkInteraction() texteditObject->setReadOnly(true); - QTest::mouseClick(&window, Qt::LeftButton, 0, linkPos.toPoint()); + QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, linkPos.toPoint()); QTRY_COMPARE(spy.count(), 2); QTRY_COMPARE(hover.count(), 3); QCOMPARE(spy.last()[0].toString(), link); @@ -2545,7 +2580,7 @@ void tst_qquicktextedit::linkInteraction() QCOMPARE(texteditObject->hoveredLink(), link); QCOMPARE(texteditObject->linkAt(linkPos.x(), linkPos.y()), link); - QTest::mouseClick(&window, Qt::LeftButton, 0, textPos.toPoint()); + QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, textPos.toPoint()); QTRY_COMPARE(spy.count(), 2); QTRY_COMPARE(hover.count(), 4); QCOMPARE(hover.last()[0].toString(), QString()); @@ -2567,9 +2602,9 @@ void tst_qquicktextedit::cursorDelegate() QQuickView view(source); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject"); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); // Delegate creation is deferred until focus in or cursor visibility is forced. QVERIFY(!textEditObject->findChild<QQuickItem*>("cursorInstance")); QVERIFY(!textEditObject->isCursorVisible()); @@ -2591,7 +2626,7 @@ void tst_qquicktextedit::cursorDelegate() textEditObject->setCursorPosition(0); const QPoint point1 = textEditObject->positionToRectangle(5).center().toPoint(); QTest::qWait(400); //ensure this isn't treated as a double-click - QTest::mouseClick(&view, Qt::LeftButton, 0, point1); + QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, point1); QTest::qWait(50); QTRY_VERIFY(textEditObject->cursorPosition() != 0); QCOMPARE(textEditObject->cursorRectangle().x(), delegateObject->x()); @@ -2601,10 +2636,10 @@ void tst_qquicktextedit::cursorDelegate() textEditObject->setCursorPosition(0); const QPoint point2 = textEditObject->positionToRectangle(10).center().toPoint(); QTest::qWait(400); //ensure this isn't treated as a double-click - QTest::mousePress(&view, Qt::LeftButton, 0, point1); + QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, point1); QMouseEvent mv(QEvent::MouseMove, point2, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); QGuiApplication::sendEvent(&view, &mv); - QTest::mouseRelease(&view, Qt::LeftButton, 0, point2); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, point2); QTest::qWait(50); QTRY_COMPARE(textEditObject->cursorRectangle().x(), delegateObject->x()); QCOMPARE(textEditObject->cursorRectangle().y(), delegateObject->y()); @@ -2612,7 +2647,7 @@ void tst_qquicktextedit::cursorDelegate() textEditObject->setReadOnly(true); textEditObject->setCursorPosition(0); QTest::qWait(400); //ensure this isn't treated as a double-click - QTest::mouseClick(&view, Qt::LeftButton, 0, textEditObject->positionToRectangle(5).center().toPoint()); + QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, textEditObject->positionToRectangle(5).center().toPoint()); QTest::qWait(50); QTRY_VERIFY(textEditObject->cursorPosition() != 0); QCOMPARE(textEditObject->cursorRectangle().x(), delegateObject->x()); @@ -2620,7 +2655,7 @@ void tst_qquicktextedit::cursorDelegate() textEditObject->setCursorPosition(0); QTest::qWait(400); //ensure this isn't treated as a double-click - QTest::mouseClick(&view, Qt::LeftButton, 0, textEditObject->positionToRectangle(5).center().toPoint()); + QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, textEditObject->positionToRectangle(5).center().toPoint()); QTest::qWait(50); QTRY_VERIFY(textEditObject->cursorPosition() != 0); QCOMPARE(textEditObject->cursorRectangle().x(), delegateObject->x()); @@ -2666,7 +2701,7 @@ void tst_qquicktextedit::cursorDelegate() } //Test Delegate gets deleted - textEditObject->setCursorDelegate(0); + textEditObject->setCursorDelegate(nullptr); QVERIFY(!textEditObject->findChild<QQuickItem*>("cursorInstance")); } @@ -2682,9 +2717,9 @@ void tst_qquicktextedit::remoteCursorDelegate() view.setSource(testFileUrl("cursorTestRemote.qml")); view.showNormal(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject"); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); // Delegate is created on demand, and so won't be available immediately. Focus in or // setCursorVisible(true) will trigger creation. @@ -2708,7 +2743,7 @@ void tst_qquicktextedit::cursorVisible() QQuickView view(testFileUrl("cursorVisible.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QCOMPARE(&view, qGuiApp->focusWindow()); QCOMPARE(edit.isCursorVisible(), false); @@ -2740,13 +2775,13 @@ void tst_qquicktextedit::cursorVisible() QWindow alternateView; alternateView.show(); alternateView.requestActivate(); - QTest::qWaitForWindowActive(&alternateView); + QVERIFY(QTest::qWaitForWindowActive(&alternateView)); QCOMPARE(edit.isCursorVisible(), false); QCOMPARE(spy.count(), 6); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QCOMPARE(edit.isCursorVisible(), true); QCOMPARE(spy.count(), 7); @@ -2829,7 +2864,7 @@ void tst_qquicktextedit::delegateLoading() QTRY_VERIFY(view.rootObject());//Wait for loading to finish. QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject"); // view.rootObject()->dumpObjectTree(); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); textEditObject->setFocus(true); QQuickItem *delegate; delegate = view.rootObject()->findChild<QQuickItem*>("delegateOkay"); @@ -2853,7 +2888,7 @@ void tst_qquicktextedit::cursorDelegateHeight() QQuickView view(testFileUrl("cursorHeight.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject"); QVERIFY(textEditObject); // Delegate creation is deferred until focus in or cursor visibility is forced. @@ -2881,7 +2916,7 @@ void tst_qquicktextedit::cursorDelegateHeight() QCOMPARE(delegateObject->height(), textEditObject->cursorRectangle().height()); // Test that the delegate gets deleted - textEditObject->setCursorDelegate(0); + textEditObject->setCursorDelegate(nullptr); QVERIFY(!textEditObject->findChild<QQuickItem*>("cursorInstance")); } @@ -2895,11 +2930,11 @@ void tst_qquicktextedit::navigation() window.show(); window.requestActivate(); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextEdit *input = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window.rootObject()->property("myInput"))); - QVERIFY(input != 0); + QVERIFY(input != nullptr); QTRY_VERIFY(input->hasActiveFocus()); simulateKey(&window, Qt::Key_Left); QVERIFY(!input->hasActiveFocus()); @@ -2933,7 +2968,7 @@ void tst_qquicktextedit::copyAndPaste() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); // copy and paste QCOMPARE(textEdit->text().length(), 12); @@ -3009,7 +3044,7 @@ void tst_qquicktextedit::canPaste() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); // check initial value - QTBUG-17765 QTextDocument document; @@ -3027,7 +3062,7 @@ void tst_qquicktextedit::canPasteEmpty() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); // check initial value - QTBUG-17765 QTextDocument document; @@ -3046,11 +3081,11 @@ void tst_qquicktextedit::middleClickPaste() window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(window.rootObject()); - QVERIFY(textEditObject != 0); + QVERIFY(textEditObject != nullptr); textEditObject->setFocus(true); @@ -3082,11 +3117,11 @@ void tst_qquicktextedit::readOnly() window.show(); window.requestActivate(); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window.rootObject()->property("myInput"))); - QVERIFY(edit != 0); + QVERIFY(edit != nullptr); QTRY_VERIFY(edit->hasActiveFocus()); QVERIFY(edit->isReadOnly()); QString initial = edit->text(); @@ -3117,7 +3152,7 @@ void tst_qquicktextedit::textInput() QQuickView view(testFileUrl("inputMethodEvent.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject()); QVERIFY(edit); QVERIFY(edit->hasActiveFocus()); @@ -3170,7 +3205,7 @@ void tst_qquicktextedit::inputMethodUpdate() QQuickView view(testFileUrl("inputMethodEvent.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject()); QVERIFY(edit); QVERIFY(edit->hasActiveFocus()); @@ -3204,7 +3239,7 @@ void tst_qquicktextedit::inputMethodUpdate() // programmatical selections trigger update platformInputContext.clear(); edit->selectAll(); - QCOMPARE(platformInputContext.m_updateCallCount, 1); + QVERIFY(platformInputContext.m_updateCallCount > 0); // font changes platformInputContext.clear(); @@ -3260,7 +3295,7 @@ void tst_qquicktextedit::openInputPanel() QQuickView view(testFileUrl("openInputPanel.qml")); view.showNormal(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject()); QVERIFY(edit); @@ -3274,7 +3309,7 @@ void tst_qquicktextedit::openInputPanel() // input panel should open on focus QPoint centerPoint(view.width()/2, view.height()/2); - Qt::KeyboardModifiers noModifiers = 0; + Qt::KeyboardModifiers noModifiers = Qt::NoModifier; QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint); QGuiApplication::processEvents(); QVERIFY(edit->hasActiveFocus()); @@ -3325,7 +3360,7 @@ void tst_qquicktextedit::openInputPanel() QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint); QCOMPARE(qApp->inputMethod()->isVisible(), false); - inputMethodPrivate->testContext = 0; + inputMethodPrivate->testContext = nullptr; } void tst_qquicktextedit::geometrySignals() @@ -3346,7 +3381,7 @@ void tst_qquicktextedit::pastingRichText_QTBUG_14003() component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickTextEdit *obj = qobject_cast<QQuickTextEdit*>(component.create()); - QTRY_VERIFY(obj != 0); + QTRY_VERIFY(obj != nullptr); QTRY_COMPARE(obj->textFormat(), QQuickTextEdit::PlainText); QMimeData *mData = new QMimeData; @@ -3388,6 +3423,18 @@ void tst_qquicktextedit::implicitSize() QCOMPARE(textObject->height(), textObject->implicitHeight()); } +void tst_qquicktextedit::implicitSize_QTBUG_63153() +{ + QString componentStr = "import QtQuick 2.0\nTextEdit { }"; + QQmlComponent textComponent(&engine); + textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create()); + textObject->setText("short"); + qreal shortImplicitWidth = textObject->implicitWidth(); + textObject->setText("in contrast to short this is long"); + QVERIFY2(shortImplicitWidth < textObject->implicitWidth(), qPrintable(QString("%1 < %2").arg(textObject->implicitWidth()).arg(shortImplicitWidth))); +} + void tst_qquicktextedit::contentSize() { QString componentStr = "import QtQuick 2.0\nTextEdit { width: 75; height: 16; font.pixelSize: 10 }"; @@ -3446,7 +3493,7 @@ void tst_qquicktextedit::implicitSizeBinding() void tst_qquicktextedit::signal_editingfinished() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); window->setBaseSize(QSize(800,600)); window->setSource(testFileUrl("signal_editingfinished.qml")); @@ -3455,7 +3502,7 @@ void tst_qquicktextedit::signal_editingfinished() QVERIFY(QTest::qWaitForWindowActive(window)); QCOMPARE(QGuiApplication::focusWindow(), window); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickTextEdit *input1 = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window->rootObject()->property("input1"))); QVERIFY(input1); @@ -3646,7 +3693,7 @@ void tst_qquicktextedit::preeditCursorRectangle() QQuickView view(testFileUrl("inputMethodEvent.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject()); QVERIFY(edit); @@ -3729,7 +3776,7 @@ void tst_qquicktextedit::inputMethodComposing() QQuickView view(testFileUrl("inputContext.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject()); QVERIFY(edit); @@ -3843,7 +3890,7 @@ void tst_qquicktextedit::cursorRectangleSize() QFETCH(bool, useCursorDelegate); QQuickView *window = new QQuickView(testFileUrl("positionAt.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window->rootObject()); QQmlComponent cursorDelegate(window->engine()); @@ -3856,11 +3903,11 @@ void tst_qquicktextedit::cursorRectangleSize() textEdit->setX(10); textEdit->setY(10); textEdit->setCursorPosition(3); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); textEdit->setFocus(true); window->show(); window->requestActivate(); - QTest::qWaitForWindowActive(window); + QVERIFY(QTest::qWaitForWindowActive(window)); QInputMethodQueryEvent event(Qt::ImCursorRectangle); qApp->sendEvent(textEdit, &event); @@ -3994,7 +4041,7 @@ void tst_qquicktextedit::getText() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); QCOMPARE(textEdit->getText(start, end), expectedText); } @@ -4095,7 +4142,7 @@ void tst_qquicktextedit::getFormattedText() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); textEdit->setTextFormat(textFormat); textEdit->setText(text); @@ -4221,7 +4268,7 @@ void tst_qquicktextedit::append() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); textEdit->setTextFormat(textFormat); textEdit->select(selectionStart, selectionEnd); @@ -4436,7 +4483,7 @@ void tst_qquicktextedit::insert() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); textEdit->setTextFormat(textFormat); textEdit->select(selectionStart, selectionEnd); @@ -4678,7 +4725,7 @@ void tst_qquicktextedit::remove() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); textEdit->setTextFormat(textFormat); textEdit->select(selectionStart, selectionEnd); @@ -4859,13 +4906,13 @@ void tst_qquicktextedit::keySequence() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); QQuickWindow window; textEdit->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textEdit->hasActiveFocus()); @@ -5021,13 +5068,13 @@ void tst_qquicktextedit::undo() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); QQuickWindow window; textEdit->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textEdit->hasActiveFocus()); QVERIFY(!textEdit->canUndo()); @@ -5107,13 +5154,13 @@ void tst_qquicktextedit::redo() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); QQuickWindow window; textEdit->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textEdit->hasActiveFocus()); QVERIFY(!textEdit->canUndo()); @@ -5328,13 +5375,13 @@ void tst_qquicktextedit::undo_keypressevents() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); QQuickWindow window; textEdit->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textEdit->hasActiveFocus()); simulateKeys(&window, keys); @@ -5352,13 +5399,13 @@ void tst_qquicktextedit::clear() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); QQuickWindow window; textEdit->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textEdit->hasActiveFocus()); QSignalSpy spy(textEdit, SIGNAL(canUndoChanged())); @@ -5462,7 +5509,7 @@ void tst_qquicktextedit::embeddedImages() QQmlComponent textComponent(&engine, qmlfile); QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.beginCreate(engine.rootContext())); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); const int baseUrlPropertyIndex = textObject->metaObject()->indexOfProperty("serverBaseUrl"); if (baseUrlPropertyIndex != -1) { @@ -5490,11 +5537,11 @@ void tst_qquicktextedit::embeddedImages() void tst_qquicktextedit::emptytags_QTBUG_22058() { QQuickView window(testFileUrl("qtbug-22058.qml")); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QQuickTextEdit *input = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window.rootObject()->property("inputField"))); QVERIFY(input->hasActiveFocus()); @@ -5513,7 +5560,7 @@ void tst_qquicktextedit::cursorRectangle_QTBUG_38947() window.show(); window.requestActivate(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); QQuickTextEdit *edit = window.rootObject()->findChild<QQuickTextEdit *>("textedit"); QVERIFY(edit); @@ -5551,7 +5598,7 @@ void tst_qquicktextedit::doubleSelect_QTBUG_38704() QQmlComponent textEditComponent(&engine); textEditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); - QVERIFY(textEdit != 0); + QVERIFY(textEdit != nullptr); QSignalSpy selectionSpy(textEdit, SIGNAL(selectedTextChanged())); @@ -5575,7 +5622,7 @@ void tst_qquicktextedit::padding() QQuickItem *root = window->rootObject(); QVERIFY(root); QQuickTextEdit *obj = qobject_cast<QQuickTextEdit*>(root); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); qreal cw = obj->contentWidth(); qreal ch = obj->contentHeight(); @@ -5654,6 +5701,36 @@ void tst_qquicktextedit::QTBUG_51115_readOnlyResetsSelection() QCOMPARE(obj->selectedText(), QString()); } +void tst_qquicktextedit::keys_shortcutoverride() +{ + // Tests that QML TextEdit receives Keys.onShortcutOverride (QTBUG-68711) + QQuickView view; + view.setSource(testFileUrl("keys_shortcutoverride.qml")); + view.show(); + view.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + QObject *root = view.rootObject(); + QVERIFY(root); + + QQuickTextEdit *textEdit = root->findChild<QQuickTextEdit*>(); + QVERIFY(textEdit); + QQuickRectangle *rectangle = root->findChild<QQuickRectangle*>(QLatin1String("rectangle")); + QVERIFY(rectangle); + + // Precondition: check if its not already changed + QCOMPARE(root->property("who").value<QString>(), QLatin1String("nobody")); + + // send Key_Escape to the Rectangle + QVERIFY(rectangle->hasActiveFocus()); + QTest::keyPress(&view, Qt::Key_Escape); + QCOMPARE(root->property("who").value<QString>(), QLatin1String("Rectangle")); + + // send Key_Escape to TextEdit + textEdit->setFocus(true); + QTest::keyPress(&view, Qt::Key_Escape); + QCOMPARE(root->property("who").value<QString>(), QLatin1String("TextEdit")); +} + QTEST_MAIN(tst_qquicktextedit) #include "tst_qquicktextedit.moc" diff --git a/tests/auto/quick/qquicktextinput/BLACKLIST b/tests/auto/quick/qquicktextinput/BLACKLIST deleted file mode 100644 index e9f4f11c58..0000000000 --- a/tests/auto/quick/qquicktextinput/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -# QTBUG-41895 -[tripleClickSelectsAll] -windows diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index 67921e1fd0..ed2d535fda 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -215,6 +215,9 @@ private slots: void clearInputMask(); void keypress_inputMask_data(); void keypress_inputMask(); + void keypress_inputMethod_inputMask(); + void keypress_inputMask_withValidator_data(); + void keypress_inputMask_withValidator(); void hasAcceptableInputMask_data(); void hasAcceptableInputMask(); void maskCharacter_data(); @@ -297,7 +300,7 @@ void tst_qquicktextinput::cleanup() { // ensure not even skipped tests with custom input context leave it dangling QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); - inputMethodPrivate->testContext = 0; + inputMethodPrivate->testContext = nullptr; } tst_qquicktextinput::tst_qquicktextinput() @@ -329,7 +332,7 @@ void tst_qquicktextinput::text() textinputComponent.setData("import QtQuick 2.0\nTextInput { text: \"\" }", QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->text(), QString("")); QCOMPARE(textinputObject->length(), 0); @@ -343,7 +346,7 @@ void tst_qquicktextinput::text() textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->text(), standard.at(i)); QCOMPARE(textinputObject->length(), standard.at(i).length()); @@ -360,7 +363,7 @@ void tst_qquicktextinput::width() textinputComponent.setData("import QtQuick 2.0\nTextInput { text: \"\" }", QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->width(), 0.0); delete textinputObject; @@ -398,7 +401,7 @@ void tst_qquicktextinput::width() qreal metricWidth = ceil(layout.boundingRect().width()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); int delta = abs(int(int(textinputObject->width()) - metricWidth)); QVERIFY(delta <= 3.0); // As best as we can hope for cross-platform. @@ -415,7 +418,7 @@ void tst_qquicktextinput::font() textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->font().pointSize(), 40); QCOMPARE(textinputObject->font().bold(), false); QCOMPARE(textinputObject->font().italic(), false); @@ -429,7 +432,7 @@ void tst_qquicktextinput::font() textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->font().bold(), true); QCOMPARE(textinputObject->font().italic(), false); @@ -442,7 +445,7 @@ void tst_qquicktextinput::font() textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->font().italic(), true); QCOMPARE(textinputObject->font().bold(), false); @@ -455,7 +458,7 @@ void tst_qquicktextinput::font() textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->font().family(), QString("Helvetica")); QCOMPARE(textinputObject->font().bold(), false); QCOMPARE(textinputObject->font().italic(), false); @@ -469,7 +472,7 @@ void tst_qquicktextinput::font() textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->font().family(), QString("")); delete textinputObject; @@ -536,7 +539,7 @@ void tst_qquicktextinput::color() QQmlComponent textinputComponent(&engine); textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->color(), QColor(colorStrings.at(i))); delete textinputObject; @@ -549,7 +552,7 @@ void tst_qquicktextinput::color() QQmlComponent textinputComponent(&engine); textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->selectionColor(), QColor(colorStrings.at(i))); delete textinputObject; @@ -562,7 +565,7 @@ void tst_qquicktextinput::color() QQmlComponent textinputComponent(&engine); textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->selectedTextColor(), QColor(colorStrings.at(i))); delete textinputObject; @@ -578,7 +581,7 @@ void tst_qquicktextinput::color() textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QCOMPARE(textinputObject->color(), testColor); delete textinputObject; @@ -595,7 +598,7 @@ void tst_qquicktextinput::wrap() QQuickTextInput *textObject = qobject_cast<QQuickTextInput*>(textComponent.create()); textHeight = textObject->height(); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->wrapMode(), QQuickTextInput::WrapAnywhere); QCOMPARE(textObject->width(), 300.); @@ -608,7 +611,7 @@ void tst_qquicktextinput::wrap() textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); QQuickTextInput *textObject = qobject_cast<QQuickTextInput*>(textComponent.create()); - QVERIFY(textObject != 0); + QVERIFY(textObject != nullptr); QCOMPARE(textObject->width(), 30.); QVERIFY(textObject->height() > textHeight); @@ -650,7 +653,7 @@ void tst_qquicktextinput::selection() QQmlComponent textinputComponent(&engine); textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); //Test selection follows cursor @@ -747,7 +750,7 @@ void tst_qquicktextinput::persistentSelection() QQuickView window(testFileUrl("persistentSelection.qml")); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(window.rootObject()); QVERIFY(input); @@ -790,7 +793,7 @@ void tst_qquicktextinput::overwriteMode() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); QSignalSpy spy(textInput, SIGNAL(overwriteModeChanged(bool))); @@ -798,7 +801,7 @@ void tst_qquicktextinput::overwriteMode() textInput->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textInput->hasActiveFocus()); @@ -1068,7 +1071,7 @@ void tst_qquicktextinput::moveCursorSelection() QQmlComponent textinputComponent(&engine); textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); textinputObject->setCursorPosition(cursorPosition); textinputObject->moveCursorSelection(movePosition, mode); @@ -1276,7 +1279,7 @@ void tst_qquicktextinput::moveCursorSelectionSequence() QQmlComponent textinputComponent(&engine); textinputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput*>(textinputComponent.create()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); textinputObject->setCursorPosition(cursorPosition); @@ -1301,19 +1304,19 @@ void tst_qquicktextinput::dragMouseSelection() window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(window.rootObject()); - QVERIFY(textInputObject != 0); + QVERIFY(textInputObject != nullptr); // press-and-drag-and-release from x1 to x2 int x1 = 10; int x2 = 70; int y = textInputObject->height()/2; - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(x1,y)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x1,y)); QTest::mouseMove(&window, QPoint(x2, y)); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(x2,y)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x2,y)); QString str1; QTRY_VERIFY((str1 = textInputObject->selectedText()).length() > 3); QTRY_VERIFY(str1.length() > 3); @@ -1321,9 +1324,9 @@ void tst_qquicktextinput::dragMouseSelection() // press and drag the current selection. x1 = 40; x2 = 100; - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(x1,y)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x1,y)); QTest::mouseMove(&window, QPoint(x2, y)); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(x2,y)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x2,y)); QString str2 = textInputObject->selectedText(); QTRY_VERIFY(str2.length() > 3); @@ -1362,11 +1365,11 @@ void tst_qquicktextinput::mouseSelectionMode() window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(window.rootObject()); - QVERIFY(textInputObject != 0); + QVERIFY(textInputObject != nullptr); textInputObject->setFocus(focus); textInputObject->setFocusOnPress(focusOnPress); @@ -1375,9 +1378,9 @@ void tst_qquicktextinput::mouseSelectionMode() int x1 = 10; int x2 = 70; int y = textInputObject->height()/2; - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(x1,y)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x1,y)); QTest::mouseMove(&window, QPoint(x2,y)); // doesn't work - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(x2,y)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x2,y)); if (selectWords) { QTRY_COMPARE(textInputObject->selectedText(), text); } else { @@ -1468,7 +1471,7 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() QQuickView window(testFileUrl("horizontalAlignment_RightToLeft.qml")); QQuickTextInput *textInput = window.rootObject()->findChild<QQuickTextInput*>("text"); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); window.show(); const QString rtlText = textInput->text(); @@ -1542,7 +1545,7 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft() QCOMPARE(textInput->boundingRect().left(), qreal(0)); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textInput->hasActiveFocus()); // If there is no committed text, the preedit text should determine the alignment. @@ -1615,7 +1618,7 @@ void tst_qquicktextinput::verticalAlignment() { QQuickView window(testFileUrl("horizontalAlignment.qml")); QQuickTextInput *textInput = window.rootObject()->findChild<QQuickTextInput*>("text"); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); window.showNormal(); QCOMPARE(textInput->vAlign(), QQuickTextInput::AlignTop); @@ -1802,13 +1805,13 @@ void tst_qquicktextinput::boundingRect() void tst_qquicktextinput::positionAt() { QQuickView window(testFileUrl("positionAt.qml")); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput *>(window.rootObject()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); // Check autoscrolled... @@ -1892,13 +1895,13 @@ void tst_qquicktextinput::positionAt() void tst_qquicktextinput::maxLength() { QQuickView window(testFileUrl("maxLength.qml")); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput *>(window.rootObject()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QVERIFY(textinputObject->text().isEmpty()); QCOMPARE(textinputObject->maxLength(), 10); foreach (const QString &str, standard) { @@ -1924,9 +1927,9 @@ void tst_qquicktextinput::masks() QQuickView window(testFileUrl("masks.qml")); window.show(); window.requestActivate(); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput *>(window.rootObject()); - QVERIFY(textinputObject != 0); + QVERIFY(textinputObject != nullptr); QTRY_VERIFY(textinputObject->hasActiveFocus()); QCOMPARE(textinputObject->text().length(), 0); QCOMPARE(textinputObject->inputMask(), QString("HHHHhhhh; ")); @@ -1954,9 +1957,9 @@ void tst_qquicktextinput::validators() QQuickView window(testFileUrl("validators.qml")); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QLocale defaultLocale; QLocale enLocale("en"); @@ -1987,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); @@ -2244,12 +2244,12 @@ void tst_qquicktextinput::inputMethods() QQuickView window(testFileUrl("inputmethods.qml")); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); // test input method hints - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(window.rootObject()); - QVERIFY(input != 0); + QVERIFY(input != nullptr); QVERIFY(input->inputMethodHints() & Qt::ImhNoPredictiveText); QSignalSpy inputMethodHintSpy(input, SIGNAL(inputMethodHintsChanged())); input->setInputMethodHints(Qt::ImhUppercaseOnly); @@ -2291,8 +2291,9 @@ void tst_qquicktextinput::inputMethods() QGuiApplication::sendEvent(input, &event); QCOMPARE(input->text(), QString("Our Goodbye world!")); QCOMPARE(input->displayText(), QString("Our Goodbye world!")); - QCOMPARE(input->cursorPosition(), 7); + QCOMPARE(input->cursorPosition(), 3); + input->setCursorPosition(7); QInputMethodEvent preeditEvent("PREEDIT", QList<QInputMethodEvent::Attribute>()); QGuiApplication::sendEvent(input, &preeditEvent); QCOMPARE(input->text(), QString("Our Goodbye world!")); @@ -2335,9 +2336,9 @@ void tst_qquicktextinput::signal_accepted() QQuickView window(testFileUrl("signal_accepted.qml")); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("input"))); QVERIFY(input); @@ -2377,9 +2378,9 @@ void tst_qquicktextinput::signal_editingfinished() QQuickView window(testFileUrl("signal_editingfinished.qml")); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *input1 = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("input1"))); QVERIFY(input1); @@ -2447,7 +2448,7 @@ void tst_qquicktextinput::signal_textEdited() QQuickWindow window; window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QQuickTextInput *input = new QQuickTextInput(window.contentItem()); QVERIFY(input); @@ -2504,11 +2505,11 @@ void tst_qquicktextinput::navigation() window.show(); window.requestActivate(); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("myInput"))); - QVERIFY(input != 0); + QVERIFY(input != nullptr); input->setCursorPosition(0); QTRY_VERIFY(input->hasActiveFocus()); simulateKey(&window, Qt::Key_Left); @@ -2553,11 +2554,11 @@ void tst_qquicktextinput::navigation_RTL() window.show(); window.requestActivate(); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("myInput"))); - QVERIFY(input != 0); + QVERIFY(input != nullptr); const quint16 arabic_str[] = { 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0638, 0x0643, 0x00646, 0x0647, 0x0633, 0x0647}; input->setText(QString::fromUtf16(arabic_str, 11)); @@ -2594,7 +2595,7 @@ void tst_qquicktextinput::copyAndPaste() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); // copy and paste QCOMPARE(textInput->text().length(), 12); @@ -2673,7 +2674,7 @@ void tst_qquicktextinput::copyAndPaste() QCOMPARE(clipboard->text(), QString("My password")); clipboard->clear(); } else { - QVERIFY(clipboard->text().isEmpty()); + QVERIFY(!clipboard->ownsSelection() || clipboard->text().isEmpty()); } index++; } @@ -2692,13 +2693,13 @@ void tst_qquicktextinput::copyAndPasteKeySequence() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); QQuickWindow window; textInput->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); // copy and paste QVERIFY(textInput->hasActiveFocus()); @@ -2741,7 +2742,7 @@ void tst_qquicktextinput::copyAndPasteKeySequence() QCOMPARE(clipboard->text(), QString("My password")); clipboard->clear(); } else { - QVERIFY(clipboard->text().isEmpty()); + QVERIFY(!clipboard->ownsClipboard() || clipboard->text().isEmpty()); } index++; } @@ -2759,7 +2760,7 @@ void tst_qquicktextinput::canPasteEmpty() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); bool cp = !textInput->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0; QCOMPARE(textInput->canPaste(), cp); @@ -2775,7 +2776,7 @@ void tst_qquicktextinput::canPaste() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); bool cp = !textInput->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0; QCOMPARE(textInput->canPaste(), cp); @@ -2792,11 +2793,11 @@ void tst_qquicktextinput::middleClickPaste() window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(window.rootObject()); - QVERIFY(textInputObject != 0); + QVERIFY(textInputObject != nullptr); textInputObject->setFocus(true); @@ -2831,7 +2832,7 @@ void tst_qquicktextinput::passwordCharacter() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); textInput->setPasswordCharacter("X"); qreal implicitWidth = textInput->implicitWidth(); @@ -2857,9 +2858,9 @@ void tst_qquicktextinput::cursorDelegate() QQuickView view(source); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextInput *textInputObject = view.rootObject()->findChild<QQuickTextInput*>("textInputObject"); - QVERIFY(textInputObject != 0); + QVERIFY(textInputObject != nullptr); // Delegate is created on demand, and so won't be available immediately. Focus in or // setCursorVisible(true) will trigger creation. QTRY_VERIFY(!textInputObject->findChild<QQuickItem*>("cursorInstance")); @@ -2885,7 +2886,7 @@ void tst_qquicktextinput::cursorDelegate() textInputObject->setCursorPosition(0); const QPoint point1 = textInputObject->positionToRectangle(5).center().toPoint(); QTest::qWait(400); //ensure this isn't treated as a double-click - QTest::mouseClick(&view, Qt::LeftButton, 0, point1); + QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, point1); QTest::qWait(50); QTRY_VERIFY(textInputObject->cursorPosition() != 0); QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); @@ -2895,10 +2896,10 @@ void tst_qquicktextinput::cursorDelegate() textInputObject->setCursorPosition(0); const QPoint point2 = textInputObject->positionToRectangle(10).center().toPoint(); QTest::qWait(400); //ensure this isn't treated as a double-click - QTest::mousePress(&view, Qt::LeftButton, 0, point1); + QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, point1); QMouseEvent mv(QEvent::MouseMove, point2, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); QGuiApplication::sendEvent(&view, &mv); - QTest::mouseRelease(&view, Qt::LeftButton, 0, point2); + QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, point2); QTest::qWait(50); QTRY_COMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y()); @@ -2906,7 +2907,7 @@ void tst_qquicktextinput::cursorDelegate() textInputObject->setReadOnly(true); textInputObject->setCursorPosition(0); QTest::qWait(400); //ensure this isn't treated as a double-click - QTest::mouseClick(&view, Qt::LeftButton, 0, textInputObject->positionToRectangle(5).center().toPoint()); + QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, textInputObject->positionToRectangle(5).center().toPoint()); QTest::qWait(50); QTRY_VERIFY(textInputObject->cursorPosition() != 0); QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); @@ -2914,7 +2915,7 @@ void tst_qquicktextinput::cursorDelegate() textInputObject->setCursorPosition(0); QTest::qWait(400); //ensure this isn't treated as a double-click - QTest::mouseClick(&view, Qt::LeftButton, 0, textInputObject->positionToRectangle(5).center().toPoint()); + QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, textInputObject->positionToRectangle(5).center().toPoint()); QTest::qWait(50); QTRY_VERIFY(textInputObject->cursorPosition() != 0); QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x()); @@ -2960,7 +2961,7 @@ void tst_qquicktextinput::cursorDelegate() } //Test Delegate gets deleted - textInputObject->setCursorDelegate(0); + textInputObject->setCursorDelegate(nullptr); QVERIFY(!textInputObject->findChild<QQuickItem*>("cursorInstance")); } @@ -2975,9 +2976,9 @@ void tst_qquicktextinput::remoteCursorDelegate() view.setSource(testFileUrl("cursorTestRemote.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextInput *textInputObject = view.rootObject()->findChild<QQuickTextInput*>("textInputObject"); - QVERIFY(textInputObject != 0); + QVERIFY(textInputObject != nullptr); // Delegate is created on demand, and so won't be available immediately. Focus in or // setCursorVisible(true) will trigger creation. @@ -3002,7 +3003,7 @@ void tst_qquicktextinput::cursorVisible() QQuickView view(testFileUrl("cursorVisible.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QCOMPARE(input.isCursorVisible(), false); @@ -3033,13 +3034,13 @@ void tst_qquicktextinput::cursorVisible() QQuickView alternateView; alternateView.show(); alternateView.requestActivate(); - QTest::qWaitForWindowActive(&alternateView); + QVERIFY(QTest::qWaitForWindowActive(&alternateView)); QCOMPARE(input.isCursorVisible(), false); QCOMPARE(spy.count(), 6); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QCOMPARE(input.isCursorVisible(), true); QCOMPARE(spy.count(), 7); @@ -3303,11 +3304,11 @@ void tst_qquicktextinput::readOnly() window.show(); window.requestActivate(); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("myInput"))); - QVERIFY(input != 0); + QVERIFY(input != nullptr); QTRY_VERIFY(input->hasActiveFocus()); QVERIFY(input->isReadOnly()); QVERIFY(!input->isCursorVisible()); @@ -3331,13 +3332,13 @@ void tst_qquicktextinput::echoMode() QQuickView window(testFileUrl("echoMode.qml")); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("myInput"))); - QVERIFY(input != 0); + QVERIFY(input != nullptr); QTRY_VERIFY(input->hasActiveFocus()); QString initial = input->text(); Qt::InputMethodHints ref; @@ -3407,9 +3408,9 @@ void tst_qquicktextinput::passwordEchoDelay() QQuickView window(testFileUrl("echoMode.qml")); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); - QVERIFY(window.rootObject() != 0); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("myInput"))); QVERIFY(input); @@ -3474,8 +3475,8 @@ void tst_qquicktextinput::passwordEchoDelay() void tst_qquicktextinput::simulateKey(QWindow *view, int key) { - QKeyEvent press(QKeyEvent::KeyPress, key, 0); - QKeyEvent release(QKeyEvent::KeyRelease, key, 0); + QKeyEvent press(QKeyEvent::KeyPress, key, nullptr); + QKeyEvent release(QKeyEvent::KeyRelease, key, nullptr); QGuiApplication::sendEvent(view, &press); QGuiApplication::sendEvent(view, &release); @@ -3496,7 +3497,7 @@ void tst_qquicktextinput::focusOnPress() QQmlComponent texteditComponent(&engine); texteditComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput*>(texteditComponent.create()); - QVERIFY(textInputObject != 0); + QVERIFY(textInputObject != nullptr); QCOMPARE(textInputObject->focusOnPress(), true); QCOMPARE(textInputObject->hasFocus(), false); @@ -3513,12 +3514,12 @@ void tst_qquicktextinput::focusOnPress() textInputObject->setParentItem(window.contentItem()); window.showNormal(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QCOMPARE(textInputObject->hasFocus(), false); QCOMPARE(textInputObject->hasActiveFocus(), false); - Qt::KeyboardModifiers noModifiers = 0; + Qt::KeyboardModifiers noModifiers = Qt::NoModifier; QTest::mousePress(&window, Qt::LeftButton, noModifiers); QGuiApplication::processEvents(); QCOMPARE(textInputObject->hasFocus(), true); @@ -3571,7 +3572,7 @@ void tst_qquicktextinput::focusOnPressOnlyOneItem() QQuickView window(testFileUrl("focusOnlyOneOnPress.qml")); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QQuickTextInput *first = window.rootObject()->findChild<QQuickTextInput*>("first"); QQuickTextInput *second = window.rootObject()->findChild<QQuickTextInput*>("second"); @@ -3592,7 +3593,7 @@ void tst_qquicktextinput::focusOnPressOnlyOneItem() // // this is a contrived example to be sure, but at the end of this, the // important thing is that only one thing should have activeFocus. - Qt::KeyboardModifiers noModifiers = 0; + Qt::KeyboardModifiers noModifiers = nullptr; QTest::mousePress(&window, Qt::LeftButton, noModifiers, QPoint(10, 10)); // make sure the press is processed. @@ -3615,7 +3616,7 @@ void tst_qquicktextinput::openInputPanel() QQuickView view(testFileUrl("openInputPanel.qml")); view.showNormal(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(view.rootObject()); QVERIFY(input); @@ -3627,7 +3628,7 @@ void tst_qquicktextinput::openInputPanel() QCOMPARE(qApp->inputMethod()->isVisible(), false); // input panel should open on focus - Qt::KeyboardModifiers noModifiers = 0; + Qt::KeyboardModifiers noModifiers = nullptr; QTest::mousePress(&view, Qt::LeftButton, noModifiers); QGuiApplication::processEvents(); QVERIFY(input->hasActiveFocus()); @@ -3683,7 +3684,7 @@ void tst_qquicktextinput::openInputPanel() class MyTextInput : public QQuickTextInput { public: - MyTextInput(QQuickItem *parent = 0) : QQuickTextInput(parent) + MyTextInput(QQuickItem *parent = nullptr) : QQuickTextInput(parent) { nbPaint = 0; } @@ -3704,7 +3705,7 @@ void tst_qquicktextinput::setHAlignClearCache() input.setParentItem(view.contentItem()); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QTRY_COMPARE(input.nbPaint, 1); input.setHAlign(QQuickTextInput::AlignRight); //Changing the alignment should trigger a repaint @@ -3724,7 +3725,7 @@ void tst_qquicktextinput::focusOutClearSelection() input2.componentComplete(); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QVERIFY(input.hasActiveFocus()); input.select(2,5); //The selection should work @@ -3745,7 +3746,7 @@ void tst_qquicktextinput::focusOutNotClearSelection() input.componentComplete(); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QVERIFY(input.hasActiveFocus()); input.select(2,5); @@ -3838,7 +3839,7 @@ void tst_qquicktextinput::preeditAutoScroll() QQuickView view(testFileUrl("preeditAutoScroll.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(view.rootObject()); QVERIFY(input); QVERIFY(input->hasActiveFocus()); @@ -3924,7 +3925,7 @@ void tst_qquicktextinput::preeditCursorRectangle() QQuickView view(testFileUrl("inputMethodEvent.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(view.rootObject()); QVERIFY(input); QVERIFY(input->hasActiveFocus()); @@ -4007,7 +4008,7 @@ void tst_qquicktextinput::inputContextMouseHandler() view.showNormal(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QTextLayout layout(text); layout.setFont(input->font()); @@ -4043,7 +4044,7 @@ void tst_qquicktextinput::inputMethodComposing() QQuickView view(testFileUrl("inputContext.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(view.rootObject()); QVERIFY(input); QVERIFY(input->hasActiveFocus()); @@ -4149,7 +4150,7 @@ void tst_qquicktextinput::inputMethodUpdate() QQuickView view(testFileUrl("inputContext.qml")); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextInput *input = qobject_cast<QQuickTextInput *>(view.rootObject()); QVERIFY(input); QVERIFY(input->hasActiveFocus()); @@ -4228,18 +4229,18 @@ void tst_qquicktextinput::inputMethodUpdate() void tst_qquicktextinput::cursorRectangleSize() { QQuickView *window = new QQuickView(testFileUrl("positionAt.qml")); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickTextInput *textInput = qobject_cast<QQuickTextInput *>(window->rootObject()); // make sure cursor rectangle is not at (0,0) textInput->setX(10); textInput->setY(10); textInput->setCursorPosition(3); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); textInput->setFocus(true); window->show(); window->requestActivate(); - QTest::qWaitForWindowActive(window); + QVERIFY(QTest::qWaitForWindowActive(window)); QVERIFY(textInput->hasActiveFocus()); QInputMethodQueryEvent event(Qt::ImCursorRectangle); @@ -4271,7 +4272,7 @@ void tst_qquicktextinput::tripleClickSelectsAll() QQuickView view(QUrl::fromLocalFile(qmlfile)); view.show(); view.requestActivate(); - QTest::qWaitForWindowActive(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); QQuickTextInput* input = qobject_cast<QQuickTextInput*>(view.rootObject()); QVERIFY(input); @@ -4283,24 +4284,24 @@ void tst_qquicktextinput::tripleClickSelectsAll() // Clicking on the same point inside TextInput three times in a row // should trigger a triple click, thus selecting all the text. QPoint pointInside = input->position().toPoint() + QPoint(2,2); - QTest::mouseDClick(&view, Qt::LeftButton, 0, pointInside); - QTest::mouseClick(&view, Qt::LeftButton, 0, pointInside); + QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, pointInside); + QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, pointInside); QGuiApplication::processEvents(); QCOMPARE(input->selectedText(), hello); // Now it simulates user moving the mouse between the second and the third click. // In this situation, we don't expect a triple click. QPoint pointInsideButFar = QPoint(input->width(),input->height()) - QPoint(2,2); - QTest::mouseDClick(&view, Qt::LeftButton, 0, pointInside); - QTest::mouseClick(&view, Qt::LeftButton, 0, pointInsideButFar); + QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, pointInside); + QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, pointInsideButFar); QGuiApplication::processEvents(); QVERIFY(input->selectedText().isEmpty()); // And now we press the third click too late, so no triple click event is triggered. - QTest::mouseDClick(&view, Qt::LeftButton, 0, pointInside); + QTest::mouseDClick(&view, Qt::LeftButton, Qt::NoModifier, pointInside); QGuiApplication::processEvents(); QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 1); - QTest::mouseClick(&view, Qt::LeftButton, 0, pointInside); + QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, pointInside); QGuiApplication::processEvents(); QVERIFY(input->selectedText().isEmpty()); } @@ -4370,7 +4371,7 @@ void tst_qquicktextinput::getText() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); QCOMPARE(textInput->getText(start, end), expectedText); } @@ -4710,7 +4711,7 @@ void tst_qquicktextinput::insert() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); textInput->select(selectionStart, selectionEnd); @@ -5065,7 +5066,7 @@ void tst_qquicktextinput::remove() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); textInput->select(selectionStart, selectionEnd); @@ -5260,14 +5261,14 @@ void tst_qquicktextinput::keySequence() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); textInput->setEchoMode(echoMode); QQuickWindow window; textInput->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textInput->hasActiveFocus()); simulateKey(&window, layoutDirection); @@ -5422,13 +5423,13 @@ void tst_qquicktextinput::undo() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); QQuickWindow window; textInput->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textInput->hasActiveFocus()); QVERIFY(!textInput->canUndo()); @@ -5508,13 +5509,13 @@ void tst_qquicktextinput::redo() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); QQuickWindow window; textInput->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textInput->hasActiveFocus()); QVERIFY(!textInput->canUndo()); @@ -5840,13 +5841,13 @@ void tst_qquicktextinput::undo_keypressevents() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); QQuickWindow window; textInput->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textInput->hasActiveFocus()); simulateKeys(&window, keys); @@ -5864,13 +5865,13 @@ void tst_qquicktextinput::clear() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); QQuickWindow window; textInput->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textInput->hasActiveFocus()); QVERIFY(!textInput->canUndo()); @@ -5918,7 +5919,7 @@ void tst_qquicktextinput::backspaceSurrogatePairs() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); textInput->setText(text); textInput->setCursorPosition(text.length()); @@ -5952,8 +5953,8 @@ void tst_qquicktextinput::QTBUG_19956() QQuickView window(testFileUrl(url)); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); - QVERIFY(window.rootObject() != 0); + QVERIFY(QTest::qWaitForWindowActive(&window)); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *input = qobject_cast<QQuickTextInput*>(window.rootObject()); QVERIFY(input); input->setFocus(true); @@ -5985,14 +5986,14 @@ 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); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); - QVERIFY(window.rootObject() != 0); + QVERIFY(QTest::qWaitForWindowActive(&window)); + QVERIFY(window.rootObject() != nullptr); QQuickTextInput *input = qobject_cast<QQuickTextInput*>(window.rootObject()); QVERIFY(input); input->setFocus(true); @@ -6110,6 +6111,87 @@ void tst_qquicktextinput::negativeDimensions() QCOMPARE(input->height(), qreal(-1)); } +void tst_qquicktextinput::keypress_inputMask_withValidator_data() +{ + QTest::addColumn<QString>("mask"); + QTest::addColumn<qreal>("validatorMinimum"); + QTest::addColumn<qreal>("validatorMaximum"); + QTest::addColumn<int>("decimals"); + QTest::addColumn<QString>("validatorRegExp"); + QTest::addColumn<KeyList>("keys"); + QTest::addColumn<QString>("expectedText"); + QTest::addColumn<QString>("expectedDisplayText"); + + { + KeyList keys; + // inserting '1212' then two backspaces + keys << Qt::Key_Home << "1212" << Qt::Key_Backspace << Qt::Key_Backspace; + QTest::newRow("backspaceWithInt") << QString("9999;_") << 1.0 << 9999.00 << 0 << QString() + << keys << QString("12") << QString("12__"); + } + { + KeyList keys; + // inserting '12.12' then two backspaces + keys << Qt::Key_Home << "12.12" << Qt::Key_Backspace << Qt::Key_Backspace; + QTest::newRow("backspaceWithDouble") << QString("99.99;_") << 1.0 << 99.99 << 2 << QString() + << keys << QString("12.") << QString("12.__"); + } + { + KeyList keys; + // inserting '1111.11' then two backspaces + keys << Qt::Key_Home << "1111.11" << Qt::Key_Backspace << Qt::Key_Backspace; + QTest::newRow("backspaceWithRegExp") << QString("9999;_") << 0.0 << 0.0 << 0 + << QString("/^[-]?((\\.\\d+)|(\\d+(\\.\\d+)?))$/") + << keys << QString("11") << QString("11__"); + } + { + KeyList keys; + // inserting '99' - QTBUG-64616 + keys << Qt::Key_Home << "99"; + QTest::newRow("invalidTextWithRegExp") << QString("X9;_") << 0.0 << 0.0 << 0 + << QString("/[+-][0+9]/") + << keys << QString("") << QString("__"); + } +} + +void tst_qquicktextinput::keypress_inputMask_withValidator() +{ + QFETCH(QString, mask); + QFETCH(qreal, validatorMinimum); + QFETCH(qreal, validatorMaximum); + QFETCH(int, decimals); + QFETCH(QString, validatorRegExp); + QFETCH(KeyList, keys); + QFETCH(QString, expectedText); + QFETCH(QString, expectedDisplayText); + + QString componentStr = "import QtQuick 2.0\nTextInput { focus: true; inputMask: \"" + mask + "\"\n"; + if (!validatorRegExp.isEmpty()) + componentStr += "validator: RegExpValidator { regExp: " + validatorRegExp + " }\n}"; + else if (decimals > 0) + componentStr += QString("validator: DoubleValidator { bottom: %1; decimals: %2; top: %3 }\n}"). + arg(validatorMinimum).arg(decimals).arg(validatorMaximum); + else + componentStr += QString("validator: IntValidator { bottom: %1; top: %2 }\n}"). + arg((int)validatorMinimum).arg((int)validatorMaximum); + + QQmlComponent textInputComponent(&engine); + textInputComponent.setData(componentStr.toLatin1(), QUrl()); + QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); + QVERIFY(textInput != nullptr); + + QQuickWindow window; + textInput->setParentItem(window.contentItem()); + window.show(); + window.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + QVERIFY(textInput->hasActiveFocus()); + + simulateKeys(&window, keys); + + QCOMPARE(textInput->text(), expectedText); + QCOMPARE(textInput->displayText(), expectedDisplayText); +} void tst_qquicktextinput::setInputMask_data() { @@ -6326,7 +6408,7 @@ void tst_qquicktextinput::setInputMask() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); // then either insert using insert() or keyboard if (insert_text) { @@ -6336,7 +6418,7 @@ void tst_qquicktextinput::setInputMask() textInput->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textInput->hasActiveFocus()); simulateKey(&window, Qt::Key_Home); @@ -6383,7 +6465,7 @@ void tst_qquicktextinput::inputMask() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); QCOMPARE(textInput->inputMask(), expectedMask); } @@ -6394,7 +6476,7 @@ void tst_qquicktextinput::clearInputMask() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); QVERIFY(!textInput->inputMask().isEmpty()); textInput->setInputMask(QString()); @@ -6466,13 +6548,13 @@ void tst_qquicktextinput::keypress_inputMask() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); QQuickWindow window; textInput->setParentItem(window.contentItem()); window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QVERIFY(textInput->hasActiveFocus()); simulateKeys(&window, keys); @@ -6481,6 +6563,48 @@ void tst_qquicktextinput::keypress_inputMask() QCOMPARE(textInput->displayText(), expectedDisplayText); } +void tst_qquicktextinput::keypress_inputMethod_inputMask() +{ + // Similar to the keypress_inputMask test, but this is done solely via + // input methods + QString componentStr = "import QtQuick 2.0\nTextInput { focus: true; inputMask: \"AA.AA.AA\" }"; + QQmlComponent textInputComponent(&engine); + textInputComponent.setData(componentStr.toLatin1(), QUrl()); + QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); + QVERIFY(textInput != nullptr); + + QQuickWindow window; + textInput->setParentItem(window.contentItem()); + window.show(); + window.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + QVERIFY(textInput->hasActiveFocus()); + + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("EE"); + QGuiApplication::sendEvent(textInput, &event); + } + QCOMPARE(textInput->cursorPosition(), 3); + QCOMPARE(textInput->text(), QStringLiteral("EE..")); + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("EE"); + QGuiApplication::sendEvent(textInput, &event); + } + QCOMPARE(textInput->cursorPosition(), 6); + QCOMPARE(textInput->text(), QStringLiteral("EE.EE.")); + { + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("EE"); + QGuiApplication::sendEvent(textInput, &event); + } + QCOMPARE(textInput->cursorPosition(), 8); + QCOMPARE(textInput->text(), QStringLiteral("EE.EE.EE")); +} void tst_qquicktextinput::hasAcceptableInputMask_data() { @@ -6512,7 +6636,7 @@ void tst_qquicktextinput::hasAcceptableInputMask() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); // test that invalid input (for required) work for optionalMask textInput->setText(invalid); @@ -6566,7 +6690,7 @@ void tst_qquicktextinput::maskCharacter() QQmlComponent textInputComponent(&engine); textInputComponent.setData(componentStr.toLatin1(), QUrl()); QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); - QVERIFY(textInput != 0); + QVERIFY(textInput != nullptr); for (int i = 0; i < input.size(); ++i) { QString in = QString(input.at(i)); @@ -6579,7 +6703,7 @@ void tst_qquicktextinput::maskCharacter() class TestValidator : public QValidator { public: - TestValidator(QObject *parent = 0) : QValidator(parent) { } + TestValidator(QObject *parent = nullptr) : QValidator(parent) { } State validate(QString &input, int &) const { return input == QStringLiteral("ok") ? Acceptable : Intermediate; } void fixup(QString &input) const { input = QStringLiteral("ok"); } @@ -6590,7 +6714,7 @@ void tst_qquicktextinput::fixup() QQuickWindow window; window.show(); window.requestActivate(); - QTest::qWaitForWindowActive(&window); + QVERIFY(QTest::qWaitForWindowActive(&window)); QQuickTextInput *input = new QQuickTextInput(window.contentItem()); input->setValidator(new TestValidator(input)); @@ -6799,7 +6923,7 @@ void tst_qquicktextinput::padding() QQuickItem *root = window->rootObject(); QVERIFY(root); QQuickTextInput *obj = qobject_cast<QQuickTextInput*>(root); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); qreal cw = obj->contentWidth(); qreal ch = obj->contentHeight(); diff --git a/tests/auto/quick/qquickview/qquickview.pro b/tests/auto/quick/qquickview/qquickview.pro index 1302908bf7..12b24a4e27 100644 --- a/tests/auto/quick/qquickview/qquickview.pro +++ b/tests/auto/quick/qquickview/qquickview.pro @@ -5,6 +5,7 @@ macx:CONFIG -= app_bundle SOURCES += tst_qquickview.cpp include (../../shared/util.pri) +include (../shared/util.pri) TESTDATA = data/* diff --git a/tests/auto/quick/qquickview/tst_qquickview.cpp b/tests/auto/quick/qquickview/tst_qquickview.cpp index 04d21457e6..e259ed1ae7 100644 --- a/tests/auto/quick/qquickview/tst_qquickview.cpp +++ b/tests/auto/quick/qquickview/tst_qquickview.cpp @@ -36,29 +36,7 @@ #include <QtCore/QDebug> #include <QtQml/qqmlengine.h> -class SizeChangesListener : public QObject, public QVector<QSize> -{ - Q_OBJECT -public: - explicit SizeChangesListener(QQuickItem *item); -private slots: - void onSizeChanged(); -private: - QQuickItem *item; - -}; - -SizeChangesListener::SizeChangesListener(QQuickItem *item) : - item(item) -{ - connect(item, &QQuickItem::widthChanged, this, &SizeChangesListener::onSizeChanged); - connect(item, &QQuickItem::heightChanged, this, &SizeChangesListener::onSizeChanged); -} - -void SizeChangesListener::onSizeChanged() -{ - append(QSize(item->width(), item->height())); -} +#include "../shared/geometrytestutil.h" class tst_QQuickView : public QQmlDataTest { @@ -164,7 +142,7 @@ void tst_QQuickView::resizemodeitem() // size update from view QCoreApplication::processEvents(); // make sure the last resize events are gone - SizeChangesListener sizeListener(item); + QSizeChangeListener sizeListener(item); view->resize(QSize(200,300)); QTRY_COMPARE(item->width(), 200.0); @@ -234,11 +212,11 @@ void tst_QQuickView::engine() QQmlEngine *engine = new QQmlEngine; QVERIFY(!engine->incubationController()); - QQuickView *view = new QQuickView(engine, 0); + QQuickView *view = new QQuickView(engine, nullptr); QVERIFY(view); QCOMPARE(engine->incubationController(), view->incubationController()); - QQuickView *view2 = new QQuickView(engine, 0); + QQuickView *view2 = new QQuickView(engine, nullptr); QVERIFY(view); QCOMPARE(engine->incubationController(), view->incubationController()); delete view; @@ -250,7 +228,7 @@ void tst_QQuickView::engine() QVERIFY(!engine->incubationController()); QQuickView *view3 = new QQuickView; - QQuickView *view4 = new QQuickView(view3->engine(), 0); + QQuickView *view4 = new QQuickView(view3->engine(), nullptr); QVERIFY(view3->engine()); QVERIFY(view4->engine()); diff --git a/tests/auto/quick/qquickvisualdatamodel/data/create.qml b/tests/auto/quick/qquickvisualdatamodel/data/create.qml index 9f4b754552..ba63bc778d 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/create.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/create.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 ListView { width: 200 @@ -6,7 +7,7 @@ ListView { property var persistentHandle - model: VisualDataModel { + model: DelegateModel { id: visualModel persistedItems.includeByDefault: true diff --git a/tests/auto/quick/qquickvisualdatamodel/data/datalist-package.qml b/tests/auto/quick/qquickvisualdatamodel/data/datalist-package.qml index ae3bd81d91..3fc33755d3 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/datalist-package.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/datalist-package.qml @@ -1,10 +1,11 @@ import QtQuick 2.0 +import QtQml.Models 2.12 ListView { width: 100 height: 100 model: visualModel.parts.package - VisualDataModel { + DelegateModel { id: visualModel objectName: "visualModel" model: myModel diff --git a/tests/auto/quick/qquickvisualdatamodel/data/datalist.qml b/tests/auto/quick/qquickvisualdatamodel/data/datalist.qml index 8ce59caddc..074f5ad26f 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/datalist.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/datalist.qml @@ -1,9 +1,10 @@ import QtQuick 2.0 +import QtQml.Models 2.12 ListView { width: 100 height: 100 - model: VisualDataModel { + model: DelegateModel { id: visualModel objectName: "visualModel" model: myModel diff --git a/tests/auto/quick/qquickvisualdatamodel/data/externalManagedModel.qml b/tests/auto/quick/qquickvisualdatamodel/data/externalManagedModel.qml new file mode 100644 index 0000000000..44c157b824 --- /dev/null +++ b/tests/auto/quick/qquickvisualdatamodel/data/externalManagedModel.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tests of the QtQuick module 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.Window 2.2 +import QtQuick 2.6 +import QtQml.Models 2.11 +import example 1.0 + +Window { + visible: true + property bool running: rebuildTimer.running + ListView { + anchors.fill: parent + model: delegateModel + } + + DelegateModel { + id: delegateModel + model: objectsProvider.objects + delegate: Item {} + } + + Timer { + id: rebuildTimer + running: true + repeat: true + interval: 1 + + property int count: 0 + onTriggered: { + objectsProvider.rebuild(); + if (++count === 10) + running = false; + } + } + + ObjectsProvider { + id: objectsProvider + } +} diff --git a/tests/auto/quick/qquickvisualdatamodel/data/groups-invalid.qml b/tests/auto/quick/qquickvisualdatamodel/data/groups-invalid.qml index 70c6f9f995..c40abc1112 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/groups-invalid.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/groups-invalid.qml @@ -1,14 +1,15 @@ import QtQuick 2.0 +import QtQml.Models 2.12 -VisualDataModel { +DelegateModel { id: visualModel objectName: "visualModel" groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" }, - VisualDataGroup { id: unnamed; objectName: "unnamed" }, - VisualDataGroup { id: capitalised; objectName: "capitalised"; name: "Capitalised" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" }, + DelegateModelGroup { id: unnamed; objectName: "unnamed" }, + DelegateModelGroup { id: capitalised; objectName: "capitalised"; name: "Capitalised" } ] } diff --git a/tests/auto/quick/qquickvisualdatamodel/data/groups-package.qml b/tests/auto/quick/qquickvisualdatamodel/data/groups-package.qml index ea5ad5d3bd..ada472e376 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/groups-package.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/groups-package.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 ListView { width: 100 @@ -12,14 +13,14 @@ ListView { } model: visualModel.parts.package - VisualDataModel { + DelegateModel { id: visualModel objectName: "visualModel" groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: myModel @@ -28,16 +29,16 @@ ListView { property variant test1: name property variant test2: index - property variant test3: VisualDataModel.itemsIndex - property variant test4: VisualDataModel.inItems - property variant test5: VisualDataModel.visibleIndex - property variant test6: VisualDataModel.inVisible - property variant test7: VisualDataModel.selectedIndex - property variant test8: VisualDataModel.inSelected - property variant test9: VisualDataModel.groups - - function hide() { VisualDataModel.inVisible = false } - function select() { VisualDataModel.inSelected = true } + property variant test3: DelegateModel.itemsIndex + property variant test4: DelegateModel.inItems + property variant test5: DelegateModel.visibleIndex + property variant test6: DelegateModel.inVisible + property variant test7: DelegateModel.selectedIndex + property variant test8: DelegateModel.inSelected + property variant test9: DelegateModel.groups + + function hide() { DelegateModel.inVisible = false } + function select() { DelegateModel.inSelected = true } Item { Package.name: "package" diff --git a/tests/auto/quick/qquickvisualdatamodel/data/groups.qml b/tests/auto/quick/qquickvisualdatamodel/data/groups.qml index 7502dd2502..ba9b5e5e1f 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/groups.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/groups.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 ListView { width: 100 @@ -12,14 +13,14 @@ ListView { } model: visualModel - VisualDataModel { + DelegateModel { id: visualModel objectName: "visualModel" groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: myModel @@ -31,16 +32,16 @@ ListView { height: 2 property variant test1: name property variant test2: index - property variant test3: VisualDataModel.itemsIndex - property variant test4: VisualDataModel.inItems - property variant test5: VisualDataModel.visibleIndex - property variant test6: VisualDataModel.inVisible - property variant test7: VisualDataModel.selectedIndex - property variant test8: VisualDataModel.inSelected - property variant test9: VisualDataModel.groups - - function hide() { VisualDataModel.inVisible = false } - function select() { VisualDataModel.inSelected = true } + property variant test3: DelegateModel.itemsIndex + property variant test4: DelegateModel.inItems + property variant test5: DelegateModel.visibleIndex + property variant test6: DelegateModel.inVisible + property variant test7: DelegateModel.selectedIndex + property variant test8: DelegateModel.inSelected + property variant test9: DelegateModel.groups + + function hide() { DelegateModel.inVisible = false } + function select() { DelegateModel.inSelected = true } } } } diff --git a/tests/auto/quick/qquickvisualdatamodel/data/invalidAttachment.qml b/tests/auto/quick/qquickvisualdatamodel/data/invalidAttachment.qml index 2758f56d0f..adc52a7281 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/invalidAttachment.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/invalidAttachment.qml @@ -1,15 +1,16 @@ import QtQuick 2.0 +import QtQml.Models 2.12 Item { - property VisualDataModel invalidVdm: VisualDataModel.model + property DelegateModel invalidVdm: DelegateModel.model Repeater { model: 1 delegate: Item { id: outer objectName: "delegate" - property VisualDataModel validVdm: outer.VisualDataModel.model - property VisualDataModel invalidVdm: inner.VisualDataModel.model + property DelegateModel validVdm: outer.DelegateModel.model + property DelegateModel invalidVdm: inner.DelegateModel.model Item { id: inner diff --git a/tests/auto/quick/qquickvisualdatamodel/data/itemsDestroyed_package.qml b/tests/auto/quick/qquickvisualdatamodel/data/itemsDestroyed_package.qml index b47f22dc34..3c61991fcb 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/itemsDestroyed_package.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/itemsDestroyed_package.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 Item { width: 100 @@ -9,7 +10,7 @@ Item { model: visualModel.parts.list } - VisualDataModel { + DelegateModel { id: visualModel model: myModel diff --git a/tests/auto/quick/qquickvisualdatamodel/data/listmodelproperties-package.qml b/tests/auto/quick/qquickvisualdatamodel/data/listmodelproperties-package.qml index b6b56727e8..827d6a609e 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/listmodelproperties-package.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/listmodelproperties-package.qml @@ -1,17 +1,18 @@ import QtQuick 2.0 +import QtQml.Models 2.12 ListView { width: 100 height: 100 model: visualModel.parts.package - VisualDataModel { + DelegateModel { id: visualModel objectName: "visualModel" groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: ListModel { diff --git a/tests/auto/quick/qquickvisualdatamodel/data/listmodelproperties.qml b/tests/auto/quick/qquickvisualdatamodel/data/listmodelproperties.qml index d2dfc37e07..1c3e07ba4f 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/listmodelproperties.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/listmodelproperties.qml @@ -1,15 +1,16 @@ import QtQuick 2.0 +import QtQml.Models 2.12 ListView { width: 100 height: 100 - model: VisualDataModel { + model: DelegateModel { id: visualModel objectName: "visualModel" groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: ListModel { diff --git a/tests/auto/quick/qquickvisualdatamodel/data/multipleroleproperties-package.qml b/tests/auto/quick/qquickvisualdatamodel/data/multipleroleproperties-package.qml index 964ac426f8..32a7e8571e 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/multipleroleproperties-package.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/multipleroleproperties-package.qml @@ -1,17 +1,18 @@ import QtQuick 2.0 +import QtQml.Models 2.12 import tst_qquickvisualdatamodel 1.0 ListView { width: 100 height: 100 model: visualModel.parts.package - VisualDataModel { + DelegateModel { id: visualModel objectName: "visualModel" groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: StandardItemModel { diff --git a/tests/auto/quick/qquickvisualdatamodel/data/multipleroleproperties.qml b/tests/auto/quick/qquickvisualdatamodel/data/multipleroleproperties.qml index 77e30b69b9..436aff3da9 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/multipleroleproperties.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/multipleroleproperties.qml @@ -1,16 +1,17 @@ import QtQuick 2.0 +import QtQml.Models 2.12 import tst_qquickvisualdatamodel 1.0 ListView { width: 100 height: 100 - model: VisualDataModel { + model: DelegateModel { id: visualModel objectName: "visualModel" groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: StandardItemModel { diff --git a/tests/auto/quick/qquickvisualdatamodel/data/objectlistproperties-package.qml b/tests/auto/quick/qquickvisualdatamodel/data/objectlistproperties-package.qml index c69e54c2f8..9b5198068f 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/objectlistproperties-package.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/objectlistproperties-package.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 import tst_qquickvisualdatamodel 1.0 ListView { @@ -6,7 +7,7 @@ ListView { height: 100 model: visualModel.parts.package - VisualDataModel { + DelegateModel { id: visualModel objectName: "visualModel" @@ -18,8 +19,8 @@ ListView { ] groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: objects diff --git a/tests/auto/quick/qquickvisualdatamodel/data/objectlistproperties.qml b/tests/auto/quick/qquickvisualdatamodel/data/objectlistproperties.qml index 0dbe2f5459..1941cdc6f2 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/objectlistproperties.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/objectlistproperties.qml @@ -1,10 +1,11 @@ import QtQuick 2.0 +import QtQml.Models 2.12 import tst_qquickvisualdatamodel 1.0 ListView { width: 100 height: 100 - model: VisualDataModel { + model: DelegateModel { id: visualModel objectName: "visualModel" @@ -16,8 +17,8 @@ ListView { ] groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: objects diff --git a/tests/auto/quick/qquickvisualdatamodel/data/onChanged.qml b/tests/auto/quick/qquickvisualdatamodel/data/onChanged.qml index 71dc7d72d7..4a0d75b0f1 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/onChanged.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/onChanged.qml @@ -1,6 +1,7 @@ import QtQuick 2.0 +import QtQml.Models 2.12 -VisualDataModel { +DelegateModel { id: vm property var inserted @@ -42,7 +43,7 @@ VisualDataModel { } groups: [ - VisualDataGroup { + DelegateModelGroup { id: vi; property var inserted @@ -56,7 +57,7 @@ VisualDataModel { vi.removed = removed } }, - VisualDataGroup { + DelegateModelGroup { id: si; property var inserted diff --git a/tests/auto/quick/qquickvisualdatamodel/data/packageView.qml b/tests/auto/quick/qquickvisualdatamodel/data/packageView.qml index e3719a8be0..e6cb856c1e 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/packageView.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/packageView.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 Item { width: 240 @@ -34,7 +35,7 @@ Item { } - VisualDataModel { + DelegateModel { id: visualModel delegate: myDelegate diff --git a/tests/auto/quick/qquickvisualdatamodel/data/singleroleproperties-package.qml b/tests/auto/quick/qquickvisualdatamodel/data/singleroleproperties-package.qml index 1af1b3858d..8da63c8d22 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/singleroleproperties-package.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/singleroleproperties-package.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQml.Models 2.12 import tst_qquickvisualdatamodel 1.0 ListView { @@ -6,13 +7,13 @@ ListView { height: 100 model: visualModel.parts.package - VisualDataModel { + DelegateModel { id: visualModel objectName: "visualModel" groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: SingleRoleModel { diff --git a/tests/auto/quick/qquickvisualdatamodel/data/singleroleproperties.qml b/tests/auto/quick/qquickvisualdatamodel/data/singleroleproperties.qml index 50a5ded6ff..0c217ca763 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/singleroleproperties.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/singleroleproperties.qml @@ -1,16 +1,17 @@ import QtQuick 2.0 +import QtQml.Models 2.12 import tst_qquickvisualdatamodel 1.0 ListView { width: 100 height: 100 - model: VisualDataModel { + model: DelegateModel { id: visualModel objectName: "visualModel" groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: SingleRoleModel { diff --git a/tests/auto/quick/qquickvisualdatamodel/data/stringlistproperties-package.qml b/tests/auto/quick/qquickvisualdatamodel/data/stringlistproperties-package.qml index d1a4604b77..79a4c97b5b 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/stringlistproperties-package.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/stringlistproperties-package.qml @@ -1,17 +1,18 @@ import QtQuick 2.0 +import QtQml.Models 2.12 import tst_qquickvisualdatamodel 1.0 ListView { width: 100 height: 100 model: visualModel.parts.package - VisualDataModel { + DelegateModel { id: visualModel objectName: "visualModel" groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: [ diff --git a/tests/auto/quick/qquickvisualdatamodel/data/stringlistproperties.qml b/tests/auto/quick/qquickvisualdatamodel/data/stringlistproperties.qml index a075ccb4d9..69de807614 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/stringlistproperties.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/stringlistproperties.qml @@ -1,16 +1,17 @@ import QtQuick 2.0 +import QtQml.Models 2.12 import tst_qquickvisualdatamodel 1.0 ListView { width: 100 height: 100 - model: VisualDataModel { + model: DelegateModel { id: visualModel objectName: "visualModel" groups: [ - VisualDataGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, - VisualDataGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } + DelegateModelGroup { id: visibleItems; objectName: "visibleItems"; name: "visible"; includeByDefault: true }, + DelegateModelGroup { id: selectedItems; objectName: "selectedItems"; name: "selected" } ] model: [ diff --git a/tests/auto/quick/qquickvisualdatamodel/data/visualdatamodel.qml b/tests/auto/quick/qquickvisualdatamodel/data/visualdatamodel.qml index e3ae1d1772..8779a0bae8 100644 --- a/tests/auto/quick/qquickvisualdatamodel/data/visualdatamodel.qml +++ b/tests/auto/quick/qquickvisualdatamodel/data/visualdatamodel.qml @@ -1,6 +1,7 @@ import QtQuick 2.0 +import QtQml.Models 2.12 -VisualDataModel { +DelegateModel { function setRoot() { rootIndex = modelIndex(0); } diff --git a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp index cabfb97914..fac8283e2c 100644 --- a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp +++ b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 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. @@ -76,13 +76,13 @@ class SingleRoleModel : public QAbstractItemModel public: struct Branch; struct Node { - Node(const QString &display = QString()) : branch(0), display(display) {} + Node(const QString &display = QString()) : branch(nullptr), display(display) {} Branch *branch; QString display; }; struct Branch { - Branch(Branch *parent = 0) : parent(parent) {} + Branch(Branch *parent = nullptr) : parent(parent) {} ~Branch() { foreach (const Node &child, children) delete child.branch; } int indexOf(Branch *branch) const { for (int i = 0; i < children.count(); ++i) { @@ -96,7 +96,7 @@ public: }; - SingleRoleModel(const QStringList &list = QStringList(), const QByteArray &role = "name", QObject *parent = 0) + SingleRoleModel(const QStringList &list = QStringList(), const QByteArray &role = "name", QObject *parent = nullptr) : QAbstractItemModel(parent), m_role(role) { foreach (const QString &string, list) @@ -255,7 +255,7 @@ class StandardItemModel : public QStandardItemModel Q_PROPERTY(QQmlListProperty<StandardItem> items READ items CONSTANT) Q_CLASSINFO("DefaultProperty", "items") public: - QQmlListProperty<StandardItem> items() { return QQmlListProperty<StandardItem>(this, 0, append, 0, 0, 0); } + QQmlListProperty<StandardItem> items() { return QQmlListProperty<StandardItem>(this, nullptr, append, nullptr, nullptr, nullptr); } static void append(QQmlListProperty<StandardItem> *property, StandardItem *item) { @@ -270,7 +270,7 @@ class DataSubObject : public QObject Q_PROPERTY(QString subName READ subName WRITE setSubName NOTIFY subNameChanged) public: - DataSubObject(QObject *parent=0) : QObject(parent) {} + DataSubObject(QObject *parent=nullptr) : QObject(parent) {} QString subName() const { return m_subName; } void setSubName(const QString &name) { @@ -296,8 +296,8 @@ class DataObject : public QObject Q_PROPERTY(QObject *object READ object) public: - DataObject(QObject *parent=0) : QObject(parent) {} - DataObject(const QString &name, const QString &color, QObject *parent=0) + DataObject(QObject *parent=nullptr) : QObject(parent) {} + DataObject(const QString &name, const QString &color, QObject *parent=nullptr) : QObject(parent), m_name(name), m_color(color), m_object(new DataSubObject(this)) { } @@ -336,11 +336,11 @@ class ItemRequester : public QObject { Q_OBJECT public: - ItemRequester(QObject *parent = 0) + ItemRequester(QObject *parent = nullptr) : QObject(parent) - , itemInitialized(0) - , itemCreated(0) - , itemDestroyed(0) + , itemInitialized(nullptr) + , itemCreated(nullptr) + , itemDestroyed(nullptr) , indexInitialized(-1) , indexCreated(-1) { @@ -431,6 +431,7 @@ private slots: void asynchronousMove_data(); void asynchronousCancel(); void invalidContext(); + void externalManagedModel(); private: template <int N> void groups_verify( @@ -511,7 +512,7 @@ void tst_qquickvisualdatamodel::rootIndex() engine.rootContext()->setContextProperty("myModel", &model); QQmlDelegateModel *obj = qobject_cast<QQmlDelegateModel*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QMetaObject::invokeMethod(obj, "setRoot"); QCOMPARE(qvariant_cast<QModelIndex>(obj->rootIndex()), model.index(0,0)); @@ -549,10 +550,10 @@ void tst_qquickvisualdatamodel::updateLayout() view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQuickText *name = findItem<QQuickText>(contentItem, "display", 0); QVERIFY(name); @@ -599,10 +600,10 @@ void tst_qquickvisualdatamodel::childChanged() view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQmlDelegateModel *vdm = listview->findChild<QQmlDelegateModel*>("visualModel"); vdm->setRootIndex(QVariant::fromValue(model.indexFromItem(model.item(1,0)))); @@ -624,7 +625,7 @@ void tst_qquickvisualdatamodel::childChanged() listview->forceLayout(); name = findItem<QQuickText>(contentItem, "display", 1); - QVERIFY(name != 0); + QVERIFY(name != nullptr); QCOMPARE(name->text(), QString("Row 2 Child Item 2")); model.item(1,0)->takeRow(1); @@ -662,10 +663,10 @@ void tst_qquickvisualdatamodel::objectListModel() view.setSource(testFileUrl("objectlist.qml")); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQuickText *name = findItem<QQuickText>(contentItem, "name", 0); QCOMPARE(name->text(), QString("Item 1")); @@ -701,10 +702,10 @@ void tst_qquickvisualdatamodel::singleRole() view.setSource(testFileUrl("singlerole1.qml")); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQuickText *name = findItem<QQuickText>(contentItem, "name", 1); QCOMPARE(name->text(), QString("two")); @@ -723,10 +724,10 @@ void tst_qquickvisualdatamodel::singleRole() view.setSource(testFileUrl("singlerole2.qml")); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQuickText *name = findItem<QQuickText>(contentItem, "name", 1); QCOMPARE(name->text(), QString("two")); @@ -745,10 +746,10 @@ void tst_qquickvisualdatamodel::singleRole() view.setSource(testFileUrl("singlerole2.qml")); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQuickText *name = findItem<QQuickText>(contentItem, "name", 1); QCOMPARE(name->text(), QString("two")); @@ -771,10 +772,10 @@ void tst_qquickvisualdatamodel::modelProperties() view.setSource(testFileUrl("modelproperties.qml")); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", 1); QVERIFY(delegate); @@ -804,10 +805,10 @@ void tst_qquickvisualdatamodel::modelProperties() view.setSource(testFileUrl("modelproperties.qml")); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", 1); QVERIFY(delegate); @@ -833,10 +834,10 @@ void tst_qquickvisualdatamodel::modelProperties() view.setSource(testFileUrl("modelproperties.qml")); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", 0); QVERIFY(delegate); @@ -875,10 +876,10 @@ void tst_qquickvisualdatamodel::modelProperties() view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQuickItem *delegate = findItem<QQuickItem>(contentItem, "delegate", 1); QVERIFY(delegate); @@ -917,13 +918,13 @@ void tst_qquickvisualdatamodel::noDelegate() view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQmlDelegateModel *vdm = listview->findChild<QQmlDelegateModel*>("visualModel"); - QVERIFY(vdm != 0); + QVERIFY(vdm != nullptr); QCOMPARE(vdm->count(), 3); - vdm->setDelegate(0); + vdm->setDelegate(nullptr); QCOMPARE(vdm->count(), 0); } @@ -955,7 +956,7 @@ void tst_qquickvisualdatamodel::itemsDestroyed() QVERIFY(delegate = findItem<QQuickItem>(view.contentItem(), "delegate", 1)); } - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QVERIFY(!delegate); } @@ -975,16 +976,16 @@ void tst_qquickvisualdatamodel::packagesDestroyed() qApp->processEvents(); QQuickListView *leftview = findItem<QQuickListView>(view.rootObject(), "leftList"); - QTRY_VERIFY(leftview != 0); + QTRY_VERIFY(leftview != nullptr); QQuickListView *rightview = findItem<QQuickListView>(view.rootObject(), "rightList"); - QTRY_VERIFY(rightview != 0); + QTRY_VERIFY(rightview != nullptr); QQuickItem *leftContent = leftview->contentItem(); - QTRY_VERIFY(leftContent != 0); + QTRY_VERIFY(leftContent != nullptr); QQuickItem *rightContent = rightview->contentItem(); - QTRY_VERIFY(rightContent != 0); + QTRY_VERIFY(rightContent != nullptr); leftview->forceLayout(); rightview->forceLayout(); @@ -1052,7 +1053,7 @@ void tst_qquickvisualdatamodel::qaimRowsMoved() engine.rootContext()->setContextProperty("myModel", &model); QQmlDelegateModel *obj = qobject_cast<QQmlDelegateModel*>(c.create()); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QSignalSpy spy(obj, SIGNAL(modelUpdated(QQmlChangeSet,bool))); model.emitMove(sourceFirst, sourceLast, destinationChild); @@ -1213,11 +1214,11 @@ void tst_qquickvisualdatamodel::watchedRoles() QQmlDelegateModel *vdm = qobject_cast<QQmlDelegateModel*>(object.data()); QVERIFY(vdm); - // VisualDataModel doesn't initialize model data until the first item is requested. + // DelegateModel doesn't initialize model data until the first item is requested. QQuickItem *item = qobject_cast<QQuickItem*>(vdm->object(0)); QVERIFY(item); vdm->release(item); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // Ensure released items are deleted before test exits. + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); // Ensure released items are deleted before test exits. QSignalSpy spy(vdm, SIGNAL(modelUpdated(QQmlChangeSet,bool))); QQmlChangeSet changeSet; @@ -1305,7 +1306,7 @@ void tst_qquickvisualdatamodel::hasModelChildren() QCOMPARE(vdm->count(), 4); - QQuickItem *item = 0; + QQuickItem *item = nullptr; item = qobject_cast<QQuickItem*>(vdm->object(0)); QVERIFY(item); @@ -1326,7 +1327,7 @@ void tst_qquickvisualdatamodel::hasModelChildren() QVERIFY(item); QCOMPARE(item->property("modelChildren").toBool(), false); vdm->release(item); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // Ensure released items are deleted before test exits. + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); // Ensure released items are deleted before test exits. QCOMPARE(vdm->stringValue(0, QLatin1String("hasModelChildren")), QVariant(true).toString()); QCOMPARE(vdm->stringValue(1, QLatin1String("hasModelChildren")), QVariant(false).toString()); @@ -1355,7 +1356,7 @@ void tst_qquickvisualdatamodel::setValue() QCOMPARE(vdm->count(), 3); - QQuickItem *item = 0; + QQuickItem *item = nullptr; item = qobject_cast<QQuickItem*>(vdm->object(0)); QVERIFY(item); @@ -1366,7 +1367,7 @@ void tst_qquickvisualdatamodel::setValue() vdm->release(item); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // Ensure released items are deleted before test exits. + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); // Ensure released items are deleted before test exits. } void tst_qquickvisualdatamodel::remove_data() @@ -1406,10 +1407,10 @@ void tst_qquickvisualdatamodel::remove() view.setSource(testFileUrl("groups.qml")); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel *>(qvariant_cast<QObject *>(listview->model())); QVERIFY(visualModel); @@ -1456,22 +1457,22 @@ void tst_qquickvisualdatamodel::remove() QCOMPARE(delegate->property("test3").toInt(), iIndex[i]); } } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: remove: index out of range"); evaluate<void>(visualModel, "items.remove(-8, 4)"); QCOMPARE(listview->count(), 7); QCOMPARE(visualModel->items()->count(), 7); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: remove: index out of range"); evaluate<void>(visualModel, "items.remove(12, 2)"); QCOMPARE(listview->count(), 7); QCOMPARE(visualModel->items()->count(), 7); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: invalid count"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: remove: invalid count"); evaluate<void>(visualModel, "items.remove(5, 3)"); QCOMPARE(listview->count(), 7); QCOMPARE(visualModel->items()->count(), 7); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: remove: invalid count"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: remove: invalid count"); evaluate<void>(visualModel, "items.remove(5, -2)"); QCOMPARE(listview->count(), 7); QCOMPARE(visualModel->items()->count(), 7); @@ -1515,10 +1516,10 @@ void tst_qquickvisualdatamodel::move() view.setSource(testFileUrl("groups.qml")); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel *>(qvariant_cast<QObject *>(listview->model())); QVERIFY(visualModel); @@ -1593,37 +1594,37 @@ void tst_qquickvisualdatamodel::move() QCOMPARE(delegate->property("test3").toInt(), iIndex[i]); } } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: invalid count"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: move: invalid count"); evaluate<void>(visualModel, "items.move(5, 2, -2)"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: from index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: move: from index out of range"); evaluate<void>(visualModel, "items.move(-6, 2, 1)"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: from index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: move: from index out of range"); evaluate<void>(visualModel, "items.move(15, 2, 1)"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: from index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: move: from index out of range"); evaluate<void>(visualModel, "items.move(11, 1, 3)"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: to index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: move: to index out of range"); evaluate<void>(visualModel, "items.move(2, -5, 1)"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: to index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: move: to index out of range"); evaluate<void>(visualModel, "items.move(2, 14, 1)"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: move: to index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: move: to index out of range"); evaluate<void>(visualModel, "items.move(2, 11, 4)"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); @@ -1704,10 +1705,10 @@ void tst_qquickvisualdatamodel::groups() view.setSource(source); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQmlDelegateModel *visualModel = listview->findChild<QQmlDelegateModel *>("visualModel"); QVERIFY(visualModel); @@ -1786,82 +1787,82 @@ void tst_qquickvisualdatamodel::groups() static const bool sMember[] = { f, f, f, f, f, f, f, f, t, t, f, f }; VERIFY_GROUPS; } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: invalid count"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: addGroups: invalid count"); evaluate<void>(visualModel, "items.addGroups(11, -4, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: addGroups: index out of range"); evaluate<void>(visualModel, "items.addGroups(-1, 3, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: addGroups: index out of range"); evaluate<void>(visualModel, "items.addGroups(14, 3, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: addGroups: invalid count"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: addGroups: invalid count"); evaluate<void>(visualModel, "items.addGroups(11, 5, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: invalid count"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: setGroups: invalid count"); evaluate<void>(visualModel, "items.setGroups(11, -4, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: setGroups: index out of range"); evaluate<void>(visualModel, "items.setGroups(-1, 3, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: setGroups: index out of range"); evaluate<void>(visualModel, "items.setGroups(14, 3, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: setGroups: invalid count"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: setGroups: invalid count"); evaluate<void>(visualModel, "items.setGroups(11, 5, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: invalid count"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: removeGroups: invalid count"); evaluate<void>(visualModel, "items.removeGroups(11, -4, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: removeGroups: index out of range"); evaluate<void>(visualModel, "items.removeGroups(-1, 3, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: removeGroups: index out of range"); evaluate<void>(visualModel, "items.removeGroups(14, 3, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); QCOMPARE(visibleItems->count(), 9); QCOMPARE(selectedItems->count(), 2); } { - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: removeGroups: invalid count"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: removeGroups: invalid count"); evaluate<void>(visualModel, "items.removeGroups(11, 5, \"items\")"); QCOMPARE(listview->count(), 12); QCOMPARE(visualModel->items()->count(), 12); @@ -2024,10 +2025,10 @@ void tst_qquickvisualdatamodel::get() view.setSource(testFileUrl("groups.qml")); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel *>(qvariant_cast<QObject *>(listview->model())); QVERIFY(visualModel); @@ -2038,9 +2039,6 @@ void tst_qquickvisualdatamodel::get() QQmlDelegateModelGroup *selectedItems = visualModel->findChild<QQmlDelegateModelGroup *>("selectedItems"); QVERIFY(selectedItems); - QV8Engine *v8Engine = QQmlEnginePrivate::getV8Engine(ctxt->engine()); - QVERIFY(v8Engine); - const bool f = false; const bool t = true; @@ -2153,7 +2151,7 @@ void tst_qquickvisualdatamodel::get() void tst_qquickvisualdatamodel::invalidGroups() { QUrl source = testFileUrl("groups-invalid.qml"); - QTest::ignoreMessage(QtWarningMsg, (source.toString() + ":12:9: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("Group names must start with a lower case letter")).toUtf8()); + QTest::ignoreMessage(QtWarningMsg, (source.toString() + ":13:9: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("Group names must start with a lower case letter")).toUtf8()); QQmlComponent component(&engine, source); QScopedPointer<QObject> object(component.create()); @@ -2320,10 +2318,10 @@ void tst_qquickvisualdatamodel::create() view.setSource(testFileUrl("create.qml")); QQuickListView *listview = qobject_cast<QQuickListView*>(view.rootObject()); - QVERIFY(listview != 0); + QVERIFY(listview != nullptr); QQuickItem *contentItem = listview->contentItem(); - QVERIFY(contentItem != 0); + QVERIFY(contentItem != nullptr); QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel *>(qvariant_cast<QObject *>(listview->model())); QVERIFY(visualModel); @@ -2334,35 +2332,35 @@ void tst_qquickvisualdatamodel::create() // persistedItems.includeByDefault is true, so all items belong to persistedItems initially. QVERIFY(delegate = findItem<QQuickItem>(contentItem, "delegate", 1)); - QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); + QCOMPARE(evaluate<bool>(delegate, "DelegateModel.inPersistedItems"), true); // changing include by default doesn't remove persistance. evaluate<void>(visualModel, "persistedItems.includeByDefault = false"); - QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); + QCOMPARE(evaluate<bool>(delegate, "DelegateModel.inPersistedItems"), true); // removing from persistedItems does. evaluate<void>(visualModel, "persistedItems.remove(0, 20)"); QCOMPARE(listview->count(), 20); - QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false); + QCOMPARE(evaluate<bool>(delegate, "DelegateModel.inPersistedItems"), false); // Request an item instantiated by the view. QVERIFY(delegate = qobject_cast<QQuickItem *>(evaluate<QObject *>(visualModel, "items.create(1)"))); QCOMPARE(delegate.data(), findItem<QQuickItem>(contentItem, "delegate", 1)); - QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); + QCOMPARE(evaluate<bool>(delegate, "DelegateModel.inPersistedItems"), true); QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1); - evaluate<void>(delegate, "VisualDataModel.inPersistedItems = false"); + evaluate<void>(delegate, "DelegateModel.inPersistedItems = false"); QCOMPARE(listview->count(), 20); QCoreApplication::sendPostedEvents(delegate, QEvent::DeferredDelete); QVERIFY(delegate); - QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false); + QCOMPARE(evaluate<bool>(delegate, "DelegateModel.inPersistedItems"), false); QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0); // Request an item not instantiated by the view. QVERIFY(!findItem<QQuickItem>(contentItem, "delegate", 15)); QVERIFY(delegate = qobject_cast<QQuickItem *>(evaluate<QObject *>(visualModel, "items.create(15)"))); QCOMPARE(delegate.data(), findItem<QQuickItem>(contentItem, "delegate", 15)); - QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); + QCOMPARE(evaluate<bool>(delegate, "DelegateModel.inPersistedItems"), true); QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1); evaluate<void>(visualModel, "persistedItems.remove(0)"); @@ -2374,28 +2372,28 @@ void tst_qquickvisualdatamodel::create() QVERIFY(!findItem<QQuickItem>(contentItem, "delegate", 16)); QVERIFY(delegate = qobject_cast<QQuickItem *>(evaluate<QObject *>(visualModel, "items.create(16)"))); QCOMPARE(delegate.data(), findItem<QQuickItem>(contentItem, "delegate", 16)); - QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); + QCOMPARE(evaluate<bool>(delegate, "DelegateModel.inPersistedItems"), true); QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1); evaluate<void>(listview, "positionViewAtIndex(19, ListView.End)"); QCOMPARE(listview->count(), 20); - evaluate<void>(delegate, "VisualDataModel.groups = [\"items\"]"); + evaluate<void>(delegate, "DelegateModel.groups = [\"items\"]"); QCoreApplication::sendPostedEvents(delegate, QEvent::DeferredDelete); QVERIFY(delegate); - QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false); + QCOMPARE(evaluate<bool>(delegate, "DelegateModel.inPersistedItems"), false); QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0); // Request and release an item instantiated by the view, then scroll the view so it releases it. QVERIFY(findItem<QQuickItem>(contentItem, "delegate", 17)); QVERIFY(delegate = qobject_cast<QQuickItem *>(evaluate<QObject *>(visualModel, "items.create(17)"))); QCOMPARE(delegate.data(), findItem<QQuickItem>(contentItem, "delegate", 17)); - QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); + QCOMPARE(evaluate<bool>(delegate, "DelegateModel.inPersistedItems"), true); QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 1); evaluate<void>(visualModel, "items.removeGroups(17, \"persistedItems\")"); QCoreApplication::sendPostedEvents(delegate, QEvent::DeferredDelete); QVERIFY(delegate); - QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), false); + QCOMPARE(evaluate<bool>(delegate, "DelegateModel.inPersistedItems"), false); QCOMPARE(evaluate<int>(visualModel, "persistedItems.count"), 0); evaluate<void>(listview, "positionViewAtIndex(1, ListView.Beginning)"); QCOMPARE(listview->count(), 20); @@ -2410,7 +2408,7 @@ void tst_qquickvisualdatamodel::create() evaluate<void>(listview, "positionViewAtIndex(19, ListView.End)"); QCOMPARE(listview->count(), 20); QVERIFY(delegate = findItem<QQuickItem>(contentItem, "delegate", 18)); - QCOMPARE(evaluate<bool>(delegate, "VisualDataModel.inPersistedItems"), true); + QCOMPARE(evaluate<bool>(delegate, "DelegateModel.inPersistedItems"), true); QCoreApplication::sendPostedEvents(delegate, QEvent::DeferredDelete); QVERIFY(delegate); evaluate<void>(listview, "positionViewAtIndex(1, ListView.Beginning)"); @@ -2431,11 +2429,11 @@ void tst_qquickvisualdatamodel::create() void tst_qquickvisualdatamodel::incompleteModel() { - // VisualDataModel is first populated in componentComplete. Verify various functions are + // DelegateModel is first populated in componentComplete. Verify various functions are // harmlessly ignored until then. QQmlComponent component(&engine); - component.setData("import QtQuick 2.0\n VisualDataModel {}", testFileUrl("")); + component.setData("import QtQuick 2.0\nimport QtQml.Models 2.2\nDelegateModel {}", testFileUrl("")); QScopedPointer<QObject> object(component.beginCreate(engine.rootContext())); @@ -2465,7 +2463,7 @@ void tst_qquickvisualdatamodel::incompleteModel() QCOMPARE(itemsSpy.count(), 0); QCOMPARE(persistedItemsSpy.count(), 0); - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML VisualDataGroup: get: index out of range"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML DelegateModelGroup: get: index out of range"); QVERIFY(evaluate<bool>(model, "items.get(0) === undefined")); component.completeCreate(); @@ -2999,7 +2997,7 @@ void tst_qquickvisualdatamodel::insert_data() "items.get(2).model.modelData = \"seven\"; }") << 4 << 5 << 0 << true << false << false << false << false << QString("modelData") - << (QStringList() << "eight" << "one" << "two" << "three" << "four"); + << (QStringList() << "eight" << "one" << "seven" << "three" << "four"); QTest::newRow("StringList.create prepend modelData") << stringListSource[i] @@ -3116,16 +3114,16 @@ void tst_qquickvisualdatamodel::insert() QCOMPARE(evaluate<QString>(item, "test6"), propertyData.at(i)); } - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inItems"), true); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inPersistedItems"), false); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inVisible"), true); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inSelected"), false); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.isUnresolved"), false); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inItems"), true); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inPersistedItems"), false); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inVisible"), true); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inSelected"), false); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.isUnresolved"), false); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.itemsIndex"), itemsIndex); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.persistedItemsIndex"), persisted && i > index ? 1 : 0); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.visibleIndex"), visible || i <= index ? i : i - 1); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.selectedIndex"), selected && i > index ? 1 : 0); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.itemsIndex"), itemsIndex); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.persistedItemsIndex"), persisted && i > index ? 1 : 0); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.visibleIndex"), visible || i <= index ? i : i - 1); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.selectedIndex"), selected && i > index ? 1 : 0); } else if (inItems) { get = QString("items.get(%1)").arg(index); } else if (persisted) { @@ -3154,7 +3152,7 @@ void tst_qquickvisualdatamodel::insert() QCOMPARE(evaluate<int>(visualModel, get + ".selectedIndex"), selected && i > index ? 1 : 0); } - QObject *item = 0; + QObject *item = nullptr; if (inItems) item = evaluate<QObject *>(visualModel, QString("items.create(%1)").arg(index)); @@ -3179,16 +3177,16 @@ void tst_qquickvisualdatamodel::insert() QCOMPARE(evaluate<QString>(item, "test6"), propertyData.at(index)); } - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inItems"), inItems); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inPersistedItems"), true); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inVisible"), visible); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inSelected"), selected); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.isUnresolved"), true); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inItems"), inItems); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inPersistedItems"), true); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inVisible"), visible); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inSelected"), selected); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.isUnresolved"), true); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.itemsIndex"), index); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.persistedItemsIndex"), 0); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.visibleIndex"), index); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.selectedIndex"), 0); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.itemsIndex"), index); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.persistedItemsIndex"), 0); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.visibleIndex"), index); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.selectedIndex"), 0); } void tst_qquickvisualdatamodel::resolve_data() @@ -3580,16 +3578,16 @@ void tst_qquickvisualdatamodel::resolve() QCOMPARE(evaluate<QString>(item, "test6"), propertyData.at(i)); } - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inItems"), true); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inPersistedItems"), false); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inVisible"), true); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inSelected"), false); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.isUnresolved"), false); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inItems"), true); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inPersistedItems"), false); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inVisible"), true); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inSelected"), false); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.isUnresolved"), false); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.itemsIndex"), itemsIndex); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.persistedItemsIndex"), persisted && i > index ? 1 : 0); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.visibleIndex"), visible || i <= index ? i : i - 1); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.selectedIndex"), selected && i > index ? 1 : 0); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.itemsIndex"), itemsIndex); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.persistedItemsIndex"), persisted && i > index ? 1 : 0); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.visibleIndex"), visible || i <= index ? i : i - 1); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.selectedIndex"), selected && i > index ? 1 : 0); } else if (inItems) { get = QString("items.get(%1)").arg(index); } else if (persisted) { @@ -3618,7 +3616,7 @@ void tst_qquickvisualdatamodel::resolve() QCOMPARE(evaluate<int>(visualModel, get + ".selectedIndex"), selected && i > index ? 1 : 0); } - QObject *item = 0; + QObject *item = nullptr; if (inItems) item = evaluate<QObject *>(visualModel, QString("items.create(%1)").arg(index)); @@ -3643,16 +3641,16 @@ void tst_qquickvisualdatamodel::resolve() QCOMPARE(evaluate<QString>(item, "test6"), propertyData.at(index)); } - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inItems"), inItems); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inPersistedItems"), true); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inVisible"), visible); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.inSelected"), selected); - QCOMPARE(evaluate<bool>(item, "delegate.VisualDataModel.isUnresolved"), false); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inItems"), inItems); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inPersistedItems"), true); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inVisible"), visible); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.inSelected"), selected); + QCOMPARE(evaluate<bool>(item, "delegate.DelegateModel.isUnresolved"), false); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.itemsIndex"), index); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.persistedItemsIndex"), 0); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.visibleIndex"), index); - QCOMPARE(evaluate<int>(item, "delegate.VisualDataModel.selectedIndex"), 0); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.itemsIndex"), index); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.persistedItemsIndex"), 0); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.visibleIndex"), index); + QCOMPARE(evaluate<int>(item, "delegate.DelegateModel.selectedIndex"), 0); } void tst_qquickvisualdatamodel::warnings_data() @@ -3665,67 +3663,67 @@ void tst_qquickvisualdatamodel::warnings_data() QTest::newRow("insert < 0") << testFileUrl("listmodelproperties.qml") << QString("items.insert(-2, {\"number\": \"eight\"})") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("insert: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("insert: index out of range")) << 4; QTest::newRow("insert > length") << testFileUrl("listmodelproperties.qml") << QString("items.insert(8, {\"number\": \"eight\"})") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("insert: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("insert: index out of range")) << 4; QTest::newRow("create < 0") << testFileUrl("listmodelproperties.qml") << QString("items.create(-2, {\"number\": \"eight\"})") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("create: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("create: index out of range")) << 4; QTest::newRow("create > length") << testFileUrl("listmodelproperties.qml") << QString("items.create(8, {\"number\": \"eight\"})") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("create: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("create: index out of range")) << 4; QTest::newRow("resolve from < 0") << testFileUrl("listmodelproperties.qml") << QString("items.resolve(-2, 3)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("resolve: from index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("resolve: from index out of range")) << 4; QTest::newRow("resolve from > length") << testFileUrl("listmodelproperties.qml") << QString("items.resolve(8, 3)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("resolve: from index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("resolve: from index out of range")) << 4; QTest::newRow("resolve to < 0") << testFileUrl("listmodelproperties.qml") << QString("items.resolve(3, -2)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("resolve: to index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("resolve: to index out of range")) << 4; QTest::newRow("resolve to > length") << testFileUrl("listmodelproperties.qml") << QString("items.resolve(3, 8)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("resolve: to index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("resolve: to index out of range")) << 4; QTest::newRow("resolve from invalid index") << testFileUrl("listmodelproperties.qml") << QString("items.resolve(\"two\", 3)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("resolve: from index invalid")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("resolve: from index invalid")) << 4; QTest::newRow("resolve to invalid index") << testFileUrl("listmodelproperties.qml") << QString("items.resolve(3, \"two\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("resolve: to index invalid")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("resolve: to index invalid")) << 4; QTest::newRow("resolve already resolved item") << testFileUrl("listmodelproperties.qml") << QString("items.resolve(3, 2)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("resolve: from is not an unresolved item")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("resolve: from is not an unresolved item")) << 4; QTest::newRow("resolve already resolved item") @@ -3733,193 +3731,193 @@ void tst_qquickvisualdatamodel::warnings_data() << QString("{ items.insert(0, {\"number\": \"eight\"});" "items.insert(1, {\"number\": \"seven\"});" "items.resolve(0, 1)}") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("resolve: to is not a model item")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("resolve: to is not a model item")) << 6; QTest::newRow("remove index < 0") << testFileUrl("listmodelproperties.qml") << QString("items.remove(-2, 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("remove: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("remove: index out of range")) << 4; QTest::newRow("remove index == length") << testFileUrl("listmodelproperties.qml") << QString("items.remove(4, 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("remove: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("remove: index out of range")) << 4; QTest::newRow("remove index > length") << testFileUrl("listmodelproperties.qml") << QString("items.remove(9, 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("remove: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("remove: index out of range")) << 4; QTest::newRow("remove invalid index") << testFileUrl("listmodelproperties.qml") << QString("items.remove(\"nine\", 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("remove: invalid index")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("remove: invalid index")) << 4; QTest::newRow("remove count < 0") << testFileUrl("listmodelproperties.qml") << QString("items.remove(1, -2)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("remove: invalid count")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("remove: invalid count")) << 4; QTest::newRow("remove index + count > length") << testFileUrl("listmodelproperties.qml") << QString("items.remove(2, 4, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("remove: invalid count")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("remove: invalid count")) << 4; QTest::newRow("addGroups index < 0") << testFileUrl("listmodelproperties.qml") << QString("items.addGroups(-2, 1, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("addGroups: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("addGroups: index out of range")) << 4; QTest::newRow("addGroups index == length") << testFileUrl("listmodelproperties.qml") << QString("items.addGroups(4, 1, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("addGroups: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("addGroups: index out of range")) << 4; QTest::newRow("addGroups index > length") << testFileUrl("listmodelproperties.qml") << QString("items.addGroups(9, 1, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("addGroups: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("addGroups: index out of range")) << 4; QTest::newRow("addGroups count < 0") << testFileUrl("listmodelproperties.qml") << QString("items.addGroups(1, -2, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("addGroups: invalid count")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("addGroups: invalid count")) << 4; QTest::newRow("addGroups index + count > length") << testFileUrl("listmodelproperties.qml") << QString("items.addGroups(2, 4, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("addGroups: invalid count")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("addGroups: invalid count")) << 4; QTest::newRow("removeGroups index < 0") << testFileUrl("listmodelproperties.qml") << QString("items.removeGroups(-2, 1, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("removeGroups: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("removeGroups: index out of range")) << 4; QTest::newRow("removeGroups index == length") << testFileUrl("listmodelproperties.qml") << QString("items.removeGroups(4, 1, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("removeGroups: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("removeGroups: index out of range")) << 4; QTest::newRow("removeGroups index > length") << testFileUrl("listmodelproperties.qml") << QString("items.removeGroups(9, 1, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("removeGroups: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("removeGroups: index out of range")) << 4; QTest::newRow("removeGroups count < 0") << testFileUrl("listmodelproperties.qml") << QString("items.removeGroups(1, -2, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("removeGroups: invalid count")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("removeGroups: invalid count")) << 4; QTest::newRow("removeGroups index + count > length") << testFileUrl("listmodelproperties.qml") << QString("items.removeGroups(2, 4, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("removeGroups: invalid count")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("removeGroups: invalid count")) << 4; QTest::newRow("setGroups index < 0") << testFileUrl("listmodelproperties.qml") << QString("items.setGroups(-2, 1, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("setGroups: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("setGroups: index out of range")) << 4; QTest::newRow("setGroups index == length") << testFileUrl("listmodelproperties.qml") << QString("items.setGroups(4, 1, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("setGroups: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("setGroups: index out of range")) << 4; QTest::newRow("setGroups index > length") << testFileUrl("listmodelproperties.qml") << QString("items.setGroups(9, 1, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("setGroups: index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("setGroups: index out of range")) << 4; QTest::newRow("setGroups count < 0") << testFileUrl("listmodelproperties.qml") << QString("items.setGroups(1, -2, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("setGroups: invalid count")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("setGroups: invalid count")) << 4; QTest::newRow("setGroups index + count > length") << testFileUrl("listmodelproperties.qml") << QString("items.setGroups(2, 4, \"selected\")") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("setGroups: invalid count")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("setGroups: invalid count")) << 4; QTest::newRow("move from < 0") << testFileUrl("listmodelproperties.qml") << QString("items.move(-2, 1, 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("move: from index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("move: from index out of range")) << 4; QTest::newRow("move from == length") << testFileUrl("listmodelproperties.qml") << QString("items.move(4, 1, 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("move: from index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("move: from index out of range")) << 4; QTest::newRow("move from > length") << testFileUrl("listmodelproperties.qml") << QString("items.move(9, 1, 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("move: from index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("move: from index out of range")) << 4; QTest::newRow("move invalid from") << testFileUrl("listmodelproperties.qml") << QString("items.move(\"nine\", 1, 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("move: invalid from index")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("move: invalid from index")) << 4; QTest::newRow("move to < 0") << testFileUrl("listmodelproperties.qml") << QString("items.move(1, -2, 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("move: to index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("move: to index out of range")) << 4; QTest::newRow("move to == length") << testFileUrl("listmodelproperties.qml") << QString("items.move(1, 4, 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("move: to index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("move: to index out of range")) << 4; QTest::newRow("move to > length") << testFileUrl("listmodelproperties.qml") << QString("items.move(1, 9, 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("move: to index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("move: to index out of range")) << 4; QTest::newRow("move invalid to") << testFileUrl("listmodelproperties.qml") << QString("items.move(1, \"nine\", 1)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("move: invalid to index")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("move: invalid to index")) << 4; QTest::newRow("move count < 0") << testFileUrl("listmodelproperties.qml") << QString("items.move(1, 1, -2)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("move: invalid count")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("move: invalid count")) << 4; QTest::newRow("move from + count > length") << testFileUrl("listmodelproperties.qml") << QString("items.move(2, 1, 4)") - << ("<Unknown File>: QML VisualDataGroup: " + QQmlDelegateModelGroup::tr("move: from index out of range")) + << ("<Unknown File>: QML DelegateModelGroup: " + QQmlDelegateModelGroup::tr("move: from index out of range")) << 4; } @@ -4013,7 +4011,7 @@ void tst_qquickvisualdatamodel::asynchronousInsert() connect(visualModel, SIGNAL(createdItem(int,QObject*)), &requester, SLOT(createdItem(int,QObject*))); connect(visualModel, SIGNAL(destroyingItem(QObject*)), &requester, SLOT(destroyingItem(QObject*))); - QQuickItem *item = qobject_cast<QQuickItem*>(visualModel->object(requestIndex, true)); + QQuickItem *item = qobject_cast<QQuickItem*>(visualModel->object(requestIndex, QQmlIncubator::Asynchronous)); QVERIFY(!item); QVERIFY(!requester.itemInitialized); @@ -4025,7 +4023,7 @@ void tst_qquickvisualdatamodel::asynchronousInsert() newItems.append(qMakePair(QLatin1String("New item") + QString::number(i), QString(QLatin1String("")))); model.insertItems(insertIndex, newItems); - item = qobject_cast<QQuickItem*>(visualModel->object(completeIndex, false)); + item = qobject_cast<QQuickItem*>(visualModel->object(completeIndex)); QVERIFY(item); QCOMPARE(requester.itemInitialized, item); @@ -4078,7 +4076,7 @@ void tst_qquickvisualdatamodel::asynchronousRemove() connect(visualModel, SIGNAL(createdItem(int,QObject*)), &requester, SLOT(createdItem(int,QObject*))); connect(visualModel, SIGNAL(destroyingItem(QObject*)), &requester, SLOT(destroyingItem(QObject*))); - QQuickItem *item = qobject_cast<QQuickItem*>(visualModel->object(requestIndex, true)); + QQuickItem *item = qobject_cast<QQuickItem*>(visualModel->object(requestIndex, QQmlIncubator::Asynchronous)); QVERIFY(!item); QVERIFY(!requester.itemInitialized); @@ -4099,7 +4097,7 @@ void tst_qquickvisualdatamodel::asynchronousRemove() QVERIFY(!requester.itemCreated); QVERIFY(!requester.itemDestroyed); } else { - item = qobject_cast<QQuickItem*>(visualModel->object(completeIndex, false)); + item = qobject_cast<QQuickItem*>(visualModel->object(completeIndex)); QVERIFY(item); QCOMPARE(requester.itemInitialized, item); @@ -4157,7 +4155,7 @@ void tst_qquickvisualdatamodel::asynchronousMove() connect(visualModel, SIGNAL(createdItem(int,QObject*)), &requester, SLOT(createdItem(int,QObject*))); connect(visualModel, SIGNAL(destroyingItem(QObject*)), &requester, SLOT(destroyingItem(QObject*))); - QQuickItem *item = qobject_cast<QQuickItem*>(visualModel->object(requestIndex, true)); + QQuickItem *item = qobject_cast<QQuickItem*>(visualModel->object(requestIndex, QQmlIncubator::Asynchronous)); QVERIFY(!item); QVERIFY(!requester.itemInitialized); @@ -4166,7 +4164,7 @@ void tst_qquickvisualdatamodel::asynchronousMove() model.moveItems(from, to, count); - item = qobject_cast<QQuickItem*>(visualModel->object(completeIndex, false)); + item = qobject_cast<QQuickItem*>(visualModel->object(completeIndex)); QVERIFY(item); @@ -4200,7 +4198,7 @@ void tst_qquickvisualdatamodel::asynchronousCancel() QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(c.create()); QVERIFY(visualModel); - QQuickItem *item = qobject_cast<QQuickItem*>(visualModel->object(requestIndex, true)); + QQuickItem *item = qobject_cast<QQuickItem*>(visualModel->object(requestIndex, QQmlIncubator::Asynchronous)); QVERIFY(!item); QCOMPARE(controller.incubatingObjectCount(), 1); @@ -4225,7 +4223,7 @@ void tst_qquickvisualdatamodel::invalidContext() QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(c.create(context.data())); QVERIFY(visualModel); - QQuickItem *item = qobject_cast<QQuickItem*>(visualModel->object(4, false)); + QQuickItem *item = qobject_cast<QQuickItem*>(visualModel->object(4)); QVERIFY(item); visualModel->release(item); @@ -4233,10 +4231,77 @@ void tst_qquickvisualdatamodel::invalidContext() model.insertItem(4, "new item", ""); - item = qobject_cast<QQuickItem*>(visualModel->object(4, false)); + item = qobject_cast<QQuickItem*>(visualModel->object(4)); QVERIFY(!item); } +class ObjectsProvider : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty<QObject> objects READ objects NOTIFY objectsChanged) + +public: + explicit ObjectsProvider(QObject *parent = nullptr) : QObject(parent) {} + + Q_INVOKABLE void rebuild() + { + for (auto old: m_objects) + old->deleteLater(); + + m_objects.clear(); + emit objectsChanged(); + + const int size = std::rand() & 0xff; + for (int i = 0; i < size; ++i) { + auto newElement = new QObject(this); + QQmlEngine::setObjectOwnership(newElement, QQmlEngine::CppOwnership); + m_objects.push_back(newElement); + } + emit objectsChanged(); + } + + Q_INVOKABLE QQmlListProperty<QObject> objects() + { + return QQmlListProperty<QObject>(this, nullptr, &ObjectsProvider::listLength, + &ObjectsProvider::listAt); + } + + static int listLength(QQmlListProperty<QObject> *property) + { + auto objectsProvider = qobject_cast<ObjectsProvider*>(property->object); + return objectsProvider ? objectsProvider->m_objects.length() : 0; + } + + static QObject* listAt(QQmlListProperty<QObject> *property, int index) + { + auto objectsProvider = qobject_cast<ObjectsProvider*>(property->object); + return objectsProvider ? objectsProvider->m_objects.at(index) : nullptr; + } + +signals: + void objectsChanged(); + +private: + QList<QObject *> m_objects; +}; + +void tst_qquickvisualdatamodel::externalManagedModel() +{ + qmlRegisterType<ObjectsProvider>("example", 1, 0, "ObjectsProvider"); + + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("externalManagedModel.qml")); + QVERIFY(component.isReady()); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QVERIFY(object->property("running").toBool()); + + // Make sure it runs to completion without crashing. + QTRY_VERIFY(!object->property("running").toBool()); +} + QTEST_MAIN(tst_qquickvisualdatamodel) #include "tst_qquickvisualdatamodel.moc" diff --git a/tests/auto/quick/qquickwindow/BLACKLIST b/tests/auto/quick/qquickwindow/BLACKLIST new file mode 100644 index 0000000000..bb9f403188 --- /dev/null +++ b/tests/auto/quick/qquickwindow/BLACKLIST @@ -0,0 +1,3 @@ +# QTBUG-62177 +[attachedProperty] +osx diff --git a/tests/auto/quick/qquickwindow/data/unloadSubWindow.qml b/tests/auto/quick/qquickwindow/data/unloadSubWindow.qml index bf9df4867d..8c409781d4 100644 --- a/tests/auto/quick/qquickwindow/data/unloadSubWindow.qml +++ b/tests/auto/quick/qquickwindow/data/unloadSubWindow.qml @@ -10,8 +10,10 @@ Window { id: loader2 sourceComponent : Window { id: inner - visible: true - Component.onCompleted: root.transientWindow = inner + Component.onCompleted: { + root.transientWindow = inner; + inner.show(); + } } } Component.onDestruction: { diff --git a/tests/auto/quick/qquickwindow/data/windowattached.qml b/tests/auto/quick/qquickwindow/data/windowattached.qml index 9d61a02452..66083db428 100644 --- a/tests/auto/quick/qquickwindow/data/windowattached.qml +++ b/tests/auto/quick/qquickwindow/data/windowattached.qml @@ -19,7 +19,6 @@ Rectangle { property Window extraWindow: Window { objectName: "extraWindow" title: "extra window" - visible: true Text { objectName: "extraWindowText" anchors.centerIn: parent diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 91d577fb6f..a862604fc1 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -37,6 +37,7 @@ #include <QtQml/QQmlComponent> #include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickloader_p.h> +#include <QtQuick/private/qquickmousearea_p.h> #include "../../shared/util.h" #include "../shared/visualtestutil.h" #include "../shared/viewtestutil.h" @@ -47,6 +48,8 @@ #include <QOpenGLFunctions> #include <QSGRendererInterface> +Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") + struct TouchEventData { QEvent::Type type; QWidget *widget; @@ -70,10 +73,10 @@ static QTouchEvent::TouchPoint makeTouchPoint(QQuickItem *item, const QPointF &p return tp; } -static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states = 0, +static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states = nullptr, const QList<QTouchEvent::TouchPoint>& touchPoints = QList<QTouchEvent::TouchPoint>()) { - TouchEventData d = { type, 0, w, states, touchPoints }; + TouchEventData d = { type, nullptr, w, states, touchPoints }; return d; } static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states, const QTouchEvent::TouchPoint &touchPoint) @@ -111,7 +114,7 @@ class RootItemAccessor : public QQuickItem public: RootItemAccessor() : m_rootItemDestroyed(false) - , m_rootItem(0) + , m_rootItem(nullptr) { } Q_INVOKABLE QQuickItem *contentItem() @@ -138,10 +141,11 @@ class TestTouchItem : public QQuickRectangle { Q_OBJECT public: - TestTouchItem(QQuickItem *parent = 0) + TestTouchItem(QQuickItem *parent = nullptr) : QQuickRectangle(parent), acceptTouchEvents(true), acceptMouseEvents(true), - mousePressId(0), - spinLoopWhenPressed(false), touchEventCount(0) + mousePressCount(0), mouseMoveCount(0), + spinLoopWhenPressed(false), touchEventCount(0), + mouseUngrabEventCount(0) { border()->setWidth(1); setAcceptedMouseButtons(Qt::LeftButton); @@ -153,15 +157,17 @@ public: setEnabled(true); setVisible(true); - lastEvent = makeTouchData(QEvent::None, window(), 0, QList<QTouchEvent::TouchPoint>());//CHECK_VALID + lastEvent = makeTouchData(QEvent::None, window(), nullptr, QList<QTouchEvent::TouchPoint>());//CHECK_VALID lastVelocity = lastVelocityFromMouseMove = QVector2D(); lastMousePos = QPointF(); lastMouseCapabilityFlags = 0; touchEventCount = 0; + mouseMoveCount = 0; + mouseUngrabEventCount = 0; } - static void clearMousePressCounter() + static void clearMouseEventCounters() { mousePressNum = mouseMoveNum = mouseReleaseNum = 0; } @@ -173,10 +179,13 @@ public: bool acceptTouchEvents; bool acceptMouseEvents; + bool grabOnRelease = false; TouchEventData lastEvent; - int mousePressId; + int mousePressCount; + int mouseMoveCount; bool spinLoopWhenPressed; int touchEventCount; + int mouseUngrabEventCount; QVector2D lastVelocity; QVector2D lastVelocityFromMouseMove; QPointF lastMousePos; @@ -204,7 +213,7 @@ public: e->ignore(); return; } - mousePressId = ++mousePressNum; + mousePressCount = ++mousePressNum; lastMousePos = e->pos(); lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e); } @@ -214,7 +223,7 @@ public: e->ignore(); return; } - ++mouseMoveNum; + mouseMoveCount = ++mouseMoveNum; lastVelocityFromMouseMove = QGuiApplicationPrivate::mouseEventVelocity(e); lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e); lastMousePos = e->pos(); @@ -230,10 +239,27 @@ public: lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e); } - bool childMouseEventFilter(QQuickItem *, QEvent *event) { - // TODO Is it a bug if a QTouchEvent comes here? - if (event->type() == QEvent::MouseButtonPress) - mousePressId = ++mousePressNum; + void mouseUngrabEvent() { + ++mouseUngrabEventCount; + } + + bool childMouseEventFilter(QQuickItem *item, QEvent *e) { + qCDebug(lcTests) << objectName() << "filtering" << e << "ahead of delivery to" << item->metaObject()->className() << item->objectName(); + switch (e->type()) { + case QEvent::MouseButtonPress: + mousePressCount = ++mousePressNum; + break; + case QEvent::MouseButtonRelease: + if (grabOnRelease) + grabMouse(); + break; + case QEvent::MouseMove: + mouseMoveCount = ++mouseMoveNum; + break; + default: + break; + } + return false; } @@ -260,17 +286,81 @@ class ConstantUpdateItem : public QQuickItem { Q_OBJECT public: - ConstantUpdateItem(QQuickItem *parent = 0) : QQuickItem(parent), iterations(0) {setFlag(ItemHasContents);} + ConstantUpdateItem(QQuickItem *parent = nullptr) : QQuickItem(parent), iterations(0) {setFlag(ItemHasContents);} int iterations; protected: QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *){ iterations++; update(); - return 0; + return nullptr; } }; +class MouseRecordingWindow : public QQuickWindow +{ +public: + explicit MouseRecordingWindow(QWindow *parent = nullptr) : QQuickWindow(parent) { } + +protected: + void mousePressEvent(QMouseEvent *event) override { + qCDebug(lcTests) << event; + m_mouseEvents << *event; + QQuickWindow::mousePressEvent(event); + } + void mouseMoveEvent(QMouseEvent *event) override { + qCDebug(lcTests) << event; + m_mouseEvents << *event; + QQuickWindow::mouseMoveEvent(event); + } + void mouseReleaseEvent(QMouseEvent *event) override { + qCDebug(lcTests) << event; + m_mouseEvents << *event; + QQuickWindow::mouseReleaseEvent(event); + } + +public: + QList<QMouseEvent> m_mouseEvents; +}; + +class MouseRecordingItem : public QQuickItem +{ +public: + MouseRecordingItem(bool acceptTouch, QQuickItem *parent = nullptr) + : QQuickItem(parent) + , m_acceptTouch(acceptTouch) + { + setSize(QSizeF(300, 300)); + setAcceptedMouseButtons(Qt::LeftButton); + } + +protected: + void touchEvent(QTouchEvent* event) override { + event->setAccepted(m_acceptTouch); + m_touchEvents << *event; + qCDebug(lcTests) << "accepted?" << event->isAccepted() << event; + } + void mousePressEvent(QMouseEvent *event) override { + qCDebug(lcTests) << event; + m_mouseEvents << *event; + } + void mouseMoveEvent(QMouseEvent *event) override { + qCDebug(lcTests) << event; + m_mouseEvents << *event; + } + void mouseReleaseEvent(QMouseEvent *event) override { + qCDebug(lcTests) << event; + m_mouseEvents << *event; + } + +public: + QList<QMouseEvent> m_mouseEvents; + QList<QTouchEvent> m_touchEvents; + +private: + bool m_acceptTouch; +}; + class tst_qquickwindow : public QQmlDataTest { Q_OBJECT @@ -301,6 +391,7 @@ private slots: void touchEvent_propagation(); void touchEvent_propagation_data(); void touchEvent_cancel(); + void touchEvent_cancelClearsMouseGrab(); void touchEvent_reentrant(); void touchEvent_velocity(); @@ -308,6 +399,8 @@ private slots: void mergeTouchPointLists(); void mouseFromTouch_basic(); + void synthMouseFromTouch_data(); + void synthMouseFromTouch(); void clearWindow(); @@ -368,6 +461,7 @@ private slots: void testHoverChildMouseEventFilter(); void testHoverTimestamp(); + void test_circleMapItem(); void pointerEventTypeAndPointCount(); @@ -377,6 +471,10 @@ private slots: void findChild(); + void testChildMouseEventFilter(); + void testChildMouseEventFilter_data(); + void cleanupGrabsOnRelease(); + private: QTouchDevice *touchDevice; QTouchDevice *touchDeviceWithVelocity; @@ -398,12 +496,12 @@ void tst_qquickwindow::openglContextCreatedSignal() window.setTitle(QTest::currentTestFunction()); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); if (window.rendererInterface()->graphicsApi() != QSGRendererInterface::OpenGL) QSKIP("Skipping OpenGL context test due to not running with OpenGL"); - QVERIFY(spy.size() > 0); + QTRY_VERIFY(spy.size() > 0); QVariant ctx = spy.at(0).at(0); QCOMPARE(qvariant_cast<QOpenGLContext *>(ctx), window.openglContext()); @@ -414,7 +512,7 @@ void tst_qquickwindow::aboutToStopSignal() QQuickWindow window; window.setTitle(QTest::currentTestFunction()); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); QSignalSpy spy(&window, SIGNAL(sceneGraphAboutToStop())); @@ -449,7 +547,7 @@ void tst_qquickwindow::constantUpdatesOnWindow_data() window.setTitle(QTest::currentTestFunction()); window.setGeometry(100, 100, 300, 200); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); const bool threaded = QQuickWindowPrivate::get(&window)->context->thread() != QGuiApplication::instance()->thread(); if (threaded) { QTest::newRow("blocked, beforeRender") << true << QByteArray(SIGNAL(beforeRendering())); @@ -486,7 +584,7 @@ void tst_qquickwindow::constantUpdatesOnWindow() bool ok = connect(&window, signal.constData(), &window, SLOT(update()), Qt::DirectConnection); Q_ASSERT(ok); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); FrameCounter counter; connect(&window, SIGNAL(frameSwapped()), &counter, SLOT(incr()), Qt::DirectConnection); @@ -507,7 +605,7 @@ void tst_qquickwindow::constantUpdatesOnWindow() void tst_qquickwindow::touchEvent_basic() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer<QQuickWindow> cleanup(window); @@ -533,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); @@ -545,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()); @@ -558,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()); @@ -598,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, @@ -612,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()); @@ -636,7 +735,7 @@ void tst_qquickwindow::touchEvent_basic() void tst_qquickwindow::touchEvent_propagation() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QFETCH(bool, acceptTouchEvents); QFETCH(bool, acceptMouseEvents); @@ -679,9 +778,8 @@ void tst_qquickwindow::touchEvent_propagation() // single touch to top item, should be received by middle item QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window); - QTest::qWait(50); + QTRY_COMPARE(middleItem->lastEvent.touchPoints.count(), 1); QVERIFY(topItem->lastEvent.touchPoints.isEmpty()); - QCOMPARE(middleItem->lastEvent.touchPoints.count(), 1); QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty()); COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos)))); @@ -690,9 +788,8 @@ void tst_qquickwindow::touchEvent_propagation() // touch top and middle items, middle item should get both events QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window) .press(1, pointInMiddleItem, window); - QTest::qWait(50); + QTRY_COMPARE(middleItem->lastEvent.touchPoints.count(), 2); QVERIFY(topItem->lastEvent.touchPoints.isEmpty()); - QCOMPARE(middleItem->lastEvent.touchPoints.count(), 2); QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty()); COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos)) @@ -710,10 +807,9 @@ void tst_qquickwindow::touchEvent_propagation() // touch top and middle items, bottom item should get all events QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window) .press(1, pointInMiddleItem, window); - QTest::qWait(50); + QTRY_COMPARE(bottomItem->lastEvent.touchPoints.count(), 2); QVERIFY(topItem->lastEvent.touchPoints.isEmpty()); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); - QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 2); COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos)) << makeTouchPoint(bottomItem, bottomItem->mapFromItem(middleItem, pos)) ))); @@ -783,7 +879,7 @@ void tst_qquickwindow::touchEvent_propagation_data() void tst_qquickwindow::touchEvent_cancel() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer<QQuickWindow> cleanup(window); @@ -807,7 +903,7 @@ void tst_qquickwindow::touchEvent_cancel() COMPARE_TOUCH_DATA(item->lastEvent, d); item->reset(); - QWindowSystemInterface::handleTouchCancelEvent(0, touchDevice); + QWindowSystemInterface::handleTouchCancelEvent(nullptr, touchDevice); QCoreApplication::processEvents(); d = makeTouchData(QEvent::TouchCancel, window); COMPARE_TOUCH_DATA(item->lastEvent, d); @@ -815,9 +911,41 @@ void tst_qquickwindow::touchEvent_cancel() delete item; } +void tst_qquickwindow::touchEvent_cancelClearsMouseGrab() +{ + TestTouchItem::clearMouseEventCounters(); + + QQuickWindow *window = new QQuickWindow; + QScopedPointer<QQuickWindow> cleanup(window); + + window->resize(250, 250); + window->setPosition(100, 100); + window->setTitle(QTest::currentTestFunction()); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + TestTouchItem *item = new TestTouchItem(window->contentItem()); + item->setPosition(QPointF(50, 50)); + item->setSize(QSizeF(150, 150)); + item->acceptMouseEvents = true; + item->acceptTouchEvents = false; + + QPointF pos(50, 50); + QTest::touchEvent(window, touchDevice).press(0, item->mapToScene(pos).toPoint(), window); + QCoreApplication::processEvents(); + + QTRY_COMPARE(item->mousePressCount, 1); + QTRY_COMPARE(item->mouseUngrabEventCount, 0); + + QWindowSystemInterface::handleTouchCancelEvent(nullptr, touchDevice); + QCoreApplication::processEvents(); + + QTRY_COMPARE(item->mouseUngrabEventCount, 1); +} + void tst_qquickwindow::touchEvent_reentrant() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer<QQuickWindow> cleanup(window); @@ -856,7 +984,7 @@ void tst_qquickwindow::touchEvent_reentrant() void tst_qquickwindow::touchEvent_velocity() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer<QQuickWindow> cleanup(window); @@ -871,23 +999,29 @@ void tst_qquickwindow::touchEvent_velocity() item->setPosition(QPointF(50, 50)); item->setSize(QSizeF(150, 150)); - QList<QWindowSystemInterface::TouchPoint> points; - QWindowSystemInterface::TouchPoint tp; - tp.id = 1; - tp.state = Qt::TouchPointPressed; - QPoint pos = window->mapToGlobal(item->mapToScene(QPointF(10, 10)).toPoint()); - tp.area = QRectF(pos, QSizeF(4, 4)); + QList<QTouchEvent::TouchPoint> points; + QTouchEvent::TouchPoint tp; + tp.setId(1); + tp.setState(Qt::TouchPointPressed); + const QPointF localPos = item->mapToScene(QPointF(10, 10)); + const QPointF screenPos = window->mapToGlobal(localPos.toPoint()); + tp.setPos(localPos); + tp.setScreenPos(screenPos); + tp.setEllipseDiameters(QSizeF(4, 4)); points << tp; - QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, + QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); QCOMPARE(item->touchEventCount, 1); - points[0].state = Qt::TouchPointMoved; - points[0].area.adjust(5, 5, 5, 5); + points[0].setState(Qt::TouchPointMoved); + points[0].setPos(localPos + QPointF(5, 5)); + points[0].setScreenPos(screenPos + QPointF(5, 5)); QVector2D velocity(1.5, 2.5); - points[0].velocity = velocity; - QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + points[0].setVelocity(velocity); + QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, + QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); QCOMPARE(item->touchEventCount, 2); @@ -899,17 +1033,20 @@ void tst_qquickwindow::touchEvent_velocity() QMatrix4x4 transformMatrix; transformMatrix.rotate(-90, 0, 0, 1); // counterclockwise QVector2D transformedVelocity = transformMatrix.mapVector(velocity).toVector2D(); - points[0].area.adjust(5, 5, 5, 5); - QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + points[0].setPos(points[0].pos() + QPointF(5, 5)); + points[0].setScreenPos(points[0].screenPos() + QPointF(5, 5)); + QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, + QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); QCOMPARE(item->lastVelocity, transformedVelocity); - QPoint itemLocalPos = item->mapFromScene(window->mapFromGlobal(points[0].area.center().toPoint())).toPoint(); + QPoint itemLocalPos = item->mapFromScene(points[0].pos()).toPoint(); QPoint itemLocalPosFromEvent = item->lastEvent.touchPoints[0].pos().toPoint(); QCOMPARE(itemLocalPos, itemLocalPosFromEvent); - points[0].state = Qt::TouchPointReleased; - QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + points[0].setState(Qt::TouchPointReleased); + QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, + QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); delete item; @@ -982,7 +1119,7 @@ void tst_qquickwindow::mouseFromTouch_basic() // should result in sending mouse events generated from the touch // with the new event propagation system. - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer<QQuickWindow> cleanup(window); window->resize(250, 250); @@ -997,25 +1134,32 @@ void tst_qquickwindow::mouseFromTouch_basic() item->setSize(QSizeF(150, 150)); item->acceptTouchEvents = false; - QList<QWindowSystemInterface::TouchPoint> points; - QWindowSystemInterface::TouchPoint tp; - tp.id = 1; - tp.state = Qt::TouchPointPressed; - QPoint pos = window->mapToGlobal(item->mapToScene(QPointF(10, 10)).toPoint()); - tp.area = QRectF(pos, QSizeF(4, 4)); + QList<QTouchEvent::TouchPoint> points; + QTouchEvent::TouchPoint tp; + tp.setId(1); + tp.setState(Qt::TouchPointPressed); + const QPointF localPos = item->mapToScene(QPointF(10, 10)); + const QPointF screenPos = window->mapToGlobal(localPos.toPoint()); + tp.setPos(localPos); + tp.setScreenPos(screenPos); + tp.setEllipseDiameters(QSizeF(4, 4)); points << tp; - QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, + QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); - points[0].state = Qt::TouchPointMoved; - points[0].area.adjust(5, 5, 5, 5); + points[0].setState(Qt::TouchPointMoved); + points[0].setPos(localPos + QPointF(5, 5)); + points[0].setScreenPos(screenPos + QPointF(5, 5)); QVector2D velocity(1.5, 2.5); - points[0].velocity = velocity; - QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + points[0].setVelocity(velocity); + QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, + QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); - points[0].state = Qt::TouchPointReleased; - QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + points[0].setState(Qt::TouchPointReleased); + QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, + QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); @@ -1023,7 +1167,7 @@ void tst_qquickwindow::mouseFromTouch_basic() QCOMPARE(item->mousePressNum, 1); QCOMPARE(item->mouseMoveNum, 1); QCOMPARE(item->mouseReleaseNum, 1); - QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(window->mapFromGlobal(points[0].area.center().toPoint())).toPoint()); + QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(points[0].pos()).toPoint()); QCOMPARE(item->lastVelocityFromMouseMove, velocity); QVERIFY((item->lastMouseCapabilityFlags & QTouchDevice::Velocity) != 0); @@ -1032,27 +1176,71 @@ void tst_qquickwindow::mouseFromTouch_basic() QMatrix4x4 transformMatrix; transformMatrix.rotate(-90, 0, 0, 1); // counterclockwise QVector2D transformedVelocity = transformMatrix.mapVector(velocity).toVector2D(); - points[0].state = Qt::TouchPointPressed; - points[0].velocity = velocity; - points[0].area = QRectF(pos, QSizeF(4, 4)); - QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + points[0].setState(Qt::TouchPointPressed); + points[0].setVelocity(velocity); + tp.setPos(localPos); + tp.setScreenPos(screenPos); + QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, + QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); - points[0].state = Qt::TouchPointMoved; - points[0].area.adjust(5, 5, 5, 5); - QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + points[0].setState(Qt::TouchPointMoved); + points[0].setPos(localPos + QPointF(5, 5)); + points[0].setScreenPos(screenPos + QPointF(5, 5)); + QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, + QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); - QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(window->mapFromGlobal(points[0].area.center().toPoint())).toPoint()); + QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(points[0].pos()).toPoint()); QCOMPARE(item->lastVelocityFromMouseMove, transformedVelocity); - points[0].state = Qt::TouchPointReleased; - QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); + points[0].setState(Qt::TouchPointReleased); + QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, + QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window)); QCoreApplication::processEvents(); QQuickTouchUtils::flush(window); delete item; } +void tst_qquickwindow::synthMouseFromTouch_data() +{ + QTest::addColumn<bool>("synthMouse"); // AA_SynthesizeMouseForUnhandledTouchEvents + QTest::addColumn<bool>("acceptTouch"); // QQuickItem::touchEvent: setAccepted() + + QTest::newRow("no synth, accept") << false << true; // suitable for touch-capable UIs + QTest::newRow("no synth, don't accept") << false << false; + QTest::newRow("synth and accept") << true << true; + QTest::newRow("synth, don't accept") << true << false; // the default +} + +void tst_qquickwindow::synthMouseFromTouch() +{ + QFETCH(bool, synthMouse); + QFETCH(bool, acceptTouch); + + QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, synthMouse); + QScopedPointer<MouseRecordingWindow> window(new MouseRecordingWindow); + QScopedPointer<MouseRecordingItem> item(new MouseRecordingItem(acceptTouch, nullptr)); + item->setParentItem(window->contentItem()); + window->resize(250, 250); + window->setPosition(100, 100); + window->setTitle(QTest::currentTestFunction()); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + QPoint p1 = QPoint(20, 20); + QPoint p2 = QPoint(30, 30); + QTest::touchEvent(window.data(), touchDevice).press(0, p1, window.data()); + QTest::touchEvent(window.data(), touchDevice).move(0, p2, window.data()); + QTest::touchEvent(window.data(), touchDevice).release(0, p2, window.data()); + + QCOMPARE(item->m_touchEvents.count(), !synthMouse && !acceptTouch ? 1 : 3); + QCOMPARE(item->m_mouseEvents.count(), (acceptTouch || !synthMouse) ? 0 : 3); + QCOMPARE(window->m_mouseEvents.count(), 0); + for (const QMouseEvent &ev : item->m_mouseEvents) + QCOMPARE(ev.source(), Qt::MouseEventSynthesizedByQt); +} + void tst_qquickwindow::clearWindow() { QQuickWindow *window = new QQuickWindow; @@ -1071,7 +1259,7 @@ void tst_qquickwindow::clearWindow() void tst_qquickwindow::mouseFiltering() { - TestTouchItem::clearMousePressCounter(); + TestTouchItem::clearMouseEventCounters(); QQuickWindow *window = new QQuickWindow; QScopedPointer<QQuickWindow> cleanup(window); @@ -1085,6 +1273,11 @@ void tst_qquickwindow::mouseFiltering() bottomItem->setObjectName("Bottom Item"); bottomItem->setSize(QSizeF(150, 150)); + TestTouchItem *siblingItem = new TestTouchItem(bottomItem); + siblingItem->setObjectName("Sibling of Middle Item"); + siblingItem->setPosition(QPointF(90, 25)); + siblingItem->setSize(QSizeF(150, 150)); + TestTouchItem *middleItem = new TestTouchItem(bottomItem); middleItem->setObjectName("Middle Item"); middleItem->setPosition(QPointF(50, 50)); @@ -1097,19 +1290,51 @@ void tst_qquickwindow::mouseFiltering() QPoint pos(100, 100); - QTest::mousePress(window, Qt::LeftButton, 0, pos); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, pos); + + // Mouse filtering propagates down the stack, so the + // correct order is + // 1. middleItem filters event + // 2. bottomItem filters event + // 3. topItem receives event + QTRY_COMPARE(middleItem->mousePressCount, 1); + QTRY_COMPARE(bottomItem->mousePressCount, 2); + QTRY_COMPARE(topItem->mousePressCount, 3); + QCOMPARE(siblingItem->mousePressCount, 0); + + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, pos); + topItem->clearMouseEventCounters(); + middleItem->clearMouseEventCounters(); + bottomItem->clearMouseEventCounters(); + siblingItem->clearMouseEventCounters(); + + // Repeat, but this time have the top item accept the press + topItem->acceptMouseEvents = true; + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, pos); // Mouse filtering propagates down the stack, so the // correct order is // 1. middleItem filters event // 2. bottomItem filters event // 3. topItem receives event - QTRY_COMPARE(middleItem->mousePressId, 1); - QTRY_COMPARE(bottomItem->mousePressId, 2); - QTRY_COMPARE(topItem->mousePressId, 3); + QTRY_COMPARE(middleItem->mousePressCount, 1); + QTRY_COMPARE(bottomItem->mousePressCount, 2); + QTRY_COMPARE(topItem->mousePressCount, 3); + QCOMPARE(siblingItem->mousePressCount, 0); + + pos += QPoint(50, 50); + QTest::mouseMove(window, pos); + + // The top item has grabbed, so the move goes there, but again + // all the ancestors can filter, even when the mouse is outside their bounds + QTRY_COMPARE(middleItem->mouseMoveCount, 1); + QTRY_COMPARE(bottomItem->mouseMoveCount, 2); + QTRY_COMPARE(topItem->mouseMoveCount, 3); + QCOMPARE(siblingItem->mouseMoveCount, 0); // clean up mouse press state for the next tests - QTest::mouseRelease(window, Qt::LeftButton, 0, pos); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, pos); } void tst_qquickwindow::qmlCreation() @@ -1177,7 +1402,7 @@ void tst_qquickwindow::defaultState() QQuickWindow cppWindow; cppWindow.show(); - QTest::qWaitForWindowExposed(&cppWindow); + QVERIFY(QTest::qWaitForWindowExposed(&cppWindow)); QCOMPARE(qmlWindow->windowState(), cppWindow.windowState()); } @@ -1194,6 +1419,10 @@ void tst_qquickwindow::grab_data() void tst_qquickwindow::grab() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QFETCH(bool, visible); QFETCH(bool, alpha); @@ -1277,44 +1506,6 @@ void tst_qquickwindow::animationsWhileHidden() QTRY_VERIFY(window->isVisible()); } -// When running on native Nvidia graphics cards on linux, the -// distance field glyph pixels have a measurable, but not visible -// pixel error. Use a custom compare function to avoid -// -// This was GT-216 with the ubuntu "nvidia-319" driver package. -// llvmpipe does not show the same issue. -// -bool compareImages(const QImage &ia, const QImage &ib) -{ - if (ia.size() != ib.size()) - qDebug() << "images are of different size" << ia.size() << ib.size(); - Q_ASSERT(ia.size() == ib.size()); - Q_ASSERT(ia.format() == ib.format()); - - int w = ia.width(); - int h = ia.height(); - const int tolerance = 5; - for (int y=0; y<h; ++y) { - const uint *as= (const uint *) ia.constScanLine(y); - const uint *bs= (const uint *) ib.constScanLine(y); - for (int x=0; x<w; ++x) { - uint a = as[x]; - uint b = bs[x]; - - // No tolerance for error in the alpha. - if ((a & 0xff000000) != (b & 0xff000000)) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) - return false; - } - } - return true; -} - void tst_qquickwindow::headless() { QQmlEngine engine; @@ -1368,7 +1559,9 @@ void tst_qquickwindow::headless() // Verify that the visual output is the same QImage newContent = window->grabWindow(); - QVERIFY(compareImages(newContent, originalContent)); + QString errorMessage; + QVERIFY2(QQuickVisualTestUtil::compareImages(newContent, originalContent, &errorMessage), + qPrintable(errorMessage)); } void tst_qquickwindow::noUpdateWhenNothingChanges() @@ -1380,7 +1573,7 @@ void tst_qquickwindow::noUpdateWhenNothingChanges() QQuickRectangle rect(window.contentItem()); window.showNormal(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); // Many platforms are broken in the sense that that they follow up // the initial expose with a second expose or more. Let these go // through before we let the test continue. @@ -1530,7 +1723,7 @@ void tst_qquickwindow::ownershipRootItem() QVERIFY(accessor); engine.collectGarbage(); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QCoreApplication::processEvents(); QVERIFY(!accessor->isRootItemDestroyed()); } @@ -1637,7 +1830,7 @@ void tst_qquickwindow::cursor() QCOMPARE(window.cursor().shape(), Qt::WaitCursor); // Try with the mouse pressed. - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100, 100)); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 100)); QTest::mouseMove(&window, QPoint(20, 20)); QCOMPARE(window.cursor().shape(), Qt::IBeamCursor); QTest::mouseMove(&window, QPoint(125, 125)); @@ -1648,12 +1841,12 @@ void tst_qquickwindow::cursor() QCOMPARE(window.cursor().shape(), Qt::ArrowCursor); QTest::mouseMove(&window, QPoint(100, 100)); QCOMPARE(window.cursor().shape(), Qt::WaitCursor); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(100, 100)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 100)); // Remove the cursor item from the scene. Theoretically this should make parentItem the // cursorItem, but given the situation will correct itself after the next mouse move it // simply unsets the window cursor for now. - childItem.setParentItem(0); + childItem.setParentItem(nullptr); QCOMPARE(window.cursor().shape(), Qt::ArrowCursor); parentItem.setCursor(Qt::SizeAllCursor); @@ -1669,7 +1862,7 @@ void tst_qquickwindow::cursor() QCOMPARE(childItem.cursor().shape(), Qt::ArrowCursor); QCOMPARE(window.cursor().shape(), Qt::ArrowCursor); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(100, 101)); + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 101)); QCOMPARE(window.cursor().shape(), Qt::SizeAllCursor); } #endif @@ -1690,8 +1883,8 @@ void tst_qquickwindow::hideThenDelete() QFETCH(bool, persistentSG); QFETCH(bool, persistentGL); - QSignalSpy *openglDestroyed = 0; - QSignalSpy *sgInvalidated = 0; + QSignalSpy *openglDestroyed = nullptr; + QSignalSpy *sgInvalidated = nullptr; { QQuickWindow window; @@ -1705,7 +1898,7 @@ void tst_qquickwindow::hideThenDelete() window.resize(400, 300); window.show(); - QTest::qWaitForWindowExposed(&window); + QVERIFY(QTest::qWaitForWindowExposed(&window)); const bool threaded = QQuickWindowPrivate::get(&window)->context->thread() != QGuiApplication::instance()->thread(); const bool isGL = window.rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL; #if QT_CONFIG(opengl) @@ -1829,7 +2022,7 @@ void tst_qquickwindow::requestActivate() QString warning = QString::fromLatin1("Mouse event MousePress not accepted by receiving window"); QWARN(warning.toLatin1().data()); } - me = QMouseEvent(QEvent::MouseButtonPress, pos, window1->mapToGlobal(pos), Qt::LeftButton, 0, Qt::NoModifier); + me = QMouseEvent(QEvent::MouseButtonPress, pos, window1->mapToGlobal(pos), Qt::LeftButton, nullptr, Qt::NoModifier); QSpontaneKeyEvent::setSpontaneous(&me); if (!qApp->notify(window1.data(), &me)) { QString warning = QString::fromLatin1("Mouse event MouseRelease not accepted by receiving window"); @@ -1855,15 +2048,20 @@ void tst_qquickwindow::testWindowVisibilityOrder() QVERIFY(window2); QVERIFY(window3); - QTest::qWaitForWindowExposed(window3); + QVERIFY(QTest::qWaitForWindowExposed(window3)); QWindowList windows = QGuiApplication::topLevelWindows(); QTRY_COMPARE(windows.size(), 5); - QCOMPARE(window3, QGuiApplication::focusWindow()); - QVERIFY(window1->isActive()); - QVERIFY(window2->isActive()); - QVERIFY(window3->isActive()); + if (qgetenv("XDG_CURRENT_DESKTOP") == "Unity" && QGuiApplication::focusWindow() != window3) { + qDebug() << "Unity (flaky QTBUG-62604): expected window3 to have focus; actual focusWindow:" + << QGuiApplication::focusWindow(); + } else { + QCOMPARE(window3, QGuiApplication::focusWindow()); + QVERIFY(window1->isActive()); + QVERIFY(window2->isActive()); + QVERIFY(window3->isActive()); + } //Test if window4 is shown 2 seconds after the application startup //with window4 visible window5 (transient child) should also become visible @@ -1872,7 +2070,7 @@ void tst_qquickwindow::testWindowVisibilityOrder() window4->setVisible(true); - QTest::qWaitForWindowExposed(window5); + QVERIFY(QTest::qWaitForWindowExposed(window5)); QVERIFY(window4->isVisible()); QVERIFY(window5->isVisible()); } @@ -1886,7 +2084,7 @@ void tst_qquickwindow::blockClosing() QVERIFY(!window.isNull()); window->setTitle(QTest::currentTestFunction()); window->show(); - QTest::qWaitForWindowExposed(window.data()); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QVERIFY(window->isVisible()); QWindowSystemInterface::handleCloseEvent(window.data()); QVERIFY(window->isVisible()); @@ -1906,7 +2104,7 @@ void tst_qquickwindow::blockCloseMethod() QVERIFY(!window.isNull()); window->setTitle(QTest::currentTestFunction()); window->show(); - QTest::qWaitForWindowExposed(window.data()); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QVERIFY(window->isVisible()); QVERIFY(QMetaObject::invokeMethod(window.data(), "close", Qt::DirectConnection)); QVERIFY(window->isVisible()); @@ -1927,7 +2125,7 @@ void tst_qquickwindow::crashWhenHoverItemDeleted() QVERIFY(!window.isNull()); window->setTitle(QTest::currentTestFunction()); window->show(); - QTest::qWaitForWindowActive(window.data()); + QVERIFY(QTest::qWaitForWindowActive(window.data())); // Simulate a move from the first rectangle to the second. Crash will happen in here // Moving instantaneously from (0, 99) to (0, 102) does not cause the crash @@ -1946,10 +2144,10 @@ void tst_qquickwindow::unloadSubWindow() QVERIFY(!window.isNull()); window->setTitle(QTest::currentTestFunction()); window->show(); - QTest::qWaitForWindowExposed(window.data()); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QPointer<QQuickWindow> transient; QTRY_VERIFY(transient = window->property("transientWindow").value<QQuickWindow*>()); - QTest::qWaitForWindowExposed(transient); + QVERIFY(QTest::qWaitForWindowExposed(transient)); // Unload the inner window (in nested Loaders) and make sure it doesn't crash QQuickLoader *loader = window->property("loader1").value<QQuickLoader*>(); @@ -1967,13 +2165,13 @@ void tst_qquickwindow::changeVisibilityInCompleted() QVERIFY(!window.isNull()); window->setTitle(QTest::currentTestFunction()); window->show(); - QTest::qWaitForWindowExposed(window.data()); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); QPointer<QQuickWindow> winVisible; QTRY_VERIFY(winVisible = window->property("winVisible").value<QQuickWindow*>()); QPointer<QQuickWindow> winVisibility; QTRY_VERIFY(winVisibility = window->property("winVisibility").value<QQuickWindow*>()); - QTest::qWaitForWindowExposed(winVisible); - QTest::qWaitForWindowExposed(winVisibility); + QVERIFY(QTest::qWaitForWindowExposed(winVisible)); + QVERIFY(QTest::qWaitForWindowExposed(winVisibility)); QVERIFY(winVisible->isVisible()); QCOMPARE(winVisibility->visibility(), QWindow::Windowed); @@ -2152,8 +2350,10 @@ void tst_qquickwindow::defaultSurfaceFormat() // Depth and stencil should be >= what has been requested. For real. But use // the context since the window's surface format is only partially updated // on most platforms. - QVERIFY(window.openglContext()->format().depthBufferSize() >= 16); - QVERIFY(window.openglContext()->format().stencilBufferSize() >= 8); + const QOpenGLContext *openglContext = nullptr; + QTRY_VERIFY((openglContext = window.openglContext()) != nullptr); + QVERIFY(openglContext->format().depthBufferSize() >= 16); + QVERIFY(openglContext->format().stencilBufferSize() >= 8); #endif QSurfaceFormat::setDefaultFormat(savedDefaultFormat); } @@ -2173,6 +2373,7 @@ void tst_qquickwindow::attachedProperty() QQuickWindow *innerWindow = view.rootObject()->findChild<QQuickWindow*>("extraWindow"); QVERIFY(innerWindow); + innerWindow->show(); innerWindow->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(innerWindow)); @@ -2184,7 +2385,7 @@ void tst_qquickwindow::attachedProperty() QCOMPARE(text->property("windowHeight").toInt(), innerWindow->height()); QCOMPARE(text->property("window").value<QQuickWindow*>(), innerWindow); - text->setParentItem(0); + text->setParentItem(nullptr); QVERIFY(!text->property("contentItem").value<QQuickItem*>()); QCOMPARE(text->property("windowWidth").toInt(), 0); QCOMPARE(text->property("windowHeight").toInt(), 0); @@ -2207,7 +2408,7 @@ public: class GlRenderJob : public QRunnable { public: - GlRenderJob(GLubyte *buf) : readPixel(buf), mutex(0), condition(0) {} + GlRenderJob(GLubyte *buf) : readPixel(buf), mutex(nullptr), condition(nullptr) {} ~GlRenderJob() {} void run() { QOpenGLContext::currentContext()->functions()->glClearColor(1.0f, 0, 0, 1.0f); @@ -2272,6 +2473,9 @@ void tst_qquickwindow::testRenderJob() window.scheduleRenderJob(new RenderJob(QQuickWindow::NoStage, &completedJobs), QQuickWindow::NoStage); QTRY_COMPARE(RenderJob::deleted, 1); + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QEXPECT_FAIL("", "NoStage job fails on offscreen/minimimal platforms", Continue); QCOMPARE(completedJobs.size(), 1); #if QT_CONFIG(opengl) @@ -2315,7 +2519,7 @@ void tst_qquickwindow::testRenderJob() class EventCounter : public QQuickRectangle { public: - EventCounter(QQuickItem *parent = 0) + EventCounter(QQuickItem *parent = nullptr) : QQuickRectangle(parent) { } @@ -2340,13 +2544,13 @@ public: m_childMouseEventFilterEventCount.clear(); } protected: - bool childMouseEventFilter(QQuickItem *, QEvent *event) Q_DECL_OVERRIDE + bool childMouseEventFilter(QQuickItem *, QEvent *event) override { m_childMouseEventFilterEventCount[event->type()]++; return m_returnTrueForType.contains(event->type()); } - bool event(QEvent *event) Q_DECL_OVERRIDE + bool event(QEvent *event) override { m_eventCount[event->type()]++; return QQuickRectangle::event(event); @@ -2423,7 +2627,7 @@ class HoverTimestampConsumer : public QQuickItem { Q_OBJECT public: - HoverTimestampConsumer(QQuickItem *parent = 0) + HoverTimestampConsumer(QQuickItem *parent = nullptr) : QQuickItem(parent) { setAcceptHoverEvents(true); @@ -2503,6 +2707,84 @@ void tst_qquickwindow::testHoverTimestamp() QCOMPARE(hoverConsumer->hoverTimestamps.last(), 5UL); } +class CircleItem : public QQuickRectangle +{ +public: + CircleItem(QQuickItem *parent = nullptr) : QQuickRectangle(parent) { } + + void setRadius(qreal radius) { + const qreal diameter = radius*2; + setWidth(diameter); + setHeight(diameter); + } + + bool childMouseEventFilter(QQuickItem *item, QEvent *event) override + { + Q_UNUSED(item) + if (event->type() == QEvent::MouseButtonPress && !contains(static_cast<QMouseEvent*>(event)->pos())) { + // This is an evil hack: in case of items that are not rectangles, we never accept the event. + // Instead the events are now delivered to QDeclarativeGeoMapItemBase which doesn't to anything with them. + // The map below it still works since it filters events and steals the events at some point. + event->setAccepted(false); + return true; + } + return false; + } + + bool contains(const QPointF &pos) const override { + // returns true if the point is inside the the embedded circle inside the (square) rect + const float radius = (float)width()/2; + const QVector2D center(radius, radius); + const QVector2D dx = QVector2D(pos) - center; + const bool ret = dx.lengthSquared() < radius*radius; + return ret; + } +}; + +void tst_qquickwindow::test_circleMapItem() +{ + QQuickWindow window; + + window.resize(250, 250); + window.setPosition(100, 100); + window.setTitle(QTest::currentTestFunction()); + + QQuickItem *root = window.contentItem(); + QQuickMouseArea *mab = new QQuickMouseArea(root); + mab->setObjectName("Bottom MouseArea"); + mab->setSize(QSizeF(100, 100)); + + CircleItem *topItem = new CircleItem(root); + topItem->setFiltersChildMouseEvents(true); + topItem->setColor(Qt::green); + topItem->setObjectName("Top Item"); + topItem->setPosition(QPointF(30, 30)); + topItem->setRadius(20); + QQuickMouseArea *mat = new QQuickMouseArea(topItem); + mat->setObjectName("Top Item/MouseArea"); + mat->setSize(QSizeF(40, 40)); + + QSignalSpy bottomSpy(mab, SIGNAL(clicked(QQuickMouseEvent *))); + QSignalSpy topSpy(mat, SIGNAL(clicked(QQuickMouseEvent *))); + + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + QTest::qWait(1000); + + QPoint pos(50, 50); + QTest::mouseClick(&window, Qt::LeftButton, Qt::KeyboardModifiers(), pos); + + QCOMPARE(topSpy.count(), 1); + QCOMPARE(bottomSpy.count(), 0); + + // Outside the "Circles" "input area", but on top of the bottomItem rectangle + pos = QPoint(66, 66); + QTest::mouseClick(&window, Qt::LeftButton, Qt::KeyboardModifiers(), pos); + + QCOMPARE(bottomSpy.count(), 1); + QCOMPARE(topSpy.count(), 1); +} + void tst_qquickwindow::pointerEventTypeAndPointCount() { QPointF localPosition(33, 66); @@ -2516,20 +2798,18 @@ void tst_qquickwindow::pointerEventTypeAndPointCount() QQuickPointerMouseEvent pme; pme.reset(&me); - QVERIFY(pme.isValid()); QCOMPARE(pme.asMouseEvent(localPosition), &me); QVERIFY(pme.asPointerMouseEvent()); QVERIFY(!pme.asPointerTouchEvent()); QVERIFY(!pme.asPointerTabletEvent()); // QVERIFY(!pe->asTabletEvent()); // TODO QCOMPARE(pme.pointCount(), 1); - QCOMPARE(pme.point(0)->scenePos(), scenePosition); + QCOMPARE(pme.point(0)->scenePosition(), scenePosition); QCOMPARE(pme.asMouseEvent(localPosition)->localPos(), localPosition); QCOMPARE(pme.asMouseEvent(localPosition)->screenPos(), screenPosition); QQuickPointerTouchEvent pte; pte.reset(&te); - QVERIFY(pte.isValid()); QCOMPARE(pte.asTouchEvent(), &te); QVERIFY(!pte.asPointerMouseEvent()); QVERIFY(pte.asPointerTouchEvent()); @@ -2576,7 +2856,7 @@ class TestDropTarget : public QQuickItem { Q_OBJECT public: - TestDropTarget(QQuickItem *parent = 0) + TestDropTarget(QQuickItem *parent = nullptr) : QQuickItem(parent) , enterDropAction(Qt::CopyAction) , moveDropAction(Qt::CopyAction) @@ -2637,10 +2917,10 @@ public: ~DragEventTester() { qDeleteAll(events); events.clear(); - enterEvent = 0; - moveEvent = 0; - dropEvent = 0; - leaveEvent = 0; + enterEvent = nullptr; + moveEvent = nullptr; + dropEvent = nullptr; + leaveEvent = nullptr; } void addEnterEvent() @@ -2849,6 +3129,400 @@ void tst_qquickwindow::findChild() QCOMPARE(window.contentItem()->findChild<QObject *>("contentItemChild"), contentItemChild); } +class DeliveryRecord : public QPair<QString, QString> +{ +public: + DeliveryRecord(const QString &filter, const QString &receiver) : QPair(filter, receiver) { } + DeliveryRecord(const QString &receiver) : QPair(QString(), receiver) { } + DeliveryRecord() : QPair() { } + QString toString() const { + if (second.isEmpty()) + return QLatin1String("Delivery(no receiver)"); + else if (first.isEmpty()) + return QString(QLatin1String("Delivery(to '%1')")).arg(second); + else + return QString(QLatin1String("Delivery('%1' filtering for '%2')")).arg(first).arg(second); + } +}; + +Q_DECLARE_METATYPE(DeliveryRecord) + +QDebug operator<<(QDebug dbg, const DeliveryRecord &pair) +{ + dbg << pair.toString(); + return dbg; +} + +typedef QVector<DeliveryRecord> DeliveryRecordVector; + +class EventItem : public QQuickRectangle +{ + Q_OBJECT +public: + EventItem(QQuickItem *parent) + : QQuickRectangle(parent) + , m_eventAccepts(true) + , m_filterReturns(true) + , m_filterAccepts(true) + , m_filterNotPreAccepted(false) + { + QSizeF psize(parent->width(), parent->height()); + psize -= QSizeF(20, 20); + setWidth(psize.width()); + setHeight(psize.height()); + setPosition(QPointF(10, 10)); + } + + void setFilterReturns(bool filterReturns) { m_filterReturns = filterReturns; } + void setFilterAccepts(bool accepts) { m_filterAccepts = accepts; } + void setEventAccepts(bool accepts) { m_eventAccepts = accepts; } + + /*! + * \internal + * + * returns false if any of the calls to childMouseEventFilter had the wrong + * preconditions. If all calls had the expected precondition, returns true. + */ + bool testFilterPreConditions() const { return !m_filterNotPreAccepted; } + static QVector<DeliveryRecord> &deliveryList() { return m_deliveryList; } + static QSet<QEvent::Type> &includedEventTypes() + { + if (m_includedEventTypes.isEmpty()) + m_includedEventTypes << QEvent::MouseButtonPress; + return m_includedEventTypes; + } + static void setExpectedDeliveryList(const QVector<DeliveryRecord> &v) { m_expectedDeliveryList = v; } + +protected: + bool childMouseEventFilter(QQuickItem *i, QEvent *e) override + { + appendEvent(this, i, e); + switch (e->type()) { + case QEvent::MouseButtonPress: + if (!e->isAccepted()) + m_filterNotPreAccepted = true; + e->setAccepted(m_filterAccepts); + // qCDebug(lcTests) << objectName() << i->objectName(); + return m_filterReturns; + default: + break; + } + return QQuickRectangle::childMouseEventFilter(i, e); + } + + bool event(QEvent *e) override + { + appendEvent(nullptr, this, e); + switch (e->type()) { + case QEvent::MouseButtonPress: + // qCDebug(lcTests) << objectName(); + e->setAccepted(m_eventAccepts); + return true; + default: + break; + } + return QQuickRectangle::event(e); + } + +private: + static void appendEvent(QQuickItem *filter, QQuickItem *receiver, QEvent *event) { + if (includedEventTypes().contains(event->type())) { + auto record = DeliveryRecord(filter ? filter->objectName() : QString(), receiver ? receiver->objectName() : QString()); + int i = m_deliveryList.count(); + if (m_expectedDeliveryList.count() > i && m_expectedDeliveryList[i] == record) + qCDebug(lcTests).noquote().nospace() << i << ": " << record; + else + qCDebug(lcTests).noquote().nospace() << i << ": " << record + << ", expected " << (m_expectedDeliveryList.count() > i ? m_expectedDeliveryList[i].toString() : QLatin1String("nothing")) << " <---"; + m_deliveryList << record; + } + } + bool m_eventAccepts; + bool m_filterReturns; + bool m_filterAccepts; + bool m_filterNotPreAccepted; + + // list of (filtering-parent . receiver) pairs + static DeliveryRecordVector m_expectedDeliveryList; + static DeliveryRecordVector m_deliveryList; + static QSet<QEvent::Type> m_includedEventTypes; +}; + +DeliveryRecordVector EventItem::m_expectedDeliveryList; +DeliveryRecordVector EventItem::m_deliveryList; +QSet<QEvent::Type> EventItem::m_includedEventTypes; + +typedef QVector<const char*> CharStarVector; + +Q_DECLARE_METATYPE(CharStarVector) + +struct InputState { + struct { + // event() behavior + bool eventAccepts; + // filterChildMouse behavior + bool returns; + bool accepts; + bool filtersChildMouseEvent; + } r[4]; +}; + +Q_DECLARE_METATYPE(InputState) + +void tst_qquickwindow::testChildMouseEventFilter_data() +{ + // HIERARCHY: + // r0->r1->r2->r3 + // + QTest::addColumn<QPoint>("mousePos"); + QTest::addColumn<InputState>("inputState"); + QTest::addColumn<DeliveryRecordVector>("expectedDeliveryOrder"); + + QTest::newRow("if filtered and rejected, do not deliver it to the item that filtered it") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, false}, + { true, false, false, false}, + { false, true, false, true}, + { false, false, false, false} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r2", "r3") + //<< DeliveryRecord("r3") // it got filtered -> do not deliver + // DeliveryRecord("r2") // r2 filtered it -> do not deliver + << DeliveryRecord("r1") + ); + + QTest::newRow("no filtering, no accepting") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, false}, + { false , false, false, false}, + { false, false, false, false}, + { false, false, false, false} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r3") + << DeliveryRecord("r2") + << DeliveryRecord("r1") + << DeliveryRecord("r0") + << DeliveryRecord("root") + ); + + QTest::newRow("all filtering, no accepting") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, true}, + { false, false, false, true}, + { false, false, false, true}, + { false, false, false, true} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r2", "r3") + << DeliveryRecord("r1", "r3") + << DeliveryRecord("r0", "r3") + << DeliveryRecord("r3") + << DeliveryRecord("r1", "r2") + << DeliveryRecord("r0", "r2") + << DeliveryRecord("r2") + << DeliveryRecord("r0", "r1") + << DeliveryRecord("r1") + << DeliveryRecord("r0") + << DeliveryRecord("root") + ); + + + QTest::newRow("some filtering, no accepting") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, true}, + { false, false, false, true}, + { false, false, false, false}, + { false, false, false, false} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r1", "r3") + << DeliveryRecord("r0", "r3") + << DeliveryRecord("r3") + << DeliveryRecord("r1", "r2") + << DeliveryRecord("r0", "r2") + << DeliveryRecord("r2") + << DeliveryRecord("r0", "r1") + << DeliveryRecord("r1") + << DeliveryRecord("r0") + << DeliveryRecord("root") + ); + + QTest::newRow("r1 accepts") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, true}, + { true , false, false, true}, + { false, false, false, false}, + { false, false, false, false} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r1", "r3") + << DeliveryRecord("r0", "r3") + << DeliveryRecord("r3") + << DeliveryRecord("r1", "r2") + << DeliveryRecord("r0", "r2") + << DeliveryRecord("r2") + << DeliveryRecord("r0", "r1") + << DeliveryRecord("r1") + ); + + QTest::newRow("r1 rejects and filters") + << QPoint(100, 100) + << InputState({ + // | event() | child mouse filter + // +---------+---------+---------+--------- + { // | accepts | returns | accepts | filtersChildMouseEvent + { false, false, false, true}, + { false , true, false, true}, + { false, false, false, false}, + { false, false, false, false} + } + }) + << (DeliveryRecordVector() + << DeliveryRecord("r1", "r3") + << DeliveryRecord("r0", "r3") +// << DeliveryRecord("r3") // since it got filtered we don't deliver to r3 + << DeliveryRecord("r1", "r2") + << DeliveryRecord("r0", "r2") +// << DeliveryRecord("r2" // since it got filtered we don't deliver to r2 + << DeliveryRecord("r0", "r1") +// << DeliveryRecord("r1") // since it acted as a filter and returned true, we don't deliver to r1 + << DeliveryRecord("r0") + << DeliveryRecord("root") + ); + +} + +void tst_qquickwindow::testChildMouseEventFilter() +{ + QFETCH(QPoint, mousePos); + QFETCH(InputState, inputState); + QFETCH(DeliveryRecordVector, expectedDeliveryOrder); + + EventItem::setExpectedDeliveryList(expectedDeliveryOrder); + + QQuickWindow window; + window.resize(500, 809); + QQuickItem *root = window.contentItem(); + root->setAcceptedMouseButtons(Qt::LeftButton); + + root->setObjectName("root"); + EventFilter *rootFilter = new EventFilter; + root->installEventFilter(rootFilter); + + // Create 4 items; each item a child of the previous item. + EventItem *r[4]; + r[0] = new EventItem(root); + r[0]->setColor(QColor(0x404040)); + r[0]->setWidth(200); + r[0]->setHeight(200); + + r[1] = new EventItem(r[0]); + r[1]->setColor(QColor(0x606060)); + + r[2] = new EventItem(r[1]); + r[2]->setColor(Qt::red); + + r[3] = new EventItem(r[2]); + r[3]->setColor(Qt::green); + + for (uint i = 0; i < sizeof(r)/sizeof(EventItem*); ++i) { + r[i]->setEventAccepts(inputState.r[i].eventAccepts); + r[i]->setFilterReturns(inputState.r[i].returns); + r[i]->setFilterAccepts(inputState.r[i].accepts); + r[i]->setFiltersChildMouseEvents(inputState.r[i].filtersChildMouseEvent); + r[i]->setObjectName(QString::fromLatin1("r%1").arg(i)); + r[i]->setAcceptedMouseButtons(Qt::LeftButton); + } + + window.show(); + window.requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + + DeliveryRecordVector &actualDeliveryOrder = EventItem::deliveryList(); + actualDeliveryOrder.clear(); + QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, mousePos); + + // Check if event got delivered to the root item. If so, append it to the list of items the event got delivered to + if (rootFilter->events.contains(QEvent::MouseButtonPress)) + actualDeliveryOrder.append(DeliveryRecord("root")); + + for (int i = 0; i < qMax(actualDeliveryOrder.count(), expectedDeliveryOrder.count()); ++i) { + const DeliveryRecord expectedNames = expectedDeliveryOrder.value(i); + const DeliveryRecord actualNames = actualDeliveryOrder.value(i); + QCOMPARE(actualNames.toString(), expectedNames.toString()); + } + + for (EventItem *item : r) { + QVERIFY(item->testFilterPreConditions()); + } + + // "restore" mouse state + QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, mousePos); +} + +void tst_qquickwindow::cleanupGrabsOnRelease() +{ + TestTouchItem::clearMouseEventCounters(); + + QQuickWindow *window = new QQuickWindow; + QScopedPointer<QQuickWindow> cleanup(window); + window->resize(250, 250); + window->setPosition(100, 100); + window->setTitle(QTest::currentTestFunction()); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + TestTouchItem *parent = new TestTouchItem(window->contentItem()); + parent->setObjectName("parent"); + parent->setSize(QSizeF(150, 150)); + parent->acceptMouseEvents = true; + parent->grabOnRelease = true; + + TestTouchItem *child = new TestTouchItem(parent); + child->setObjectName("child"); + child->setSize(QSizeF(100, 100)); + child->acceptMouseEvents = true; + + QPoint pos(80, 80); + + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, pos); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, pos); + // There is an explicit parent->grabMouse on release(!). This means grab changes from child + // to parent: + // This will emit two ungrab events: + // 1. One for the child (due to the explicit call to parent->grabMouse()) + // 2. One for the parent (since the mouse button was finally released) + QCOMPARE(child->mouseUngrabEventCount, 1); + QCOMPARE(parent->mouseUngrabEventCount, 1); +} + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc" diff --git a/tests/auto/quick/qquickxmllistmodel/data/empty.xml b/tests/auto/quick/qquickxmllistmodel/data/empty.xml deleted file mode 100644 index e69de29bb2..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/empty.xml +++ /dev/null diff --git a/tests/auto/quick/qquickxmllistmodel/data/get.qml b/tests/auto/quick/qquickxmllistmodel/data/get.qml deleted file mode 100644 index 509da7174b..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/get.qml +++ /dev/null @@ -1,61 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "model.xml" - query: "/Pets/Pet" - XmlRole { name: "name"; query: "name/string()" } - XmlRole { name: "type"; query: "type/string()" } - XmlRole { name: "age"; query: "age/number()" } - XmlRole { name: "size"; query: "size/string()" } - - id: root - - property bool preTest: false - property bool postTest: false - - function runPreTest() { - if (root.get(0) != undefined) - return; - - preTest = true; - } - - function runPostTest() { - if (root.get(-1) != undefined) - return; - - var row = root.get(0); - if (row.name != "Polly" || - row.type != "Parrot" || - row.age != 12 || - row.size != "Small") - return; - - row = root.get(1); - if (row.name != "Penny" || - row.type != "Turtle" || - row.age != 4 || - row.size != "Small") - return; - - row = root.get(7); - if (row.name != "Rover" || - row.type != "Dog" || - row.age != 0 || - row.size != "Large") - return; - - row = root.get(8); - if (row.name != "Tiny" || - row.type != "Elephant" || - row.age != 15 || - row.size != "Large") - return; - - if (root.get(9) != undefined) - return; - - postTest = true; - } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/groups.qml b/tests/auto/quick/qquickxmllistmodel/data/groups.qml deleted file mode 100644 index c1b574a822..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/groups.qml +++ /dev/null @@ -1,10 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "groups.xml" - query: "//animal[@name='Garfield']/parent::group" - - XmlRole { name: "id"; query: "@id/string()" } - XmlRole { name: "name"; query: "@name/string()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/groups.xml b/tests/auto/quick/qquickxmllistmodel/data/groups.xml deleted file mode 100644 index 5de4d2ec71..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/groups.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<groups version="2.0"> - <group id="1" name="Animals" type="root"> - <group id="11" name="dogs"> - <animal id="111" name="Lassie"/> - <animal id="112" name="Laika"/> - <animal id="113" name="Wile E. Coyote" type="fictional"/> - </group> - <group id="12" name="cats"> - <animal id="121" name="Garfield" type="fictional"/> - <animal id="122" name="Sylvester" type="fictional"/> - </group> - <group id="13" name="birds"> - <animal id="131" name="Donald Duck" type="fictional"/> - <animal id="132" name="Phoenix" type="fictional"/> - </group> - </group> -</groups> diff --git a/tests/auto/quick/qquickxmllistmodel/data/model.qml b/tests/auto/quick/qquickxmllistmodel/data/model.qml deleted file mode 100644 index 2df3927479..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/model.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "model.xml" - query: "/Pets/Pet" - XmlRole { name: "name"; query: "name/string()" } - XmlRole { name: "type"; query: "type/string()" } - XmlRole { name: "age"; query: "age/number()" } - XmlRole { name: "size"; query: "size/string()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/model.xml b/tests/auto/quick/qquickxmllistmodel/data/model.xml deleted file mode 100644 index 40cd6d0432..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/model.xml +++ /dev/null @@ -1,54 +0,0 @@ -<Pets> - <Pet> - <name>Polly</name> - <type>Parrot</type> - <age>12</age> - <size>Small</size> - </Pet> - <Pet> - <name>Penny</name> - <type>Turtle</type> - <age>4</age> - <size>Small</size> - </Pet> - <Pet> - <name>Warren</name> - <type>Rabbit</type> - <age>2</age> - <size>Small</size> - </Pet> - <Pet> - <name>Spot</name> - <type>Dog</type> - <age>9</age> - <size>Medium</size> - </Pet> - <Pet> - <name>Whiskers</name> - <type>Cat</type> - <age>2</age> - <size>Medium</size> - </Pet> - <Pet> - <name>Joey</name> - <type>Kangaroo</type> - <age>1</age> - </Pet> - <Pet> - <name>Kimba</name> - <type>Bunny</type> - <age>65</age> - <size>Large</size> - </Pet> - <Pet> - <name>Rover</name> - <type>Dog</type> - <size>Large</size> - </Pet> - <Pet> - <name>Tiny</name> - <type>Elephant</type> - <age>15</age> - <size>Large</size> - </Pet> -</Pets> diff --git a/tests/auto/quick/qquickxmllistmodel/data/model2.xml b/tests/auto/quick/qquickxmllistmodel/data/model2.xml deleted file mode 100644 index dab2ec6dc0..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/model2.xml +++ /dev/null @@ -1,14 +0,0 @@ -<Pets> - <Pet> - <name>Polly</name> - <type>Parrot</type> - <age>12</age> - <size>Small</size> - </Pet> - <Pet> - <name>Penny</name> - <type>Turtle</type> - <age>4</age> - <size>Small</size> - </Pet> -</Pets> diff --git a/tests/auto/quick/qquickxmllistmodel/data/propertychanges.qml b/tests/auto/quick/qquickxmllistmodel/data/propertychanges.qml deleted file mode 100644 index f8a97bffc3..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/propertychanges.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "model.xml" - query: "/Pets/Pet" - XmlRole { objectName: "role"; name: "name"; query: "name/string()" } - XmlRole { name: "type"; query: "type/string()" } - XmlRole { name: "age"; query: "age/number()" } - XmlRole { name: "size"; query: "size/string()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/proxyCrash.qml b/tests/auto/quick/qquickxmllistmodel/data/proxyCrash.qml deleted file mode 100644 index c0c5a25e3c..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/proxyCrash.qml +++ /dev/null @@ -1,9 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 -import SortFilterProxyModel 1.0 - -SortFilterProxyModel { - source: XmlListModel { - XmlRole { } - } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/recipes.qml b/tests/auto/quick/qquickxmllistmodel/data/recipes.qml deleted file mode 100644 index dc609e95e3..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/recipes.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "recipes.xml" - query: "/recipes/recipe" - XmlRole { name: "title"; query: "@title/string()" } - XmlRole { name: "picture"; query: "picture/string()" } - XmlRole { name: "ingredients"; query: "ingredients/string()" } - XmlRole { name: "preparation"; query: "method/string()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/recipes.xml b/tests/auto/quick/qquickxmllistmodel/data/recipes.xml deleted file mode 100644 index d71de60710..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/recipes.xml +++ /dev/null @@ -1,90 +0,0 @@ -<recipes> - <recipe title="Pancakes"> - <picture>content/pics/pancakes.jpg</picture> - <ingredients><![CDATA[<html> - <ul> - <li> 1 cup (150g) self-raising flour - <li> 1 tbs caster sugar - <li> 3/4 cup (185ml) milk - <li> 1 egg - </ul> - </html> - ]]></ingredients> - <method><![CDATA[<html> - <ol> - <li> Sift flour and sugar together into a bowl. Add a pinch of salt. - <li> Beat milk and egg together, then add to dry ingredients. Beat until smooth. - <li> Pour mixture into a pan on medium heat and cook until bubbles appear on the surface. - <li> Turn over and cook other side until golden. - </ol> - </html> - ]]></method> - </recipe> - <recipe title="Fruit Salad"> - <picture>content/pics/fruit-salad.jpg</picture> - <ingredients><![CDATA[* Seasonal Fruit]]></ingredients> - <method><![CDATA[* Chop fruit and place in a bowl.]]></method> - </recipe> - <recipe title="Vegetable Soup"> - <picture>content/pics/vegetable-soup.jpg</picture> - <ingredients><![CDATA[<html> - <ul> - <li> 1 onion - <li> 1 turnip - <li> 1 potato - <li> 1 carrot - <li> 1 head of celery - <li> 1 1/2 litres of water - </ul> - </html> - ]]></ingredients> - <method><![CDATA[<html> - <ol> - <li> Chop vegetables. - <li> Boil in water until vegetables soften. - <li> Season with salt and pepper to taste. - </ol> - </html> - ]]></method> - </recipe> - <recipe title="Hamburger"> - <picture>content/pics/hamburger.jpg</picture> - <ingredients><![CDATA[<html> - <ul> - <li> 500g minced beef - <li> Seasoning - <li> lettuce, tomato, onion, cheese - <li> 1 hamburger bun for each burger - </ul> - </html> - ]]></ingredients> - <method><![CDATA[<html> - <ol> - <li> Mix the beef, together with seasoning, in a food processor. - <li> Shape the beef into burgers. - <li> Grill the burgers for about 5 mins on each side (until cooked through) - <li> Serve each burger on a bun with ketchup, cheese, lettuce, tomato and onion. - </ol> - </html> - ]]></method> - </recipe> - <recipe title="Lemonade"> - <picture>content/pics/lemonade.jpg</picture> - <ingredients><![CDATA[<html> - <ul> - <li> 1 cup Lemon Juice - <li> 1 cup Sugar - <li> 6 Cups of Water (2 cups warm water, 4 cups cold water) - </ul> - </html> - ]]></ingredients> - <method><![CDATA[<html> - <ol> - <li> Pour 2 cups of warm water into a pitcher and stir in sugar until it dissolves. - <li> Pour in lemon juice, stir again, and add 4 cups of cold water. - <li> Chill or serve over ice cubes. - </ol> - </html> - ]]></method> - </recipe> -</recipes> diff --git a/tests/auto/quick/qquickxmllistmodel/data/roleCrash.qml b/tests/auto/quick/qquickxmllistmodel/data/roleCrash.qml deleted file mode 100644 index 6a7059bb45..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/roleCrash.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - id: model - XmlRole {} - Component.onCompleted: model.roles = 0 -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/roleErrors.qml b/tests/auto/quick/qquickxmllistmodel/data/roleErrors.qml deleted file mode 100644 index 91664b6d4a..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/roleErrors.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "model.xml" - query: "/Pets/Pet" - XmlRole { name: "name"; query: "/name/string()" } //starts with '/' - XmlRole { name: "type"; query: "type" } //no type - XmlRole { name: "age"; query: "age/" } //ends with '/' - XmlRole { name: "size"; query: "size/number()" } //wrong type -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/roleKeys.qml b/tests/auto/quick/qquickxmllistmodel/data/roleKeys.qml deleted file mode 100644 index 9f667d86e5..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/roleKeys.qml +++ /dev/null @@ -1,13 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - query: "/data/item" - XmlRole { id: nameRole; name: "name"; query: "name/string()"; isKey: true } - XmlRole { name: "age"; query: "age/number()"; isKey: true } - XmlRole { name: "sport"; query: "sport/string()" } - - function disableNameKey() { - nameRole.isKey = false; - } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/testtypes.qml b/tests/auto/quick/qquickxmllistmodel/data/testtypes.qml deleted file mode 100644 index 5ec1ffa35f..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/testtypes.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - query: "/data" - XmlRole { name: "stringValue"; query: "a-string/string()" } - XmlRole { name: "numberValue"; query: "a-number/number()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/unique.qml b/tests/auto/quick/qquickxmllistmodel/data/unique.qml deleted file mode 100644 index 322a2e4e5c..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/unique.qml +++ /dev/null @@ -1,9 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "model.xml" - query: "/Pets/Pet" - XmlRole { name: "name"; query: "name/string()" } - XmlRole { name: "name"; query: "type/string()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/qquickxmllistmodel.pro b/tests/auto/quick/qquickxmllistmodel/qquickxmllistmodel.pro deleted file mode 100644 index 902325802c..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/qquickxmllistmodel.pro +++ /dev/null @@ -1,16 +0,0 @@ -CONFIG += testcase -TARGET = tst_qquickxmllistmodel -macx:CONFIG -= app_bundle - -SOURCES += tst_qquickxmllistmodel.cpp \ - ../../../../src/imports/xmllistmodel/qqmlxmllistmodel.cpp -HEADERS += ../../../../src/imports/xmllistmodel/qqmlxmllistmodel_p.h - -include (../../shared/util.pri) - -TESTDATA = data/* - -QT += core-private gui-private qml-private network testlib xmlpatterns - -OTHER_FILES += \ - data/groups.qml diff --git a/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp b/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp deleted file mode 100644 index 757cb8f513..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp +++ /dev/null @@ -1,1004 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 <QtGlobal> -#include <math.h> -#include <QMetaObject> -#include <qtest.h> -#include <QtTest/qsignalspy.h> -#include <QtQml/qqmlnetworkaccessmanagerfactory.h> -#include <QtNetwork/qnetworkaccessmanager.h> -#include <QtNetwork/qnetworkrequest.h> -#include <QtCore/qtimer.h> -#include <QtCore/qfile.h> -#include <QtCore/qtemporaryfile.h> -#include <QtCore/qsortfilterproxymodel.h> -#include "../../shared/util.h" -#include <private/qqmlengine_p.h> - -#include <QtQml/qqmlengine.h> -#include <QtQml/qqmlcomponent.h> -#include "../../../../src/imports/xmllistmodel/qqmlxmllistmodel_p.h" - -#include <algorithm> - -typedef QPair<int, int> QQuickXmlListRange; -typedef QList<QVariantList> QQmlXmlModelData; - -Q_DECLARE_METATYPE(QList<QQuickXmlListRange>) -Q_DECLARE_METATYPE(QQmlXmlModelData) -Q_DECLARE_METATYPE(QQuickXmlListModel::Status) - -class tst_qquickxmllistmodel : public QQmlDataTest - -{ - Q_OBJECT -public: - tst_qquickxmllistmodel() {} - -private slots: - void initTestCase() { - QQmlDataTest::initTestCase(); - qRegisterMetaType<QQuickXmlListModel::Status>(); - } - - void buildModel(); - void testTypes(); - void testTypes_data(); - void cdata(); - void attributes(); - void roles(); - void roleErrors(); - void uniqueRoleNames(); - void headers(); - void xml(); - void xml_data(); - void source(); - void source_data(); - void data(); - void get(); - void reload(); - void useKeys(); - void useKeys_data(); - void noKeysValueChanges(); - void keysChanged(); - void threading(); - void threading_data(); - void propertyChanges(); - void selectAncestor(); - - void roleCrash(); - void proxyCrash(); - -private: - QString errorString(QAbstractItemModel *model) { - QString ret; - QMetaObject::invokeMethod(model, "errorString", Q_RETURN_ARG(QString, ret)); - return ret; - } - - QString makeItemXmlAndData(const QString &data, QQmlXmlModelData *modelData = 0) const - { - if (modelData) - modelData->clear(); - QString xml; - - if (!data.isEmpty()) { - QStringList items = data.split(QLatin1Char(';')); - foreach(const QString &item, items) { - if (item.isEmpty()) - continue; - QVariantList variants; - xml += QLatin1String("<item>"); - QStringList fields = item.split(QLatin1Char(',')); - foreach(const QString &field, fields) { - QStringList values = field.split(QLatin1Char('=')); - if (values.count() != 2) { - qWarning() << "makeItemXmlAndData: invalid field:" << field; - continue; - } - xml += QString("<%1>%2</%1>").arg(values[0], values[1]); - if (!modelData) - continue; - bool isNum = false; - int number = values[1].toInt(&isNum); - if (isNum) - variants << number; - else - variants << values[1]; - } - xml += QLatin1String("</item>"); - if (modelData) - modelData->append(variants); - } - } - - QString decl = "<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>"; - return decl + QLatin1String("<data>") + xml + QLatin1String("</data>"); - } - - QQmlEngine engine; -}; - -class CustomNetworkAccessManagerFactory : public QObject, public QQmlNetworkAccessManagerFactory -{ - Q_OBJECT -public: - QVariantMap lastSentHeaders; - -protected: - QNetworkAccessManager *create(QObject *parent); -}; - -class CustomNetworkAccessManager : public QNetworkAccessManager -{ - Q_OBJECT -public: - CustomNetworkAccessManager(CustomNetworkAccessManagerFactory *factory, QObject *parent) - : QNetworkAccessManager(parent), m_factory(factory) {} - -protected: - QNetworkReply *createRequest(Operation op, const QNetworkRequest &req, QIODevice * outgoingData = 0) - { - if (m_factory) { - QVariantMap map; - foreach (const QString &header, req.rawHeaderList()) - map[header] = req.rawHeader(header.toUtf8()); - m_factory->lastSentHeaders = map; - } - return QNetworkAccessManager::createRequest(op, req, outgoingData); - } - - QPointer<CustomNetworkAccessManagerFactory> m_factory; -}; - -QNetworkAccessManager *CustomNetworkAccessManagerFactory::create(QObject *parent) -{ - return new CustomNetworkAccessManager(this, parent); -} - - -void tst_qquickxmllistmodel::buildModel() -{ - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QModelIndex index = model->index(3, 0); - QCOMPARE(model->data(index, Qt::UserRole).toString(), QLatin1String("Spot")); - QCOMPARE(model->data(index, Qt::UserRole+1).toString(), QLatin1String("Dog")); - QCOMPARE(model->data(index, Qt::UserRole+2).toInt(), 9); - QCOMPARE(model->data(index, Qt::UserRole+3).toString(), QLatin1String("Medium")); - - delete model; -} - -void tst_qquickxmllistmodel::testTypes() -{ - QFETCH(QString, xml); - QFETCH(QString, roleName); - QFETCH(QVariant, expectedValue); - - QQmlComponent component(&engine, testFileUrl("testtypes.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - model->setProperty("xml",xml.toUtf8()); - QMetaObject::invokeMethod(model, "reload"); - QTRY_COMPARE(model->rowCount(), 1); - - int role = model->roleNames().key(roleName.toUtf8(), -1); - QVERIFY(role >= 0); - - QModelIndex index = model->index(0, 0); - if (expectedValue.toString() == "nan") - QVERIFY(qIsNaN(model->data(index, role).toDouble())); - else - QCOMPARE(model->data(index, role), expectedValue); - - delete model; -} - -void tst_qquickxmllistmodel::testTypes_data() -{ - QTest::addColumn<QString>("xml"); - QTest::addColumn<QString>("roleName"); - QTest::addColumn<QVariant>("expectedValue"); - - QTest::newRow("missing string field") << "<data></data>" - << "stringValue" << QVariant(""); - QTest::newRow("empty string") << "<data><a-string></a-string></data>" - << "stringValue" << QVariant(""); - QTest::newRow("1-char string") << "<data><a-string>5</a-string></data>" - << "stringValue" << QVariant("5"); - QTest::newRow("string ok") << "<data><a-string>abc def g</a-string></data>" - << "stringValue" << QVariant("abc def g"); - - QTest::newRow("missing number field") << "<data></data>" - << "numberValue" << QVariant(""); - double nan = qQNaN(); - QTest::newRow("empty number field") << "<data><a-number></a-number></data>" - << "numberValue" << QVariant(nan); - QTest::newRow("number field with string") << "<data><a-number>a string</a-number></data>" - << "numberValue" << QVariant(nan); - QTest::newRow("-1") << "<data><a-number>-1</a-number></data>" - << "numberValue" << QVariant("-1"); - QTest::newRow("-1.5") << "<data><a-number>-1.5</a-number></data>" - << "numberValue" << QVariant("-1.5"); - QTest::newRow("0") << "<data><a-number>0</a-number></data>" - << "numberValue" << QVariant("0"); - QTest::newRow("+1") << "<data><a-number>1</a-number></data>" - << "numberValue" << QVariant("1"); - QTest::newRow("+1.5") << "<data><a-number>1.5</a-number></data>" - << "numberValue" << QVariant("1.5"); -} - -void tst_qquickxmllistmodel::cdata() -{ - QQmlComponent component(&engine, testFileUrl("recipes.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 5); - - QVERIFY(model->data(model->index(2, 0), Qt::UserRole+2).toString().startsWith(QLatin1String("<html>"))); - - delete model; -} - -void tst_qquickxmllistmodel::attributes() -{ - QQmlComponent component(&engine, testFileUrl("recipes.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 5); - QCOMPARE(model->data(model->index(2, 0), Qt::UserRole).toString(), QLatin1String("Vegetable Soup")); - - delete model; -} - -void tst_qquickxmllistmodel::roles() -{ - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(roleNames.count(), 4); - QVERIFY(roleNames.key("name", -1) >= 0); - QVERIFY(roleNames.key("type", -1) >= 0); - QVERIFY(roleNames.key("age", -1) >= 0); - QVERIFY(roleNames.key("size", -1) >= 0); - - QSet<int> roles; - roles.insert(roleNames.key("name")); - roles.insert(roleNames.key("type")); - roles.insert(roleNames.key("age")); - roles.insert(roleNames.key("size")); - QCOMPARE(roles.count(), 4); - - delete model; -} - -void tst_qquickxmllistmodel::roleErrors() -{ - QQmlComponent component(&engine, testFileUrl("roleErrors.qml")); - QTest::ignoreMessage(QtWarningMsg, (testFileUrl("roleErrors.qml").toString() + ":7:5: QML XmlRole: An XmlRole query must not start with '/'").toUtf8().constData()); - QTest::ignoreMessage(QtWarningMsg, (testFileUrl("roleErrors.qml").toString() + ":10:5: QML XmlRole: invalid query: \"age/\"").toUtf8().constData()); - - //### make sure we receive all expected warning messages. - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QModelIndex index = model->index(3, 0); - //### should any of these return valid values? - QCOMPARE(model->data(index, Qt::UserRole), QVariant()); - QCOMPARE(model->data(index, Qt::UserRole+1), QVariant()); - QCOMPARE(model->data(index, Qt::UserRole+2), QVariant()); - - QEXPECT_FAIL("", "QTBUG-10797", Continue); - QCOMPARE(model->data(index, Qt::UserRole+3), QVariant()); - - delete model; -} - -void tst_qquickxmllistmodel::uniqueRoleNames() -{ - QQmlComponent component(&engine, testFileUrl("unique.qml")); - QTest::ignoreMessage(QtWarningMsg, (testFileUrl("unique.qml").toString() + ":8:5: QML XmlRole: \"name\" duplicates a previous role name and will be disabled.").toUtf8().constData()); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(roleNames.count(), 1); - - delete model; -} - - -void tst_qquickxmllistmodel::xml() -{ - QFETCH(QString, xml); - QFETCH(int, count); - - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - - QSignalSpy spy(model, SIGNAL(statusChanged(QQuickXmlListModel::Status))); - QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->property("progress").toDouble(), qreal(0.0)); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Loading); - QTRY_COMPARE(spy.count(), 1); spy.clear(); - QTest::qWait(50); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Ready); - QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); - QCOMPARE(model->rowCount(), 9); - - // if xml is empty (i.e. clearing) it won't have any effect if a source is set - if (xml.isEmpty()) - model->setProperty("source",QUrl()); - model->setProperty("xml",xml); - QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); // immediately goes to 1.0 if using setXml() - QTRY_COMPARE(spy.count(), 1); spy.clear(); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Loading); - QTRY_COMPARE(spy.count(), 1); spy.clear(); - if (xml.isEmpty()) - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Null); - else - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Ready); - QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->rowCount(), count); - - delete model; -} - -void tst_qquickxmllistmodel::xml_data() -{ - QTest::addColumn<QString>("xml"); - QTest::addColumn<int>("count"); - - QTest::newRow("xml with no items") << "<Pets></Pets>" << 0; - QTest::newRow("empty xml") << "" << 0; - QTest::newRow("one item") << "<Pets><Pet><name>Hobbes</name><type>Tiger</type><age>7</age><size>Large</size></Pet></Pets>" << 1; -} - -void tst_qquickxmllistmodel::headers() -{ - // ensure the QNetworkAccessManagers created for this test are immediately deleted - QQmlEngine qmlEng; - - CustomNetworkAccessManagerFactory factory; - qmlEng.setNetworkAccessManagerFactory(&factory); - - QQmlComponent component(&qmlEng, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Ready); - - QVariantMap expectedHeaders; - expectedHeaders["Accept"] = "application/xml,*/*"; - - QCOMPARE(factory.lastSentHeaders.count(), expectedHeaders.count()); - foreach (const QString &header, expectedHeaders.keys()) { - QVERIFY(factory.lastSentHeaders.contains(header)); - QCOMPARE(factory.lastSentHeaders[header].toString(), expectedHeaders[header].toString()); - } - - delete model; -} - -void tst_qquickxmllistmodel::source() -{ - QFETCH(QUrl, source); - QFETCH(int, count); - QFETCH(QQuickXmlListModel::Status, status); - - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QSignalSpy spy(model, SIGNAL(statusChanged(QQuickXmlListModel::Status))); - - QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->property("progress").toDouble(), qreal(0.0)); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Loading); - QTRY_COMPARE(spy.count(), 1); spy.clear(); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Ready); - QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); - QCOMPARE(model->rowCount(), 9); - - model->setProperty("source",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)); - QTRY_COMPARE(spy.count(), 1); spy.clear(); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Loading); - QVERIFY(errorString(model).isEmpty()); - - QEventLoop loop; - QTimer timer; - timer.setSingleShot(true); - connect(model, SIGNAL(statusChanged(QQuickXmlListModel::Status)), &loop, SLOT(quit())); - connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); - timer.start(20000); - loop.exec(); - - if (spy.count() == 0 && status != QQuickXmlListModel::Ready) { - qWarning("QQuickXmlListModel invalid source test timed out"); - } else { - QCOMPARE(spy.count(), 1); spy.clear(); - } - - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), status); - QCOMPARE(model->rowCount(), count); - - if (status == QQuickXmlListModel::Ready) - QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); - - QCOMPARE(errorString(model).isEmpty(), status == QQuickXmlListModel::Ready); - - delete model; -} - -void tst_qquickxmllistmodel::source_data() -{ - QTest::addColumn<QUrl>("source"); - QTest::addColumn<int>("count"); - QTest::addColumn<QQuickXmlListModel::Status>("status"); - - QTest::newRow("valid") << testFileUrl("model2.xml") << 2 - << QQuickXmlListModel::Ready; - QTest::newRow("invalid") << QUrl("http://blah.blah/blah.xml") << 0 - << QQuickXmlListModel::Error; - - // empty file - QTemporaryFile *temp = new QTemporaryFile(this); - if (temp->open()) - QTest::newRow("empty file") << QUrl::fromLocalFile(temp->fileName()) << 0 - << QQuickXmlListModel::Ready; - temp->close(); -} - -void tst_qquickxmllistmodel::data() -{ - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - - for (int i=0; i<9; i++) { - QModelIndex index = model->index(i, 0); - for (int j=0; j<model->roleNames().count(); j++) { - QCOMPARE(model->data(index, j), QVariant()); - } - } - QTRY_COMPARE(model->rowCount(), 9); - - delete model; -} - -void tst_qquickxmllistmodel::get() -{ - QQmlComponent component(&engine, testFileUrl("get.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - - QVERIFY(model != 0); - - QVERIFY(QMetaObject::invokeMethod(model, "runPreTest")); - QCOMPARE(model->property("preTest").toBool(), true); - - QTRY_COMPARE(model->rowCount(), 9); - - QVERIFY(QMetaObject::invokeMethod(model, "runPostTest")); - QCOMPARE(model->property("postTest").toBool(), true); - - delete model; -} - -void tst_qquickxmllistmodel::reload() -{ - // If no keys are used, the model should be rebuilt from scratch when - // reload() is called. - - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QSignalSpy spyInsert(model, SIGNAL(rowsInserted(QModelIndex,int,int))); - QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); - QSignalSpy spyCount(model, SIGNAL(countChanged())); - //reload multiple times to test the xml query aborting - QMetaObject::invokeMethod(model, "reload"); - QMetaObject::invokeMethod(model, "reload"); - QCoreApplication::processEvents(); - QMetaObject::invokeMethod(model, "reload"); - QMetaObject::invokeMethod(model, "reload"); - QTRY_COMPARE(spyCount.count(), 0); - QTRY_COMPARE(spyInsert.count(), 1); - QTRY_COMPARE(spyRemove.count(), 1); - - QCOMPARE(spyInsert[0][1].toInt(), 0); - QCOMPARE(spyInsert[0][2].toInt(), 8); - - QCOMPARE(spyRemove[0][1].toInt(), 0); - QCOMPARE(spyRemove[0][2].toInt(), 8); - - delete model; -} - -void tst_qquickxmllistmodel::useKeys() -{ - // If using incremental updates through keys, the model should only - // insert & remove some of the items, instead of throwing everything - // away and causing the view to repaint the whole view. - - QFETCH(QString, oldXml); - QFETCH(int, oldCount); - QFETCH(QString, newXml); - QFETCH(QQmlXmlModelData, newData); - QFETCH(QList<QQuickXmlListRange>, insertRanges); - QFETCH(QList<QQuickXmlListRange>, removeRanges); - - QQmlComponent component(&engine, testFileUrl("roleKeys.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - - model->setProperty("xml",oldXml); - QTRY_COMPARE(model->rowCount(), oldCount); - - QSignalSpy spyInsert(model, SIGNAL(rowsInserted(QModelIndex,int,int))); - QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); - QSignalSpy spyCount(model, SIGNAL(countChanged())); - - model->setProperty("xml",newXml); - - if (oldCount != newData.count()) { - QTRY_COMPARE(model->rowCount(), newData.count()); - QCOMPARE(spyCount.count(), 1); - } else { - QTRY_VERIFY(spyInsert.count() > 0 || spyRemove.count() > 0); - QCOMPARE(spyCount.count(), 0); - } - - QList<int> roles = model->roleNames().keys(); - std::sort(roles.begin(), roles.end()); - for (int i=0; i<model->rowCount(); i++) { - QModelIndex index = model->index(i, 0); - for (int j=0; j<roles.count(); j++) - QCOMPARE(model->data(index, roles.at(j)), newData[i][j]); - } - - QCOMPARE(spyInsert.count(), insertRanges.count()); - for (int i=0; i<spyInsert.count(); i++) { - QCOMPARE(spyInsert[i][1].toInt(), insertRanges[i].first); - QCOMPARE(spyInsert[i][2].toInt(), insertRanges[i].first + insertRanges[i].second - 1); - } - - QCOMPARE(spyRemove.count(), removeRanges.count()); - for (int i=0; i<spyRemove.count(); i++) { - QCOMPARE(spyRemove[i][1].toInt(), removeRanges[i].first); - QCOMPARE(spyRemove[i][2].toInt(), removeRanges[i].first + removeRanges[i].second - 1); - } - - delete model; -} - -void tst_qquickxmllistmodel::useKeys_data() -{ - QTest::addColumn<QString>("oldXml"); - QTest::addColumn<int>("oldCount"); - QTest::addColumn<QString>("newXml"); - QTest::addColumn<QQmlXmlModelData>("newData"); - QTest::addColumn<QList<QQuickXmlListRange> >("insertRanges"); - QTest::addColumn<QList<QQuickXmlListRange> >("removeRanges"); - - QQmlXmlModelData modelData; - - QTest::newRow("append 1") - << makeItemXmlAndData("name=A,age=25,sport=Football") << 1 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(1, 1)) - << QList<QQuickXmlListRange>(); - - QTest::newRow("append multiple") - << makeItemXmlAndData("name=A,age=25,sport=Football") << 1 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(1, 2)) - << QList<QQuickXmlListRange>(); - - QTest::newRow("insert in different spots") - << makeItemXmlAndData("name=B,age=35,sport=Athletics") << 1 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(0, 1) << qMakePair(2,2)) - << QList<QQuickXmlListRange>(); - - QTest::newRow("insert in middle") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=D,age=55,sport=Golf") << 2 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(1, 2)) - << QList<QQuickXmlListRange>(); - - QTest::newRow("remove first") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics") << 2 - << makeItemXmlAndData("name=B,age=35,sport=Athletics", &modelData) - << modelData - << QList<QQuickXmlListRange>() - << (QList<QQuickXmlListRange>() << qMakePair(0, 1)); - - QTest::newRow("remove last") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics") << 2 - << makeItemXmlAndData("name=A,age=25,sport=Football", &modelData) - << modelData - << QList<QQuickXmlListRange>() - << (QList<QQuickXmlListRange>() << qMakePair(1, 1)); - - QTest::newRow("remove from multiple spots") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf;name=E,age=65,sport=Fencing") << 5 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=C,age=45,sport=Curling", &modelData) - << modelData - << QList<QQuickXmlListRange>() - << (QList<QQuickXmlListRange>() << qMakePair(1, 1) << qMakePair(3,2)); - - QTest::newRow("remove all") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling") << 3 - << makeItemXmlAndData("", &modelData) - << modelData - << QList<QQuickXmlListRange>() - << (QList<QQuickXmlListRange>() << qMakePair(0, 3)); - - QTest::newRow("replace item") - << makeItemXmlAndData("name=A,age=25,sport=Football") << 1 - << makeItemXmlAndData("name=ZZZ,age=25,sport=Football", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(0, 1)) - << (QList<QQuickXmlListRange>() << qMakePair(0, 1)); - - QTest::newRow("add and remove simultaneously, in different spots") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf") << 4 - << makeItemXmlAndData("name=B,age=35,sport=Athletics;name=E,age=65,sport=Fencing", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(1, 1)) - << (QList<QQuickXmlListRange>() << qMakePair(0, 1) << qMakePair(2,2)); - - QTest::newRow("insert at start, remove at end i.e. rss feed") - << makeItemXmlAndData("name=C,age=45,sport=Curling;name=D,age=55,sport=Golf;name=E,age=65,sport=Fencing") << 3 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(0, 2)) - << (QList<QQuickXmlListRange>() << qMakePair(1, 2)); - - QTest::newRow("remove at start, insert at end") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling") << 3 - << makeItemXmlAndData("name=C,age=45,sport=Curling;name=D,age=55,sport=Golf;name=E,age=65,sport=Fencing", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(1, 2)) - << (QList<QQuickXmlListRange>() << qMakePair(0, 2)); - - QTest::newRow("all data has changed") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35") << 2 - << makeItemXmlAndData("name=C,age=45,sport=Curling;name=D,age=55,sport=Golf", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(0, 2)) - << (QList<QQuickXmlListRange>() << qMakePair(0, 2)); -} - -void tst_qquickxmllistmodel::noKeysValueChanges() -{ - // The 'key' roles are 'name' and 'age', as defined in roleKeys.qml. - // If a 'sport' value is changed, the model should not be reloaded, - // since 'sport' is not marked as a key. - - QQmlComponent component(&engine, testFileUrl("roleKeys.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - - QString xml; - - xml = makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics"); - model->setProperty("xml",xml); - QTRY_COMPARE(model->rowCount(), 2); - - model->setProperty("xml",""); - - QSignalSpy spyInsert(model, SIGNAL(rowsInserted(QModelIndex,int,int))); - QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); - QSignalSpy spyCount(model, SIGNAL(countChanged())); - - xml = makeItemXmlAndData("name=A,age=25,sport=AussieRules;name=B,age=35,sport=Athletics"); - model->setProperty("xml",xml); - - QList<int> roles = model->roleNames().keys(); - std::sort(roles.begin(), roles.end()); - // wait for the new xml data to be set, and verify no signals were emitted - QTRY_VERIFY(model->data(model->index(0, 0), roles.at(2)).toString() != QLatin1String("Football")); - QCOMPARE(model->data(model->index(0, 0), roles.at(2)).toString(), QLatin1String("AussieRules")); - - QCOMPARE(spyInsert.count(), 0); - QCOMPARE(spyRemove.count(), 0); - QCOMPARE(spyCount.count(), 0); - - QCOMPARE(model->rowCount(), 2); - - delete model; -} - -void tst_qquickxmllistmodel::keysChanged() -{ - // If the key roles change, the next time the data is reloaded, it should - // delete all its data and build a clean model (i.e. same behaviour as - // if no keys are set). - - QQmlComponent component(&engine, testFileUrl("roleKeys.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - - QString xml = makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics"); - model->setProperty("xml",xml); - QTRY_COMPARE(model->rowCount(), 2); - - model->setProperty("xml",""); - - QSignalSpy spyInsert(model, SIGNAL(rowsInserted(QModelIndex,int,int))); - QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); - QSignalSpy spyCount(model, SIGNAL(countChanged())); - - QVERIFY(QMetaObject::invokeMethod(model, "disableNameKey")); - model->setProperty("xml",xml); - - QTRY_VERIFY(spyInsert.count() > 0 && spyRemove.count() > 0); - - QCOMPARE(spyInsert.count(), 1); - QCOMPARE(spyInsert[0][1].toInt(), 0); - QCOMPARE(spyInsert[0][2].toInt(), 1); - - QCOMPARE(spyRemove.count(), 1); - QCOMPARE(spyRemove[0][1].toInt(), 0); - QCOMPARE(spyRemove[0][2].toInt(), 1); - - QCOMPARE(spyCount.count(), 0); - - delete model; -} - -void tst_qquickxmllistmodel::threading() -{ - QFETCH(int, xmlDataCount); - - QQmlComponent component(&engine, testFileUrl("roleKeys.qml")); - - QAbstractItemModel *m1 = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(m1 != 0); - QAbstractItemModel *m2 = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(m2 != 0); - QAbstractItemModel *m3 = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(m3 != 0); - - for (int dataCount=0; dataCount<xmlDataCount; dataCount++) { - - QString data1, data2, data3; - for (int i=0; i<dataCount; i++) { - data1 += "name=A" + QString::number(i) + ",age=1" + QString::number(i) + ",sport=Football;"; - data2 += "name=B" + QString::number(i) + ",age=2" + QString::number(i) + ",sport=Athletics;"; - data3 += "name=C" + QString::number(i) + ",age=3" + QString::number(i) + ",sport=Curling;"; - } - - //Set the xml data multiple times with randomized order and mixed with multiple event loops - //to test the xml query reloading/aborting, the result should be stable. - m1->setProperty("xml",makeItemXmlAndData(data1)); - m2->setProperty("xml",makeItemXmlAndData(data2)); - m3->setProperty("xml",makeItemXmlAndData(data3)); - QCoreApplication::processEvents(); - m2->setProperty("xml",makeItemXmlAndData(data2)); - m1->setProperty("xml",makeItemXmlAndData(data1)); - m2->setProperty("xml",makeItemXmlAndData(data2)); - QCoreApplication::processEvents(); - m3->setProperty("xml",makeItemXmlAndData(data3)); - QCoreApplication::processEvents(); - m2->setProperty("xml",makeItemXmlAndData(data2)); - m1->setProperty("xml",makeItemXmlAndData(data1)); - m2->setProperty("xml",makeItemXmlAndData(data2)); - m3->setProperty("xml",makeItemXmlAndData(data3)); - QCoreApplication::processEvents(); - m2->setProperty("xml",makeItemXmlAndData(data2)); - m3->setProperty("xml",makeItemXmlAndData(data3)); - m3->setProperty("xml",makeItemXmlAndData(data3)); - QCoreApplication::processEvents(); - - QTRY_VERIFY(m1->rowCount() == dataCount && m2->rowCount() == dataCount && m3->rowCount() == dataCount); - - for (int i=0; i<dataCount; i++) { - QModelIndex index = m1->index(i, 0); - QList<int> roles = m1->roleNames().keys(); - std::sort(roles.begin(), roles.end()); - QCOMPARE(m1->data(index, roles.at(0)).toString(), QLatin1Char('A') + QString::number(i)); - QCOMPARE(m1->data(index, roles.at(1)).toString(), QLatin1Char('1') + QString::number(i)); - QCOMPARE(m1->data(index, roles.at(2)).toString(), QString("Football")); - - index = m2->index(i, 0); - roles = m2->roleNames().keys(); - std::sort(roles.begin(), roles.end()); - QCOMPARE(m2->data(index, roles.at(0)).toString(), QLatin1Char('B') + QString::number(i)); - QCOMPARE(m2->data(index, roles.at(1)).toString(), QLatin1Char('2') + QString::number(i)); - QCOMPARE(m2->data(index, roles.at(2)).toString(), QString("Athletics")); - - index = m3->index(i, 0); - roles = m3->roleNames().keys(); - std::sort(roles.begin(), roles.end()); - QCOMPARE(m3->data(index, roles.at(0)).toString(), QLatin1Char('C') + QString::number(i)); - QCOMPARE(m3->data(index, roles.at(1)).toString(), QLatin1Char('3') + QString::number(i)); - QCOMPARE(m3->data(index, roles.at(2)).toString(), QString("Curling")); - } - } - - delete m1; - delete m2; - delete m3; -} - -void tst_qquickxmllistmodel::threading_data() -{ - QTest::addColumn<int>("xmlDataCount"); - - QTest::newRow("1") << 1; - QTest::newRow("2") << 2; - QTest::newRow("10") << 10; -} - -void tst_qquickxmllistmodel::propertyChanges() -{ - QQmlComponent component(&engine, testFileUrl("propertychanges.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel*>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QObject *role = model->findChild<QObject*>("role"); - QVERIFY(role); - - QSignalSpy nameSpy(role, SIGNAL(nameChanged())); - QSignalSpy querySpy(role, SIGNAL(queryChanged())); - QSignalSpy isKeySpy(role, SIGNAL(isKeyChanged())); - - role->setProperty("name","size"); - role->setProperty("query","size/string()"); - role->setProperty("isKey",true); - - QCOMPARE(role->property("name").toString(), QString("size")); - QCOMPARE(role->property("query").toString(), QString("size/string()")); - QVERIFY(role->property("isKey").toBool()); - - QCOMPARE(nameSpy.count(),1); - QCOMPARE(querySpy.count(),1); - QCOMPARE(isKeySpy.count(),1); - - role->setProperty("name","size"); - role->setProperty("query","size/string()"); - role->setProperty("isKey",true); - - QCOMPARE(nameSpy.count(),1); - QCOMPARE(querySpy.count(),1); - QCOMPARE(isKeySpy.count(),1); - - QSignalSpy sourceSpy(model, SIGNAL(sourceChanged())); - QSignalSpy xmlSpy(model, SIGNAL(xmlChanged())); - QSignalSpy modelQuerySpy(model, SIGNAL(queryChanged())); - QSignalSpy namespaceDeclarationsSpy(model, SIGNAL(namespaceDeclarationsChanged())); - - model->setProperty("source",QUrl("")); - model->setProperty("xml","<Pets><Pet><name>Polly</name><type>Parrot</type><age>12</age><size>Small</size></Pet></Pets>"); - model->setProperty("query","/Pets"); - model->setProperty("namespaceDeclarations","declare namespace media=\"http://search.yahoo.com/mrss/\";"); - - QCOMPARE(model->property("source").toUrl(), QUrl("")); - QCOMPARE(model->property("xml").toString(), QString("<Pets><Pet><name>Polly</name><type>Parrot</type><age>12</age><size>Small</size></Pet></Pets>")); - QCOMPARE(model->property("query").toString(), QString("/Pets")); - QCOMPARE(model->property("namespaceDeclarations").toString(), QString("declare namespace media=\"http://search.yahoo.com/mrss/\";")); - - QTRY_COMPARE(model->rowCount(), 1); - - QCOMPARE(sourceSpy.count(),1); - QCOMPARE(xmlSpy.count(),1); - QCOMPARE(modelQuerySpy.count(),1); - QCOMPARE(namespaceDeclarationsSpy.count(),1); - - model->setProperty("source",QUrl("")); - model->setProperty("xml","<Pets><Pet><name>Polly</name><type>Parrot</type><age>12</age><size>Small</size></Pet></Pets>"); - model->setProperty("query","/Pets"); - model->setProperty("namespaceDeclarations","declare namespace media=\"http://search.yahoo.com/mrss/\";"); - - QCOMPARE(sourceSpy.count(),1); - QCOMPARE(xmlSpy.count(),1); - QCOMPARE(modelQuerySpy.count(),1); - QCOMPARE(namespaceDeclarationsSpy.count(),1); - - QTRY_COMPARE(model->rowCount(), 1); - delete model; -} - -void tst_qquickxmllistmodel::selectAncestor() -{ - QQmlComponent component(&engine, testFileUrl("groups.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 1); - - QModelIndex index = model->index(0, 0); - QCOMPARE(model->data(index, Qt::UserRole).toInt(), 12); - QCOMPARE(model->data(index, Qt::UserRole+1).toString(), QLatin1String("cats")); -} - -void tst_qquickxmllistmodel::roleCrash() -{ - // don't crash - QQmlComponent component(&engine, testFileUrl("roleCrash.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - delete model; -} - -class SortFilterProxyModel : public QSortFilterProxyModel -{ - Q_OBJECT - Q_PROPERTY(QObject *source READ source WRITE setSource) - -public: - SortFilterProxyModel(QObject *parent = 0) : QSortFilterProxyModel(parent) { sort(0); } - QObject *source() const { return sourceModel(); } - void setSource(QObject *source) { setSourceModel(qobject_cast<QAbstractItemModel *>(source)); } -}; - -void tst_qquickxmllistmodel::proxyCrash() -{ - qmlRegisterType<SortFilterProxyModel>("SortFilterProxyModel", 1, 0, "SortFilterProxyModel"); - - // don't crash - QQmlComponent component(&engine, testFileUrl("proxyCrash.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - delete model; -} - -QTEST_MAIN(tst_qquickxmllistmodel) - -#include "tst_qquickxmllistmodel.moc" diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index 2ff606488c..7257a99d2a 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -25,6 +25,7 @@ qtConfig(opengl(es1|es2)?) { PRIVATETESTS += \ nokeywords \ + propertyrequirements \ qquickanimations \ qquickapplication \ qquickbehaviors \ @@ -40,13 +41,10 @@ PRIVATETESTS += \ qquickstyledtext \ qquickstates \ qquicksystempalette \ - qquicktimeline \ - qquickxmllistmodel + qquicktimeline -# This test requires the xmlpatterns module -!qtHaveModule(xmlpatterns): PRIVATETESTS -= qquickxmllistmodel - -QUICKTESTS = \ +QUICKTESTS += \ + pointerhandlers \ qquickaccessible \ qquickanchors \ qquickanimatedimage \ @@ -65,6 +63,7 @@ QUICKTESTS = \ qquickitem2 \ qquickitemlayer \ qquicklistview \ + qquicktableview \ qquickloader \ qquickmousearea \ qquickmultipointtoucharea \ @@ -91,6 +90,9 @@ QUICKTESTS = \ SUBDIRS += $$PUBLICTESTS +# Following tests are too slow on qemu + software backend +boot2qt: QUICKTESTS -= qquickgridview qquicklistview qquicktableview qquickpositioners + !qtConfig(accessibility):QUICKTESTS -= qquickaccessible qtConfig(private_tests) { diff --git a/tests/auto/quick/rendernode/tst_rendernode.cpp b/tests/auto/quick/rendernode/tst_rendernode.cpp index e0fe2c42fc..0e06ee6f50 100644 --- a/tests/auto/quick/rendernode/tst_rendernode.cpp +++ b/tests/auto/quick/rendernode/tst_rendernode.cpp @@ -120,7 +120,7 @@ private: class MessUpNode : public QSGRenderNode, protected QOpenGLFunctions { public: - MessUpNode() : initialized(false) { } + MessUpNode() {} StateFlags changedStates() const override { @@ -157,7 +157,7 @@ public: glBindFramebuffer(GL_FRAMEBUFFER, fbo); } - bool initialized; + bool initialized = false; }; class MessUpItem : public QQuickItem @@ -213,6 +213,11 @@ void tst_rendernode::renderOrder() { if (QGuiApplication::primaryScreen()->depth() < 24) QSKIP("This test does not work at display depths < 24"); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("RenderOrder.qml"); const qreal scaleFactor = QGuiApplication::primaryScreen()->devicePixelRatio(); @@ -237,6 +242,11 @@ void tst_rendernode::messUpState() { if (QGuiApplication::primaryScreen()->depth() < 24) QSKIP("This test does not work at display depths < 24"); + + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QImage fb = runTest("MessUpState.qml"); int x1 = 0; int x2 = fb.width() / 2; @@ -290,6 +300,10 @@ public: void tst_rendernode::matrix() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + qmlRegisterType<StateRecordingRenderNodeItem>("RenderNode", 1, 0, "StateRecorder"); StateRecordingRenderNode::matrices.clear(); runTest("matrix.qml"); diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp index 2cd3a041c8..063358c795 100644 --- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp +++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp @@ -47,6 +47,9 @@ #include "../../shared/util.h" #include "../shared/visualtestutil.h" +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qpa/qplatformintegration.h> + using namespace QQuickVisualTestUtil; class PerPixelRect : public QQuickItem @@ -113,7 +116,8 @@ private slots: private: bool m_brokenMipmapSupport; - QQuickView *createView(const QString &file, QWindow *parent = 0, int x = -1, int y = -1, int w = -1, int h = -1); + QQuickView *createView(const QString &file, QWindow *parent = nullptr, int x = -1, int y = -1, int w = -1, int h = -1); + bool isRunningOnOpenGL(); }; template <typename T> class ScopedList : public QList<T> { @@ -131,38 +135,40 @@ void tst_SceneGraph::initTestCase() qDebug() << "RenderLoop: " << loop; #if QT_CONFIG(opengl) - QOpenGLContext context; - context.setFormat(loop->sceneGraphContext()->defaultSurfaceFormat()); - context.create(); - QSurfaceFormat format = context.format(); - - QOffscreenSurface surface; - surface.setFormat(format); - surface.create(); - if (!context.makeCurrent(&surface)) - qFatal("Failed to create a GL context..."); - - QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - qDebug() << "R/G/B/A Buffers: " << format.redBufferSize() << format.greenBufferSize() << format.blueBufferSize() << format.alphaBufferSize(); - qDebug() << "Depth Buffer: " << format.depthBufferSize(); - qDebug() << "Stencil Buffer: " << format.stencilBufferSize(); - qDebug() << "Samples: " << format.samples(); - int textureSize; - funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &textureSize); - qDebug() << "Max Texture Size: " << textureSize; - qDebug() << "GL_VENDOR: " << (const char *) funcs->glGetString(GL_VENDOR); - qDebug() << "GL_RENDERER: " << (const char *) funcs->glGetString(GL_RENDERER); - QByteArray version = (const char *) funcs->glGetString(GL_VERSION); - qDebug() << "GL_VERSION: " << version.constData(); - QSet<QByteArray> exts = context.extensions(); - QByteArray all; - foreach (const QByteArray &e, exts) all += ' ' + e; - qDebug() << "GL_EXTENSIONS: " << all.constData(); - - m_brokenMipmapSupport = version.contains("Mesa 10.1") || version.contains("Mesa 9."); - qDebug() << "Broken Mipmap: " << m_brokenMipmapSupport; - - context.doneCurrent(); + if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { + QOpenGLContext context; + context.setFormat(loop->sceneGraphContext()->defaultSurfaceFormat()); + context.create(); + QSurfaceFormat format = context.format(); + + QOffscreenSurface surface; + surface.setFormat(format); + surface.create(); + if (!context.makeCurrent(&surface)) + qFatal("Failed to create a GL context..."); + + QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); + qDebug() << "R/G/B/A Buffers: " << format.redBufferSize() << format.greenBufferSize() << format.blueBufferSize() << format.alphaBufferSize(); + qDebug() << "Depth Buffer: " << format.depthBufferSize(); + qDebug() << "Stencil Buffer: " << format.stencilBufferSize(); + qDebug() << "Samples: " << format.samples(); + int textureSize; + funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &textureSize); + qDebug() << "Max Texture Size: " << textureSize; + qDebug() << "GL_VENDOR: " << (const char *) funcs->glGetString(GL_VENDOR); + qDebug() << "GL_RENDERER: " << (const char *) funcs->glGetString(GL_RENDERER); + QByteArray version = (const char *) funcs->glGetString(GL_VERSION); + qDebug() << "GL_VERSION: " << version.constData(); + QSet<QByteArray> exts = context.extensions(); + QByteArray all; + foreach (const QByteArray &e, exts) all += ' ' + e; + qDebug() << "GL_EXTENSIONS: " << all.constData(); + + m_brokenMipmapSupport = version.contains("Mesa 10.1") || version.contains("Mesa 9."); + qDebug() << "Broken Mipmap: " << m_brokenMipmapSupport; + + context.doneCurrent(); + } #endif } @@ -225,12 +231,16 @@ void tst_SceneGraph::manyWindows_data() #if QT_CONFIG(opengl) struct ShareContextResetter { public: - ~ShareContextResetter() { qt_gl_set_global_share_context(0); } + ~ShareContextResetter() { qt_gl_set_global_share_context(nullptr); } }; #endif void tst_SceneGraph::manyWindows() { + if ((QGuiApplication::platformName() == QLatin1String("offscreen")) + || (QGuiApplication::platformName() == QLatin1String("minimal"))) + QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + QFETCH(QString, file); QFETCH(bool, toplevel); QFETCH(bool, shared); @@ -254,27 +264,30 @@ void tst_SceneGraph::manyWindows() const int COUNT = 4; QImage baseLine; + QString errorMessage; for (int i=0; i<COUNT; ++i) { views << createView(file, parent.data(), (i % 2) * 100, (i / 2) * 100, 100, 100); } for (int i=0; i<COUNT; ++i) { QQuickView *view = views.at(i); - QTest::qWaitForWindowExposed(view); + QVERIFY(QTest::qWaitForWindowExposed(view)); QImage content = view->grabWindow(); if (i == 0) { baseLine = content; QVERIFY(containsSomethingOtherThanWhite(baseLine)); } else { - QVERIFY(compareImages(content, baseLine)); + QVERIFY2(compareImages(content, baseLine, &errorMessage), + qPrintable(errorMessage)); } } // Wipe and recreate one (scope pointer delets it...) delete views.takeLast(); QQuickView *last = createView(file, parent.data(), 100, 100, 100, 100); - QTest::qWaitForWindowExposed(last); + QVERIFY(QTest::qWaitForWindowExposed(last)); views << last; - QVERIFY(compareImages(baseLine, last->grabWindow())); + QVERIFY2(compareImages(baseLine, last->grabWindow(), &errorMessage), + qPrintable(errorMessage)); // Wipe and recreate all qDeleteAll(views); @@ -285,9 +298,10 @@ void tst_SceneGraph::manyWindows() } for (int i=0; i<COUNT; ++i) { QQuickView *view = views.at(i); - QTest::qWaitForWindowExposed(view); + QVERIFY(QTest::qWaitForWindowExposed(view)); QImage content = view->grabWindow(); - QVERIFY(compareImages(content, baseLine)); + QVERIFY2(compareImages(content, baseLine, &errorMessage), + qPrintable(errorMessage)); } } @@ -430,12 +444,8 @@ void tst_SceneGraph::render_data() void tst_SceneGraph::render() { - QQuickView dummy; - dummy.show(); - QTest::qWaitForWindowExposed(&dummy); - if (dummy.rendererInterface()->graphicsApi() != QSGRendererInterface::OpenGL) + if (!isRunningOnOpenGL()) QSKIP("Skipping complex rendering tests due to not running with OpenGL"); - dummy.hide(); QFETCH(QString, file); QFETCH(QList<Sample>, baseStage); @@ -485,6 +495,9 @@ void tst_SceneGraph::render() // current on the other window. void tst_SceneGraph::hideWithOtherContext() { + if (!isRunningOnOpenGL()) + QSKIP("Skipping OpenGL context test due to not running with OpenGL"); + QWindow window; window.setSurfaceType(QWindow::OpenGLSurface); window.resize(100, 100); @@ -500,9 +513,6 @@ void tst_SceneGraph::hideWithOtherContext() view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - if (view.rendererInterface()->graphicsApi() != QSGRendererInterface::OpenGL) - QSKIP("Skipping OpenGL context test due to not running with OpenGL"); - renderingOnMainThread = view.openglContext()->thread() == QGuiApplication::instance()->thread(); // Make the local context current on the local window... @@ -542,13 +552,24 @@ void tst_SceneGraph::createTextureFromImage() QQuickView view; view.show(); - QTest::qWaitForWindowExposed(&view); + QVERIFY(QTest::qWaitForWindowExposed(&view)); QTRY_VERIFY(view.isSceneGraphInitialized()); QScopedPointer<QSGTexture> texture(view.createTextureFromImage(image, (QQuickWindow::CreateTextureOptions) flags)); QCOMPARE(texture->hasAlphaChannel(), expectedAlpha); } +bool tst_SceneGraph::isRunningOnOpenGL() +{ + bool retval = false; + QQuickView dummy; + dummy.show(); + QTest::qWaitForWindowExposed(&dummy); + if (dummy.rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL) + retval = true; + dummy.hide(); + return retval; +} #include "tst_scenegraph.moc" diff --git a/tests/auto/quick/shared/geometrytestutil.cpp b/tests/auto/quick/shared/geometrytestutil.cpp new file mode 100644 index 0000000000..07a755e9a5 --- /dev/null +++ b/tests/auto/quick/shared/geometrytestutil.cpp @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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 "geometrytestutil.h" + +#include <QQuickItem> + +QSizeChangeListener::QSizeChangeListener(QQuickItem *item) : + item(item) +{ + connect(item, &QQuickItem::widthChanged, this, &QSizeChangeListener::onSizeChanged); + connect(item, &QQuickItem::heightChanged, this, &QSizeChangeListener::onSizeChanged); +} + +void QSizeChangeListener::onSizeChanged() +{ + append(QSize(item->width(), item->height())); +} diff --git a/tests/auto/quick/shared/geometrytestutil.h b/tests/auto/quick/shared/geometrytestutil.h new file mode 100644 index 0000000000..2cf19ed7ff --- /dev/null +++ b/tests/auto/quick/shared/geometrytestutil.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE: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$ +** +****************************************************************************/ + +#ifndef QQUICKGEOMETRYTESTUTIL_H +#define QQUICKGEOMETRYTESTUTIL_H + +#include <QObject> +#include <QVector> +#include <QSize> + +QT_FORWARD_DECLARE_CLASS(QQuickItem) + +class QSizeChangeListener : public QObject, public QVector<QSize> +{ + Q_OBJECT +public: + explicit QSizeChangeListener(QQuickItem *item); +private slots: + void onSizeChanged(); +private: + QQuickItem *item; +}; + +#endif // QQUICKGEOMETRYTESTUTIL_H diff --git a/tests/auto/quick/shared/util.pri b/tests/auto/quick/shared/util.pri index bd2d202f1d..359c312328 100644 --- a/tests/auto/quick/shared/util.pri +++ b/tests/auto/quick/shared/util.pri @@ -2,8 +2,10 @@ QT += core-private gui-private qml-private quick-private HEADERS += $$PWD/visualtestutil.h \ + $$PWD/geometrytestutil.h \ $$PWD/viewtestutil.h SOURCES += $$PWD/visualtestutil.cpp \ + $$PWD/geometrytestutil.cpp \ $$PWD/viewtestutil.cpp DEFINES += QT_QMLTEST_DATADIR=\\\"$${_PRO_FILE_PWD_}/data\\\" diff --git a/tests/auto/quick/shared/viewtestutil.cpp b/tests/auto/quick/shared/viewtestutil.cpp index cb2b8be97a..5631ffe047 100644 --- a/tests/auto/quick/shared/viewtestutil.cpp +++ b/tests/auto/quick/shared/viewtestutil.cpp @@ -28,6 +28,7 @@ #include "viewtestutil.h" +#include <QtCore/QRandomGenerator> #include <QtQuick/QQuickView> #include <QtQuick/QQuickView> #include <QtGui/QScreen> @@ -37,6 +38,7 @@ #include <private/qquickwindow_p.h> #include <private/qquickitemview_p_p.h> +QT_BEGIN_NAMESPACE QQuickView *QQuickViewTestUtil::createView() { @@ -152,6 +154,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(); @@ -173,7 +181,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 @@ -356,7 +364,6 @@ QQuickViewTestUtil::StressTestModel::StressTestModel() t->setInterval(500); t->start(); - qsrand(qHash(QDateTime::currentDateTime())); connect(t, &QTimer::timeout, this, &StressTestModel::updateModel); } @@ -374,7 +381,7 @@ void QQuickViewTestUtil::StressTestModel::updateModel() { if (m_rowCount > 10) { for (int i = 0; i < 10; ++i) { - int rnum = qrand() % m_rowCount; + int rnum = QRandomGenerator::global()->bounded(m_rowCount); beginRemoveRows(QModelIndex(), rnum, rnum); m_rowCount--; endRemoveRows(); @@ -382,7 +389,7 @@ void QQuickViewTestUtil::StressTestModel::updateModel() } if (m_rowCount < 20) { for (int i = 0; i < 10; ++i) { - int rnum = qrand() % m_rowCount; + int rnum = QRandomGenerator::global()->bounded(m_rowCount); beginInsertRows(QModelIndex(), rnum, rnum); m_rowCount++; endInsertRows(); @@ -398,7 +405,7 @@ bool QQuickViewTestUtil::testVisibleItems(const QQuickItemViewPrivate *priv, boo for (int i = 0; i < priv->visibleItems.count(); ++i) { FxViewItem *item = priv->visibleItems.at(i); if (!item) { - *failItem = Q_NULLPTR; + *failItem = nullptr; return false; } #if 0 @@ -445,3 +452,32 @@ namespace QQuickTouchUtils { } } + +namespace QQuickTest { + // Initialize view, set Url, center in available geometry, move mouse away if desired + bool initView(QQuickView &v, const QUrl &url, bool moveMouseOut, QByteArray *errorMessage) + { + v.setBaseSize(QSize(240,320)); + v.setSource(url); + while (v.status() == QQuickView::Loading) + QTest::qWait(10); + if (v.status() != QQuickView::Ready) { + foreach (const QQmlError &e, v.errors()) + errorMessage->append(e.toString().toLocal8Bit() + '\n'); + return false; + } + const QRect screenGeometry = v.screen()->availableGeometry(); + const QSize size = v.size(); + const QPoint offset = QPoint(size.width() / 2, size.height() / 2); + v.setFramePosition(screenGeometry.center() - offset); + #if QT_CONFIG(cursor) // Get the cursor out of the way. + if (moveMouseOut) + QCursor::setPos(v.geometry().topRight() + QPoint(100, 100)); + #else + Q_UNUSED(moveMouseOut) + #endif + return true; + } +} + +QT_END_NAMESPACE diff --git a/tests/auto/quick/shared/viewtestutil.h b/tests/auto/quick/shared/viewtestutil.h index b11d5e4859..5e725fdf11 100644 --- a/tests/auto/quick/shared/viewtestutil.h +++ b/tests/auto/quick/shared/viewtestutil.h @@ -37,6 +37,8 @@ QT_FORWARD_DECLARE_CLASS(QQuickView) QT_FORWARD_DECLARE_CLASS(QQuickItemViewPrivate) QT_FORWARD_DECLARE_CLASS(FxViewItem) +QT_BEGIN_NAMESPACE + namespace QQuickViewTestUtil { QQuickView *createView(); @@ -76,6 +78,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 +107,8 @@ namespace QQuickViewTestUtil using QAbstractListModel::dataChanged; + int columns = 1; + private: QList<QPair<QString,QString> > list; }; @@ -182,6 +187,12 @@ namespace QQuickTouchUtils { void flush(QQuickWindow *window); } +namespace QQuickTest { + bool initView(QQuickView &v, const QUrl &url, bool moveMouseOut, QByteArray *errorMessage); +} + +QT_END_NAMESPACE + Q_DECLARE_METATYPE(QQuickViewTestUtil::QaimModel*) Q_DECLARE_METATYPE(QQuickViewTestUtil::ListChange) Q_DECLARE_METATYPE(QList<QQuickViewTestUtil::ListChange>) diff --git a/tests/auto/quick/shared/visualtestutil.cpp b/tests/auto/quick/shared/visualtestutil.cpp index eabfe5368b..de2cf2bd5b 100644 --- a/tests/auto/quick/shared/visualtestutil.cpp +++ b/tests/auto/quick/shared/visualtestutil.cpp @@ -66,12 +66,18 @@ void QQuickVisualTestUtil::dumpTree(QQuickItem *parent, int depth) // distance field glyph pixels have a measurable, but not visible // pixel error. This was GT-216 with the ubuntu "nvidia-319" driver package. // llvmpipe does not show the same issue. -bool QQuickVisualTestUtil::compareImages(const QImage &ia, const QImage &ib) + +bool QQuickVisualTestUtil::compareImages(const QImage &ia, const QImage &ib, QString *errorMessage) { - if (ia.size() != ib.size()) - qDebug() << "images are of different size" << ia.size() << ib.size(); - Q_ASSERT(ia.size() == ib.size()); - Q_ASSERT(ia.format() == ib.format()); + if (ia.size() != ib.size()) { + QDebug(errorMessage) << "Images are of different size:" << ia.size() << ib.size() + << "DPR:" << ia.devicePixelRatio() << ib.devicePixelRatio(); + return false; + } + if (ia.format() != ib.format()) { + QDebug(errorMessage) << "Images are of different formats:" << ia.format() << ib.format(); + return false; + } int w = ia.width(); int h = ia.height(); @@ -84,14 +90,14 @@ bool QQuickVisualTestUtil::compareImages(const QImage &ia, const QImage &ib) uint b = bs[x]; // No tolerance for error in the alpha. - if ((a & 0xff000000) != (b & 0xff000000)) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) + if ((a & 0xff000000) != (b & 0xff000000) + || qAbs(qRed(a) - qRed(b)) > tolerance + || qAbs(qRed(a) - qRed(b)) > tolerance + || qAbs(qRed(a) - qRed(b)) > tolerance) { + QDebug(errorMessage) << "Mismatch at:" << x << y << ':' + << hex << showbase << a << b; return false; + } } } return true; diff --git a/tests/auto/quick/shared/visualtestutil.h b/tests/auto/quick/shared/visualtestutil.h index 2daf86cd83..e623e3e225 100644 --- a/tests/auto/quick/shared/visualtestutil.h +++ b/tests/auto/quick/shared/visualtestutil.h @@ -97,10 +97,7 @@ namespace QQuickVisualTestUtil return items; } - bool compareImages(const QImage &ia, const QImage &ib); + bool compareImages(const QImage &ia, const QImage &ib, QString *errorMessage); } -#define QQUICK_VERIFY_POLISH(item) \ - QTRY_COMPARE(QQuickItemPrivate::get(item)->polishScheduled, false) - #endif // QQUICKVISUALTESTUTIL_H diff --git a/tests/auto/quick/sharedimage/tst_sharedimage.cpp b/tests/auto/quick/sharedimage/tst_sharedimage.cpp index b91fc8a0de..afadb76ad0 100644 --- a/tests/auto/quick/sharedimage/tst_sharedimage.cpp +++ b/tests/auto/quick/sharedimage/tst_sharedimage.cpp @@ -90,7 +90,7 @@ void tst_sharedimage::compareToPlainLoad() engine.loadData(i ? sharedScript : plainScript); QVERIFY(engine.rootObjects().size()); QQuickImage *obj = qobject_cast<QQuickImage*>(engine.rootObjects().at(0)); - QVERIFY(obj != 0); + QVERIFY(obj != nullptr); QTRY_VERIFY(!obj->image().isNull()); images[i] = obj->image(); } diff --git a/tests/auto/quick/touchmouse/BLACKLIST b/tests/auto/quick/touchmouse/BLACKLIST new file mode 100644 index 0000000000..b2ba52eca9 --- /dev/null +++ b/tests/auto/quick/touchmouse/BLACKLIST @@ -0,0 +1,2 @@ +[buttonOnDelayedPressFlickable] +windows gcc developer-build diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index 39f2961927..7fccb895db 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -28,8 +28,10 @@ #include <QtTest/QtTest> +#include <QDebug> #include <QtGui/qstylehints.h> +#include <private/qdebug_p.h> #include <QtQuick/qquickview.h> #include <QtQuick/qquickitem.h> @@ -46,6 +48,8 @@ #include "../../shared/util.h" #include "../shared/viewtestutil.h" +Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests") + struct Event { Event(QEvent::Type t, QPoint mouse, QPoint global) @@ -62,6 +66,21 @@ struct Event QList<QTouchEvent::TouchPoint> points; }; +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const struct Event &event) { + QDebugStateSaver saver(dbg); + dbg.nospace(); + dbg << "Event("; + QtDebugUtils::formatQEnum(dbg, event.type); + if (event.points.isEmpty()) + dbg << " @ " << event.mousePos << " global " << event.mousePosGlobal; + else + dbg << ", " << event.points.count() << " touchpoints: " << event.points; + dbg << ')'; + return dbg; +} +#endif + class EventItem : public QQuickItem { Q_OBJECT @@ -70,10 +89,13 @@ Q_SIGNALS: void onTouchEvent(QQuickItem *receiver); public: - EventItem(QQuickItem *parent = 0) - : QQuickItem(parent), touchUngrabCount(0), acceptMouse(false), acceptTouch(false), filterTouch(false), point0(-1) + EventItem(QQuickItem *parent = nullptr) + : QQuickItem(parent) { setAcceptedMouseButtons(Qt::LeftButton); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + setAcceptTouchEvents(true); +#endif } void touchEvent(QTouchEvent *event) @@ -121,10 +143,10 @@ public: } QList<Event> eventList; - int touchUngrabCount; - bool acceptMouse; - bool acceptTouch; - bool filterTouch; // when used as event filter + int touchUngrabCount = 0; + bool acceptMouse = false; + bool acceptTouch = false; + bool filterTouch = false; // when used as event filter bool eventFilter(QObject *, QEvent *event) { @@ -143,7 +165,7 @@ public: } return false; } - int point0; + int point0 = -1; }; class tst_TouchMouse : public QQmlDataTest @@ -157,6 +179,7 @@ public: private slots: void initTestCase(); + void simpleTouchEvent_data(); void simpleTouchEvent(); void testEventFilter(); void mouse(); @@ -201,27 +224,34 @@ private: QQuickView *tst_TouchMouse::createView() { - QQuickView *window = new QQuickView(0); + QQuickView *window = new QQuickView(nullptr); return window; } void tst_TouchMouse::initTestCase() { - // This test assumes that we don't get synthesized mouse events from QGuiApplication - qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); - QQmlDataTest::initTestCase(); qmlRegisterType<EventItem>("Qt.test", 1, 0, "EventItem"); } +void tst_TouchMouse::simpleTouchEvent_data() +{ + QTest::addColumn<bool>("synthMouse"); // AA_SynthesizeMouseForUnhandledTouchEvents + QTest::newRow("no synth") << false; + QTest::newRow("synth") << true; +} + void tst_TouchMouse::simpleTouchEvent() { + QFETCH(bool, synthMouse); + qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, synthMouse); + QScopedPointer<QQuickView> window(createView()); window->setSource(testFileUrl("singleitem.qml")); window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); QVERIFY(eventItem1); @@ -232,16 +262,16 @@ void tst_TouchMouse::simpleTouchEvent() QTest::touchEvent(window.data(), device).press(0, p1, window.data()); QQuickTouchUtils::flush(window.data()); // Get a touch and then mouse event offered - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); p1 += QPoint(10, 0); QTest::touchEvent(window.data(), device).move(0, p1, window.data()); QQuickTouchUtils::flush(window.data()); // Not accepted, no updates - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); QTest::touchEvent(window.data(), device).release(0, p1, window.data()); QQuickTouchUtils::flush(window.data()); - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); eventItem1->eventList.clear(); // Accept touch @@ -269,10 +299,11 @@ void tst_TouchMouse::simpleTouchEvent() p1 = QPoint(20, 20); QTest::touchEvent(window.data(), device).press(0, p1, window.data()); QQuickTouchUtils::flush(window.data()); - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); - QCOMPARE(window->mouseGrabberItem(), eventItem1); + if (synthMouse) + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); + QCOMPARE(window->mouseGrabberItem(), synthMouse ? eventItem1 : nullptr); QPoint localPos = eventItem1->mapFromScene(p1).toPoint(); QPoint globalPos = window->mapToGlobal(p1); @@ -280,21 +311,31 @@ void tst_TouchMouse::simpleTouchEvent() QCOMPARE(eventItem1->eventList.at(0).points.at(0).pos().toPoint(), localPos); QCOMPARE(eventItem1->eventList.at(0).points.at(0).scenePos().toPoint(), scenePos); QCOMPARE(eventItem1->eventList.at(0).points.at(0).screenPos().toPoint(), globalPos); - QCOMPARE(eventItem1->eventList.at(1).mousePos, localPos); - QCOMPARE(eventItem1->eventList.at(1).mousePosGlobal, globalPos); + if (synthMouse) { + QCOMPARE(eventItem1->eventList.at(1).mousePos, localPos); + QCOMPARE(eventItem1->eventList.at(1).mousePosGlobal, globalPos); + } p1 += QPoint(10, 0); QTest::touchEvent(window.data(), device).move(0, p1, window.data()); QQuickTouchUtils::flush(window.data()); - QCOMPARE(eventItem1->eventList.size(), 4); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate); - QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 4 : 1); + if (synthMouse) { + QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate); + QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); + } + // else, if there was no synth-mouse and we didn't accept the touch, + // TouchUpdate was not sent to eventItem1 either. QTest::touchEvent(window.data(), device).release(0, p1, window.data()); QQuickTouchUtils::flush(window.data()); - QCOMPARE(eventItem1->eventList.size(), 7); - QCOMPARE(eventItem1->eventList.at(4).type, QEvent::TouchEnd); - QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseButtonRelease); - QCOMPARE(eventItem1->eventList.at(6).type, QEvent::UngrabMouse); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 7 : 1); + if (synthMouse) { + QCOMPARE(eventItem1->eventList.at(4).type, QEvent::TouchEnd); + QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseButtonRelease); + QCOMPARE(eventItem1->eventList.at(6).type, QEvent::UngrabMouse); + } + // else, if there was no synth-mouse and we didn't accept the touch, + // TouchEnd was not sent to eventItem1 either. eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -307,16 +348,17 @@ void tst_TouchMouse::simpleTouchEvent() p1 = QPoint(20, 20); QTest::touchEvent(window.data(), device).press(0, p1, window.data()); QQuickTouchUtils::flush(window.data()); - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); - QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); + if (synthMouse) + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); p1 += QPoint(10, 0); QTest::touchEvent(window.data(), device).move(0, p1, window.data()); QQuickTouchUtils::flush(window.data()); - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); QTest::touchEvent(window.data(), device).release(0, p1, window.data()); QQuickTouchUtils::flush(window.data()); - QCOMPARE(eventItem1->eventList.size(), 2); + QCOMPARE(eventItem1->eventList.size(), synthMouse ? 2 : 1); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -383,7 +425,7 @@ void tst_TouchMouse::mouse() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); QVERIFY(eventItem1); @@ -413,7 +455,7 @@ void tst_TouchMouse::touchOverMouse() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); QVERIFY(eventItem1); @@ -453,7 +495,7 @@ void tst_TouchMouse::mouseOverTouch() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); QVERIFY(eventItem1); @@ -494,7 +536,7 @@ void tst_TouchMouse::buttonOnFlickable() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable"); QVERIFY(flickable); @@ -572,7 +614,7 @@ void tst_TouchMouse::buttonOnFlickable() QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data()); QVERIFY(windowPriv->touchMouseId != -1); auto pointerEvent = windowPriv->pointerEventInstance(QQuickPointerDevice::touchDevices().at(0)); - QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), eventItem1); QCOMPARE(window->mouseGrabberItem(), eventItem1); int dragDelta = -qApp->styleHints()->startDragDistance(); @@ -594,7 +636,7 @@ void tst_TouchMouse::buttonOnFlickable() QCOMPARE(window->mouseGrabberItem(), flickable); QVERIFY(windowPriv->touchMouseId != -1); - QCOMPARE(pointerEvent->point(0)->grabber(), flickable); + QCOMPARE(pointerEvent->point(0)->exclusiveGrabber(), flickable); QVERIFY(flickable->isMovingVertically()); QTest::touchEvent(window.data(), device).release(0, p3, window.data()); @@ -612,7 +654,7 @@ void tst_TouchMouse::touchButtonOnFlickable() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable"); QVERIFY(flickable); @@ -633,7 +675,7 @@ void tst_TouchMouse::touchButtonOnFlickable() QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window.data()); QVERIFY(windowPriv->touchMouseId == -1); auto pointerEvent = windowPriv->pointerEventInstance(QQuickPointerDevice::touchDevices().at(0)); - QCOMPARE(pointerEvent->point(0)->grabber(), eventItem2); + QCOMPARE(pointerEvent->point(0)->grabberItem(), eventItem2); QCOMPARE(window->mouseGrabberItem(), nullptr); int dragDelta = qApp->styleHints()->startDragDistance() * -0.7; @@ -649,12 +691,12 @@ void tst_TouchMouse::touchButtonOnFlickable() QTest::touchEvent(window.data(), device).move(0, p3, window.data()); QQuickTouchUtils::flush(window.data()); + QTRY_COMPARE(eventItem2->touchUngrabCount, 1); QVERIFY(eventItem2->eventList.size() > 2); QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchUpdate); - QCOMPARE(eventItem2->touchUngrabCount, 1); QCOMPARE(window->mouseGrabberItem(), flickable); QVERIFY(windowPriv->touchMouseId != -1); - QCOMPARE(pointerEvent->point(0)->grabber(), flickable); + QCOMPARE(pointerEvent->point(0)->grabberItem(), flickable); QVERIFY(flickable->isMovingVertically()); QTest::touchEvent(window.data(), device).release(0, p3, window.data()); @@ -664,14 +706,18 @@ void tst_TouchMouse::touchButtonOnFlickable() void tst_TouchMouse::buttonOnDelayedPressFlickable_data() { QTest::addColumn<bool>("scrollBeforeDelayIsOver"); + QTest::addColumn<bool>("releaseBeforeDelayIsOver"); // the item should never see the event, // due to the pressDelay which never delivers if we start moving - QTest::newRow("scroll before press delay is over") << true; + QTest::newRow("scroll before press delay is over") << true << false; + + // after release, the item should see the press and release via event replay (QTBUG-61144) + QTest::newRow("release before press delay is over") << false << true; // wait until the "button" sees the press but then // start moving: the button gets a press and cancel event - QTest::newRow("scroll after press delay is over") << false; + QTest::newRow("scroll after press delay is over") << false << false; } void tst_TouchMouse::buttonOnDelayedPressFlickable() @@ -680,6 +726,7 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() // - eventItem1 y: 100, height 100 // - eventItem2 y: 300, height 100 QFETCH(bool, scrollBeforeDelayIsOver); + QFETCH(bool, releaseBeforeDelayIsOver); qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); filteredEventList.clear(); @@ -689,7 +736,7 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable"); QVERIFY(flickable); @@ -718,11 +765,12 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() // touch press QPoint p1 = QPoint(10, 110); + QPoint pEnd = p1; QTest::touchEvent(window.data(), device).press(0, p1, window.data()); QQuickTouchUtils::flush(window.data()); - if (scrollBeforeDelayIsOver) { - // no events, the flickable got scrolled, the button sees nothing + if (scrollBeforeDelayIsOver || releaseBeforeDelayIsOver) { + // no events yet: press is delayed QCOMPARE(eventItem1->eventList.size(), 0); } else { // wait until the button sees the press @@ -731,45 +779,64 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() QCOMPARE(filteredEventList.count(), 1); } - p1 += QPoint(0, -10); - QPoint p2 = p1 + QPoint(0, -10); - QPoint p3 = p2 + QPoint(0, -10); - QQuickTouchUtils::flush(window.data()); - QTest::touchEvent(window.data(), device).move(0, p1, window.data()); - QQuickTouchUtils::flush(window.data()); - QTest::touchEvent(window.data(), device).move(0, p2, window.data()); - QQuickTouchUtils::flush(window.data()); - QTest::touchEvent(window.data(), device).move(0, p3, window.data()); - QQuickTouchUtils::flush(window.data()); - QTRY_VERIFY(flickable->isMovingVertically()); + if (!releaseBeforeDelayIsOver) { + // move the touchpoint: try to flick + p1 += QPoint(0, -10); + QPoint p2 = p1 + QPoint(0, -10); + pEnd = p2 + QPoint(0, -10); + QQuickTouchUtils::flush(window.data()); + QTest::touchEvent(window.data(), device).move(0, p1, window.data()); + QQuickTouchUtils::flush(window.data()); + QTest::touchEvent(window.data(), device).move(0, p2, window.data()); + QQuickTouchUtils::flush(window.data()); + QTest::touchEvent(window.data(), device).move(0, pEnd, window.data()); + QQuickTouchUtils::flush(window.data()); + QTRY_VERIFY(flickable->isMovingVertically()); + + if (scrollBeforeDelayIsOver) { + QCOMPARE(eventItem1->eventList.size(), 0); + QCOMPARE(filteredEventList.count(), 0); + } else { + // see at least press, move and ungrab + QTRY_VERIFY(eventItem1->eventList.size() > 2); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); + QCOMPARE(eventItem1->eventList.last().type, QEvent::UngrabMouse); + QCOMPARE(filteredEventList.count(), 1); + } - if (scrollBeforeDelayIsOver) { - QCOMPARE(eventItem1->eventList.size(), 0); - QCOMPARE(filteredEventList.count(), 0); - } else { - // see at least press, move and ungrab - QTRY_VERIFY(eventItem1->eventList.size() > 2); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); - QCOMPARE(eventItem1->eventList.last().type, QEvent::UngrabMouse); - QCOMPARE(filteredEventList.count(), 1); + // flickable should have the mouse grab, and have moved the itemForTouchPointId + // for the touchMouseId to the new grabber. + QCOMPARE(window->mouseGrabberItem(), flickable); + QVERIFY(windowPriv->touchMouseId != -1); + auto pointerEvent = windowPriv->pointerEventInstance(QQuickPointerDevice::touchDevices().at(0)); + QCOMPARE(pointerEvent->point(0)->grabberItem(), flickable); } - // flickable should have the mouse grab, and have moved the itemForTouchPointId - // for the touchMouseId to the new grabber. - QCOMPARE(window->mouseGrabberItem(), flickable); - QVERIFY(windowPriv->touchMouseId != -1); - auto pointerEvent = windowPriv->pointerEventInstance(QQuickPointerDevice::touchDevices().at(0)); - QCOMPARE(pointerEvent->point(0)->grabber(), flickable); - - QTest::touchEvent(window.data(), device).release(0, p3, window.data()); + QTest::touchEvent(window.data(), device).release(0, pEnd, window.data()); QQuickTouchUtils::flush(window.data()); - // We should not have received any synthesised mouse events from Qt gui, - // just the delayed press. - if (scrollBeforeDelayIsOver) - QCOMPARE(filteredEventList.count(), 0); - else - QCOMPARE(filteredEventList.count(), 1); + if (releaseBeforeDelayIsOver) { + // when the touchpoint was released, the child saw the delayed press and the release in sequence + qCDebug(lcTests) << "expected delivered events: press, release, ungrab" << eventItem1->eventList; + qCDebug(lcTests) << "expected filtered events: delayed press, release" << filteredEventList; + QTRY_COMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); + QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonRelease); + QCOMPARE(eventItem1->eventList.last().type, QEvent::UngrabMouse); + // QQuickWindow filters the delayed press and release + QCOMPARE(filteredEventList.count(), 2); + QCOMPARE(filteredEventList.at(0).type, QEvent::MouseButtonPress); + QCOMPARE(filteredEventList.at(1).type, QEvent::MouseButtonRelease); + } else { + // QQuickWindow filters the delayed press if there was one; otherwise nothing + if (scrollBeforeDelayIsOver) { + QCOMPARE(filteredEventList.count(), 0); + } else { + qCDebug(lcTests) << "expected filtered event: delayed press" << filteredEventList; + QCOMPARE(filteredEventList.count(), 1); + QCOMPARE(filteredEventList.at(0).type, QEvent::MouseButtonPress); + } + } } void tst_TouchMouse::buttonOnTouch() @@ -787,7 +854,7 @@ void tst_TouchMouse::buttonOnTouch() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); QVERIFY(pinchArea); @@ -805,6 +872,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); @@ -816,9 +884,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); @@ -829,7 +897,7 @@ void tst_TouchMouse::buttonOnTouch() eventItem1->eventList.clear(); // Normal mouse click - QTest::mouseClick(window.data(), Qt::LeftButton, 0, p1); + QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, p1); QCOMPARE(eventItem1->eventList.size(), 3); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonRelease); @@ -841,9 +909,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); @@ -851,24 +919,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); @@ -882,7 +950,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); @@ -892,24 +960,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(); @@ -923,7 +991,7 @@ void tst_TouchMouse::pinchOnFlickable() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); QVERIFY(pinchArea); @@ -1004,7 +1072,7 @@ void tst_TouchMouse::flickableOnPinch() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickPinchArea *pinchArea = window->rootObject()->findChild<QQuickPinchArea*>("pincharea"); QVERIFY(pinchArea); @@ -1083,7 +1151,7 @@ void tst_TouchMouse::mouseOnFlickableOnPinch() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QRect windowRect = QRect(window->position(), window->size()); QCursor::setPos(windowRect.center()); @@ -1216,7 +1284,7 @@ void tst_TouchMouse::tapOnDismissiveTopMouseAreaClicksBottomOne() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); QQuickMouseArea *bottomMouseArea = window->rootObject()->findChild<QQuickMouseArea*>("rear mouseArea"); @@ -1256,7 +1324,7 @@ void tst_TouchMouse::touchGrabCausesMouseUngrab() window->show(); QQuickViewTestUtil::centerOnScreen(window.data()); QVERIFY(QTest::qWaitForWindowActive(window.data())); - QVERIFY(window->rootObject() != 0); + QVERIFY(window->rootObject() != nullptr); EventItem *leftItem = window->rootObject()->findChild<EventItem*>("leftItem"); QVERIFY(leftItem); @@ -1290,7 +1358,7 @@ void tst_TouchMouse::touchGrabCausesMouseUngrab() // has been grabbed by another item. QCOMPARE(leftItem->eventList.size(), 1); QCOMPARE(leftItem->eventList.at(0).type, QEvent::UngrabMouse); - QCOMPARE(window->mouseGrabberItem(), (QQuickItem*)0); + QCOMPARE(window->mouseGrabberItem(), (QQuickItem*)nullptr); } void tst_TouchMouse::touchPointDeliveryOrder() @@ -1315,6 +1383,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"); @@ -1330,7 +1399,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 @@ -1340,7 +1409,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); @@ -1348,49 +1417,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() @@ -1406,13 +1475,13 @@ void tst_TouchMouse::hoverEnabled() window->show(); QVERIFY(QTest::qWaitForWindowActive(window.data())); QQuickItem *root = window->rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); QQuickMouseArea *mouseArea1 = root->findChild<QQuickMouseArea*>("mouseArea1"); - QVERIFY(mouseArea1 != 0); + QVERIFY(mouseArea1 != nullptr); QQuickMouseArea *mouseArea2 = root->findChild<QQuickMouseArea*>("mouseArea2"); - QVERIFY(mouseArea2 != 0); + QVERIFY(mouseArea2 != nullptr); QSignalSpy enterSpy1(mouseArea1, SIGNAL(entered())); QSignalSpy exitSpy1(mouseArea1, SIGNAL(exited())); @@ -1489,7 +1558,7 @@ void tst_TouchMouse::implicitUngrab() QVERIFY(QTest::qWaitForWindowActive(window.data())); QQuickItem *root = window->rootObject(); - QVERIFY(root != 0); + QVERIFY(root != nullptr); EventItem *eventItem = root->findChild<EventItem*>("eventItem1"); eventItem->acceptMouse = true; QPoint p1(20, 20); |