aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-02-17 01:01:00 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-02-17 10:21:59 +0100
commit3e758800b4daf8fbc870a2ff5d54fce9d4402ce8 (patch)
treeba237b9da1c7dfd08bf13e71c5dbd6b3c2e77633 /tests
parent925a0e499a5dbdb180fd9969a79abf96006ce4fd (diff)
parent55546991e24ca6799709cbe0171b9ab87216c35f (diff)
Merge remote-tracking branch 'origin/5.15' into dev
Conflicts: src/imports/qtqml/plugin.cpp src/qml/qml/qqml.h src/qml/qml/qqmlmetatype.cpp src/qml/qml/qqmlmetatype_p.h src/qml/qml/qqmltypeloader.cpp src/qml/types/qqmlbind.cpp src/quick/items/qquickitemsmodule.cpp tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp Change-Id: I52548938a582cb6510271ed4bc3a9aa0c3c11df6
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qml/debugger/debugger.pro1
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml4
-rw-r--r--tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp10
-rw-r--r--tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml41
-rw-r--r--tests/auto/qml/debugger/qqmldebugtranslationservice/qqmldebugtranslationservice.pro12
-rw-r--r--tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp80
-rw-r--r--tests/auto/qml/qjsvalue/tst_qjsvalue.cpp7
-rw-r--r--tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml106
-rw-r--r--tests/auto/qml/qmlformat/data/Annotations.formatted.qml106
-rw-r--r--tests/auto/qml/qmlformat/data/Annotations.qml76
-rw-r--r--tests/auto/qml/qmlformat/tst_qmlformat.cpp12
-rw-r--r--tests/auto/qml/qqmlconnections/data/underscore.qml14
-rw-r--r--tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp15
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp40
-rw-r--r--tests/auto/qml/qqmlenginecleanup/data/MyItem.qml2
-rw-r--r--tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp13
-rw-r--r--tests/auto/qml/qqmllanguage/data/SimpleItem.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/arrayToContainer.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/inlineComponentWithAlias.qml17
-rw-r--r--tests/auto/qml/qqmllanguage/data/inlineComponentWithId.qml14
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h9
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp60
-rw-r--r--tests/auto/qml/qqmlparser/qqmlparser.pro1
-rw-r--r--tests/auto/qml/qqmlparser/tst_qqmlparser.cpp3
-rw-r--r--tests/auto/qml/qqmlproperty/data/interfaceBinding2.qml27
-rw-r--r--tests/auto/qml/qqmlproperty/interfaces.h161
-rw-r--r--tests/auto/qml/qqmlproperty/qqmlproperty.pro8
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp101
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp60
-rw-r--r--tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml38
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp11
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml31
-rw-r--r--tests/auto/quick/qquicklistview/data/headerSnapToItem.qml67
-rw-r--r--tests/auto/quick/qquicklistview/data/requiredObjectListModel.qml15
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp658
-rw-r--r--tests/auto/quick/qquickloader/data/statusChanged.qml16
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp14
-rw-r--r--tests/auto/quick/qquickmousearea/BLACKLIST4
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp4
-rw-r--r--tests/auto/shared/astdump.pri7
-rw-r--r--tests/auto/shared/qqmljsastdumper.cpp1081
-rw-r--r--tests/auto/shared/qqmljsastdumper.h446
-rw-r--r--tests/manual/pointer/main.qml3
-rw-r--r--tests/manual/pointer/qml.qrc5
-rw-r--r--tests/manual/pointer/resources/cursor-airbrush.pngbin0 -> 823 bytes
-rw-r--r--tests/manual/pointer/resources/cursor-eraser.pngbin0 -> 1454 bytes
-rw-r--r--tests/manual/pointer/resources/cursor-felt-marker.pngbin0 -> 513 bytes
-rw-r--r--tests/manual/pointer/resources/cursor-pencil.pngbin0 -> 1307 bytes
-rw-r--r--tests/manual/pointer/tabletCanvasDrawing.qml242
50 files changed, 3576 insertions, 80 deletions
diff --git a/tests/auto/qml/debugger/debugger.pro b/tests/auto/qml/debugger/debugger.pro
index 5c328fbfcc..890e722aa3 100644
--- a/tests/auto/qml/debugger/debugger.pro
+++ b/tests/auto/qml/debugger/debugger.pro
@@ -4,6 +4,7 @@ SUBDIRS += qqmldebugjsserver
PUBLICTESTS += \
qdebugmessageservice \
+ qqmldebugtranslationservice \
qqmlenginedebugservice \
qqmldebugjs \
qqmlinspector \
diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml b/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml
index deba24cf91..a7231df48b 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml
+++ b/tests/auto/qml/debugger/qqmldebugjs/data/oncompleted.qml
@@ -36,5 +36,9 @@ Item {
}
id: root
property int a: 10
+
+ Item {
+ property int b: 11
+ }
}
diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
index 3f424d16f2..91470e0651 100644
--- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
+++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp
@@ -896,6 +896,16 @@ void tst_QQmlDebugJS::evaluateInContext()
QVERIFY(waitForClientSignal(SIGNAL(result())));
QTRY_COMPARE(responseBody(m_client).value("value").toInt(), 20);
+
+ auto childObjects = object.children;
+ QVERIFY(childObjects.count() > 0); // QQmlComponentAttached is also in there
+ QCOMPARE(childObjects[0].className, QString::fromLatin1("Item"));
+
+ // "b" accessible in context of surrounding (child) object
+ m_client->evaluate(QLatin1String("b"), -1, childObjects[0].debugId);
+ QVERIFY(waitForClientSignal(SIGNAL(result())));
+
+ QTRY_COMPARE(responseBody(m_client).value("value").toInt(), 11);
}
void tst_QQmlDebugJS::getScripts()
diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml
new file mode 100644
index 0000000000..234496577a
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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
+import QtQuick.Controls 2.12
+
+Item {
+ width: 360
+ height: 360
+
+ Text {
+ text: qsTr("hello")
+ width: parent.width / 10
+ elide: Text.ElideRight
+ }
+}
diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/qqmldebugtranslationservice.pro b/tests/auto/qml/debugger/qqmldebugtranslationservice/qqmldebugtranslationservice.pro
new file mode 100644
index 0000000000..32e60e306d
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/qqmldebugtranslationservice.pro
@@ -0,0 +1,12 @@
+CONFIG += testcase
+TARGET = tst_qdebugtranslationservice
+QT += network testlib gui-private core-private qmldebug-private
+macos:CONFIG -= app_bundle
+
+SOURCES += tst_qqmldebugtranslationservice.cpp
+
+include(../shared/debugutil.pri)
+
+TESTDATA = data/*
+
+OTHER_FILES += data/test.qml
diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp b/tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp
new file mode 100644
index 0000000000..01ee805dee
--- /dev/null
+++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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$
+**
+****************************************************************************/
+
+//QQmlDebugTest
+#include <debugutil_p.h>
+#include <qqmldebugprocess_p.h>
+
+#include <private/qqmldebugclient_p.h>
+#include <private/qqmldebugtranslationclient_p.h>
+#include <private/qqmldebugconnection_p.h>
+#include <private/qpacket_p.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtTest/qtest.h>
+
+const char *QMLFILE = "test.qml";
+
+class tst_QQmlDebugTranslationService : public QQmlDebugTest
+{
+ Q_OBJECT
+
+private slots:
+ void pluginConnection();
+
+private:
+ QList<QQmlDebugClient *> createClients() override;
+ QPointer<QQmlDebugTranslationClient> m_client;
+};
+
+QList<QQmlDebugClient *> tst_QQmlDebugTranslationService::createClients()
+{
+ m_client = new QQmlDebugTranslationClient(m_connection);
+
+ QObject::connect(m_client, &QQmlDebugClient::stateChanged, m_client, [this](QQmlDebugClient::State newState) {
+ QCOMPARE(newState, m_client->state());
+ });
+
+ return {m_client};
+}
+
+void tst_QQmlDebugTranslationService::pluginConnection()
+{
+ auto executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml";
+ auto services = "DebugTranslation";
+ auto extraArgs = testFile(QMLFILE);
+ auto block = true;
+
+ auto result = QQmlDebugTest::connectTo(executable, services, extraArgs, block);
+ QCOMPARE(result, ConnectSuccess);
+}
+
+QTEST_MAIN(tst_QQmlDebugTranslationService)
+
+#include "tst_qqmldebugtranslationservice.moc"
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
index d6e85f973f..b561e5f398 100644
--- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
+++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp
@@ -1128,6 +1128,10 @@ void tst_QJSValue::toVariant()
// array
{
+ auto handler = qInstallMessageHandler([](QtMsgType type, const QMessageLogContext &, const QString &) {
+ if (type == QtMsgType::QtWarningMsg)
+ QFAIL("Converting QJSValue to QVariant should not cause error messages");
+ });
QVariantList listIn;
listIn << 123 << "hello";
QJSValue array = eng.toScriptValue(listIn);
@@ -1145,8 +1149,9 @@ void tst_QJSValue::toVariant()
QCOMPARE(array2.property("length").toInt(), array.property("length").toInt());
for (int i = 0; i < array.property("length").toInt(); ++i)
QVERIFY(array2.property(i).strictlyEquals(array.property(i)));
- }
+ qInstallMessageHandler(handler);
+ }
}
void tst_QJSValue::toQObject_nonQObject_data()
diff --git a/tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml b/tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml
new file mode 100644
index 0000000000..a05c2125dc
--- /dev/null
+++ b/tests/auto/qml/qmlformat/data/Annotations.formatted.nosort.qml
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![2]
+import QtQuick 2.0
+//![2]
+import QtCharts 2.0
+
+@Pippo {
+ atg1: 3
+}
+@Annotation2 {
+}
+Item {
+ //![1]
+
+ @AnnotateMore {
+ property int x: 5
+ }
+ @AnnotateALot {
+ }
+
+ property variant othersSlice: 0
+ @Annotate {
+ }
+
+ anchors.fill: parent
+ @SuperComplete {
+ binding: late
+ }
+ Component.onCompleted: {
+ // You can also manipulate slices dynamically, like append a slice or set a slice exploded
+ othersSlice = pieSeries.append("Others", 52);
+ pieSeries.find("Volkswagen").exploded = true;
+ }
+ //![1]
+ ChartView {
+ id: chart
+
+ title: "Top-5 car brand shares in Finland"
+ anchors.fill: parent
+ legend.alignment: Qt.AlignBottom
+ antialiasing: true
+
+ @ExtraAnnotation {
+ signal pippo()
+ }
+ PieSeries {
+ id: pieSeries
+
+ PieSlice {
+ label: "Volkswagen"
+ value: 13.5
+ }
+
+ PieSlice {
+ label: "Toyota"
+ value: 10.9
+ }
+
+ PieSlice {
+ label: "Ford"
+ value: 8.6
+ }
+
+ PieSlice {
+ label: "Skoda"
+ value: 8.2
+ }
+
+ PieSlice {
+ label: "Volvo"
+ value: 6.8
+ }
+
+ }
+
+ }
+
+}
diff --git a/tests/auto/qml/qmlformat/data/Annotations.formatted.qml b/tests/auto/qml/qmlformat/data/Annotations.formatted.qml
new file mode 100644
index 0000000000..a142d4cb74
--- /dev/null
+++ b/tests/auto/qml/qmlformat/data/Annotations.formatted.qml
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![2]
+import QtCharts 2.0
+//![2]
+import QtQuick 2.0
+
+@Pippo {
+ atg1: 3
+}
+@Annotation2 {
+}
+Item {
+ //![1]
+
+ @AnnotateMore {
+ property int x: 5
+ }
+ @AnnotateALot {
+ }
+
+ property variant othersSlice: 0
+ @Annotate {
+ }
+
+ anchors.fill: parent
+ @SuperComplete {
+ binding: late
+ }
+ Component.onCompleted: {
+ // You can also manipulate slices dynamically, like append a slice or set a slice exploded
+ othersSlice = pieSeries.append("Others", 52);
+ pieSeries.find("Volkswagen").exploded = true;
+ }
+ //![1]
+ ChartView {
+ id: chart
+
+ title: "Top-5 car brand shares in Finland"
+ anchors.fill: parent
+ legend.alignment: Qt.AlignBottom
+ antialiasing: true
+
+ @ExtraAnnotation {
+ signal pippo()
+ }
+ PieSeries {
+ id: pieSeries
+
+ PieSlice {
+ label: "Volkswagen"
+ value: 13.5
+ }
+
+ PieSlice {
+ label: "Toyota"
+ value: 10.9
+ }
+
+ PieSlice {
+ label: "Ford"
+ value: 8.6
+ }
+
+ PieSlice {
+ label: "Skoda"
+ value: 8.2
+ }
+
+ PieSlice {
+ label: "Volvo"
+ value: 6.8
+ }
+
+ }
+
+ }
+
+}
diff --git a/tests/auto/qml/qmlformat/data/Annotations.qml b/tests/auto/qml/qmlformat/data/Annotations.qml
new file mode 100644
index 0000000000..2d3d7d2cfd
--- /dev/null
+++ b/tests/auto/qml/qmlformat/data/Annotations.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 or (at your option) 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.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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![2]
+import QtQuick 2.0
+//![2]
+import QtCharts 2.0
+
+@Pippo{ atg1:3 }
+@Annotation2{}
+Item {
+ @Annotate{}
+ anchors.fill: parent
+ @AnnotateMore{
+ property int x: 5
+ }
+ @AnnotateALot{}
+ property variant othersSlice: 0
+
+ //![1]
+ ChartView {
+ id: chart
+ title: "Top-5 car brand shares in Finland"
+ anchors.fill: parent
+ legend.alignment: Qt.AlignBottom
+ antialiasing: true
+
+@ExtraAnnotation{
+ signal pippo
+}
+ PieSeries {
+ id: pieSeries
+ PieSlice { label: "Volkswagen"; value: 13.5 }
+ PieSlice { label: "Toyota"; value: 10.9 }
+ PieSlice { label: "Ford"; value: 8.6 }
+ PieSlice { label: "Skoda"; value: 8.2 }
+ PieSlice { label: "Volvo"; value: 6.8 }
+ }
+ }
+
+@SuperComplete{
+binding: late
+}
+ Component.onCompleted: {
+ // You can also manipulate slices dynamically, like append a slice or set a slice exploded
+ othersSlice = pieSeries.append("Others", 52.0);
+ pieSeries.find("Volkswagen").exploded = true;
+ }
+ //![1]
+}
diff --git a/tests/auto/qml/qmlformat/tst_qmlformat.cpp b/tests/auto/qml/qmlformat/tst_qmlformat.cpp
index c7714304b8..21d5ae46a9 100644
--- a/tests/auto/qml/qmlformat/tst_qmlformat.cpp
+++ b/tests/auto/qml/qmlformat/tst_qmlformat.cpp
@@ -41,6 +41,8 @@ private Q_SLOTS:
void testFormat();
void testFormatNoSort();
+ void testAnnotations();
+ void testAnnotationsNoSort();
void testReadOnlyProps();
void testStatesAndTransitions();
@@ -185,6 +187,16 @@ void TestQmlformat::testFormatNoSort()
QCOMPARE(runQmlformat(testFile("Example1.qml"), false, true), readTestFile("Example1.formatted.nosort.qml"));
}
+void TestQmlformat::testAnnotations()
+{
+ QCOMPARE(runQmlformat(testFile("Annotations.qml"), true, true), readTestFile("Annotations.formatted.qml"));
+}
+
+void TestQmlformat::testAnnotationsNoSort()
+{
+ QCOMPARE(runQmlformat(testFile("Annotations.qml"), false, true), readTestFile("Annotations.formatted.nosort.qml"));
+}
+
void TestQmlformat::testReadOnlyProps()
{
QCOMPARE(runQmlformat(testFile("readOnlyProps.qml"), false, true), readTestFile("readOnlyProps.formatted.qml"));
diff --git a/tests/auto/qml/qqmlconnections/data/underscore.qml b/tests/auto/qml/qqmlconnections/data/underscore.qml
new file mode 100644
index 0000000000..0f73dc8f17
--- /dev/null
+++ b/tests/auto/qml/qqmlconnections/data/underscore.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.12
+
+Item {
+ id: item
+ property bool success: false
+ property bool sanityCheck: false
+ property int __underscore_property: 0
+ on__Underscore_propertyChanged: item.sanityCheck = true
+
+ Connections {
+ target: item
+ on__Underscore_propertyChanged: item.success = true
+ }
+}
diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
index 07af519a3d..f144002875 100644
--- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
+++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp
@@ -77,6 +77,8 @@ private slots:
void noAcceleratedGlobalLookup_data() { prefixes(); }
void noAcceleratedGlobalLookup();
+ void bindToPropertyWithUnderscoreChangeHandler();
+
private:
QQmlEngine engine;
void prefixes();
@@ -474,6 +476,19 @@ void tst_qqmlconnections::noAcceleratedGlobalLookup()
QCOMPARE(val.toInt(), int(Proxy::EnumValue));
}
+void tst_qqmlconnections::bindToPropertyWithUnderscoreChangeHandler()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("underscore.qml"));
+ QScopedPointer<QObject> root {component.create()};
+ QVERIFY(root);
+ QQmlProperty underscoreProperty(root.get(), "__underscore_property");
+ QVERIFY(underscoreProperty.isValid());
+ underscoreProperty.write(42);
+ QVERIFY(root->property("sanityCheck").toBool());
+ QVERIFY(root->property("success").toBool());
+}
+
QTEST_MAIN(tst_qqmlconnections)
#include "tst_qqmlconnections.moc"
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml
index 75beafd1ee..c2c8c1b52b 100644
--- a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.write.error.qml
@@ -12,7 +12,7 @@ Item {
function performTest() {
// we have NOT registered QList<QPoint> as a type
- var pointList = [ Qt.point(7,7), Qt.point(8,8), Qt.point(9,9) ];
+ var pointList = [ Qt.point(7,7), "hello world", Qt.point(8,8), Qt.point(9,9) ];
msco.pointListProperty = pointList; // error.
}
}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index a05933d071..61dc393998 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -74,6 +74,7 @@ public:
private slots:
void initTestCase();
+ void arrayIncludesValueType();
void assignBasicTypes();
void assignDate_data();
void assignDate();
@@ -414,6 +415,36 @@ void tst_qqmlecmascript::initTestCase()
registerTypes();
}
+void tst_qqmlecmascript::arrayIncludesValueType()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ // It is vital that QtQuick is imported below else we get a warning about
+ // QQml_colorProvider and tst_qqmlecmascript::signalParameterTypes fails due
+ // to some static variable being initialized with the wrong value
+ component.setData(R"(
+ import QtQuick 2.15
+ import QtQml 2.15
+ QtObject {
+ id: root
+ property color r: Qt.rgba(1, 0, 0)
+ property color g: Qt.rgba(0, 1, 0)
+ property color b: Qt.rgba(0, 0, 1)
+ property var colors: [r, g, b]
+ property bool success: false
+
+ Component.onCompleted: {
+ root.success = root.colors.includes(root.g)
+ }
+ }
+ )", QUrl("testData"));
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o);
+ auto success = o->property("success");
+ QVERIFY(success.isValid());
+ QVERIFY(success.toBool());
+}
+
void tst_qqmlecmascript::assignBasicTypes()
{
QQmlEngine engine;
@@ -5792,13 +5823,12 @@ void tst_qqmlecmascript::sequenceConversionWrite()
MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
QVERIFY(seq != nullptr);
- // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
- QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QJSValue to QVector<QPoint>");
- QTest::ignoreMessage(QtWarningMsg, warningOne.toLatin1().constData());
-
+ // Behavior change in 5.14: due to added auto-magical conversions, it is possible to assign to
+ // QList<QPoint>, even though it is not a registered sequence type
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression("Could not convert array value at position 1 from QString to QPoint"));
QMetaObject::invokeMethod(object, "performTest");
- QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
+ QList<QPoint> pointList; pointList << QPoint(7, 7) << QPoint(0,0) << QPoint(8, 8) << QPoint(9, 9); // original values, shouldn't have changed
QCOMPARE(seq->pointListProperty(), pointList);
delete object;
diff --git a/tests/auto/qml/qqmlenginecleanup/data/MyItem.qml b/tests/auto/qml/qqmlenginecleanup/data/MyItem.qml
new file mode 100644
index 0000000000..4bb8dfb486
--- /dev/null
+++ b/tests/auto/qml/qqmlenginecleanup/data/MyItem.qml
@@ -0,0 +1,2 @@
+import QtQuick 2.12
+Item {}
diff --git a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
index 0e70933ec6..26b2b839ea 100644
--- a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
+++ b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp
@@ -45,6 +45,7 @@ private slots:
void test_qmlClearTypeRegistrations();
void test_valueTypeProviderModule(); // QTBUG-43004
void test_customModuleCleanup();
+ void test_qmlListCleared();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -187,6 +188,18 @@ void tst_qqmlenginecleanup::test_customModuleCleanup()
}
}
+void tst_qqmlenginecleanup::test_qmlListCleared()
+{
+ {
+ QQmlEngine engine;
+ auto url = testFileUrl("MyItem.qml");
+ QQmlComponent comp(&engine, url);
+ QScopedPointer<QObject> item {comp.create()};
+ QCOMPARE(QQmlMetaType::qmlRegisteredListTypeCount(), 1);
+ }
+ QCOMPARE(QQmlMetaType::qmlRegisteredListTypeCount(), 0);
+}
+
QTEST_MAIN(tst_qqmlenginecleanup)
#include "tst_qqmlenginecleanup.moc"
diff --git a/tests/auto/qml/qqmllanguage/data/SimpleItem.qml b/tests/auto/qml/qqmllanguage/data/SimpleItem.qml
new file mode 100644
index 0000000000..c7bce2bc78
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/SimpleItem.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.15
+
+Item {
+ property int i: 42
+}
diff --git a/tests/auto/qml/qqmllanguage/data/arrayToContainer.qml b/tests/auto/qml/qqmllanguage/data/arrayToContainer.qml
new file mode 100644
index 0000000000..ee400eb41f
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/arrayToContainer.qml
@@ -0,0 +1,7 @@
+import QtQml 2.14
+import qt.test 1.0
+
+TestItem {
+ property var vector
+ positions: vector
+}
diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentWithAlias.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentWithAlias.qml
new file mode 100644
index 0000000000..ab125e9323
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/inlineComponentWithAlias.qml
@@ -0,0 +1,17 @@
+import QtQuick 2.15
+
+Item {
+ id: root
+ component IC: SimpleItem {
+ width: i
+ Rectangle {
+ id: rect
+ color: "lime"
+ }
+ property alias color: rect.color
+ }
+ width: 200
+ IC {
+ objectName: "icInstance"
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentWithId.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentWithId.qml
new file mode 100644
index 0000000000..c4093bad2f
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/inlineComponentWithId.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.15
+
+Item {
+ id: root
+ component IC: SimpleItem {
+ id: root
+ width: root.i
+ property color color: "red"
+ }
+ width: 200
+ IC {
+ objectName: "icInstance"
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index 39502372e6..148179cb9c 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -1440,17 +1440,22 @@ public:
int base() const { return 43; }
};
+class Local : public QObject
+{
+ Q_OBJECT
+};
+
class Foreign
{
Q_GADGET
- QML_FOREIGN(QObject)
+ QML_FOREIGN(Local)
QML_NAMED_ELEMENT(Foreign)
};
class ForeignExtended
{
Q_GADGET
- QML_FOREIGN(QObject)
+ QML_FOREIGN(Local)
QML_NAMED_ELEMENT(ForeignExtended)
QML_EXTENDED(Extension)
};
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 1e382d7ee2..d4760fa7e9 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -325,6 +325,9 @@ private slots:
void overrideSingleton();
void revisionedPropertyOfAttachedObjectProperty();
+ void arrayToContainer();
+ void qualifiedScopeInCustomParser();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -5627,6 +5630,9 @@ void tst_qqmllanguage::inlineComponent_data()
QTest::newRow("Non-toplevel IC is found") << testFileUrl("inlineComponentUser5.qml") << QColorConstants::Svg::red << 24;
QTest::newRow("Resolved in correct order") << testFileUrl("inlineComponentOrder.qml") << QColorConstants::Blue << 200;
+
+ QTest::newRow("ID resolves correctly") << testFileUrl("inlineComponentWithId.qml") << QColorConstants::Svg::red << 42;
+ QTest::newRow("Alias resolves correctly") << testFileUrl("inlineComponentWithAlias.qml") << QColorConstants::Svg::lime << 42;
}
void tst_qqmllanguage::inlineComponentReferenceCycle_data()
@@ -5717,6 +5723,60 @@ void tst_qqmllanguage::nonExistingInlineComponent()
QCOMPARE(error.column(), column);
}
+class TestItem : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY( QVector<QPointF> positions MEMBER m_points )
+
+public:
+ TestItem() = default;
+ QVector< QPointF > m_points;
+};
+
+
+Q_DECLARE_METATYPE(QVector<QPointF>);
+void tst_qqmllanguage::arrayToContainer()
+{
+ QQmlEngine engine;
+ qmlRegisterType<TestItem>("qt.test", 1, 0, "TestItem");
+ QVector<QPointF> points { QPointF (2.0, 3.0) };
+ engine.rootContext()->setContextProperty("test", QVariant::fromValue(points));
+ QQmlComponent component(&engine, testFileUrl("arrayToContainer.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<TestItem> root(qobject_cast<TestItem *>(component.createWithInitialProperties( {{"vector", QVariant::fromValue(points)}} )));
+ QVERIFY(root);
+ QCOMPARE(root->m_points.at(0), QPointF (2.0, 3.0) );
+}
+
+class EnumTester : public QObject
+{
+ Q_OBJECT
+public:
+ enum Types
+ {
+ FIRST = 0,
+ SECOND,
+ THIRD
+ };
+ Q_ENUM(Types)
+};
+
+void tst_qqmllanguage::qualifiedScopeInCustomParser()
+{
+ qmlRegisterUncreatableType<EnumTester>("scoped.custom.test", 1, 0, "EnumTester",
+ "Object only creatable in C++");
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQml.Models 2.12\n"
+ "import scoped.custom.test 1.0 as BACKEND\n"
+ "ListModel {\n"
+ " ListElement { text: \"a\"; type: BACKEND.EnumTester.FIRST }\n"
+ "}\n", QUrl());
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmlparser/qqmlparser.pro b/tests/auto/qml/qqmlparser/qqmlparser.pro
index d8e4b0dd06..7f117b3157 100644
--- a/tests/auto/qml/qqmlparser/qqmlparser.pro
+++ b/tests/auto/qml/qqmlparser/qqmlparser.pro
@@ -11,3 +11,4 @@ cross_compile: DEFINES += QTEST_CROSS_COMPILED
TESTDATA = data/*
include (../../shared/util.pri)
+include (../../shared/astdump.pri)
diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
index 981fe7407e..8483bd1f95 100644
--- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
+++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
@@ -33,6 +33,7 @@
#include <private/qqmljsast_p.h>
#include "../../shared/util.h"
+#include "../../shared/qqmljsastdumper.h"
#include <qtest.h>
#include <QDir>
@@ -583,7 +584,7 @@ void tst_qqmlparser::annotations()
Parser parser2(&engine2);
QVERIFY(parser2.parse());
- // to do: compare for equality skipping annotations
+ QCOMPARE(AstDumper::diff(parser.ast(), parser2.rootNode(), 3, DumperOptions::NoAnnotations | DumperOptions::NoLocations), QString());
}
}
diff --git a/tests/auto/qml/qqmlproperty/data/interfaceBinding2.qml b/tests/auto/qml/qqmlproperty/data/interfaceBinding2.qml
new file mode 100644
index 0000000000..e7c5dc7344
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/interfaceBinding2.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.12
+import io.qt.bugreports 2.0
+Item {
+ InterfaceConsumer2 {
+ objectName: "a1"
+ i: A2 {
+ property int i: 42
+ }
+ }
+
+ InterfaceConsumer2 {
+ objectName: "a2"
+ property A2 a: A2 {
+ property int i: 43
+ }
+ i: a
+ }
+
+ InterfaceConsumer2 {
+ objectName: "a3"
+ property A2 a: A2 {
+ id : aa
+ property int i: 44
+ }
+ i: aa
+ }
+}
diff --git a/tests/auto/qml/qqmlproperty/interfaces.h b/tests/auto/qml/qqmlproperty/interfaces.h
new file mode 100644
index 0000000000..2c06c5f594
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/interfaces.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 INTERFACES_H
+#define INTERFACES_H
+
+#include <QtQml/qqml.h>
+
+struct Interface {
+};
+
+QT_BEGIN_NAMESPACE
+#define MyInterface_iid "io.qt.bugreports.Interface"
+Q_DECLARE_INTERFACE(Interface, MyInterface_iid);
+QT_END_NAMESPACE
+
+class A : public QObject, Interface {
+ Q_OBJECT
+ Q_INTERFACES(Interface)
+};
+
+class B : public QObject, Interface {
+ Q_OBJECT
+ Q_INTERFACES(Interface)
+};
+
+class C : public QObject {
+ Q_OBJECT
+};
+
+struct Interface2
+{
+ Q_GADGET
+ QML_INTERFACE
+};
+
+QT_BEGIN_NAMESPACE
+#define MyInterface2_iid "io.qt.bugreports.Interface2"
+Q_DECLARE_INTERFACE(Interface2, MyInterface2_iid);
+QT_END_NAMESPACE
+
+class A2 : public QObject, Interface2 {
+ Q_OBJECT
+ QML_ELEMENT
+ Q_INTERFACES(Interface2)
+};
+
+class B2 : public QObject, Interface2 {
+ Q_OBJECT
+ QML_ELEMENT
+ Q_INTERFACES(Interface2)
+};
+
+class C2 : public QObject {
+ Q_OBJECT
+ QML_ELEMENT
+};
+
+class InterfaceConsumer : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(Interface *i READ interface WRITE setInterface NOTIFY interfaceChanged)
+ Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged)
+
+public:
+
+ Interface* interface() const
+ {
+ return m_interface;
+ }
+ void setInterface(Interface* interface)
+ {
+ QObject* object = reinterpret_cast<QObject*>(interface);
+ m_testValue = object->property("i").toInt();
+ emit testValueChanged();
+ if (m_interface == interface)
+ return;
+
+ m_interface = interface;
+ emit interfaceChanged();
+ }
+
+ int testValue() {
+ return m_testValue;
+ }
+
+signals:
+ void interfaceChanged();
+ void testValueChanged();
+
+private:
+ Interface* m_interface = nullptr;
+ int m_testValue = 0;
+};
+
+
+class InterfaceConsumer2 : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(Interface2 *i READ interface WRITE setInterface NOTIFY interfaceChanged)
+ Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged)
+
+ QML_ELEMENT
+
+public:
+
+ Interface2* interface() const
+ {
+ return m_interface;
+ }
+ void setInterface(Interface2* interface2)
+ {
+ QObject* object = reinterpret_cast<QObject*>(interface2);
+ m_testValue = object->property("i").toInt();
+ emit testValueChanged();
+ if (m_interface == interface2)
+ return;
+
+ m_interface = interface2;
+ emit interfaceChanged();
+ }
+
+ int testValue() {
+ return m_testValue;
+ }
+
+signals:
+ void interfaceChanged();
+ void testValueChanged();
+
+private:
+ Interface2 *m_interface = nullptr;
+ int m_testValue = 0;
+};
+
+#endif // INTERFACES_H
diff --git a/tests/auto/qml/qqmlproperty/qqmlproperty.pro b/tests/auto/qml/qqmlproperty/qqmlproperty.pro
index b1bcf1f17d..4d42975369 100644
--- a/tests/auto/qml/qqmlproperty/qqmlproperty.pro
+++ b/tests/auto/qml/qqmlproperty/qqmlproperty.pro
@@ -1,7 +1,10 @@
-CONFIG += testcase
+CONFIG += testcase qmltypes
TARGET = tst_qqmlproperty
macx:CONFIG -= app_bundle
+QML_IMPORT_NAME = io.qt.bugreports
+QML_IMPORT_VERSION = 2.0
+
SOURCES += tst_qqmlproperty.cpp
include (../../shared/util.pri)
@@ -9,3 +12,6 @@ include (../../shared/util.pri)
TESTDATA = data/*
QT += core-private gui-private qml-private testlib
+
+HEADERS += \
+ interfaces.h
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index 83e173f379..8a96fc52c5 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -25,6 +25,8 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+
+#include "interfaces.h"
#include <qtest.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
@@ -160,6 +162,8 @@ private slots:
void bindingToAlias();
void nestedQQmlPropertyMap();
+
+ void underscorePropertyChangeHandler();
private:
QQmlEngine engine;
};
@@ -2090,74 +2094,20 @@ void tst_qqmlproperty::nullPropertyBinding()
QMetaObject::invokeMethod(root.get(), "tog");
}
-struct Interface {
-};
-
-QT_BEGIN_NAMESPACE
-#define MyInterface_iid "io.qt.bugreports.Interface"
-Q_DECLARE_INTERFACE(Interface, MyInterface_iid);
-QT_END_NAMESPACE
-
-class A : public QObject, Interface {
- Q_OBJECT
- Q_INTERFACES(Interface)
-};
-
-class B : public QObject, Interface {
- Q_OBJECT
- Q_INTERFACES(Interface)
-};
-
-class C : public QObject {
- Q_OBJECT
-};
-
-class InterfaceConsumer : public QObject {
- Q_OBJECT
- Q_PROPERTY(Interface* i READ interface WRITE setInterface NOTIFY interfaceChanged)
- Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged)
-
-
-public:
-
- Interface* interface() const
- {
- return m_interface;
- }
- void setInterface(Interface* interface)
- {
- QObject* object = reinterpret_cast<QObject*>(interface);
- m_testValue = object->property("i").toInt();
- emit testValueChanged();
- if (m_interface == interface)
- return;
-
- m_interface = interface;
- emit interfaceChanged();
- }
-
- int testValue() {
- return m_testValue;
- }
-
-signals:
- void interfaceChanged();
- void testValueChanged();
-
-private:
- Interface* m_interface = nullptr;
- int m_testValue = 0;
-};
void tst_qqmlproperty::interfaceBinding()
{
-
- qmlRegisterInterface<Interface>("Interface");
- qmlRegisterType<A>("io.qt.bugreports", 1, 0, "A");
- qmlRegisterType<B>("io.qt.bugreports", 1, 0, "B");
- qmlRegisterType<C>("io.qt.bugreports", 1, 0, "C");
- qmlRegisterType<InterfaceConsumer>("io.qt.bugreports", 1, 0, "InterfaceConsumer");
-
- const QUrl url = testFileUrl("interfaceBinding.qml");
+ qmlRegisterInterface<Interface>("Interface");
+ qmlRegisterType<A>("io.qt.bugreports", 1, 0, "A");
+ qmlRegisterType<B>("io.qt.bugreports", 1, 0, "B");
+ qmlRegisterType<C>("io.qt.bugreports", 1, 0, "C");
+ qmlRegisterType<InterfaceConsumer>("io.qt.bugreports", 1, 0, "InterfaceConsumer");
+
+ const QVector<QUrl> urls = {
+ testFileUrl("interfaceBinding.qml"),
+ testFileUrl("interfaceBinding2.qml")
+ };
+
+ for (const QUrl &url : urls) {
QQmlEngine engine;
QQmlComponent component(&engine, url);
QScopedPointer<QObject> root(component.create());
@@ -2165,6 +2115,7 @@ void tst_qqmlproperty::interfaceBinding()
QCOMPARE(root->findChild<QObject*>("a1")->property("testValue").toInt(), 42);
QCOMPARE(root->findChild<QObject*>("a2")->property("testValue").toInt(), 43);
QCOMPARE(root->findChild<QObject*>("a3")->property("testValue").toInt(), 44);
+ }
}
void tst_qqmlproperty::floatToStringPrecision_data()
@@ -2241,6 +2192,24 @@ void tst_qqmlproperty::nestedQQmlPropertyMap()
QCOMPARE(success.read().toString(), QLatin1String("success"));
}
+void tst_qqmlproperty::underscorePropertyChangeHandler()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(R"(
+ import QtQuick 2.12
+
+ Item {
+ property int __withUnderScore
+ }
+ )", QUrl::fromLocalFile("."));
+ QScopedPointer<QObject> root { component.create() };
+ QVERIFY(root);
+ QQmlProperty changeHandler(root.get(), "on__WithUnderScoreChanged");
+ QVERIFY(changeHandler.isValid());
+ QVERIFY(changeHandler.isSignalProperty());
+}
+
QTEST_MAIN(tst_qqmlproperty)
#include "tst_qqmlproperty.moc"
diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp
index d0b3bc3d36..ca6463f365 100644
--- a/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp
@@ -55,6 +55,7 @@ private slots:
void initTestCase();
void singleTouch();
+ void tabletStylus();
void simultaneousMultiTouch();
void pressedMultipleButtons_data();
void pressedMultipleButtons();
@@ -136,6 +137,65 @@ void tst_PointHandler::singleTouch()
QCOMPARE(translationSpy.count(), 3);
}
+void tst_PointHandler::tabletStylus()
+{
+ qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents, false);
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "pointTracker.qml");
+ QQuickView * window = windowPtr.data();
+ QQuickPointHandler *handler = window->rootObject()->findChild<QQuickPointHandler *>("pointHandler");
+ QVERIFY(handler);
+ handler->setAcceptedDevices(QQuickPointerDevice::Stylus);
+
+ QSignalSpy activeSpy(handler, SIGNAL(activeChanged()));
+ QSignalSpy pointSpy(handler, SIGNAL(pointChanged()));
+ QSignalSpy translationSpy(handler, SIGNAL(translationChanged()));
+
+ QPoint point(100,100);
+ const qint64 stylusId = 1234567890;
+
+ QWindowSystemInterface::handleTabletEvent(window, point, window->mapToGlobal(point),
+ QTabletEvent::Stylus, QTabletEvent::Pen, Qt::LeftButton, 0.5, 25, 35, 0.6, 12.3, 3, stylusId, Qt::NoModifier);
+ 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::LeftButton);
+ QCOMPARE(handler->point().pressure(), 0.5);
+ QCOMPARE(handler->point().rotation(), 12.3);
+ QCOMPARE(handler->point().uniqueId().numericId(), stylusId);
+ QCOMPARE(handler->translation(), QVector2D());
+ QCOMPARE(translationSpy.count(), 1);
+
+ point += QPoint(10, 10);
+ QWindowSystemInterface::handleTabletEvent(window, point, window->mapToGlobal(point),
+ QTabletEvent::Stylus, QTabletEvent::Pen, Qt::LeftButton, 0.45, 23, 33, 0.57, 15.6, 3.4, stylusId, Qt::NoModifier);
+ QTRY_COMPARE(pointSpy.count(), 2);
+ QCOMPARE(handler->active(), true);
+ QCOMPARE(activeSpy.count(), 1);
+ 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::LeftButton);
+ QCOMPARE(handler->point().pressure(), 0.45);
+ QCOMPARE(handler->point().rotation(), 15.6);
+ QCOMPARE(handler->point().uniqueId().numericId(), stylusId);
+ QVERIFY(handler->point().velocity().x() > 0);
+ QVERIFY(handler->point().velocity().y() > 0);
+ QCOMPARE(handler->translation(), QVector2D(10, 10));
+ QCOMPARE(translationSpy.count(), 2);
+
+ QWindowSystemInterface::handleTabletEvent(window, point, window->mapToGlobal(point),
+ QTabletEvent::Stylus, QTabletEvent::Pen, Qt::NoButton, 0, 0, 0, 0, 0, 0, stylusId, Qt::NoModifier);
+ 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;
diff --git a/tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml b/tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml
new file mode 100644
index 0000000000..6f7bc89793
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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.14
+
+Flickable {
+ id: flickable
+ // Deliberately has no size set.
+
+ Text {
+ text: flickable.visibleArea.xPosition
+ }
+}
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index 5364530ca8..f3659290eb 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -205,6 +205,7 @@ private slots:
void overshoot_reentrant();
void synchronousDrag_data();
void synchronousDrag();
+ void visibleAreaBinding();
private:
void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to);
@@ -2540,6 +2541,16 @@ void tst_qquickflickable::synchronousDrag()
QTest::touchEvent(window, touchDevice).release(0, p5, window);
}
+// QTBUG-81098: tests that a binding to visibleArea doesn't result
+// in a division-by-zero exception (when exceptions are enabled).
+void tst_qquickflickable::visibleAreaBinding()
+{
+ QScopedPointer<QQuickView> window(new QQuickView);
+ window->setSource(testFileUrl("visibleAreaBinding.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+ // Shouldn't crash.
+}
+
QTEST_MAIN(tst_qquickflickable)
#include "tst_qquickflickable.moc"
diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
index 07af6a77ac..0732884c97 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
@@ -1100,5 +1100,36 @@ Item {
waitForRendering(rootRect.layout)
compare(rootRect.item1.width, 100)
}
+
+//---------------------------
+ Component {
+ id: rowlayoutWithTextItems_Component
+ RowLayout {
+ Text {
+ Layout.fillWidth: true
+ text: "OneWord"
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ }
+ Text {
+ Layout.fillWidth: true
+ text: "OneWord"
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ }
+ }
+ }
+
+ // QTBUG-73683
+ function test_rowlayoutWithTextItems() {
+ var layout = createTemporaryObject(rowlayoutWithTextItems_Component, container)
+ waitForRendering(layout)
+ for (var i = 0; i < 3; i++) {
+ ignoreWarning(/Qt Quick Layouts: Detected recursive rearrange. Aborting after two iterations./)
+ }
+ ignoreWarning(/Qt Quick Layouts: Polish loop detected. Aborting after two iterations./)
+ layout.width = layout.width - 2 // set the size to be smaller than its "minimum size"
+ waitForRendering(layout) // do not exit before all warnings have been received
+
+ // DO NOT CRASH due to stack overflow (or loop endlessly due to updatePolish()/polish() loop)
+ }
}
}
diff --git a/tests/auto/quick/qquicklistview/data/headerSnapToItem.qml b/tests/auto/quick/qquicklistview/data/headerSnapToItem.qml
new file mode 100644
index 0000000000..1e5a811630
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/headerSnapToItem.qml
@@ -0,0 +1,67 @@
+import QtQuick 2.12
+
+Rectangle {
+
+ width: 240
+ height: 320
+ color: "#ffffff"
+
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ width: list.orientation == ListView.Vertical ? 240 : 20
+ height: list.orientation == ListView.Vertical ? 20 : 240
+ border.width: 1
+ border.color: "black"
+ Text {
+ text: index + ":" + (list.orientation == ListView.Vertical ? parent.y : parent.x).toFixed(0)
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+
+ ListView {
+ id: list
+ objectName: "list"
+ focus: true
+ width: 240
+ height: 200
+ clip: true
+ snapMode: ListView.SnapToItem
+ headerPositioning: ListView.OverlayHeader
+ model: 30
+ delegate: myDelegate
+ orientation: ListView.Vertical
+ verticalLayoutDirection: ListView.BottomToTop
+
+ header: Rectangle {
+ width: list.orientation == Qt.Vertical ? 240 : 30
+ height: list.orientation == Qt.Vertical ? 30 : 240
+ objectName: "header";
+ color: "green"
+ z: 11
+ Text {
+ anchors.centerIn: parent
+ text: "header " + (list.orientation == ListView.Vertical ? parent.y : parent.x).toFixed(1)
+ }
+ }
+ }
+
+ Rectangle {
+ color: "red"
+ opacity: 0.5
+ width: txt.implicitWidth + 50
+ height: txt.implicitHeight
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+
+ Text {
+ id: txt
+ anchors.centerIn: parent
+ text: "header position: " + (list.orientation == ListView.Vertical ? list.headerItem.y : list.headerItem.x).toFixed(1)
+ + "\ncontent position: " + (list.orientation == ListView.Vertical ? list.contentY : list.contentX).toFixed(1)
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/data/requiredObjectListModel.qml b/tests/auto/quick/qquicklistview/data/requiredObjectListModel.qml
new file mode 100644
index 0000000000..f6380ed5aa
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/requiredObjectListModel.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+
+ListView {
+ width: 100
+ height: 100
+ required model
+
+ delegate: Rectangle {
+ required color
+ required property string name
+
+ height: 25
+ width: 100
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 9a8dfee9d2..b141e235d5 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -30,6 +30,7 @@
#include <QtCore/QStringListModel>
#include <QtCore/QSortFilterProxyModel>
#include <QtGui/QStandardItemModel>
+#include <QtGui/QStyleHints>
#include <QtQuick/qquickview.h>
#include <QtQuickTest/QtQuickTest>
#include <QtQml/qqmlengine.h>
@@ -40,6 +41,7 @@
#include <QtQuick/private/qquicklistview_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
#include <QtQuick/private/qquicktext_p.h>
+#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQmlModels/private/qqmlobjectmodel_p.h>
#include <QtQmlModels/private/qqmllistmodel_p.h>
#include <QtQmlModels/private/qqmldelegatemodel_p.h>
@@ -185,6 +187,8 @@ private slots:
void creationContext();
void snapToItem_data();
void snapToItem();
+ void headerSnapToItem_data();
+ void headerSnapToItem();
void snapToItemWithSpacing_QTBUG_59852();
void snapOneItemResize_QTBUG_43555();
void snapOneItem_data();
@@ -291,6 +295,8 @@ private slots:
void moveObjectModelItemToAnotherObjectModel();
void changeModelAndDestroyTheOldOne();
+ void requiredObjectListModel();
+
private:
template <class T> void items(const QUrl &source);
template <class T> void changed(const QUrl &source);
@@ -5412,6 +5418,604 @@ void tst_QQuickListView::snapToItemWithSpacing_QTBUG_59852()
releaseView(window);
}
+static void drag_helper(QWindow *window, QPoint *startPos, const QPoint &delta)
+{
+ QPoint pos = *startPos;
+ int dragDistance = delta.manhattanLength();
+ Q_ASSERT(qAbs(delta.x()) >= 1 || qAbs(delta.y()) >= 1);
+
+ const int stepSize = 8;
+ QPoint unitVector(0, 0);
+ if (delta.x())
+ unitVector.setX(qBound(-1, delta.x(), 1));
+ if (delta.y())
+ unitVector.setY(qBound(-1, delta.y(), 1));
+ QPoint dragStepSize = unitVector * stepSize;
+ int nDragSteps = qAbs(dragDistance/stepSize);
+
+ for (int i = 0 ; i < nDragSteps; ++i) {
+ QTest::mouseMove(window, pos);
+ pos += dragStepSize;
+ }
+ // Move to the final position
+ pos = *startPos + delta;
+ QTest::mouseMove(window, pos);
+ *startPos = pos;
+}
+
+static void dragtwice(QWindow *window, QPoint *startPos, const QPoint &delta1, const QPoint &delta2)
+{
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QPoint &pos = *startPos;
+ QPoint unitVector(0, 0);
+ if (delta1.x())
+ unitVector.setX(qBound(-1, delta1.x(), 1));
+ if (delta1.y())
+ unitVector.setY(qBound(-1, delta1.y(), 1));
+
+ // go just beyond the drag theshold
+ drag_helper(window, &pos, unitVector * (dragThreshold + 1));
+ drag_helper(window, &pos, unitVector);
+
+ // next drag will actually scroll the listview
+ if (delta1.manhattanLength() >= 1)
+ drag_helper(window, &pos, delta1);
+ if (delta2.manhattanLength() >= 1)
+ drag_helper(window, &pos, delta2);
+}
+
+struct MyListView : public QQuickListView{
+ qreal contentPosition() const
+ {
+ return (orientation() == QQuickListView::Horizontal ? contentX(): contentY());
+ }
+
+ qreal headerPosition() const
+ {
+ return (orientation() == QQuickListView::Horizontal ? headerItem()->x() : headerItem()->y());
+ }
+};
+
+void tst_QQuickListView::headerSnapToItem()
+{
+ QFETCH(QQuickItemView::LayoutDirection, layoutDirection);
+ QFETCH(QQuickListView::HeaderPositioning, headerPositioning);
+ QFETCH(int, firstDragDistance);
+ QFETCH(int, secondDragDistance);
+ QFETCH(int, expectedContentPosition);
+ QFETCH(int, expectedHeaderPosition);
+
+ QQuickView *window = getView();
+ window->setSource(testFileUrl("headerSnapToItem.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ MyListView *listview = static_cast<MyListView *>(findItem<QQuickListView>(window->rootObject(), "list"));
+ QVERIFY(listview != nullptr);
+
+ const bool horizontal = layoutDirection < QQuickItemView::VerticalTopToBottom;
+ listview->setOrientation(horizontal ? QQuickListView::Horizontal : QQuickListView::Vertical);
+
+ if (horizontal)
+ listview->setLayoutDirection(static_cast<Qt::LayoutDirection>(layoutDirection));
+ else
+ listview->setVerticalLayoutDirection(static_cast<QQuickItemView::VerticalLayoutDirection>(layoutDirection));
+
+ listview->setHeaderPositioning(headerPositioning);
+ QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+
+ QQuickItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != nullptr);
+ QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
+ QVERIFY(header != nullptr);
+ QCOMPARE(header, listview->headerItem());
+
+ QPoint startPos = (QPointF(listview->width(), listview->height())/2).toPoint();
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, startPos, 200);
+
+ QPoint firstDragDelta(0, firstDragDistance);
+ QPoint secondDragDelta = QPoint(0, secondDragDistance);
+ if (horizontal) {
+ firstDragDelta = firstDragDelta.transposed();
+ secondDragDelta = secondDragDelta.transposed();
+ }
+
+ dragtwice(window, &startPos, firstDragDelta, secondDragDelta);
+
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, startPos, 200); // Wait 200 ms before we release to avoid trigger a flick
+
+ // wait for the "fixup" animation to finish
+ QTest::qWaitFor([&]()
+ { return !listview->isMoving();}
+ );
+
+ QCOMPARE(listview->contentPosition(), expectedContentPosition);
+ QCOMPARE(listview->headerPosition(), expectedHeaderPosition);
+}
+
+void tst_QQuickListView::headerSnapToItem_data()
+{
+ QTest::addColumn<QQuickItemView::LayoutDirection>("layoutDirection");
+ QTest::addColumn<QQuickListView::HeaderPositioning>("headerPositioning");
+ QTest::addColumn<int>("firstDragDistance");
+ QTest::addColumn<int>("secondDragDistance");
+ QTest::addColumn<int>("expectedContentPosition");
+ QTest::addColumn<int>("expectedHeaderPosition");
+
+ // --------------------
+ // InlineHeader TopToBottom
+ QTest::newRow("InlineHeader TopToBottom -10") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -10 << 0
+ << -30 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -14") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -14 << 0
+ << -30 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -16") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -16 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -30") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -30 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -39") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -39 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -41") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -41 << 0
+ << 20 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -65+10") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -65 << 10
+ << 20 << -30;
+
+ // --------------------
+ // InlineHeader BottomToTop
+ QTest::newRow("InlineHeader BottomToTop +10") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 10 << 0
+ << -170 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +14") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 14 << 0
+ << -170 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +16") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 16 << 0
+ << -200 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +30") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 30 << 0
+ << -200 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +39") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 39 << 0
+ << -200 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +41") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 41 << 0
+ << -220 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +65-10") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 65 << -10
+ << -220 << 0;
+
+ // --------------------
+ // InlineHeader LeftToRight
+ QTest::newRow("InlineHeader LeftToRight -10") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -10 << 0
+ << -30 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -14") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -14 << 0
+ << -30 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -16") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -16 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -30") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -30 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -39") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -39 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -41") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -41 << 0
+ << 20 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -65+10") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -65 << 10
+ << 20 << -30;
+
+ // --------------------
+ // InlineHeader RightToLeft
+ QTest::newRow("InlineHeader RightToLeft +10") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 10 << 0
+ << -210 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +14") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 14 << 0
+ << -210 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +16") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 16 << 0
+ << -240 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +30") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 30 << 0
+ << -240 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +39") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 39 << 0
+ << -240 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +41") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 41 << 0
+ << -260 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +65-10") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 65 << -10
+ << -260 << 0;
+
+ // --------------------
+ // OverlayHeader TopToBottom
+ QTest::newRow("OverlayHeader TopToBottom +9") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::OverlayHeader
+ << 9 << 0
+ << -30 << -30;
+
+ QTest::newRow("OverlayHeader TopToBottom -9") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::OverlayHeader
+ << -9 << 0
+ << -30 << -30;
+
+ QTest::newRow("OverlayHeader TopToBottom -11") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::OverlayHeader
+ << -11 << 0
+ << -10 << -10;
+
+ QTest::newRow("OverlayHeader TopToBottom -29") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::OverlayHeader
+ << -29 << 0
+ << -10 << -10;
+
+ QTest::newRow("OverlayHeader TopToBottom -31") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::OverlayHeader
+ << -31 << 0
+ << 10 << 10;
+
+ // --------------------
+ // OverlayHeader BottomToTop
+ QTest::newRow("OverlayHeader BottomToTop -9") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::OverlayHeader
+ << -9 << 0
+ << -170 << 0;
+
+ QTest::newRow("OverlayHeader BottomToTop +9") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::OverlayHeader
+ << 9 << 0
+ << -170 << 0;
+
+ QTest::newRow("OverlayHeader BottomToTop +11") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::OverlayHeader
+ << 11 << 0
+ << -190 << -20;
+
+ QTest::newRow("OverlayHeader BottomToTop +29") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::OverlayHeader
+ << 29 << 0
+ << -190 << -20;
+
+ QTest::newRow("OverlayHeader BottomToTop +31") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::OverlayHeader
+ << 31 << 0
+ << -210 << -40;
+
+ // --------------------
+ // OverlayHeader LeftToRight
+ QTest::newRow("OverlayHeader LeftToRight +9") << QQuickItemView::LeftToRight
+ << QQuickListView::OverlayHeader
+ << 9 << 0
+ << -30 << -30;
+
+ QTest::newRow("OverlayHeader LeftToRight -9") << QQuickItemView::LeftToRight
+ << QQuickListView::OverlayHeader
+ << -9 << 0
+ << -30 << -30;
+
+ QTest::newRow("OverlayHeader LeftToRight -11") << QQuickItemView::LeftToRight
+ << QQuickListView::OverlayHeader
+ << -11 << 0
+ << -10 << -10;
+
+ QTest::newRow("OverlayHeader LeftToRight -29") << QQuickItemView::LeftToRight
+ << QQuickListView::OverlayHeader
+ << -29 << 0
+ << -10 << -10;
+
+ QTest::newRow("OverlayHeader LeftToRight -31") << QQuickItemView::LeftToRight
+ << QQuickListView::OverlayHeader
+ << -31 << 0
+ << 10 << 10;
+
+ // --------------------
+ // OverlayHeader RightToLeft
+ QTest::newRow("OverlayHeader RightToLeft -9") << QQuickItemView::RightToLeft
+ << QQuickListView::OverlayHeader
+ << -9 << 0
+ << -210 << 0;
+
+ QTest::newRow("OverlayHeader RightToLeft +9") << QQuickItemView::RightToLeft
+ << QQuickListView::OverlayHeader
+ << 9 << 0
+ << -210 << 0;
+
+ QTest::newRow("OverlayHeader RightToLeft +11") << QQuickItemView::RightToLeft
+ << QQuickListView::OverlayHeader
+ << 11 << 0
+ << -230 << -20;
+
+ QTest::newRow("OverlayHeader RightToLeft +29") << QQuickItemView::RightToLeft
+ << QQuickListView::OverlayHeader
+ << 29 << 0
+ << -230 << -20;
+
+ QTest::newRow("OverlayHeader RightToLeft +31") << QQuickItemView::RightToLeft
+ << QQuickListView::OverlayHeader
+ << 31 << 0
+ << -250 << -40;
+
+ // --------------------
+ // PullbackHeader TopToBottom
+ QTest::newRow("PullbackHeader TopToBottom -2") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -2 << 0
+ << -30 << -30;
+
+ QTest::newRow("PullbackHeader TopToBottom -10") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -10 << 0
+ << -30 << -30;
+
+ QTest::newRow("PullbackHeader TopToBottom -11") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -11 << 0
+ << -10 << -10;
+
+ QTest::newRow("PullbackHeader TopToBottom -14") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -14 << 0
+ << -10 << -10;
+
+ QTest::newRow("PullbackHeader TopToBottom -16") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -16 << 0
+ << 0 << -30;
+
+ QTest::newRow("PullbackHeader TopToBottom -20") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -20 << 0
+ << 0 << -30;
+
+ QTest::newRow("PullbackHeader TopToBottom -65+10") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -65 << 10
+ << 20 << -10;
+
+ QTest::newRow("PullbackHeader TopToBottom -65+20") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -65 << 20
+ << 10 << 10;
+
+ // Should move header even if contentY doesn't move (its aligned with top)
+ QTest::newRow("PullbackHeader TopToBottom -55+5") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -55 << 5
+ << 20 << -10;
+
+ // Should move header even if contentY doesn't move (it's aligned with header)
+ QTest::newRow("PullbackHeader TopToBottom -76+16") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -76 << 16
+ << 30 << 30;
+
+ // --------------------
+ // PullbackHeader BottomToTop
+ QTest::newRow("PullbackHeader BottomToTop +2") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +2 << 0
+ << -170 << 0;
+
+ QTest::newRow("PullbackHeader BottomToTop +9") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +9 << 0
+ << -170 << 0;
+
+ QTest::newRow("PullbackHeader BottomToTop +11") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +11 << 0
+ << -190 << -20;
+
+ QTest::newRow("PullbackHeader BottomToTop +14") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +14 << 0
+ << -190 << -20;
+
+ QTest::newRow("PullbackHeader BottomToTop +16") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +16 << 0
+ << -200 << 0;
+
+ QTest::newRow("PullbackHeader BottomToTop +20") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +20 << 0
+ << -200 << 0;
+
+ QTest::newRow("PullbackHeader BottomToTop +65-10") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +65 << -10
+ << -220 << -20;
+
+ QTest::newRow("PullbackHeader BottomToTop +65-20") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +65 << -20
+ << -210 << -40;
+
+ // Should move header even if contentY doesn't move (it's aligned with top)
+ QTest::newRow("PullbackHeader BottomToTop +55-5") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << 55 << -5
+ << -220 << -20;
+
+ // Should move header even if contentY doesn't move (it's aligned with header)
+ QTest::newRow("PullbackHeader BottomToTop +76-16") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << 76 << -16
+ << -230 << -60;
+
+ // --------------------
+ // PullbackHeader LeftToRight
+ QTest::newRow("PullbackHeader LeftToRight -2") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -2 << 0
+ << -30 << -30;
+
+ QTest::newRow("PullbackHeader LeftToRight -10") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -10 << 0
+ << -30 << -30;
+
+ QTest::newRow("PullbackHeader LeftToRight -11") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -11 << 0
+ << -10 << -10;
+
+ QTest::newRow("PullbackHeader LeftToRight -14") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -14 << 0
+ << -10 << -10;
+
+ QTest::newRow("PullbackHeader LeftToRight -16") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -16 << 0
+ << 0 << -30;
+
+ QTest::newRow("PullbackHeader LeftToRight -20") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -20 << 0
+ << 0 << -30;
+
+ QTest::newRow("PullbackHeader LeftToRight -65+10") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -65 << 10
+ << 20 << -10;
+
+ QTest::newRow("PullbackHeader LeftToRight -65+20") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -65 << 20
+ << 10 << 10;
+
+ // Should move header even if contentX doesn't move (its aligned with top)
+ QTest::newRow("PullbackHeader LeftToRight -55+5") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -55 << 5
+ << 20 << -10;
+
+ // Should move header even if contentX doesn't move (it's aligned with header)
+ QTest::newRow("PullbackHeader LeftToRight -76+16") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -76 << 16
+ << 30 << 30;
+
+ // --------------------
+ // PullbackHeader RightToLeft
+ QTest::newRow("PullbackHeader RightToLeft +2") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +2 << 0
+ << -210 << 0;
+
+ QTest::newRow("PullbackHeader RightToLeft +9") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +9 << 0
+ << -210 << 0;
+
+ QTest::newRow("PullbackHeader RightToLeft +11") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +11 << 0
+ << -230 << -20;
+
+ QTest::newRow("PullbackHeader RightToLeft +14") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +14 << 0
+ << -230 << -20;
+
+ QTest::newRow("PullbackHeader RightToLeft +16") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +16 << 0
+ << -240 << 0;
+
+ QTest::newRow("PullbackHeader RightToLeft +20") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +20 << 0
+ << -240 << 0;
+
+ QTest::newRow("PullbackHeader RightToLeft +65-10") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +65 << -10
+ << -260 << -20;
+
+ QTest::newRow("PullbackHeader RightToLeft +65-20") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +65 << -20
+ << -250 << -40;
+
+ // Should move header even if contentX doesn't move (it's aligned with top)
+ QTest::newRow("PullbackHeader RightToLeft +55-5") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << 55 << -5
+ << -260 << -20;
+
+ // Should move header even if contentX doesn't move (it's aligned with header)
+ QTest::newRow("PullbackHeader RightToLeft +76-16") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << 76 << -16
+ << -270 << -60;
+
+}
+
void tst_QQuickListView::snapOneItemResize_QTBUG_43555()
{
QScopedPointer<QQuickView> window(createView());
@@ -9431,6 +10035,60 @@ void tst_QQuickListView::changeModelAndDestroyTheOldOne() // QTBUG-80203
// no crash
}
+class DataObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(QString color READ color CONSTANT)
+
+public:
+ DataObject(QObject *parent = nullptr) : QObject(parent) {}
+ DataObject(const QString &name, const QString &color, QObject *parent = nullptr)
+ : QObject(parent), m_name(name), m_color(color) {}
+
+ QString name() const { return m_name; }
+ QString color() const { return m_color; }
+
+private:
+ QString m_name;
+ QString m_color;
+};
+
+void tst_QQuickListView::requiredObjectListModel()
+{
+ QList<QObject *> dataList = {
+ new DataObject("Item 1", "red", this),
+ new DataObject("Item 2", "green", this),
+ new DataObject("Item 3", "blue", this),
+ new DataObject("Item 4", "yellow", this)
+ };
+
+ const auto deleter = qScopeGuard([&](){ qDeleteAll(dataList); });
+ Q_UNUSED(deleter);
+
+ QQuickView view;
+ view.setInitialProperties({{ "model", QVariant::fromValue(dataList) }});
+ view.setSource(testFileUrl("requiredObjectListModel.qml"));
+ view.show();
+
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ const auto *root = qobject_cast<QQuickListView *>(view.rootObject());
+ QVERIFY(root);
+
+ QCOMPARE(root->count(), dataList.count());
+
+ for (int i = 0, end = dataList.count(); i != end; ++i) {
+ const auto *rect = qobject_cast<QQuickRectangle *>(root->itemAtIndex(i));
+ QVERIFY(rect);
+ const auto *data = qobject_cast<DataObject *>(dataList.at(i));
+ QVERIFY(data);
+
+ QCOMPARE(rect->color(), QColor(data->color()));
+ QCOMPARE(rect->property("name").toString(), data->name());
+ }
+}
+
QTEST_MAIN(tst_QQuickListView)
#include "tst_qquicklistview.moc"
diff --git a/tests/auto/quick/qquickloader/data/statusChanged.qml b/tests/auto/quick/qquickloader/data/statusChanged.qml
new file mode 100644
index 0000000000..fe46bc7b24
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/statusChanged.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.12
+import QtQuick.Window 2.12
+
+Window {
+ id: root
+ property int statusChangedCounter: 0
+ property alias status: loader.status
+ visible: true; width: 640; height: 480
+ Loader {
+ id: loader
+ anchors.fill: parent
+ asynchronous: true
+ source: "./RedRect.qml"
+ onStatusChanged: root.statusChangedCounter++
+ }
+}
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index e05b7ae9ce..91d0bcab2e 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -39,6 +39,7 @@
#include "testhttpserver.h"
#include "../../shared/util.h"
#include "../shared/geometrytestutil.h"
+#include <QQmlApplicationEngine>
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
@@ -128,6 +129,7 @@ private slots:
void rootContext();
void sourceURLKeepComponent();
+ void statusChangeOnlyEmittedOnce();
};
Q_DECLARE_METATYPE(QList<QQmlError>)
@@ -1456,6 +1458,18 @@ void tst_QQuickLoader::sourceURLKeepComponent()
}
+// QTBUG-82002
+void tst_QQuickLoader::statusChangeOnlyEmittedOnce()
+{
+ QQmlApplicationEngine engine;
+ auto url = testFileUrl("statusChanged.qml");
+ engine.load(url);
+ auto root = engine.rootObjects().at(0);
+ QVERIFY(root);
+ QTRY_COMPARE(QQuickLoader::Status(root->property("status").toInt()), QQuickLoader::Ready);
+ QCOMPARE(root->property("statusChangedCounter").toInt(), 2); // 1xLoading + 1xReady*/
+}
+
QTEST_MAIN(tst_QQuickLoader)
#include "tst_qquickloader.moc"
diff --git a/tests/auto/quick/qquickmousearea/BLACKLIST b/tests/auto/quick/qquickmousearea/BLACKLIST
index 6dbe3e11b6..1491116f59 100644
--- a/tests/auto/quick/qquickmousearea/BLACKLIST
+++ b/tests/auto/quick/qquickmousearea/BLACKLIST
@@ -1,2 +1,6 @@
[pressAndHold]
macos ci
+
+# QTBUG-78153
+[nestedStopAtBounds]
+opensuse-leap
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index bf58ce961c..0bf83c267a 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -2860,7 +2860,7 @@ void tst_qquickwindow::pointerEventTypeAndPointCount()
QList<QTouchEvent::TouchPoint>() << QTouchEvent::TouchPoint(1));
- QQuickPointerMouseEvent pme;
+ QQuickPointerMouseEvent pme(nullptr, QQuickPointerDevice::genericMouseDevice());
pme.reset(&me);
QCOMPARE(pme.asMouseEvent(localPosition), &me);
QVERIFY(pme.asPointerMouseEvent());
@@ -2872,7 +2872,7 @@ void tst_qquickwindow::pointerEventTypeAndPointCount()
QCOMPARE(pme.asMouseEvent(localPosition)->localPos(), localPosition);
QCOMPARE(pme.asMouseEvent(localPosition)->screenPos(), screenPosition);
- QQuickPointerTouchEvent pte;
+ QQuickPointerTouchEvent pte(nullptr, QQuickPointerDevice::touchDevice(touchDevice));
pte.reset(&te);
QCOMPARE(pte.asTouchEvent(), &te);
QVERIFY(!pte.asPointerMouseEvent());
diff --git a/tests/auto/shared/astdump.pri b/tests/auto/shared/astdump.pri
new file mode 100644
index 0000000000..365b12fc51
--- /dev/null
+++ b/tests/auto/shared/astdump.pri
@@ -0,0 +1,7 @@
+
+INCLUDEPATH += $$PWD
+HEADERS += \
+ $$PWD/qqmljsastdumper.h
+
+SOURCES += \
+ $$PWD/qqmljsastdumper.cpp
diff --git a/tests/auto/shared/qqmljsastdumper.cpp b/tests/auto/shared/qqmljsastdumper.cpp
new file mode 100644
index 0000000000..bc21d8d4e5
--- /dev/null
+++ b/tests/auto/shared/qqmljsastdumper.cpp
@@ -0,0 +1,1081 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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: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$
+**/
+#include "qqmljsastdumper.h"
+#include <private/qqmljsast_p.h>
+#include <QtCore/QDebug>
+#include <QtCore/QString>
+#include <QtCore/QTextStream>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+using namespace AST;
+/*!
+\internal
+\enum QQmlJS::DumperOptions
+
+This enum type specifies the options for the AstDumper.
+The values can be combined with the '|' operator, and checked using the '&' operator.
+
+\value None
+ Default dumping options
+\value NoLocations
+ Does not dump SourceLocations, allowing one to compare equivalent AST
+ generated by code formatted differently
+\value NoAnnotations
+ Does not dump annotations
+\value DumpNode
+ Does dump a <Node></Node> in preVisit/postVisit
+*/
+
+/*!
+\internal
+\class QQmlJS::AstDumper
+\brief Dumps or compares AST in an xml like format, mostly for testing/debugging
+
+Initialize it with a lambda that dumps a string, and configure it with .setX methods.
+If \l{indent} is set to a non zero value the xml is indented by that amount, and
+\l{baseIndent} is the initial indent.
+If \l{emitNode} is true the node tag is emitted in the preVisit/postVisit.
+If \l{emitLocation} is true the SourceLocations are emitted.
+If \l{emitAnnotations} is true annotations are emitted
+
+The implementation has unnecessary roundtrips to QString, but it is supposed to be used
+for debugging purposes...
+
+Probably you will not use the visitor at all but rather the static method diff or
+the qDebug() and ostream operator << that use the visitor...
+
+\fn AstDumper::diff(AST::Node *n1, AST::Node *n2, int nContext, DumperOptions opt, int indent)
+
+\brief compares the two AST::Node n1 and n2 and returns a string describing their first difference
+
+If there are no differences the empty string is returned, so .isEmpty() can be use to check
+for no differences.
+\l{nContext} decides how much context is printed out.
+
+*/
+
+
+QDebug operator<<(QDebug d, AST::Node *n) {
+ QDebug noQuote = d.noquote().nospace();
+ AstDumper visitor([&noQuote](const QString &s){ noQuote << s; });
+ Node::accept(n, &visitor);
+ return d;
+}
+
+
+std::ostream &operator<<(std::ostream &stream, AST::Node *n) {
+ AstDumper visitor([&stream](const QString &s){ stream << s.toStdString(); });
+ Node::accept(n, &visitor);
+ return stream;
+}
+
+bool operator & (DumperOptions lhs, DumperOptions rhs) {
+ return bool(static_cast<int>(lhs) & static_cast<int>(rhs));
+}
+
+DumperOptions operator | (DumperOptions lhs, DumperOptions rhs) {
+ return DumperOptions(static_cast<int>(lhs) | static_cast<int>(rhs));
+}
+
+QString AstDumper::diff(AST::Node *n1, AST::Node *n2, int nContext, DumperOptions opt, int indent) {
+ QString s1, s2;
+ QTextStream d1(&s1), d2(&s2);
+ AstDumper visitor1=AstDumper([&d1](const QString &s){ d1 << s; }, opt, indent);
+ AstDumper visitor2=AstDumper([&d2](const QString &s){ d2 << s; }, opt, indent);
+ Node::accept(n1, &visitor1);
+ Node::accept(n2, &visitor2);
+ d1.seek(0);
+ d2.seek(0);
+ std::vector<QString> preLines(nContext);
+ int nLine = 0;
+ bool same = true;
+ QString l1, l2;
+ while (same && !d1.atEnd() && !d2.atEnd()) {
+ l1=d1.readLine();
+ l2=d2.readLine();
+ if (l1 == l2)
+ preLines[nLine++ % nContext] = l1;
+ else
+ same = false;
+ }
+ QString res;
+ QTextStream ss(&res);
+ if (!same || !d1.atEnd() || !d2.atEnd()) {
+ for (int iline = qMin(nLine, nContext); iline > 0; --iline) {
+ ss << QLatin1String(" ") << preLines[(nLine - iline) % nContext] << QLatin1String("\n");
+ }
+ int iline = 0;
+ if (!same) {
+ ss << QLatin1String("-") << l1 << QLatin1String("\n");
+ ++iline;
+ }
+ if (same && nContext == 0)
+ nContext = 1;
+ for (;iline < nContext && !d1.atEnd(); iline ++) {
+ l1 = d1.readLine();
+ ss << QLatin1String("-") << l1 << QLatin1String("\n");
+ }
+ iline = 0;
+ if (!same) {
+ ss << QLatin1String("+") << l2 << QLatin1String("\n");
+ ++iline;
+ }
+ for (;iline < nContext && !d2.atEnd(); iline ++) {
+ l2 = d2.readLine();
+ ss << QLatin1String("+") << l2 << QLatin1String("\n");
+ }
+ }
+ return res;
+}
+
+QString AstDumper::printNode(Node *n, DumperOptions opt, int indent, int baseIndent)
+{
+ QString res;
+ QTextStream d(&res);
+ AstDumper visitor=AstDumper([&d](const QString &s){ d << s; }, opt, indent, baseIndent);
+ Node::accept(n, &visitor);
+ return res;
+}
+
+AstDumper::AstDumper(const std::function<void(const QString &)> &dumper, DumperOptions options, int indent, int baseIndent):
+ dumper(dumper), options(options), indent(indent), baseIndent(baseIndent) {}
+
+void AstDumper::start(const QString &str) {
+ dumper(QString::fromLatin1(" ").repeated(baseIndent));
+ dumper(QLatin1String("<"));
+ dumper(str);
+ dumper(QLatin1String(">\n"));
+ baseIndent += indent;
+}
+
+void AstDumper::start(const char *str) {
+ start(QLatin1String(str));
+}
+
+void AstDumper::stop(const QString &str) {
+ baseIndent -= indent;
+ dumper(QString::fromLatin1(" ").repeated(baseIndent));
+ dumper(QLatin1String("</"));
+ dumper(str);
+ dumper(QLatin1String(">\n"));
+}
+
+void AstDumper::stop(const char *str) {
+ stop(QLatin1String(str));
+}
+
+QString AstDumper::qs(const QString &s) {
+ QString res(s);
+ return QLatin1String("\"") + res
+ .replace(QLatin1String("\\"), QLatin1String("\\\\"))
+ .replace(QLatin1String("\""), QLatin1String("\\\"")) + QLatin1String("\"");
+}
+
+QString AstDumper::qs(const char *s) {
+ return qs(QLatin1String(s));
+}
+
+QString AstDumper::qs(const QStringRef &s) {
+ return qs(s.toString());
+}
+
+QString AstDumper::loc(const AST::SourceLocation &s) {
+ if (noLocations() || !s.isValid())
+ return QLatin1String("\"\"");
+ else {
+ return QLatin1String("\"off:%1 len:%2 l:%3 c:%4\"").arg(QString::number(s.offset), QString::number(s.length), QString::number(s.startLine), QString::number(s.startColumn));
+ }
+}
+
+QString AstDumper::boolStr(bool v) { return (v ? qs("true"): qs("false")); }
+
+bool AstDumper::preVisit(Node *) { if (dumpNode()) start("Node"); return true; }
+
+void AstDumper::postVisit(Node *) { if (dumpNode()) stop("Node"); }
+
+bool AstDumper::visit(UiProgram *) { start("UiProgram"); return true; }
+
+bool AstDumper::visit(UiHeaderItemList *) { start("UiHeaderItemList"); return true; }
+
+bool AstDumper::visit(UiPragma *el) {
+ start(QLatin1String("UiPragma name=%1 pragmaToken=%2 semicolonToken=%3")
+ .arg(qs(el->name), loc(el->pragmaToken), loc(el->semicolonToken)));
+ return true;
+}
+
+bool AstDumper::visit(UiImport *el)
+{
+ start(QLatin1String("UiImport fileName=%1 importId=%2 importToken=%3 fileNameToken=%4 asToken=%5 importIdToken=%6 semicolonToken=%7")
+ .arg(qs(el->fileName), qs(el->importId), loc(el->importToken), loc(el->fileNameToken), loc(el->asToken), loc(el->importIdToken), loc(el->semicolonToken)));
+ return true;
+}
+
+bool AstDumper::visit(UiPublicMember *el) {
+ QString typeStr = ((el->type == UiPublicMember::Signal) ? QLatin1String("Signal") :
+ (el->type == UiPublicMember::Property) ? QLatin1String("Property") : QLatin1String("Unexpected(%1)").arg(el->type));
+ start(QLatin1String("UiPublicMember type=%1 typeModifier=%2 name=%3 isDefaultMember=%4 isReadonlyMember=%5 isRequired=%6 "
+ "defaultToken=%7 readonlyToken=%8 propertyToken=%9 requiredToken=%10 typeModifierToken=%11 typeToken=%12 "
+ "identifierToken=%13 colonToken=%14 semicolonToken=%15")
+ .arg(qs(typeStr), qs(el->typeModifier), qs(el->name),
+ el->isDefaultMember, el->isReadonlyMember, el->isRequired,
+ loc(el->defaultToken), loc(el->readonlyToken), loc(el->propertyToken),
+ loc(el->requiredToken), loc(el->typeModifierToken), loc(el->typeToken),
+ loc(el->identifierToken), loc(el->colonToken), loc(el->semicolonToken)
+ ));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ Node::accept(el->memberType, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiSourceElement *el) {
+ start(QLatin1String("UiSourceElement"));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiObjectDefinition *el) {
+ start("UiObjectDefinition");
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiObjectInitializer *el) {
+ start(QLatin1String("UiObjectInitializer lbraceToken=%1 rbraceToken=%2")
+ .arg(loc(el->lbraceToken), loc(el->rbraceToken)));
+ return true;
+}
+
+bool AstDumper::visit(AST::UiObjectBinding *el) {
+ start(QLatin1String("UiObjectBinding colonToken=%1 hasOnToken=%2")
+ .arg(loc(el->colonToken), boolStr(el->hasOnToken)));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiScriptBinding *el) {
+ start(QLatin1String("UiScriptBinding colonToken=%1")
+ .arg(loc(el->colonToken)));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiArrayBinding *el) {
+ start(QLatin1String("UiArrayBinding colonToken=%1 lbracketToken=%2 rbracketToken=%3")
+ .arg(loc(el->colonToken), loc(el->lbracketToken), loc(el->rbracketToken)));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiParameterList *el) {
+ start(QLatin1String("UiArrayBinding name=%1 commaToken=%2 propertyTypeToken=%3 identifierToken=%4 colonToken=%5")
+ .arg(qs(el->name), loc(el->commaToken), loc(el->propertyTypeToken), loc(el->identifierToken), loc(el->colonToken)));
+ Node::accept(el->type, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiObjectMemberList *) { start("UiObjectMemberList"); return true; }
+
+bool AstDumper::visit(AST::UiArrayMemberList *el) {
+ start(QLatin1String("UiArrayMemberList commaToken=%1")
+ .arg(loc(el->commaToken)));
+ return true;
+}
+
+bool AstDumper::visit(AST::UiQualifiedId *el) {
+ start(QLatin1String("UiQualifiedId name=%1 identifierToken=%2")
+ .arg(qs(el->name), loc(el->identifierToken)));
+ Node::accept(el->next, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiEnumDeclaration *el) {
+ start(QLatin1String("UiEnumDeclaration enumToken=%1 rbraceToken=%2 name=%3")
+ .arg(loc(el->enumToken), loc(el->rbraceToken), qs(el->name)));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiEnumMemberList *el) {
+ start(QLatin1String("UiEnumMemberList member=%1 value=%2 memberToken=%3 valueToken=%4")
+ .arg(qs(el->member), qs(QString::number(el->value)), loc(el->memberToken), loc(el->valueToken)));
+ return true;
+}
+
+bool AstDumper::visit(AST::UiVersionSpecifier *el) {
+ start(QLatin1String("UiVersionSpecifier majorVersion=%1 minorVersion=%2 majorToken=%3 minorToken=%4")
+ .arg(qs(QString::number(el->version.majorVersion())),
+ qs(QString::number(el->version.minorVersion())),
+ loc(el->majorToken), loc(el->minorToken)));
+ return true;
+}
+
+bool AstDumper::visit(AST::UiInlineComponent *el) {
+ start(QLatin1String("UiInlineComponent name=%1 componentToken=%2")
+ .arg(qs(el->name), loc(el->componentToken)));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(UiRequired *el)
+{
+ start(QLatin1String("UiRequired name=%1 requiredToken=%2 semicolonToken=%3")
+ .arg(qs(el->name), loc(el->requiredToken), loc(el->semicolonToken)));
+ return true;
+}
+
+bool AstDumper::visit(UiAnnotation *)
+{
+ start(QLatin1String("UiAnnotation"));
+ return true;
+}
+
+bool AstDumper::visit(UiAnnotationList *)
+{
+ start(QLatin1String("UiAnnotationList"));
+ return true;
+}
+
+void AstDumper::endVisit(AST::UiProgram *) { stop("UiProgram"); }
+
+void AstDumper::endVisit(AST::UiImport *el) {
+ Node::accept(el->version, this);
+ stop("UiImport");
+}
+
+void AstDumper::endVisit(AST::UiHeaderItemList *) { stop("UiHeaderItemList"); }
+
+void AstDumper::endVisit(AST::UiPragma *) { stop("UiPragma"); }
+
+void AstDumper::endVisit(AST::UiPublicMember *el) {
+ Node::accept(el->parameters, this);
+ stop("UiPublicMember");
+}
+
+void AstDumper::endVisit(AST::UiSourceElement *) { stop("UiSourceElement"); }
+void AstDumper::endVisit(AST::UiObjectDefinition *) { stop("UiObjectDefinition"); }
+void AstDumper::endVisit(AST::UiObjectInitializer *) { stop("UiObjectInitializer"); }
+void AstDumper::endVisit(AST::UiObjectBinding *) { stop("UiObjectBinding"); }
+void AstDumper::endVisit(AST::UiScriptBinding *) { stop("UiScriptBinding"); }
+void AstDumper::endVisit(AST::UiArrayBinding *) { stop("UiArrayBinding"); }
+void AstDumper::endVisit(AST::UiParameterList *el) {
+ stop("UiParameterList");
+ Node::accept(el->next, this); // put other args at the same level as this one...
+}
+void AstDumper::endVisit(AST::UiObjectMemberList *) { stop("UiObjectMemberList"); }
+void AstDumper::endVisit(AST::UiArrayMemberList *) { stop("UiArrayMemberList"); }
+void AstDumper::endVisit(AST::UiQualifiedId *) { stop("UiQualifiedId"); }
+void AstDumper::endVisit(AST::UiEnumDeclaration *) { stop("UiEnumDeclaration"); }
+void AstDumper::endVisit(AST::UiEnumMemberList *el) {
+ stop("UiEnumMemberList");
+ Node::accept(el->next, this); // put other enum members at the same level as this one...
+}
+void AstDumper::endVisit(AST::UiVersionSpecifier *) { stop("UiVersionSpecifier"); }
+void AstDumper::endVisit(AST::UiInlineComponent *) { stop("UiInlineComponent"); }
+void AstDumper::endVisit(UiRequired *) { stop("UiRequired"); }
+void AstDumper::endVisit(UiAnnotation *) { stop("UiAnnotation"); }
+void AstDumper::endVisit(UiAnnotationList *) { stop("UiAnnotationList"); }
+
+// QQmlJS
+bool AstDumper::visit(AST::ThisExpression *el) {
+ start(QLatin1String("ThisExpression thisToken=%1")
+ .arg(loc(el->thisToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ThisExpression *) { stop("ThisExpression"); }
+
+bool AstDumper::visit(AST::IdentifierExpression *el) {
+ start(QLatin1String("IdentifierExpression name=%1 identiferToken=%2")
+ .arg(qs(el->name), loc(el->identifierToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::IdentifierExpression *) { stop("IdentifierExpression"); }
+
+bool AstDumper::visit(AST::NullExpression *el) {
+ start(QLatin1String("NullExpression nullToken=%1")
+ .arg(loc(el->nullToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NullExpression *) { stop("NullExpression"); }
+
+bool AstDumper::visit(AST::TrueLiteral *el) {
+ start(QLatin1String("TrueLiteral trueToken=%1")
+ .arg(loc(el->trueToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::TrueLiteral *) { stop("TrueLiteral"); }
+
+bool AstDumper::visit(AST::FalseLiteral *el) {
+ start(QLatin1String("FalseLiteral falseToken=%1")
+ .arg(loc(el->falseToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::FalseLiteral *) { stop("FalseLiteral"); }
+
+bool AstDumper::visit(AST::SuperLiteral *el) {
+ start(QLatin1String("SuperLiteral superToken=%1")
+ .arg(loc(el->superToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::SuperLiteral *) { stop("SuperLiteral"); }
+
+bool AstDumper::visit(AST::StringLiteral *el) {
+ start(QLatin1String("StringLiteral value=%1 literalToken=%2")
+ .arg(qs(el->value), loc(el->literalToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::StringLiteral *) { stop("StringLiteral"); }
+
+bool AstDumper::visit(AST::TemplateLiteral *el) {
+ start(QLatin1String("TemplateLiteral value=%1 rawValue=%2 literalToken=%3")
+ .arg(qs(el->value), qs(el->rawValue), loc(el->literalToken)));
+ Node::accept(el->expression, this);
+ return true;
+}
+void AstDumper::endVisit(AST::TemplateLiteral *) { stop("TemplateLiteral"); }
+
+bool AstDumper::visit(AST::NumericLiteral *el) {
+ start(QLatin1String("NumericLiteral value=%1 literalToken=%2")
+ .arg(qs(QString::number(el->value)), loc(el->literalToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NumericLiteral *) { stop("NumericLiteral"); }
+
+bool AstDumper::visit(AST::RegExpLiteral *el) {
+ start(QLatin1String("RegExpLiteral pattern=%1 flags=%2 literalToken=%3")
+ .arg(qs(el->pattern), qs(QString::number(el->flags, 16)), loc(el->literalToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::RegExpLiteral *) { stop("RegExpLiteral"); }
+
+bool AstDumper::visit(AST::ArrayPattern *el) {
+ start(QLatin1String("ArrayPattern lbracketToken=%1, commaToken=%2, rbracketToken=%3 parseMode=%4")
+ .arg(loc(el->lbracketToken),loc(el->commaToken),loc(el->rbracketToken), qs(QString::number(el->parseMode, 16))));
+ return true;
+}
+void AstDumper::endVisit(AST::ArrayPattern *) { stop("ArrayPattern"); }
+
+bool AstDumper::visit(AST::ObjectPattern *el) {
+ start(QLatin1String("ObjectPattern lbraceToken=%1 rbraceToken=%2 parseMode=%3")
+ .arg(loc(el->lbraceToken), loc(el->rbraceToken), qs(QString::number(el->parseMode, 16))));
+ return true;
+}
+void AstDumper::endVisit(AST::ObjectPattern *) { stop("ObjectPattern"); }
+
+bool AstDumper::visit(AST::PatternElementList *) { start("PatternElementList"); return true; }
+void AstDumper::endVisit(AST::PatternElementList *) { stop("PatternElementList"); }
+
+bool AstDumper::visit(AST::PatternPropertyList *) { start("PatternPropertyList"); return true; }
+void AstDumper::endVisit(AST::PatternPropertyList *) { stop("PatternPropertyList"); }
+
+bool AstDumper::visit(AST::PatternElement *el) {
+ start(QLatin1String("PatternElement identifierToken=%1 bindingIdentifier=%2 type=%3 scope=%4 isForDeclaration=%5")
+ .arg(loc(el->identifierToken), qs(el->bindingIdentifier), qs(QString::number(el->type, 16)),
+ qs(QString::number(static_cast<int>(el->scope), 16)), boolStr(el->isForDeclaration)));
+ return true;
+}
+void AstDumper::endVisit(AST::PatternElement *) { stop("PatternElement"); }
+
+bool AstDumper::visit(AST::PatternProperty *el) {
+ start(QLatin1String("PatternProperty identifierToken=%1 bindingIdentifier=%2 type=%3 scope=%4 isForDeclaration=%5 colonToken=%6")
+ .arg(loc(el->identifierToken), qs(el->bindingIdentifier), qs(QString::number(el->type, 16)),
+ qs(QString::number(static_cast<int>(el->scope), 16)), boolStr(el->isForDeclaration), loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::PatternProperty *) { stop("PatternProperty"); }
+
+bool AstDumper::visit(AST::Elision *el) {
+ start(QLatin1String("Elision commaToken=%1")
+ .arg(loc(el->commaToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::Elision *el) {
+ stop("Elision");
+ Node::accept(el->next, this); // emit other elisions at the same level
+}
+
+bool AstDumper::visit(AST::NestedExpression *el) {
+ start(QLatin1String("NestedExpression lparenToken=%1 rparenToken=%2")
+ .arg(loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NestedExpression *) { stop("NestedExpression"); }
+
+bool AstDumper::visit(AST::IdentifierPropertyName *el) {
+ start(QLatin1String("IdentifierPropertyName id=%1 propertyNameToken=%2")
+ .arg(qs(el->id), loc(el->propertyNameToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::IdentifierPropertyName *) { stop("IdentifierPropertyName"); }
+
+bool AstDumper::visit(AST::StringLiteralPropertyName *el) {
+ start(QLatin1String("StringLiteralPropertyName id=%1 propertyNameToken=%2")
+ .arg(qs(el->id), loc(el->propertyNameToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::StringLiteralPropertyName *) { stop("StringLiteralPropertyName"); }
+
+bool AstDumper::visit(AST::NumericLiteralPropertyName *el) {
+ start(QLatin1String("NumericLiteralPropertyName id=%1 propertyNameToken=%2")
+ .arg(qs(QString::number(el->id)),loc(el->propertyNameToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NumericLiteralPropertyName *) { stop("NumericLiteralPropertyName"); }
+
+bool AstDumper::visit(AST::ComputedPropertyName *) {
+ start(QLatin1String("ComputedPropertyName"));
+ return true;
+}
+void AstDumper::endVisit(AST::ComputedPropertyName *) { stop("ComputedPropertyName"); }
+
+bool AstDumper::visit(AST::ArrayMemberExpression *el) {
+ start(QLatin1String("ArrayMemberExpression lbraketToken=%1 rbraketToken=%2")
+ .arg(loc(el->lbracketToken), loc(el->rbracketToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ArrayMemberExpression *) { stop("ArrayMemberExpression"); }
+
+bool AstDumper::visit(AST::FieldMemberExpression *el) {
+ start(QLatin1String("FieldMemberExpression name=%1 dotToken=%2 identifierToken=%3")
+ .arg(qs(el->name), loc(el->dotToken), loc(el->identifierToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::FieldMemberExpression *) { stop("FieldMemberExpression"); }
+
+bool AstDumper::visit(AST::TaggedTemplate *) {
+ start(QLatin1String("TaggedTemplate"));
+ return true;
+}
+void AstDumper::endVisit(AST::TaggedTemplate *) { stop("TaggedTemplate"); }
+
+bool AstDumper::visit(AST::NewMemberExpression *el) {
+ start(QLatin1String("NewMemberExpression newToken=%1 lparenToken=%2 rparenToken=%3")
+ .arg(loc(el->newToken), loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NewMemberExpression *) { stop("NewMemberExpression"); }
+
+bool AstDumper::visit(AST::NewExpression *el) {
+ start(QLatin1String("NewExpression newToken=%1")
+ .arg(loc(el->newToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NewExpression *) { stop("NewExpression"); }
+
+bool AstDumper::visit(AST::CallExpression *el) {
+ start(QLatin1String("CallExpression lparenToken=%1 rparenToken=%2")
+ .arg(loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::CallExpression *) { stop("CallExpression"); }
+
+bool AstDumper::visit(AST::ArgumentList *el) {
+ start(QLatin1String("ArgumentList commaToken=%1 isSpreadElement=%2")
+ .arg(loc(el->commaToken), boolStr(el->isSpreadElement)));
+ return true;
+}
+void AstDumper::endVisit(AST::ArgumentList *) { stop("ArgumentList"); }
+
+bool AstDumper::visit(AST::PostIncrementExpression *el) {
+ start(QLatin1String("PostIncrementExpression incrementToken=%1")
+ .arg(loc(el->incrementToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::PostIncrementExpression *) { stop("PostIncrementExpression"); }
+
+bool AstDumper::visit(AST::PostDecrementExpression *el) {
+ start(QLatin1String("PostDecrementExpression decrementToken=%1")
+ .arg(loc(el->decrementToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::PostDecrementExpression *) { stop("PostDecrementExpression"); }
+
+bool AstDumper::visit(AST::DeleteExpression *el) {
+ start(QLatin1String("DeleteExpression deleteToken=%1")
+ .arg(loc(el->deleteToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::DeleteExpression *) { stop("DeleteExpression"); }
+
+bool AstDumper::visit(AST::VoidExpression *el) {
+ start(QLatin1String("VoidExpression voidToken=%1")
+ .arg(loc(el->voidToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::VoidExpression *) { stop("VoidExpression"); }
+
+bool AstDumper::visit(AST::TypeOfExpression *el) {
+ start(QLatin1String("TypeOfExpression typeofToken=%1")
+ .arg(loc(el->typeofToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::TypeOfExpression *) { stop("TypeOfExpression"); }
+
+bool AstDumper::visit(AST::PreIncrementExpression *el) {
+ start(QLatin1String("PreIncrementExpression incrementToken=%1")
+ .arg(loc(el->incrementToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::PreIncrementExpression *) { stop("PreIncrementExpression"); }
+
+bool AstDumper::visit(AST::PreDecrementExpression *el) {
+ start(QLatin1String("PreDecrementExpression decrementToken=%1")
+ .arg(loc(el->decrementToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::PreDecrementExpression *) { stop("PreDecrementExpression"); }
+
+bool AstDumper::visit(AST::UnaryPlusExpression *el) {
+ start(QLatin1String("UnaryPlusExpression plusToken=%1")
+ .arg(loc(el->plusToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::UnaryPlusExpression *) { stop("UnaryPlusExpression"); }
+
+bool AstDumper::visit(AST::UnaryMinusExpression *el) {
+ start(QLatin1String("UnaryMinusExpression minusToken=%1")
+ .arg(loc(el->minusToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::UnaryMinusExpression *) { stop("UnaryMinusExpression"); }
+
+bool AstDumper::visit(AST::TildeExpression *el) {
+ start(QLatin1String("TildeExpression tildeToken=%1")
+ .arg(loc(el->tildeToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::TildeExpression *) { stop("TildeExpression"); }
+
+bool AstDumper::visit(AST::NotExpression *el) {
+ start(QLatin1String("NotExpression notToken=%1")
+ .arg(loc(el->notToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NotExpression *) { stop("NotExpression"); }
+
+bool AstDumper::visit(AST::BinaryExpression *el) {
+ start(QLatin1String("BinaryExpression op=%1 operatorToken=%2")
+ .arg(qs(QString::number(el->op,16)), loc(el->operatorToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::BinaryExpression *) { stop("BinaryExpression"); }
+
+bool AstDumper::visit(AST::ConditionalExpression *el) {
+ start(QLatin1String("ConditionalExpression questionToken=%1 colonToken=%2")
+ .arg(loc(el->questionToken), loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ConditionalExpression *) { stop("ConditionalExpression"); }
+
+bool AstDumper::visit(AST::Expression *el) {
+ start(QLatin1String("Expression commaToken=%1")
+ .arg(loc(el->commaToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::Expression *) { stop("Expression"); }
+
+bool AstDumper::visit(AST::Block *el) {
+ start(QLatin1String("Block lbraceToken=%1 rbraceToken=%2")
+ .arg(loc(el->lbraceToken), loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::Block *) { stop("Block"); }
+
+bool AstDumper::visit(AST::StatementList *) {
+ start(QLatin1String("StatementList"));
+ return true;
+}
+void AstDumper::endVisit(AST::StatementList *) { stop("StatementList"); }
+
+bool AstDumper::visit(AST::VariableStatement *el) {
+ start(QLatin1String("VariableStatement declarationKindToken=%1")
+ .arg(loc(el->declarationKindToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::VariableStatement *) { stop("VariableStatement"); }
+
+bool AstDumper::visit(AST::VariableDeclarationList *el) {
+ start(QLatin1String("VariableDeclarationList commaToken=%1")
+ .arg(loc(el->commaToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::VariableDeclarationList *) { stop("VariableDeclarationList"); }
+
+bool AstDumper::visit(AST::EmptyStatement *el) {
+ start(QLatin1String("EmptyStatement semicolonToken=%1")
+ .arg(loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::EmptyStatement *) { stop("EmptyStatement"); }
+
+bool AstDumper::visit(AST::ExpressionStatement *el) {
+ start(QLatin1String("ExpressionStatement semicolonToken=%1")
+ .arg(loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ExpressionStatement *) { stop("ExpressionStatement"); }
+
+bool AstDumper::visit(AST::IfStatement *el) {
+ start(QLatin1String("IfStatement ifToken=%1 lparenToken=%2 rparenToken=%3 elseToken=%4")
+ .arg(loc(el->ifToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->elseToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::IfStatement *) { stop("IfStatement"); }
+
+bool AstDumper::visit(AST::DoWhileStatement *el) {
+ start(QLatin1String("DoWhileStatement doToken=%1 whileToken=%2 lparenToken=%3 rparenToken=%4 semicolonToken=%5")
+ .arg(loc(el->doToken), loc(el->whileToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::DoWhileStatement *) { stop("DoWhileStatement"); }
+
+bool AstDumper::visit(AST::WhileStatement *el) {
+ start(QLatin1String("WhileStatement whileToken=%1 lparenToken=%2 rparenToken=%3")
+ .arg(loc(el->whileToken), loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::WhileStatement *) { stop("WhileStatement"); }
+
+bool AstDumper::visit(AST::ForStatement *el) {
+ start(QLatin1String("ForStatement forToken=%1 lparenToken=%2 firstSemicolonToken=%3 secondSemicolonToken=%4 rparenToken=%5")
+ .arg(loc(el->forToken), loc(el->lparenToken), loc(el->firstSemicolonToken), loc(el->secondSemicolonToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ForStatement *) { stop("ForStatement"); }
+
+bool AstDumper::visit(AST::ForEachStatement *el) {
+ start(QLatin1String("ForEachStatement forToken=%1 lparenToken=%2 inOfToken=%3 rparenToken=%4 type=%5")
+ .arg(loc(el->forToken), loc(el->lparenToken), loc(el->inOfToken), loc(el->rparenToken), qs(QString::number(static_cast<int>(el->type), 16))));
+ return true;
+}
+void AstDumper::endVisit(AST::ForEachStatement *) { stop("ForEachStatement"); }
+
+bool AstDumper::visit(AST::ContinueStatement *el) {
+ start(QLatin1String("ContinueStatement label=%1 continueToken=%2 identifierToken=%3 semicolonToken=%4")
+ .arg(qs(el->label), loc(el->continueToken), loc(el->identifierToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ContinueStatement *) { stop("ContinueStatement"); }
+
+bool AstDumper::visit(AST::BreakStatement *el) {
+ start(QLatin1String("BreakStatement label=%1 breakToken=%2 identifierToken=%3 semicolonToken=%4")
+ .arg(qs(el->label), loc(el->breakToken), loc(el->identifierToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::BreakStatement *) { stop("BreakStatement"); }
+
+bool AstDumper::visit(AST::ReturnStatement *el) {
+ start(QLatin1String("ReturnStatement returnToken=%1 semicolonToken=%2")
+ .arg(loc(el->returnToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ReturnStatement *) { stop("ReturnStatement"); }
+
+bool AstDumper::visit(AST::YieldExpression *el) {
+ start(QLatin1String("YieldExpression isYieldStar=%1 yieldToken=%2")
+ .arg(boolStr(el->isYieldStar), loc(el->yieldToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::YieldExpression *) { stop("YieldExpression"); }
+
+bool AstDumper::visit(AST::WithStatement *el) {
+ start(QLatin1String("WithStatement withToken=%1 lparenToken=%2 rparenToken=%3")
+ .arg(loc(el->withToken), loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::WithStatement *) { stop("WithStatement"); }
+
+bool AstDumper::visit(AST::SwitchStatement *el) {
+ start(QLatin1String("SwitchStatement switchToken=%1 lparenToken=%2 rparenToken=%3")
+ .arg(loc(el->switchToken), loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::SwitchStatement *) { stop("SwitchStatement"); }
+
+bool AstDumper::visit(AST::CaseBlock *el) {
+ start(QLatin1String("CaseBlock lbraceToken=%1 rbraceToken=%2")
+ .arg(loc(el->lbraceToken), loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::CaseBlock *) { stop("CaseBlock"); }
+
+bool AstDumper::visit(AST::CaseClauses *) {
+ start(QLatin1String("CaseClauses"));
+ return true;
+}
+void AstDumper::endVisit(AST::CaseClauses *) { stop("CaseClauses"); }
+
+bool AstDumper::visit(AST::CaseClause *el) {
+ start(QLatin1String("CaseClause caseToken=%1 colonToken=%2")
+ .arg(loc(el->caseToken), loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::CaseClause *) { stop("CaseClause"); }
+
+bool AstDumper::visit(AST::DefaultClause *el) {
+ start(QLatin1String("DefaultClause defaultToken=%1 colonToken=%2")
+ .arg(loc(el->defaultToken), loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::DefaultClause *) { stop("DefaultClause"); }
+
+bool AstDumper::visit(AST::LabelledStatement *el) {
+ start(QLatin1String("LabelledStatement label=%1 identifierToken=%2 colonToken=%3")
+ .arg(qs(el->label), loc(el->identifierToken), loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::LabelledStatement *) { stop("LabelledStatement"); }
+
+bool AstDumper::visit(AST::ThrowStatement *el) {
+ start(QLatin1String("ThrowStatement throwToken=%1 semicolonToken=%2")
+ .arg(loc(el->throwToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ThrowStatement *) { stop("ThrowStatement"); }
+
+bool AstDumper::visit(AST::TryStatement *el) {
+ start(QLatin1String("TryStatement tryToken=%1")
+ .arg(loc(el->tryToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::TryStatement *) { stop("TryStatement"); }
+
+bool AstDumper::visit(AST::Catch *el) {
+ start(QLatin1String("Catch catchToken=%1 lparenToken=%2 identifierToken=%3 rparenToken=%4")
+ .arg(loc(el->catchToken), loc(el->lparenToken), loc(el->identifierToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::Catch *) { stop("Catch"); }
+
+bool AstDumper::visit(AST::Finally *el) {
+ start(QLatin1String("Finally finallyToken=%1")
+ .arg(loc(el->finallyToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::Finally *) { stop("Finally"); }
+
+bool AstDumper::visit(AST::FunctionDeclaration *el) {
+ start(QLatin1String("FunctionDeclaration name=%1 isArrowFunction=%2 isGenerator=%3 functionToken=%4 "
+ "identifierToken=%5 lparenToken=%6 rparenToken=%7 lbraceToken=%8 rbraceToken=%9")
+ .arg(qs(el->name), boolStr(el->isArrowFunction), boolStr(el->isGenerator), loc(el->functionToken),
+ loc(el->identifierToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->lbraceToken),
+ loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::FunctionDeclaration *) { stop("FunctionDeclaration"); }
+
+bool AstDumper::visit(AST::FunctionExpression *el) {
+ start(QLatin1String("FunctionExpression name=%1 isArrowFunction=%2 isGenerator=%3 functionToken=%4 "
+ "identifierToken=%5 lparenToken=%6 rparenToken=%7 lbraceToken=%8 rbraceToken=%9")
+ .arg(qs(el->name), boolStr(el->isArrowFunction), boolStr(el->isGenerator), loc(el->functionToken),
+ loc(el->identifierToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->lbraceToken),
+ loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::FunctionExpression *) { stop("FunctionExpression"); }
+
+bool AstDumper::visit(AST::FormalParameterList *) {
+ start(QLatin1String("FormalParameterList"));
+ return true;
+}
+void AstDumper::endVisit(AST::FormalParameterList *) { stop("FormalParameterList"); }
+
+bool AstDumper::visit(AST::ClassExpression *el) {
+ start(QLatin1String("ClassExpression name=%1 classToken=%2 identifierToken=%3 lbraceToken=%4 rbraceToken=%5")
+ .arg(qs(el->name), loc(el->classToken), loc(el->identifierToken), loc(el->lbraceToken), loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ClassExpression *) { stop("ClassExpression"); }
+
+bool AstDumper::visit(AST::ClassDeclaration *el) {
+ start(QLatin1String("ClassDeclaration name=%1 classToken=%2 identifierToken=%3 lbraceToken=%4 rbraceToken=%5")
+ .arg(qs(el->name), loc(el->classToken), loc(el->identifierToken), loc(el->lbraceToken), loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ClassDeclaration *) { stop("ClassDeclaration"); }
+
+bool AstDumper::visit(AST::ClassElementList *el) {
+ start(QLatin1String("ClassElementList isStatic=%1")
+ .arg(boolStr(el->isStatic)));
+ return true;
+}
+void AstDumper::endVisit(AST::ClassElementList *) { stop("ClassElementList"); }
+
+bool AstDumper::visit(AST::Program *) {
+ start(QLatin1String("Program"));
+ return true;
+}
+void AstDumper::endVisit(AST::Program *) { stop("Program"); }
+
+bool AstDumper::visit(AST::NameSpaceImport *el) {
+ start(QLatin1String("NameSpaceImport starToken=%1 importedBindingToken=%2 importedBinding=%3")
+ .arg(loc(el->starToken), loc(el->importedBindingToken), qs(el->importedBinding)));
+ return true;
+}
+void AstDumper::endVisit(AST::NameSpaceImport *) { stop("NameSpaceImport"); }
+
+bool AstDumper::visit(AST::ImportSpecifier *el) {
+ start(QLatin1String("ImportSpecifier identifierToken=%1 importedBindingToken=%2 identifier=%3 importedBinding=%4")
+ .arg(loc(el->identifierToken), loc(el->importedBindingToken), qs(el->identifier), qs(el->importedBinding)));
+ return true;
+}
+void AstDumper::endVisit(AST::ImportSpecifier *) { stop("ImportSpecifier"); }
+
+bool AstDumper::visit(AST::ImportsList *el) {
+ start(QLatin1String("ImportsList importSpecifierToken=%1")
+ .arg(loc(el->importSpecifierToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ImportsList *) { stop("ImportsList"); }
+
+bool AstDumper::visit(AST::NamedImports *el) {
+ start(QLatin1String("NamedImports leftBraceToken=%1 rightBraceToken=%2")
+ .arg(loc(el->leftBraceToken), loc(el->rightBraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NamedImports *) { stop("NamedImports"); }
+
+bool AstDumper::visit(AST::FromClause *el) {
+ start(QLatin1String("FromClause fromToken=%1 moduleSpecifierToken=%2 moduleSpecifier=%3")
+ .arg(loc(el->fromToken), loc(el->moduleSpecifierToken), qs(el->moduleSpecifier)));
+ return true;
+}
+void AstDumper::endVisit(AST::FromClause *) { stop("FromClause"); }
+
+bool AstDumper::visit(AST::ImportClause *el) {
+ start(QLatin1String("ImportClause importedDefaultBindingToken=%1 importedDefaultBinding=%2")
+ .arg(loc(el->importedDefaultBindingToken), qs(el->importedDefaultBinding)));
+ return true;
+}
+void AstDumper::endVisit(AST::ImportClause *) { stop("ImportClause"); }
+
+bool AstDumper::visit(AST::ImportDeclaration *el) {
+ start(QLatin1String("ImportDeclaration importToken=%1 moduleSpecifierToken=%2 moduleSpecifier=%3")
+ .arg(loc(el->importToken), loc(el->moduleSpecifierToken), qs(el->moduleSpecifier)));
+ return true;
+}
+void AstDumper::endVisit(AST::ImportDeclaration *) { stop("ImportDeclaration"); }
+
+bool AstDumper::visit(AST::ExportSpecifier *el) {
+ start(QLatin1String("ExportSpecifier identifierToken=%1 exportedIdentifierToken=%2 identifier=%3 exportedIdentifier=%4")
+ .arg(loc(el->identifierToken), loc(el->exportedIdentifierToken), qs(el->identifier), qs(el->exportedIdentifier)));
+ return true;
+}
+void AstDumper::endVisit(AST::ExportSpecifier *) { stop("ExportSpecifier"); }
+
+bool AstDumper::visit(AST::ExportsList *) {
+ start(QLatin1String("ExportsList"));
+ return true;
+}
+void AstDumper::endVisit(AST::ExportsList *) { stop("ExportsList"); }
+
+bool AstDumper::visit(AST::ExportClause *el) {
+ start(QLatin1String("ExportClause leftBraceToken=%1 rightBraceToken=%2")
+ .arg(loc(el->leftBraceToken), loc(el->rightBraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ExportClause *) { stop("ExportClause"); }
+
+bool AstDumper::visit(AST::ExportDeclaration *el) {
+ start(QLatin1String("ExportDeclaration exportToken=%1 exportAll=%2 exportDefault=%3")
+ .arg(loc(el->exportToken), boolStr(el->exportAll), boolStr(el->exportDefault)));
+ return true;
+}
+void AstDumper::endVisit(AST::ExportDeclaration *) { stop("ExportDeclaration"); }
+
+bool AstDumper::visit(AST::ESModule *) {
+ start(QLatin1String("ESModule"));
+ return true;
+}
+void AstDumper::endVisit(AST::ESModule *) { stop("ESModule"); }
+
+bool AstDumper::visit(AST::DebuggerStatement *el) {
+ start(QLatin1String("DebuggerStatement debuggerToken=%1 semicolonToken=%2")
+ .arg(loc(el->debuggerToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::DebuggerStatement *) { stop("DebuggerStatement"); }
+
+bool AstDumper::visit(AST::Type *) {
+ start(QLatin1String("Type"));
+ return true;
+}
+void AstDumper::endVisit(AST::Type *) { stop("Type"); }
+
+bool AstDumper::visit(AST::TypeArgumentList *) {
+ start(QLatin1String("TypeArgumentList"));
+ return true;
+}
+void AstDumper::endVisit(AST::TypeArgumentList *) { stop("TypeArgumentList"); }
+
+bool AstDumper::visit(AST::TypeAnnotation *el) {
+ start(QLatin1String("TypeAnnotation colonToken=%1")
+ .arg(loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::TypeAnnotation *) { stop("TypeAnnotation"); }
+
+void AstDumper::throwRecursionDepthError()
+{
+ qDebug() << "Maximum statement or expression depth exceeded in AstDumper";
+}
+
+bool AstDumper::dumpNode() {
+ return options & DumperOptions::DumpNode;
+}
+
+bool AstDumper::noLocations() {
+ return options & DumperOptions::NoLocations;
+}
+
+bool AstDumper::noAnnotations() {
+ return options & DumperOptions::NoAnnotations;
+}
+
+} // end namespace QQmlJS
+
+QT_END_NAMESPACE
diff --git a/tests/auto/shared/qqmljsastdumper.h b/tests/auto/shared/qqmljsastdumper.h
new file mode 100644
index 0000000000..d8d19e351d
--- /dev/null
+++ b/tests/auto/shared/qqmljsastdumper.h
@@ -0,0 +1,446 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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: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$
+**/
+#ifndef ASTDUMPER_H
+#define ASTDUMPER_H
+
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmljsglobal_p.h>
+#include <private/qqmljsastvisitor_p.h>
+#include <QtCore/QString>
+#include <functional>
+#include <ostream>
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+
+namespace QQmlJS {
+
+enum class DumperOptions {
+ None=0,
+ NoLocations=0x1,
+ NoAnnotations=0x2,
+ DumpNode=0x4
+};
+bool operator & (DumperOptions lhs, DumperOptions rhs);
+DumperOptions operator | (DumperOptions lhs, DumperOptions rhs);
+
+// no export, currently just a supporting file...
+class AstDumper: public AST::BaseVisitor
+{
+public:
+ static QString printNode2(AST::Node *);
+
+ static QString diff(AST::Node *n1, AST::Node *n2, int nContext=3, DumperOptions opt=DumperOptions::None, int indent=0);
+ static QString printNode(AST::Node *n, DumperOptions opt=DumperOptions::None, int indent=1, int baseIndent=0);
+
+ AstDumper(const std::function <void (const QString &)> &dumper, DumperOptions options=DumperOptions::None,
+ int indent=1, int baseIndent=0);
+
+ void start(const QString &str);
+ void start(const char *str);
+ void stop(const QString &str);
+ void stop(const char *str);
+
+ QString qs(const QString &s);
+ QString qs(const char *s);
+ QString qs(const QStringRef &s);
+
+ QString loc(const AST::SourceLocation &s);
+
+ QString boolStr(bool v);
+
+ bool preVisit(AST::Node *el) override;
+ void postVisit(AST::Node *el) override;
+
+ // Ui
+ bool visit(AST::UiProgram *el) override;
+ bool visit(AST::UiHeaderItemList *) override;
+ bool visit(AST::UiPragma *el) override;
+ bool visit(AST::UiImport *el) override;
+ bool visit(AST::UiPublicMember *el) override;
+ bool visit(AST::UiSourceElement *) override;
+ bool visit(AST::UiObjectDefinition *) override;
+ bool visit(AST::UiObjectInitializer *) override;
+ bool visit(AST::UiObjectBinding *) override;
+ bool visit(AST::UiScriptBinding *) override;
+ bool visit(AST::UiArrayBinding *) override;
+ bool visit(AST::UiParameterList *) override;
+ bool visit(AST::UiObjectMemberList *) override;
+ bool visit(AST::UiArrayMemberList *) override;
+ bool visit(AST::UiQualifiedId *) override;
+ bool visit(AST::UiEnumDeclaration *) override;
+ bool visit(AST::UiEnumMemberList *) override;
+ bool visit(AST::UiVersionSpecifier *) override;
+ bool visit(AST::UiInlineComponent *) override;
+ bool visit(AST::UiRequired *) override;
+ bool visit(AST::UiAnnotation *) override;
+ bool visit(AST::UiAnnotationList *) override;
+
+ void endVisit(AST::UiProgram *) override;
+ void endVisit(AST::UiImport *) override;
+ void endVisit(AST::UiHeaderItemList *) override;
+ void endVisit(AST::UiPragma *) override;
+ void endVisit(AST::UiPublicMember *) override;
+ void endVisit(AST::UiSourceElement *) override;
+ void endVisit(AST::UiObjectDefinition *) override;
+ void endVisit(AST::UiObjectInitializer *) override;
+ void endVisit(AST::UiObjectBinding *) override;
+ void endVisit(AST::UiScriptBinding *) override;
+ void endVisit(AST::UiArrayBinding *) override;
+ void endVisit(AST::UiParameterList *) override;
+ void endVisit(AST::UiObjectMemberList *) override;
+ void endVisit(AST::UiArrayMemberList *) override;
+ void endVisit(AST::UiQualifiedId *) override;
+ void endVisit(AST::UiEnumDeclaration *) override;
+ void endVisit(AST::UiEnumMemberList *) override;
+ void endVisit(AST::UiVersionSpecifier *) override;
+ void endVisit(AST::UiInlineComponent *) override;
+ void endVisit(AST::UiRequired *) override;
+ void endVisit(AST::UiAnnotation *) override;
+ void endVisit(AST::UiAnnotationList *) override;
+
+ // QQmlJS
+ bool visit(AST::ThisExpression *) override;
+ void endVisit(AST::ThisExpression *) override;
+
+ bool visit(AST::IdentifierExpression *) override;
+ void endVisit(AST::IdentifierExpression *) override;
+
+ bool visit(AST::NullExpression *) override;
+ void endVisit(AST::NullExpression *) override;
+
+ bool visit(AST::TrueLiteral *) override;
+ void endVisit(AST::TrueLiteral *) override;
+
+ bool visit(AST::FalseLiteral *) override;
+ void endVisit(AST::FalseLiteral *) override;
+
+ bool visit(AST::SuperLiteral *) override;
+ void endVisit(AST::SuperLiteral *) override;
+
+ bool visit(AST::StringLiteral *) override;
+ void endVisit(AST::StringLiteral *) override;
+
+ bool visit(AST::TemplateLiteral *) override;
+ void endVisit(AST::TemplateLiteral *) override;
+
+ bool visit(AST::NumericLiteral *) override;
+ void endVisit(AST::NumericLiteral *) override;
+
+ bool visit(AST::RegExpLiteral *) override;
+ void endVisit(AST::RegExpLiteral *) override;
+
+ bool visit(AST::ArrayPattern *) override;
+ void endVisit(AST::ArrayPattern *) override;
+
+ bool visit(AST::ObjectPattern *) override;
+ void endVisit(AST::ObjectPattern *) override;
+
+ bool visit(AST::PatternElementList *) override;
+ void endVisit(AST::PatternElementList *) override;
+
+ bool visit(AST::PatternPropertyList *) override;
+ void endVisit(AST::PatternPropertyList *) override;
+
+ bool visit(AST::PatternElement *) override;
+ void endVisit(AST::PatternElement *) override;
+
+ bool visit(AST::PatternProperty *) override;
+ void endVisit(AST::PatternProperty *) override;
+
+ bool visit(AST::Elision *) override;
+ void endVisit(AST::Elision *) override;
+
+ bool visit(AST::NestedExpression *) override;
+ void endVisit(AST::NestedExpression *) override;
+
+ bool visit(AST::IdentifierPropertyName *) override;
+ void endVisit(AST::IdentifierPropertyName *) override;
+
+ bool visit(AST::StringLiteralPropertyName *) override;
+ void endVisit(AST::StringLiteralPropertyName *) override;
+
+ bool visit(AST::NumericLiteralPropertyName *) override;
+ void endVisit(AST::NumericLiteralPropertyName *) override;
+
+ bool visit(AST::ComputedPropertyName *) override;
+ void endVisit(AST::ComputedPropertyName *) override;
+
+ bool visit(AST::ArrayMemberExpression *) override;
+ void endVisit(AST::ArrayMemberExpression *) override;
+
+ bool visit(AST::FieldMemberExpression *) override;
+ void endVisit(AST::FieldMemberExpression *) override;
+
+ bool visit(AST::TaggedTemplate *) override;
+ void endVisit(AST::TaggedTemplate *) override;
+
+ bool visit(AST::NewMemberExpression *) override;
+ void endVisit(AST::NewMemberExpression *) override;
+
+ bool visit(AST::NewExpression *) override;
+ void endVisit(AST::NewExpression *) override;
+
+ bool visit(AST::CallExpression *) override;
+ void endVisit(AST::CallExpression *) override;
+
+ bool visit(AST::ArgumentList *) override;
+ void endVisit(AST::ArgumentList *) override;
+
+ bool visit(AST::PostIncrementExpression *) override;
+ void endVisit(AST::PostIncrementExpression *) override;
+
+ bool visit(AST::PostDecrementExpression *) override;
+ void endVisit(AST::PostDecrementExpression *) override;
+
+ bool visit(AST::DeleteExpression *) override;
+ void endVisit(AST::DeleteExpression *) override;
+
+ bool visit(AST::VoidExpression *) override;
+ void endVisit(AST::VoidExpression *) override;
+
+ bool visit(AST::TypeOfExpression *) override;
+ void endVisit(AST::TypeOfExpression *) override;
+
+ bool visit(AST::PreIncrementExpression *) override;
+ void endVisit(AST::PreIncrementExpression *) override;
+
+ bool visit(AST::PreDecrementExpression *) override;
+ void endVisit(AST::PreDecrementExpression *) override;
+
+ bool visit(AST::UnaryPlusExpression *) override;
+ void endVisit(AST::UnaryPlusExpression *) override;
+
+ bool visit(AST::UnaryMinusExpression *) override;
+ void endVisit(AST::UnaryMinusExpression *) override;
+
+ bool visit(AST::TildeExpression *) override;
+ void endVisit(AST::TildeExpression *) override;
+
+ bool visit(AST::NotExpression *) override;
+ void endVisit(AST::NotExpression *) override;
+
+ bool visit(AST::BinaryExpression *) override;
+ void endVisit(AST::BinaryExpression *) override;
+
+ bool visit(AST::ConditionalExpression *) override;
+ void endVisit(AST::ConditionalExpression *) override;
+
+ bool visit(AST::Expression *) override;
+ void endVisit(AST::Expression *) override;
+
+ bool visit(AST::Block *) override;
+ void endVisit(AST::Block *) override;
+
+ bool visit(AST::StatementList *) override;
+ void endVisit(AST::StatementList *) override;
+
+ bool visit(AST::VariableStatement *) override;
+ void endVisit(AST::VariableStatement *) override;
+
+ bool visit(AST::VariableDeclarationList *) override;
+ void endVisit(AST::VariableDeclarationList *) override;
+
+ bool visit(AST::EmptyStatement *) override;
+ void endVisit(AST::EmptyStatement *) override;
+
+ bool visit(AST::ExpressionStatement *) override;
+ void endVisit(AST::ExpressionStatement *) override;
+
+ bool visit(AST::IfStatement *) override;
+ void endVisit(AST::IfStatement *) override;
+
+ bool visit(AST::DoWhileStatement *) override;
+ void endVisit(AST::DoWhileStatement *) override;
+
+ bool visit(AST::WhileStatement *) override;
+ void endVisit(AST::WhileStatement *) override;
+
+ bool visit(AST::ForStatement *) override;
+ void endVisit(AST::ForStatement *) override;
+
+ bool visit(AST::ForEachStatement *) override;
+ void endVisit(AST::ForEachStatement *) override;
+
+ bool visit(AST::ContinueStatement *) override;
+ void endVisit(AST::ContinueStatement *) override;
+
+ bool visit(AST::BreakStatement *) override;
+ void endVisit(AST::BreakStatement *) override;
+
+ bool visit(AST::ReturnStatement *) override;
+ void endVisit(AST::ReturnStatement *) override;
+
+ bool visit(AST::YieldExpression *) override;
+ void endVisit(AST::YieldExpression *) override;
+
+ bool visit(AST::WithStatement *) override;
+ void endVisit(AST::WithStatement *) override;
+
+ bool visit(AST::SwitchStatement *) override;
+ void endVisit(AST::SwitchStatement *) override;
+
+ bool visit(AST::CaseBlock *) override;
+ void endVisit(AST::CaseBlock *) override;
+
+ bool visit(AST::CaseClauses *) override;
+ void endVisit(AST::CaseClauses *) override;
+
+ bool visit(AST::CaseClause *) override;
+ void endVisit(AST::CaseClause *) override;
+
+ bool visit(AST::DefaultClause *) override;
+ void endVisit(AST::DefaultClause *) override;
+
+ bool visit(AST::LabelledStatement *) override;
+ void endVisit(AST::LabelledStatement *) override;
+
+ bool visit(AST::ThrowStatement *) override;
+ void endVisit(AST::ThrowStatement *) override;
+
+ bool visit(AST::TryStatement *) override;
+ void endVisit(AST::TryStatement *) override;
+
+ bool visit(AST::Catch *) override;
+ void endVisit(AST::Catch *) override;
+
+ bool visit(AST::Finally *) override;
+ void endVisit(AST::Finally *) override;
+
+ bool visit(AST::FunctionDeclaration *) override;
+ void endVisit(AST::FunctionDeclaration *) override;
+
+ bool visit(AST::FunctionExpression *) override;
+ void endVisit(AST::FunctionExpression *) override;
+
+ bool visit(AST::FormalParameterList *) override;
+ void endVisit(AST::FormalParameterList *) override;
+
+ bool visit(AST::ClassExpression *) override;
+ void endVisit(AST::ClassExpression *) override;
+
+ bool visit(AST::ClassDeclaration *) override;
+ void endVisit(AST::ClassDeclaration *) override;
+
+ bool visit(AST::ClassElementList *) override;
+ void endVisit(AST::ClassElementList *) override;
+
+ bool visit(AST::Program *) override;
+ void endVisit(AST::Program *) override;
+
+ bool visit(AST::NameSpaceImport *) override;
+ void endVisit(AST::NameSpaceImport *) override;
+
+ bool visit(AST::ImportSpecifier *) override;
+ void endVisit(AST::ImportSpecifier *) override;
+
+ bool visit(AST::ImportsList *) override;
+ void endVisit(AST::ImportsList *) override;
+
+ bool visit(AST::NamedImports *) override;
+ void endVisit(AST::NamedImports *) override;
+
+ bool visit(AST::FromClause *) override;
+ void endVisit(AST::FromClause *) override;
+
+ bool visit(AST::ImportClause *) override;
+ void endVisit(AST::ImportClause *) override;
+
+ bool visit(AST::ImportDeclaration *) override;
+ void endVisit(AST::ImportDeclaration *) override;
+
+ bool visit(AST::ExportSpecifier *) override;
+ void endVisit(AST::ExportSpecifier *) override;
+
+ bool visit(AST::ExportsList *) override;
+ void endVisit(AST::ExportsList *) override;
+
+ bool visit(AST::ExportClause *) override;
+ void endVisit(AST::ExportClause *) override;
+
+ bool visit(AST::ExportDeclaration *) override;
+ void endVisit(AST::ExportDeclaration *) override;
+
+ bool visit(AST::ESModule *) override;
+ void endVisit(AST::ESModule *) override;
+
+ bool visit(AST::DebuggerStatement *) override;
+ void endVisit(AST::DebuggerStatement *) override;
+
+ bool visit(AST::Type *) override;
+ void endVisit(AST::Type *) override;
+
+ bool visit(AST::TypeArgumentList *) override;
+ void endVisit(AST::TypeArgumentList *) override;
+
+ bool visit(AST::TypeAnnotation *) override;
+ void endVisit(AST::TypeAnnotation *) override;
+
+ void throwRecursionDepthError() override;
+
+private:
+ // attributes
+ std::function <void (const QString &)> dumper;
+ DumperOptions options = DumperOptions::None;
+ int indent = 0;
+ int baseIndent = 0;
+ bool dumpNode();
+ bool noLocations();
+ bool noAnnotations();
+};
+
+QDebug operator<<(QDebug d, AST::Node *n);
+
+std::ostream &operator<<(std::ostream &stream, AST::Node *n);
+
+} // namespace AST
+
+QT_END_NAMESPACE
+
+#endif // ASTDUMPER_H
diff --git a/tests/manual/pointer/main.qml b/tests/manual/pointer/main.qml
index d382d8b23d..83e1d3b2ba 100644
--- a/tests/manual/pointer/main.qml
+++ b/tests/manual/pointer/main.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the manual tests of the Qt Toolkit.
@@ -57,6 +57,7 @@ Window {
addExample("multibuttons", "TapHandler: gesturePolicy (99 red balloons)", Qt.resolvedUrl("multibuttons.qml"))
addExample("flickable with Handlers", "Flickable with buttons, sliders etc. implemented in various ways", Qt.resolvedUrl("flickableWithHandlers.qml"))
addExample("tap and drag", "Flickable with all possible combinations of TapHandler and DragHandler children", Qt.resolvedUrl("pointerDrag.qml"))
+ addExample("tablet canvas", "PointHandler and HoverHandler with a tablet: detect the stylus, and draw", Qt.resolvedUrl("tabletCanvasDrawing.qml"))
}
}
Item {
diff --git a/tests/manual/pointer/qml.qrc b/tests/manual/pointer/qml.qrc
index 95bece180a..20956fcbac 100644
--- a/tests/manual/pointer/qml.qrc
+++ b/tests/manual/pointer/qml.qrc
@@ -13,6 +13,7 @@
<file>pointerDrag.qml</file>
<file>singlePointHandlerProperties.qml</file>
<file>sidebar.qml</file>
+ <file>tabletCanvasDrawing.qml</file>
<file>tapHandler.qml</file>
<file>content/CheckBox.qml</file>
<file>content/FakeFlickable.qml</file>
@@ -30,6 +31,10 @@
<file>content/TouchpointFeedbackSprite.qml</file>
<file>resources/arrowhead.png</file>
<file>resources/balloon.png</file>
+ <file>resources/cursor-airbrush.png</file>
+ <file>resources/cursor-eraser.png</file>
+ <file>resources/cursor-felt-marker.png</file>
+ <file>resources/cursor-pencil.png</file>
<file>resources/fighter.png</file>
<file>resources/fingersprite.png</file>
<file>resources/grabbing-location.svg</file>
diff --git a/tests/manual/pointer/resources/cursor-airbrush.png b/tests/manual/pointer/resources/cursor-airbrush.png
new file mode 100644
index 0000000000..bea756ed6f
--- /dev/null
+++ b/tests/manual/pointer/resources/cursor-airbrush.png
Binary files differ
diff --git a/tests/manual/pointer/resources/cursor-eraser.png b/tests/manual/pointer/resources/cursor-eraser.png
new file mode 100644
index 0000000000..e5488a89f2
--- /dev/null
+++ b/tests/manual/pointer/resources/cursor-eraser.png
Binary files differ
diff --git a/tests/manual/pointer/resources/cursor-felt-marker.png b/tests/manual/pointer/resources/cursor-felt-marker.png
new file mode 100644
index 0000000000..132f09aa39
--- /dev/null
+++ b/tests/manual/pointer/resources/cursor-felt-marker.png
Binary files differ
diff --git a/tests/manual/pointer/resources/cursor-pencil.png b/tests/manual/pointer/resources/cursor-pencil.png
new file mode 100644
index 0000000000..cc2f447d02
--- /dev/null
+++ b/tests/manual/pointer/resources/cursor-pencil.png
Binary files differ
diff --git a/tests/manual/pointer/tabletCanvasDrawing.qml b/tests/manual/pointer/tabletCanvasDrawing.qml
new file mode 100644
index 0000000000..c340dee5f4
--- /dev/null
+++ b/tests/manual/pointer/tabletCanvasDrawing.qml
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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: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.15
+import QtQuick.Layouts 1.15
+import "content"
+
+Rectangle {
+ width: 1024
+ height: 1024
+ color: "#444"
+
+ ColumnLayout {
+ x: -15; width: 80
+ height: parent.height
+ Slider {
+ id: hueSlider
+ width: 80; height: 200
+ Layout.fillHeight: true
+ label: "hue"
+ Rectangle {
+ color: "beige"
+ width: 30
+ height: 25
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 2
+ anchors.horizontalCenter: parent.horizontalCenter
+ Rectangle {
+ border.color: "white"
+ color: canvas.drawingColor
+ anchors.fill: parent
+ }
+ }
+ }
+ Slider {
+ id: saturationSlider
+ width: 80; height: 200
+ Layout.fillHeight: true
+ label: "sat"
+ }
+ Slider {
+ id: lightnessSlider
+ width: 80; height: 200
+ Layout.fillHeight: true
+ label: "light"
+ }
+ }
+
+ ColumnLayout {
+ x: parent.width - 65; width: 80
+ height: parent.height
+ Slider {
+ id: widthSlider
+ width: 80; height: 200
+ Layout.fillHeight: true
+ label: "width"
+ }
+ Slider {
+ id: alphaSlider
+ width: 80; height: 200
+ Layout.fillHeight: true
+ label: "alpha"
+ }
+ }
+
+ Rectangle {
+ id: rect
+ width: 640
+ height: 480
+ color: "beige"
+ anchors {
+ fill: parent
+ margins: 10
+ leftMargin: 50
+ rightMargin: 50
+ }
+
+ Canvas {
+ id: canvas
+ anchors.fill: parent
+ antialiasing: true
+ renderTarget: Canvas.FramebufferObject
+ property color drawingColor: Qt.hsla(hueSlider.value / 100.0,
+ saturationSlider.value / 100.0,
+ lightnessSlider.value / 100.0,
+ alphaSlider.value / 100.0)
+ property var points: []
+ property var pressures: []
+ property var pointerType: PointerDevice.Pen
+ onPaint: {
+ if (points.length < 2)
+ return
+ var ctx = canvas.getContext('2d');
+ ctx.save()
+ ctx.strokeStyle = pointerType === PointerDevice.Pen ? drawingColor : "beige"
+ ctx.lineCap = "round"
+ if (pressures.length === points.length) {
+ for (var i = 1; i < points.length; i++) {
+ ctx.lineWidth = pressures[i] * widthSlider.value
+ ctx.beginPath()
+ ctx.moveTo(points[i - 1].x, points[i - 1].y)
+ ctx.lineTo(points[i].x, points[i].y)
+ ctx.stroke()
+ }
+ points = points.slice(points.length - 2, 1)
+ pressures = pressures.slice(pressures.length - 2, 1)
+ } else {
+ ctx.beginPath()
+ ctx.moveTo(points[0].x, points[0].y)
+ for (var i = 1; i < points.length; i++)
+ ctx.lineTo(points[i].x, points[i].y)
+ ctx.lineWidth = widthSlider
+ ctx.stroke()
+ points = points.slice(points.length - 2, 1)
+ pressures = []
+ }
+ ctx.restore()
+ }
+ }
+
+ PointHandler {
+ acceptedPointerTypes: PointerDevice.Pen
+ onActiveChanged:
+ if (active) {
+ canvas.pointerType = PointerDevice.Pen
+ } else {
+ canvas.points = []
+ canvas.pressures = []
+ }
+ onPointChanged:
+ if (active) {
+ canvas.points.push(point.position)
+ canvas.pressures.push(point.pressure)
+ canvas.requestPaint()
+ }
+ }
+
+ PointHandler {
+ acceptedPointerTypes: PointerDevice.Eraser
+ onActiveChanged:
+ if (active) {
+ canvas.pointerType = PointerDevice.Eraser
+ } else {
+ canvas.points = []
+ canvas.pressures = []
+ }
+ onPointChanged:
+ if (active) {
+ canvas.points.push(point.position)
+ canvas.pressures.push(point.pressure)
+ canvas.requestPaint()
+ }
+ }
+
+ HoverHandler {
+ id: stylusHandler
+ acceptedDevices: PointerDevice.Stylus
+ acceptedPointerTypes: PointerDevice.Pen
+ target: Image {
+ parent: rect
+ source: stylusHandler.point.rotation === 0 ?
+ "resources/cursor-pencil.png" : "resources/cursor-felt-marker.png"
+ visible: stylusHandler.hovered
+ rotation: stylusHandler.point.rotation
+ x: stylusHandler.point.position.x
+ y: stylusHandler.point.position.y
+ }
+ }
+
+ HoverHandler {
+ id: airbrushHandler
+ acceptedDevices: PointerDevice.Airbrush
+ acceptedPointerTypes: PointerDevice.Pen
+ target: Image {
+ parent: rect
+ source: "resources/cursor-airbrush.png"
+ visible: airbrushHandler.hovered
+ x: airbrushHandler.point.position.x
+ y: airbrushHandler.point.position.y
+ }
+ }
+
+ HoverHandler {
+ id: eraserHandler
+ acceptedPointerTypes: PointerDevice.Eraser
+ target: Image {
+ parent: rect
+ source: "resources/cursor-eraser.png"
+ visible: eraserHandler.hovered
+ x: eraserHandler.point.position.x
+ y: eraserHandler.point.position.y - 32
+ }
+ }
+ }
+}