aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quick')
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp1
-rw-r--r--tests/auto/quick/qquickanimations/tst_qquickanimations.cpp36
-rw-r--r--tests/auto/quick/qquickapplication/tst_qquickapplication.cpp2
-rw-r--r--tests/auto/quick/qquickdragattached/tst_qquickdragattached.cpp3
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp25
-rw-r--r--tests/auto/quick/qquickitem/tst_qquickitem.cpp2
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp2
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml90
-rw-r--r--tests/auto/quick/qquicklayouts/tst_qquicklayouts.cpp5
-rw-r--r--tests/auto/quick/qquicklistview/data/emptymodel.qml2
-rw-r--r--tests/auto/quick/qquicklistview/data/snapToItemWithSectionAtStart.qml52
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp22
-rw-r--r--tests/auto/quick/qquicklistview2/data/nestedSnap.qml63
-rw-r--r--tests/auto/quick/qquicklistview2/data/visibleBoundToCountGreaterThanZero.qml31
-rw-r--r--tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp82
-rw-r--r--tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp10
-rw-r--r--tests/auto/quick/qquickpathview/data/qtbug46487.qml28
-rw-r--r--tests/auto/quick/qquickpathview/tst_qquickpathview.cpp63
-rw-r--r--tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp10
-rw-r--r--tests/auto/quick/qquickstates/data/anchorRewindBug3.qml38
-rw-r--r--tests/auto/quick/qquickstates/tst_qquickstates.cpp25
-rw-r--r--tests/auto/quick/qquicktableview/data/invalidateModelContextObject.qml38
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp213
-rw-r--r--tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp52
-rw-r--r--tests/auto/quick/qquicktextedit/data/hAlignVisual.qml6
-rw-r--r--tests/auto/quick/qquicktextedit/data/inFlickable.qml7
-rw-r--r--tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp161
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp19
-rw-r--r--tests/auto/quick/qquickview_extra/data/qtbug_87228.qml2
-rw-r--r--tests/auto/quick/softwarerenderer/tst_softwarerenderer.cpp4
-rw-r--r--tests/auto/quick/touchmouse/tst_touchmouse.cpp56
31 files changed, 1064 insertions, 86 deletions
diff --git a/tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp b/tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp
index fdc8981932..4c6e331efa 100644
--- a/tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp
+++ b/tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp
@@ -60,6 +60,7 @@ void tst_HowToQml::activeFocusDebugging()
auto *window = qobject_cast<QQuickWindow*>(engine.rootObjects().at(0));
window->show();
+ window->requestActivate();
QTest::ignoreMessage(QtDebugMsg, QRegularExpression("activeFocusItem: .*\"ActiveFocusDebuggingMain\""));
QVERIFY(QTest::qWaitForWindowActive(window));
diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
index 0a126a13e8..ce5473c8a5 100644
--- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
+++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
@@ -101,6 +101,7 @@ private slots:
void restartAnimationGroupWhenDirty();
void restartNestedAnimationGroupWhenDirty();
void targetsDeletedNotRemoved();
+ void alwaysRunToEndSetFalseRestartBug();
};
#define QTIMED_COMPARE(lhs, rhs) do { \
@@ -2295,6 +2296,41 @@ void tst_qquickanimations::targetsDeletedNotRemoved()
}
}
+//QTBUG-125224
+void tst_qquickanimations::alwaysRunToEndSetFalseRestartBug()
+{
+ QQuickRectangle rect;
+ QQuickSequentialAnimation sequential;
+ QQuickPropertyAnimation beginAnim;
+ QQuickPropertyAnimation endAnim;
+
+ beginAnim.setTargetObject(&rect);
+ beginAnim.setProperty("x");
+ beginAnim.setTo(200);
+ beginAnim.setDuration(1000);
+
+ endAnim.setTargetObject(&rect);
+ endAnim.setProperty("x");
+ endAnim.setFrom(200);
+ endAnim.setDuration(1000);
+
+ beginAnim.setGroup(&sequential);
+ endAnim.setGroup(&sequential);
+
+ sequential.setLoops(-1);
+ sequential.setAlwaysRunToEnd(true);
+
+ QCOMPARE(sequential.loops(), -1);
+ QVERIFY(sequential.alwaysRunToEnd());
+ sequential.start();
+ sequential.stop();
+ sequential.setAlwaysRunToEnd(false);
+ sequential.start();
+ QCOMPARE(sequential.isRunning(), true);
+ sequential.stop();
+ QCOMPARE(sequential.isRunning(), false);
+}
+
QTEST_MAIN(tst_qquickanimations)
#include "tst_qquickanimations.moc"
diff --git a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
index a440c0c2f8..b3633a9dcc 100644
--- a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
+++ b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
@@ -246,7 +246,7 @@ void tst_qquickapplication::styleHints()
{
// technically not in QQuickApplication, but testing anyway here
QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0; Item { property variant styleHints: Qt.styleHints }", QUrl::fromLocalFile(""));
+ component.setData("import QtQuick 2.0; Item { property variant styleHints: Application.styleHints }", QUrl::fromLocalFile(""));
QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
QVERIFY(item);
QQuickView view;
diff --git a/tests/auto/quick/qquickdragattached/tst_qquickdragattached.cpp b/tests/auto/quick/qquickdragattached/tst_qquickdragattached.cpp
index 5ce72a747f..d82ebe77c2 100644
--- a/tests/auto/quick/qquickdragattached/tst_qquickdragattached.cpp
+++ b/tests/auto/quick/qquickdragattached/tst_qquickdragattached.cpp
@@ -44,6 +44,9 @@ void tst_QQuickDragAttached::setMimeData_data()
QTest::addRow("text/uri-list, string")
<< makeMap("text/uri-list", QString("https://qt-project.org"))
<< QStringList{"text/uri-list"};
+ QTest::addRow("text/uri-list, RFC2483 string")
+ << makeMap("text/uri-list", QString("https://qt-project.org\r\nhttps://www.test.com"))
+ << QStringList{"text/uri-list"};
QTest::addRow("text/uri-list, strings")
<< makeMap("text/uri-list", QStringList{"file://foo", "https://www.test.com"})
<< QStringList{"text/uri-list"};
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index 343bde5f5f..ca2314c336 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -180,6 +180,11 @@ void tst_qquickimage::imageSource()
QFETCH(bool, cache);
QFETCH(QString, error);
+#if !QT_CONFIG(qml_network)
+ if (remote)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
TestHTTPServer server;
if (remote) {
QVERIFY2(server.listen(), qPrintable(server.errorString()));
@@ -550,6 +555,10 @@ void tst_qquickimage::tiling_QTBUG_6716_data()
void tst_qquickimage::noLoading()
{
+#if !QT_CONFIG(qml_network)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
qRegisterMetaType<QQuickImageBase::Status>();
TestHTTPServer server;
@@ -692,6 +701,10 @@ void tst_qquickimage::sourceSize_QTBUG_16389()
// QTBUG-15690
void tst_qquickimage::nullPixmapPaint()
{
+#if !QT_CONFIG(qml_network)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
QScopedPointer<QQuickView> window(new QQuickView(nullptr));
window->setSource(testFileUrl("nullpixmap.qml"));
window->show();
@@ -714,6 +727,10 @@ void tst_qquickimage::nullPixmapPaint()
void tst_qquickimage::imageCrash_QTBUG_22125()
{
+#if !QT_CONFIG(qml_network)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
TestHTTPServer server;
QVERIFY2(server.listen(), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
@@ -826,6 +843,10 @@ void tst_qquickimage::sourceSizeChanges()
QTRY_COMPARE(sourceSizeSpy.size(), 3);
// Remote
+#if !QT_CONFIG(qml_network)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
ctxt->setContextProperty("srcImage", server.url("/heart.png"));
QTRY_COMPARE(img->status(), QQuickImage::Ready);
QTRY_COMPARE(sourceSizeSpy.size(), 4);
@@ -959,6 +980,10 @@ void tst_qquickimage::progressAndStatusChanges()
QTRY_COMPARE(statusSpy.size(), 1);
// Loading remote file
+#if !QT_CONFIG(qml_network)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
ctxt->setContextProperty("srcImage", server.url("/heart.png"));
QTRY_COMPARE(obj->status(), QQuickImage::Loading);
QTRY_COMPARE(obj->progress(), 0.0);
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
index 061dea3ad7..1db150e675 100644
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
@@ -1527,7 +1527,7 @@ void tst_qquickitem::polishLoopDetection_data()
QTest::newRow("test1.100") << PolishItemSpans({ {1, 100} }) << 0;
QTest::newRow("test1.1002") << PolishItemSpans({ {1, 1002} }) << 3;
- QTest::newRow("test1.2020") << PolishItemSpans({ {1, 2020} }) << 10;
+ QTest::newRow("test1.2020") << PolishItemSpans({ {1, 2020} }) << 5;
QTest::newRow("test5.1") << PolishItemSpans({ {5, 1} }) << 0;
QTest::newRow("test5.10") << PolishItemSpans({ {5, 10} }) << 0;
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index ebd1749e68..f6de1b482c 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -2015,7 +2015,7 @@ void tst_QQuickItem::layoutMirroringIllegalParent()
{
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0; QtObject { LayoutMirroring.enabled: true; LayoutMirroring.childrenInherit: true }", QUrl::fromLocalFile(""));
- QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1:21: QML QtObject: LayoutDirection attached property only works with Items and Windows");
+ QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1:21: QML QtObject: LayoutMirroring attached property only works with Items and Windows");
QObject *object = component.create();
QVERIFY(object != nullptr);
}
diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
index 8524366f14..5454cf672b 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
@@ -936,7 +936,19 @@ Item {
},
layoutWidth: 0,
expectedWidths: [0]
- }
+ },{
+ tag: "preferred_infinity", // Do not crash/assert when the preferred size is infinity
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 10, preferredWidth: Number.POSITIVE_INFINITY, fillWidth: true},
+ {minimumWidth: 20, preferredWidth: Number.POSITIVE_INFINITY, fillWidth: true},
+ ]
+ },
+ layoutWidth: 31, // Important that this is between minimum and preferred width of the layout.
+ expectedWidths: [10, 21] // The result here does not have to be exact. (This
+ // test is mostly concerned about not crashing).
+ }
];
}
@@ -1178,6 +1190,78 @@ Item {
}
Component {
+ id: sizeHintBindingLoopComp
+ Item {
+ id: root
+ anchors.fill: parent
+ property var customWidth: 100
+ RowLayout {
+ id: col
+ Item {
+ id: item
+ implicitHeight: 80
+ implicitWidth: Math.max(col2.implicitWidth, root.customWidth + 20)
+ ColumnLayout {
+ id: col2
+ width: parent.width
+ Item {
+ id: rect
+ implicitWidth: root.customWidth
+ implicitHeight: 80
+ }
+ }
+ }
+ }
+ }
+ }
+
+ function test_sizeHintBindingLoopIssue() {
+ var item = createTemporaryObject(sizeHintBindingLoopComp, container)
+ waitForRendering(item)
+ item.customWidth += 10
+ waitForRendering(item)
+ verify(!LayoutSetup.bindingLoopDetected, "Detected binding loop")
+ LayoutSetup.resetBindingLoopDetectedFlag()
+ }
+
+ Component {
+ id: polishLayoutItemComp
+ Item {
+ anchors.fill: parent
+ implicitHeight: contentLayout.implicitHeight
+ implicitWidth: contentLayout.implicitWidth
+ property alias textLayout: contentLayout
+ RowLayout {
+ width: parent.width
+ height: parent.height
+ ColumnLayout {
+ id: contentLayout
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
+ Layout.maximumWidth: 200
+ Repeater {
+ model: 2
+ Text {
+ Layout.fillWidth: true
+ text: "This is a long text causing line breaks to show the bug."
+ wrapMode: Text.Wrap
+ }
+ }
+ Item {
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+ }
+
+ function test_polishLayoutItemIssue() {
+ var rootItem = createTemporaryObject(polishLayoutItemComp, container)
+ waitForRendering(rootItem)
+ var textItem = rootItem.textLayout.children[1]
+ verify(textItem.y >= rootItem.textLayout.children[0].height)
+ }
+
+ Component {
id: rearrangeNestedLayouts_Component
RowLayout {
id: layout
@@ -1520,8 +1604,8 @@ Item {
compare(rootItem.maxWidth, 66)
// Should not trigger a binding loop
- verify(!BindingLoopDetector.bindingLoopDetected, "Detected binding loop")
- BindingLoopDetector.reset()
+ verify(!LayoutSetup.bindingLoopDetected, "Detected binding loop")
+ LayoutSetup.resetBindingLoopDetectedFlag()
}
diff --git a/tests/auto/quick/qquicklayouts/tst_qquicklayouts.cpp b/tests/auto/quick/qquicklayouts/tst_qquicklayouts.cpp
index 26b01b806d..1576a00c81 100644
--- a/tests/auto/quick/qquicklayouts/tst_qquicklayouts.cpp
+++ b/tests/auto/quick/qquicklayouts/tst_qquicklayouts.cpp
@@ -15,13 +15,12 @@ public:
bool wasBindingLoopDetected() const { return mBindingLoopDetected; }
public slots:
- void reset() { mBindingLoopDetected = false; }
+ void resetBindingLoopDetectedFlag() { mBindingLoopDetected = false; }
void qmlEngineAvailable(QQmlEngine *engine)
{
connect(engine, &QQmlEngine::warnings, this, &Setup::qmlWarnings);
-
- qmlRegisterSingletonInstance("org.qtproject.Test", 1, 0, "BindingLoopDetector", this);
+ qmlRegisterSingletonInstance("org.qtproject.Test", 1, 0, "LayoutSetup", this);
}
void qmlWarnings(const QList<QQmlError> &warnings)
diff --git a/tests/auto/quick/qquicklistview/data/emptymodel.qml b/tests/auto/quick/qquicklistview/data/emptymodel.qml
index 3feec691cf..c7f1df31d2 100644
--- a/tests/auto/quick/qquicklistview/data/emptymodel.qml
+++ b/tests/auto/quick/qquicklistview/data/emptymodel.qml
@@ -6,6 +6,8 @@ Rectangle {
}
ListView {
id: list
+ width: 100
+ height: 100
model: model
delegate: Item {
}
diff --git a/tests/auto/quick/qquicklistview/data/snapToItemWithSectionAtStart.qml b/tests/auto/quick/qquicklistview/data/snapToItemWithSectionAtStart.qml
new file mode 100644
index 0000000000..0d4c233345
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/snapToItemWithSectionAtStart.qml
@@ -0,0 +1,52 @@
+import QtQuick
+
+ListView {
+ id: listView
+ width: 240
+ height: 300
+
+ model: ListModel {
+ ListElement { section: "section 1" }
+ ListElement { section: "section 1" }
+ ListElement { section: "section 1" }
+ ListElement { section: "section 2" }
+ ListElement { section: "section 2" }
+ ListElement { section: "section 2" }
+ ListElement { section: "section 3" }
+ ListElement { section: "section 3" }
+ ListElement { section: "section 3" }
+ ListElement { section: "section 4" }
+ ListElement { section: "section 4" }
+ ListElement { section: "section 4" }
+ ListElement { section: "section 5" }
+ ListElement { section: "section 5" }
+ ListElement { section: "section 5" }
+ }
+
+ section.property: "section"
+ section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
+ section.delegate: Rectangle {
+ width: listView.width
+ height: 30
+ Text {
+ anchors.fill: parent
+ text: section
+ }
+ color: "lightblue"
+ }
+
+ snapMode: ListView.SnapToItem
+
+ delegate: Rectangle {
+ width: listView.width
+ height: 30
+ Text {
+ anchors.fill: parent
+ text: index
+ }
+ border {
+ width: 1
+ color: "black"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 46e1254453..747478fc9a 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -171,6 +171,7 @@ private slots:
void headerSnapToItem_data();
void headerSnapToItem();
void snapToItemWithSpacing_QTBUG_59852();
+ void snapToItemWithSectionAtStart();
void snapOneItemResize_QTBUG_43555();
void snapOneItem_data();
void snapOneItem();
@@ -5395,6 +5396,27 @@ void tst_QQuickListView::snapToItemWithSpacing_QTBUG_59852()
releaseView(window);
}
+void tst_QQuickListView::snapToItemWithSectionAtStart() // QTBUG-30768
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("snapToItemWithSectionAtStart.qml")));
+ QQuickListView *listView = qobject_cast<QQuickListView *>(window.rootObject());
+ QTRY_VERIFY(listView);
+
+ // Both sections and elements are 30px high. The list height is 300px, so
+ // it fits exactly 10 elements. We can do some random flicks, but the
+ // content position always MUST be divisible by 30.
+ for (int i = 0; i < 10; ++i) {
+ const bool even = (i % 2 == 0);
+ const QPoint start = even ? QPoint(20, 100 + i * 5) : QPoint(20, 20 + i * 3);
+ const QPoint end = even ? start - QPoint(0, 50 + i * 10) : start + QPoint(0, 50 + i * 5);
+
+ flick(&window, start, end, 180);
+ QTRY_COMPARE(listView->isMoving(), false); // wait until it stops
+ QCOMPARE(int(listView->contentY()) % 30, 0);
+ }
+}
+
static void drag_helper(QWindow *window, QPoint *startPos, const QPoint &delta)
{
QPoint pos = *startPos;
diff --git a/tests/auto/quick/qquicklistview2/data/nestedSnap.qml b/tests/auto/quick/qquicklistview2/data/nestedSnap.qml
new file mode 100644
index 0000000000..d7f064da01
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/nestedSnap.qml
@@ -0,0 +1,63 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+pragma ComponentBehavior: Bound
+
+import QtQuick
+
+ListView {
+ id: row
+
+ width: 300
+ height: 300
+
+ orientation: Qt.Horizontal
+ snapMode: ListView.SnapOneItem
+ highlightRangeMode: ListView.StrictlyEnforceRange
+
+ model: 3
+ delegate: ListView {
+ id: column
+ objectName: "vertical column " + index
+
+ required property int index
+
+ width: 300
+ height: 300
+
+ orientation: Qt.Vertical
+ snapMode: ListView.SnapOneItem
+ highlightRangeMode: ListView.StrictlyEnforceRange
+
+ model: 3
+ delegate: Rectangle {
+ id: cell
+
+ required property int index
+
+ width: 300
+ height: 300
+ color: "transparent"
+ border.color: "#000"
+ border.width: 5
+ radius: 15
+
+ Text {
+ anchors.centerIn: parent
+ text: `Row: ${cell.index}`
+ }
+ }
+
+ Text {
+ anchors.verticalCenterOffset: -height
+ anchors.centerIn: parent
+ horizontalAlignment: Text.AlignHCenter
+ text: `Column: ${column.index}\ncurrentIndex: ${column.currentIndex}`
+ }
+ }
+
+ Text {
+ x: 10; y: 10
+ text: `currentIndex: ${row.currentIndex}`
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/visibleBoundToCountGreaterThanZero.qml b/tests/auto/quick/qquicklistview2/data/visibleBoundToCountGreaterThanZero.qml
new file mode 100644
index 0000000000..e75c779584
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/visibleBoundToCountGreaterThanZero.qml
@@ -0,0 +1,31 @@
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ property alias listView: listView
+
+ ListView {
+ id: listView
+
+ visible: count > 0 // actual defect. countChanged never fires so this never turns true
+
+ Layout.fillWidth: true
+ Layout.preferredHeight: contentHeight // grow with content, initially 0
+
+ model: ListModel {
+ id: idModel
+ }
+
+ delegate: Text {
+ required property string name
+ text: name
+ }
+
+ Timer {
+ running: true
+ interval: 10
+ repeat: true
+ onTriggered: idModel.append({name:"Hello"})
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp b/tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp
index c240f36a80..e114cc1591 100644
--- a/tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp
+++ b/tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp
@@ -18,6 +18,8 @@ Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
using namespace QQuickViewTestUtils;
using namespace QQuickVisualTestUtils;
+static const int oneSecondInMs = 1000;
+
class tst_QQuickListView2 : public QQmlDataTest
{
Q_OBJECT
@@ -35,6 +37,7 @@ private slots:
void delegateModelRefresh();
void wheelSnap();
void wheelSnap_data();
+ void nestedWheelSnap();
void sectionsNoOverlap();
void metaSequenceAsModel();
@@ -62,6 +65,7 @@ private slots:
void changingOrientationResetsPreviousAxisValues_data();
void changingOrientationResetsPreviousAxisValues();
+ void visibleBoundToCountGreaterThanZero();
private:
void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to);
@@ -838,6 +842,67 @@ void tst_QQuickListView2::wheelSnap_data()
<< 210.0;
}
+void tst_QQuickListView2::nestedWheelSnap()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("nestedSnap.qml")));
+
+ quint64 timestamp = 10;
+ auto sendWheelEvent = [&timestamp, &window](const QPoint &pixelDelta, Qt::ScrollPhase phase) {
+ const QPoint pos(100, 100);
+ QWheelEvent event(pos, window.mapToGlobal(pos), pixelDelta, pixelDelta, Qt::NoButton,
+ Qt::NoModifier, phase, false, Qt::MouseEventSynthesizedBySystem);
+ event.setAccepted(false);
+ event.setTimestamp(timestamp);
+ QGuiApplication::sendEvent(&window, &event);
+ timestamp += 50;
+ };
+
+ QQuickListView *outerListView = qobject_cast<QQuickListView *>(window.rootObject());
+ QTRY_VERIFY(outerListView);
+ QSignalSpy outerCurrentIndexSpy(outerListView, &QQuickListView::currentIndexChanged);
+ int movingAtIndex = -1;
+
+ // send horizontal pixel-delta wheel events with phases; confirm that ListView hits the next item boundary
+ sendWheelEvent({}, Qt::ScrollBegin);
+ for (int i = 1; i < 4; ++i) {
+ sendWheelEvent({-50, 0}, Qt::ScrollUpdate);
+ if (movingAtIndex < 0 && outerListView->isMoving())
+ movingAtIndex = i;
+ }
+ QVERIFY(outerListView->isDragging());
+ sendWheelEvent({}, Qt::ScrollEnd);
+ QCOMPARE(outerListView->isDragging(), false);
+ QTRY_COMPARE(outerListView->isMoving(), false); // wait until it stops
+ qCDebug(lcTests) << "outer got moving after" << movingAtIndex
+ << "horizontal events; stopped at" << outerListView->contentX() << outerListView->currentIndex();
+ QCOMPARE_GT(movingAtIndex, 0);
+ QCOMPARE(outerListView->contentX(), 300);
+ QCOMPARE(outerCurrentIndexSpy.size(), 1);
+
+ movingAtIndex = -1;
+ QQuickListView *innerListView = qobject_cast<QQuickListView *>(outerListView->currentItem());
+ QTRY_VERIFY(innerListView);
+ QSignalSpy innerCurrentIndexSpy(innerListView, &QQuickListView::currentIndexChanged);
+
+ // send vertical pixel-delta wheel events with phases; confirm that ListView hits the next item boundary
+ sendWheelEvent({}, Qt::ScrollBegin);
+ for (int i = 1; i < 4; ++i) {
+ sendWheelEvent({0, -50}, Qt::ScrollUpdate);
+ if (movingAtIndex < 0 && innerListView->isMoving())
+ movingAtIndex = i;
+ }
+ QVERIFY(innerListView->isDragging());
+ sendWheelEvent({}, Qt::ScrollEnd);
+ QCOMPARE(innerListView->isDragging(), false);
+ QTRY_COMPARE(innerListView->isMoving(), false); // wait until it stops
+ qCDebug(lcTests) << "inner got moving after" << movingAtIndex
+ << "vertical events; stopped at" << innerListView->contentY() << innerListView->currentIndex();
+ QCOMPARE_GT(movingAtIndex, 0);
+ QCOMPARE(innerListView->contentY(), 300);
+ QCOMPARE(innerCurrentIndexSpy.size(), 1);
+}
+
class FriendlyItemView : public QQuickItemView
{
friend class ItemViewAccessor;
@@ -1153,6 +1218,23 @@ void tst_QQuickListView2::changingOrientationResetsPreviousAxisValues() // QTBUG
QVERIFY(!listView->property("isYReset").toBool());
}
+void tst_QQuickListView2::visibleBoundToCountGreaterThanZero()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("visibleBoundToCountGreaterThanZero.qml")));
+
+ auto *listView = window.rootObject()->property("listView").value<QQuickListView *>();
+ QVERIFY(listView);
+
+ QSignalSpy countChangedSpy(listView, SIGNAL(countChanged()));
+ QVERIFY(countChangedSpy.isValid());
+
+ QTRY_COMPARE_GT_WITH_TIMEOUT(listView->count(), 1, oneSecondInMs);
+ // Using the TRY variant here as well is necessary.
+ QTRY_COMPARE_GT_WITH_TIMEOUT(countChangedSpy.count(), 1, oneSecondInMs);
+ QVERIFY(listView->isVisible());
+}
+
QTEST_MAIN(tst_QQuickListView2)
#include "tst_qquicklistview2.moc"
diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
index 6d2aa267dd..d5b3b75215 100644
--- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
+++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
@@ -939,6 +939,9 @@ void tst_QQuickMouseArea::doubleClick()
QCOMPARE(window.rootObject()->property("clicked").toInt(), 1);
QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1);
QCOMPARE(window.rootObject()->property("released").toInt(), 2);
+
+ // wait long enough to avoid affecting the next test function
+ QTest::qWait(QGuiApplication::styleHints()->mouseDoubleClickInterval());
}
void tst_QQuickMouseArea::doubleTap() // QTBUG-112434
@@ -970,6 +973,9 @@ void tst_QQuickMouseArea::doubleTap() // QTBUG-112434
QCOMPARE(mouseArea->pressed(), false);
QCOMPARE(window.rootObject()->property("clicked").toInt(), 1);
+ // avoid getting a double-click event next
+ QTest::qWait(QGuiApplication::styleHints()->mouseDoubleClickInterval());
+
// now tap with two fingers simultaneously: only one of them generates synth-mouse
QPoint p2 = p1 + QPoint(50, 5);
QTest::touchEvent(&window, device).press(2, p1).press(3, p2);
@@ -991,8 +997,8 @@ void tst_QQuickMouseArea::doubleTap() // QTBUG-112434
QTest::touchEvent(&window, device).release(4, p1).release(5, p2);
QQuickTouchUtils::flush(&window);
QCOMPARE(window.rootObject()->property("released").toInt(), 4);
- QCOMPARE(window.rootObject()->property("clicked").toInt(), 2);
- QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 2);
+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 3);
+ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1);
QCOMPARE(mouseArea->pressed(), false); // make sure it doesn't get stuck
}
diff --git a/tests/auto/quick/qquickpathview/data/qtbug46487.qml b/tests/auto/quick/qquickpathview/data/qtbug46487.qml
new file mode 100644
index 0000000000..840d77ffe4
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/qtbug46487.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+PathView {
+ id: view
+ property int delegatesCreated: 0
+ property int delegatesDestroyed: 0
+
+ width: 400
+ height: 400
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+ pathItemCount: 5
+ currentIndex: 1
+ model: customModel
+ delegate: Text {
+ text: "item: " + index + " of: " + view.count
+ Component.onCompleted: view.delegatesCreated++;
+ Component.onDestruction: view.delegatesDestroyed++;
+ }
+ path: Path {
+ startX: 50
+ startY: 0
+ PathLine {
+ x: 50
+ y: 400
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
index 90c3060235..7d41d907fb 100644
--- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
+++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
@@ -133,6 +133,7 @@ private slots:
void requiredPropertiesInDelegatePreventUnrelated();
void touchMove();
void mousePressAfterFlick();
+ void qtbug46487();
private:
QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
@@ -2895,6 +2896,68 @@ void tst_QQuickPathView::mousePressAfterFlick() // QTBUG-115121
QCOMPARE(pressedSpy.size(), 0);
}
+class CustomModel : public QAbstractListModel
+{
+public:
+ CustomModel(QObject *parent = 0) : QAbstractListModel(parent) {
+ m_values << 0 << 1 << 2 << 3 << 4;
+ }
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const {
+ Q_UNUSED(parent);
+ return m_values.count();
+ }
+ QVariant data(const QModelIndex &index, int role) const {
+ if (index.row() < 0 || m_values.count() <= index.row())
+ return QVariant();
+
+ return m_values[index.row()];
+ }
+
+ Q_INVOKABLE void shrink() {
+ beginResetModel();
+ m_values.takeLast();
+ m_values.takeLast();
+ endResetModel();
+ }
+
+private:
+ QList<int> m_values;
+};
+
+void tst_QQuickPathView::qtbug46487()
+{
+ QScopedPointer<QQuickView> window(createView());
+
+ CustomModel* model = new CustomModel;
+ QQmlContext *ctxt = window->rootContext();
+ ctxt->setContextProperty("customModel", model);
+
+ window->setSource(testFileUrl("qtbug46487.qml"));
+ window->show();
+ qApp->processEvents();
+
+ QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
+ QVERIFY(pathview);
+
+ QTest::qWait(500);
+
+ // Should create just pathItemCount amount and not destroy any
+ QCOMPARE(pathview->count(), 5);
+ QCOMPARE(pathview->property("delegatesCreated").toInt(), 5);
+ QCOMPARE(pathview->property("delegatesDestroyed").toInt(), 0);
+
+ // Resets the model and removes 2 items.
+ model->shrink();
+ QTest::qWait(500);
+
+ // Should destroy previous items (begin/endResetModel) and
+ // (re)create 3 new items.
+ QCOMPARE(pathview->count(), 3);
+ QCOMPARE(pathview->property("delegatesCreated").toInt(), 5 + 3);
+ QCOMPARE(pathview->property("delegatesDestroyed").toInt(), 5);
+}
+
QTEST_MAIN(tst_QQuickPathView)
#include "tst_qquickpathview.moc"
diff --git a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
index 590f022e4e..4e0534edf0 100644
--- a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
+++ b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
@@ -108,6 +108,11 @@ void tst_qquickpixmapcache::single()
QFETCH(bool, exists);
QFETCH(bool, neterror);
+#if !QT_CONFIG(qml_network)
+ if (target.scheme() == "http")
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
QString expectedError;
if (neterror) {
expectedError = "Error transferring " + target.toString() + " - server replied: Not found";
@@ -196,6 +201,11 @@ void tst_qquickpixmapcache::parallel()
QFETCH(int, incache);
QFETCH(int, cancel);
+#if !QT_CONFIG(qml_network)
+ if (target1.scheme() == "http" || target2.scheme() == "http")
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
QList<QUrl> targets;
targets << target1 << target2;
diff --git a/tests/auto/quick/qquickstates/data/anchorRewindBug3.qml b/tests/auto/quick/qquickstates/data/anchorRewindBug3.qml
new file mode 100644
index 0000000000..6d829be363
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/anchorRewindBug3.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ width: 100; height: 100
+
+ Rectangle {
+ id: rectangle
+ objectName: "inner"
+ color: "green"
+ // Width and height end up to be 50
+ // after root Component.onCompleted
+ width: 75
+ height: 75
+ anchors.top: root.top
+ anchors.left: root.left
+ }
+
+ // Start with anchored state
+ state: "anchored"
+ states: [
+ State {
+ name: "anchored"
+ AnchorChanges {
+ target: rectangle
+ anchors.top: undefined
+ anchors.left: undefined
+ anchors.right: root.right
+ anchors.bottom: root.bottom
+ }
+ }
+ ]
+
+ Component.onCompleted: {
+ rectangle.width = 50
+ rectangle.height = 50
+ }
+}
diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
index be1361e4ab..7332db93fd 100644
--- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp
+++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
@@ -154,6 +154,7 @@ private slots:
void anchorChangesCrash();
void anchorRewindBug();
void anchorRewindBug2();
+ void anchorRewind_keepsSize_whenStateResetsDefaultAnchors();
void script();
void restoreEntryValues();
void explicitChanges();
@@ -1087,6 +1088,30 @@ void tst_qquickstates::anchorRewindBug2()
QCOMPARE(mover->width(), qreal(50.0));
}
+// QTBUG-126057
+void tst_qquickstates::anchorRewind_keepsSize_whenStateResetsDefaultAnchors()
+{
+ // Arrange
+ QQmlEngine engine;
+
+ // NOTE: Contains two nested rectangles, inner is by default anchored to the top left corner of
+ // its parent. A state is initially "anchored" which removes the default anchoring and anchors
+ // the inner rectangle to the bottom right corner of the parent. The size of the inner rectangle
+ // is assigned to 50x50 on Component.onCompleted of outer rectangle.
+ QQmlComponent rectComponent(&engine, testFileUrl("anchorRewindBug3.qml"));
+ QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(rectComponent.create()));
+ QVERIFY(rect != nullptr);
+ QQuickRectangle *mover = rect->findChild<QQuickRectangle*>("inner");
+ QVERIFY(mover != nullptr);
+
+ // Act
+ QQuickItemPrivate::get(rect.get())->setState("");
+
+ // Assert
+ QCOMPARE(mover->width(), qreal(50.0));
+ QCOMPARE(mover->height(), qreal(50.0));
+}
+
void tst_qquickstates::script()
{
QQmlEngine engine;
diff --git a/tests/auto/quick/qquicktableview/data/invalidateModelContextObject.qml b/tests/auto/quick/qquicktableview/data/invalidateModelContextObject.qml
new file mode 100644
index 0000000000..ff552e856c
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/invalidateModelContextObject.qml
@@ -0,0 +1,38 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+ApplicationWindow {
+    width: 720
+    height: 480
+    visible: true
+
+ property alias tableView: tableView
+ property int modelData: 15
+
+ Page {
+        anchors.fill: parent
+ header: Rectangle {
+            height: 40
+            color: "red"
+        }
+ TableView {
+ id: tableView
+            anchors.fill: parent
+ model: modelData
+ contentY: Math.max(0, contentHeight - height)
+            contentHeight: 40 * rows
+ rowHeightProvider: () => 40
+            columnWidthProvider: () => 200
+ delegate : Rectangle {
+                width: 40;
+                height: 40;
+                color: "green"
+ Text {
+                    anchors.fill: parent
+                    text: index
+                }
+            }
+        }
+    }
+}
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 96137877cb..7482367057 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -162,12 +162,16 @@ private slots:
void checkSyncView_childViews_data();
void checkSyncView_childViews();
void checkSyncView_differentSizedModels();
- void checkSyncView_differentGeometry();
+ void checkSyncView_differentGeometry_vertical();
+ void checkSyncView_differentGeometry_horizontal();
+ void checkSyncView_differentGeometry_both_directions();
void checkSyncView_connect_late_data();
void checkSyncView_connect_late();
void checkSyncView_pageFlicking();
void checkSyncView_emptyModel();
void checkSyncView_topLeftChanged();
+ void checkSyncView_dontRelayoutWhileFlicking();
+ void checkSyncView_detectTopLeftPositionChanged();
void delegateWithRequiredProperties();
void checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable();
void replaceModel();
@@ -278,6 +282,7 @@ private slots:
void checkScroll_data();
void checkScroll();
void checkRebuildJsModel();
+ void invalidateTableInstanceModelContextObject();
};
tst_QQuickTableView::tst_QQuickTableView()
@@ -3070,7 +3075,7 @@ void tst_QQuickTableView::checkSyncView_differentSizedModels()
QVERIFY(tableViewHVPrivate->loadedColumns.isEmpty());
}
-void tst_QQuickTableView::checkSyncView_differentGeometry()
+void tst_QQuickTableView::checkSyncView_differentGeometry_vertical()
{
// Check that you can have two tables in a syncView relation, where
// the sync "child" is larger than the sync view. This means that the
@@ -3083,46 +3088,106 @@ void tst_QQuickTableView::checkSyncView_differentGeometry()
GET_QML_TABLEVIEW(tableViewV);
GET_QML_TABLEVIEW(tableViewHV);
- tableView->setWidth(40);
- tableView->setHeight(40);
+ tableView->setHeight(90);
+ tableViewH->setSyncView(nullptr);
+ tableViewHV->setSyncView(nullptr);
auto tableViewModel = TestModelAsVariant(100, 100);
tableView->setModel(tableViewModel);
- tableViewH->setModel(tableViewModel);
tableViewV->setModel(tableViewModel);
- tableViewHV->setModel(tableViewModel);
WAIT_UNTIL_POLISHED;
- // Check that the column widths are in sync
- for (int column = tableViewH->leftColumn(); column < tableViewH->rightColumn(); ++column) {
- QCOMPARE(tableViewH->columnWidth(column), tableView->columnWidth(column));
- QCOMPARE(tableViewHV->columnWidth(column), tableView->columnWidth(column));
- }
+ // Check that the row heights are in sync
+ for (int row = tableViewV->topRow(); row < tableViewV->bottomRow(); ++row)
+ QCOMPARE(tableViewV->rowHeight(row), tableView->rowHeight(row));
+
+ // Flick in a new row
+ tableView->setContentY(20);
// Check that the row heights are in sync
- for (int row = tableViewV->topRow(); row < tableViewV->bottomRow(); ++row) {
+ for (int row = tableViewV->topRow(); row <= tableViewV->bottomRow(); ++row)
QCOMPARE(tableViewV->rowHeight(row), tableView->rowHeight(row));
- QCOMPARE(tableViewHV->rowHeight(row), tableView->rowHeight(row));
- }
+}
+
+void tst_QQuickTableView::checkSyncView_differentGeometry_horizontal()
+{
+ // Check that you can have two tables in a syncView relation, where
+ // the sync "child" is larger than the sync view. This means that the
+ // child will display more rows and columns than the parent.
+ // In that case, the sync view will anyway need to load the same rows
+ // and columns as the child, otherwise the column and row sizes
+ // cannot be determined for the child.
+ LOAD_TABLEVIEW("syncviewsimple.qml");
+ GET_QML_TABLEVIEW(tableViewH);
+ GET_QML_TABLEVIEW(tableViewV);
+ GET_QML_TABLEVIEW(tableViewHV);
+
+ tableView->setWidth(90);
+ tableViewV->setSyncView(nullptr);
+ tableViewHV->setSyncView(nullptr);
+
+ auto tableViewModel = TestModelAsVariant(100, 100);
+
+ tableView->setModel(tableViewModel);
+ tableViewH->setModel(tableViewModel);
- // Flick a bit, and do the same test again
- tableView->setContentX(200);
- tableView->setContentY(200);
WAIT_UNTIL_POLISHED;
// Check that the column widths are in sync
- for (int column = tableViewH->leftColumn(); column < tableViewH->rightColumn(); ++column) {
+ for (int column = tableViewH->leftColumn(); column < tableViewH->rightColumn(); ++column)
QCOMPARE(tableViewH->columnWidth(column), tableView->columnWidth(column));
- QCOMPARE(tableViewHV->columnWidth(column), tableView->columnWidth(column));
- }
+
+ // Flick in a new column
+ tableView->setContentX(20);
+
+ // Check that the column widths are in sync
+ for (int column = tableViewH->leftColumn(); column < tableViewH->rightColumn(); ++column)
+ QCOMPARE(tableViewH->columnWidth(column), tableView->columnWidth(column));
+}
+
+void tst_QQuickTableView::checkSyncView_differentGeometry_both_directions() {
+ // Check that you can have two tables in a syncView relation, where
+ // the sync "child" is larger than the sync view. This means that the
+ // child will display more rows and columns than the parent.
+ // In that case, the sync view will anyway need to load the same rows
+ // and columns as the child, otherwise the column and row sizes
+ // cannot be determined for the child.
+ LOAD_TABLEVIEW("syncviewsimple.qml");
+ GET_QML_TABLEVIEW(tableViewH);
+ GET_QML_TABLEVIEW(tableViewV);
+ GET_QML_TABLEVIEW(tableViewHV);
+
+ tableView->setWidth(90);
+ tableView->setHeight(90);
+ tableViewHV->setSyncView(nullptr);
+
+ auto tableViewModel = TestModelAsVariant(100, 100);
+
+ tableView->setModel(tableViewModel);
+ tableViewH->setModel(tableViewModel);
+ tableViewV->setModel(tableViewModel);
+
+ WAIT_UNTIL_POLISHED;
// Check that the row heights are in sync
- for (int row = tableViewV->topRow(); row < tableViewV->bottomRow(); ++row) {
+ for (int row = tableViewV->topRow(); row < tableViewV->bottomRow(); ++row)
QCOMPARE(tableViewV->rowHeight(row), tableView->rowHeight(row));
- QCOMPARE(tableViewHV->rowHeight(row), tableView->rowHeight(row));
- }
+ // Check that the column widths are in sync
+ for (int column = tableViewH->leftColumn(); column < tableViewH->rightColumn(); ++column)
+ QCOMPARE(tableViewH->columnWidth(column), tableView->columnWidth(column));
+
+ // Flick in a new row
+ tableView->setContentX(20);
+ tableView->setContentY(20);
+
+ // Check that the row heights are in sync
+ for (int row = tableViewV->topRow(); row <= tableViewV->bottomRow(); ++row)
+ QCOMPARE(tableViewV->rowHeight(row), tableView->rowHeight(row));
+ // Check that the column widths are in sync
+ for (int column = tableViewH->leftColumn(); column < tableViewH->rightColumn(); ++column)
+ QCOMPARE(tableViewH->columnWidth(column), tableView->columnWidth(column));
}
void tst_QQuickTableView::checkSyncView_connect_late_data()
@@ -3328,6 +3393,85 @@ void tst_QQuickTableView::checkSyncView_topLeftChanged()
QCOMPARE(tableViewV->topRow(), tableView->topRow());
}
+void tst_QQuickTableView::checkSyncView_dontRelayoutWhileFlicking()
+{
+ // Check that we don't do a full relayout in a sync child when
+ // a new row or column is flicked into the view. Normal load
+ // and unload of edges should suffice, equal to how the main
+ // TableView (syncView) does it.
+ LOAD_TABLEVIEW("syncviewsimple.qml");
+ GET_QML_TABLEVIEW(tableViewHV);
+
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+ tableViewHV->setModel(model);
+
+ tableView->setColumnWidthProvider(QJSValue());
+ tableView->setRowHeightProvider(QJSValue());
+ view->rootObject()->setProperty("delegateWidth", 50);
+ view->rootObject()->setProperty("delegateHeight", 50);
+
+ WAIT_UNTIL_POLISHED;
+
+ // To check that we don't do a relayout when flicking horizontally, we use a "trick"
+ // where we check the rebuildOptions when we receive the rightColumnChanged
+ // signal. If this signal is emitted as a part of a relayout, rebuildOptions
+ // would still be different from RebuildOption::None at that point.
+ bool columnFlickedIn = false;
+ connect(tableViewHV, &QQuickTableView::rightColumnChanged, [&] {
+ columnFlickedIn = true;
+ QCOMPARE(tableViewHVPrivate->rebuildOptions, QQuickTableViewPrivate::RebuildOption::None);
+ });
+
+ // We do the same for vertical flicking
+ bool rowFlickedIn = false;
+ connect(tableViewHV, &QQuickTableView::bottomRowChanged, [&] {
+ rowFlickedIn = true;
+ QCOMPARE(tableViewHVPrivate->rebuildOptions, QQuickTableViewPrivate::RebuildOption::None);
+ });
+
+ // Move the main tableview so that a new column is flicked in
+ tableView->setContentX(60);
+ QTRY_VERIFY(columnFlickedIn);
+
+ // Move the main tableview so that a new row is flicked in
+ tableView->setContentY(60);
+ QTRY_VERIFY(rowFlickedIn);
+}
+
+void tst_QQuickTableView::checkSyncView_detectTopLeftPositionChanged()
+{
+ // It can happen that, during a resize of columns or rows from using a float-based
+ // slider, that the position of the top-left delegate item is shifted a bit left or
+ // right because of rounding issues. And this again can over time, as you flick, make
+ // the loadedTableOuterRect get slightly out of sync in the sync child compared to the
+ // sync view. TableView will detect if this happens (in syncSyncView), and correct for
+ // it. And this test will test that it works.
+ LOAD_TABLEVIEW("syncviewsimple.qml");
+ GET_QML_TABLEVIEW(tableViewHV);
+
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+ tableViewHV->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Writing an auto test to trigger this rounding issue is very hard. So to keep it
+ // simple, we cheat by just moving the loadedTableOuterRect directly, and
+ // check that the syncView child detects it, and corrects it, upon doing a
+ // forceLayout()
+ tableViewPrivate->loadedTableOuterRect.moveLeft(20);
+ tableViewPrivate->loadedTableOuterRect.moveTop(30);
+ tableViewPrivate->relayoutTableItems();
+ tableViewHV->forceLayout();
+
+ QCOMPARE(tableViewPrivate->loadedTableOuterRect.left(), 20);
+ QCOMPARE(tableViewHVPrivate->loadedTableOuterRect.left(), 20);
+
+ QCOMPARE(tableViewPrivate->loadedTableOuterRect.top(), 30);
+ QCOMPARE(tableViewHVPrivate->loadedTableOuterRect.top(), 30);
+}
+
void tst_QQuickTableView::checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable()
{
LOAD_TABLEVIEW("plaintableview.qml");
@@ -7523,6 +7667,29 @@ void tst_QQuickTableView::checkRebuildJsModel()
QCOMPARE(tableView->property(modelUpdated).toInt(), 1);
}
+void tst_QQuickTableView::invalidateTableInstanceModelContextObject()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("invalidateModelContextObject.qml"));
+
+ std::unique_ptr<QQuickWindow> window(qobject_cast<QQuickWindow*>(component.create()));
+ QVERIFY(window);
+
+ auto tableView = window->property("tableView").value<QQuickTableView *>();
+ QVERIFY(tableView);
+
+ const int modelData = window->property("modelData").toInt();
+ QTRY_COMPARE(tableView->rows(), modelData);
+
+ bool tableViewDestroyed = false;
+ connect(tableView, &QObject::destroyed, [&] {
+ tableViewDestroyed = true;
+ });
+
+ window.reset();
+ QTRY_COMPARE(tableViewDestroyed, true);
+}
+
QTEST_MAIN(tst_QQuickTableView)
#include "tst_qquicktableview.moc"
diff --git a/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp b/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp
index 63d4f24a54..23d2e006ba 100644
--- a/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp
+++ b/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp
@@ -3,14 +3,17 @@
#include <qtest.h>
#include <QtTest/QtTest>
+#include <QtQuick/QQuickView>
#include <QtQuick/QQuickTextDocument>
#include <QtQuick/QQuickItem>
#include <QtQuick/private/qquicktextedit_p.h>
#include <QtQuick/private/qquicktextdocument_p.h>
#include <QtGui/QTextDocument>
+#include <QtGui/QTextBlock>
#include <QtGui/QTextDocumentWriter>
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlComponent>
+#include <QtQuickTest/QtQuickTest>
#include <QtQuickTestUtils/private/qmlutils_p.h>
class tst_qquicktextdocument : public QQmlDataTest
@@ -22,6 +25,8 @@ public:
private slots:
void textDocumentWriter();
void textDocumentWithImage();
+ void changeCharFormatInRange_data();
+ void changeCharFormatInRange();
};
QString text = QStringLiteral("foo bar");
@@ -68,6 +73,53 @@ void tst_qquicktextdocument::textDocumentWithImage()
QCOMPARE(image, document.resource(QTextDocument::ImageResource, name).value<QImage>());
}
+void tst_qquicktextdocument::changeCharFormatInRange_data()
+{
+ QTest::addColumn<bool>("editBlock");
+
+ QTest::newRow("begin/end") << true;
+ QTest::newRow("no edit block") << false; // QTBUG-126886 : don't crash
+}
+
+void tst_qquicktextdocument::changeCharFormatInRange()
+{
+ QFETCH(bool, editBlock);
+ QQuickView window(testFileUrl("text.qml"));
+ window.showNormal();
+ QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window.rootObject());
+ QVERIFY(textEdit);
+ QVERIFY(textEdit->textDocument());
+
+ auto *doc = textEdit->textDocument()->textDocument();
+ QVERIFY(doc);
+
+ QSignalSpy contentSpy(doc, &QTextDocument::contentsChanged);
+ const auto data = QStringLiteral("Format String");
+ doc->setPlainText(data);
+ const auto block = doc->findBlockByNumber(0);
+
+ auto formatText = [block, data] {
+ QTextLayout::FormatRange formatText;
+ formatText.start = 0;
+ formatText.length = data.size();
+ formatText.format.setForeground(Qt::green);
+ block.layout()->setFormats({formatText});
+ };
+
+ // change the char format of this block, and verify visual effect
+ if (editBlock) {
+ QTextCursor cursor(doc);
+ cursor.beginEditBlock();
+ formatText();
+ cursor.endEditBlock();
+ } else {
+ formatText();
+ }
+
+ QVERIFY(QQuickTest::qWaitForPolish(textEdit));
+ QCOMPARE(contentSpy.size(), editBlock ? 2 : 1);
+}
+
QTEST_MAIN(tst_qquicktextdocument)
#include "tst_qquicktextdocument.moc"
diff --git a/tests/auto/quick/qquicktextedit/data/hAlignVisual.qml b/tests/auto/quick/qquicktextedit/data/hAlignVisual.qml
index 1280a655f0..f532a9aa36 100644
--- a/tests/auto/quick/qquicktextedit/data/hAlignVisual.qml
+++ b/tests/auto/quick/qquicktextedit/data/hAlignVisual.qml
@@ -4,11 +4,11 @@ Rectangle {
width: 200
height: 100
- Text {
- objectName: "textItem"
+ TextEdit {
+ objectName: "textEditItem"
text: "AA\nBBBBBBB\nCCCCCCCCCCCCCCCC"
anchors.centerIn: parent
- horizontalAlignment: Text.AlignLeft
+ horizontalAlignment: TextEdit.AlignLeft
font.pointSize: 12
font.family: "Times New Roman"
}
diff --git a/tests/auto/quick/qquicktextedit/data/inFlickable.qml b/tests/auto/quick/qquicktextedit/data/inFlickable.qml
index 7a896db29b..183ddd6701 100644
--- a/tests/auto/quick/qquicktextedit/data/inFlickable.qml
+++ b/tests/auto/quick/qquicktextedit/data/inFlickable.qml
@@ -1,6 +1,7 @@
import QtQuick 2.0
Flickable {
+ id: flick
width: 320; height: 120; contentHeight: text.height
TextEdit {
id: text
@@ -8,4 +9,10 @@ Flickable {
font.pixelSize: 20
text: "several\nlines\nof\ntext\n-\ntry\nto\nflick"
}
+ Text {
+ color: "red"
+ parent: flick // stay on top
+ anchors.right: parent.right
+ text: flick.contentY.toFixed(1)
+ }
}
diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
index 15f538ac3c..44745f8263 100644
--- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
@@ -8,6 +8,8 @@
#include <QtQuick/QQuickTextDocument>
#include <QtQuickTest/QtQuickTest>
#include <QTextDocument>
+#include <QtGui/qtextobject.h>
+#include <QtGui/QTextTable>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlexpression.h>
@@ -43,6 +45,8 @@ DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+// #define DEBUG_WRITE_INPUT
+
static bool isPlatformWayland()
{
return !QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive);
@@ -143,6 +147,8 @@ private slots:
void largeTextObservesViewport();
void largeTextSelection();
void renderingAroundSelection();
+ void largeTextTables_data();
+ void largeTextTables();
void signal_editingfinished();
@@ -221,7 +227,6 @@ private:
void simulateKey(QWindow *, int key, Qt::KeyboardModifiers modifiers = {});
bool isMainFontFixed();
- static bool hasWindowActivation();
QStringList standard;
QStringList richText;
@@ -972,8 +977,8 @@ void tst_qquicktextedit::hAlignVisual()
view.showNormal();
QVERIFY(QTest::qWaitForWindowExposed(&view));
- QQuickText *text = view.rootObject()->findChild<QQuickText*>("textItem");
- QVERIFY(text != nullptr);
+ QQuickTextEdit *text = view.rootObject()->findChild<QQuickTextEdit*>("textEditItem");
+ QVERIFY(text);
// Try to check whether alignment works by checking the number of black
// pixels in the thirds of the grabbed image.
@@ -1000,7 +1005,7 @@ void tst_qquicktextedit::hAlignVisual()
}
{
// HCenter Align
- text->setHAlign(QQuickText::AlignHCenter);
+ text->setHAlign(QQuickTextEdit::AlignHCenter);
QImage image = view.grabWindow();
const int left = numberOfNonWhitePixels(centeredSection1, centeredSection2, image);
const int mid = numberOfNonWhitePixels(centeredSection2, centeredSection3, image);
@@ -1010,7 +1015,7 @@ void tst_qquicktextedit::hAlignVisual()
}
{
// Right Align
- text->setHAlign(QQuickText::AlignRight);
+ text->setHAlign(QQuickTextEdit::AlignRight);
QImage image = view.grabWindow();
const int left = numberOfNonWhitePixels(centeredSection1, centeredSection2, image);
const int mid = numberOfNonWhitePixels(centeredSection2, centeredSection3, image);
@@ -1022,36 +1027,36 @@ void tst_qquicktextedit::hAlignVisual()
text->setWidth(200);
{
- // Left Align
+ // Right Align
QImage image = view.grabWindow();
- int x = qCeil(text->implicitWidth() * view.devicePixelRatio());
- int left = numberOfNonWhitePixels(0, x, image);
- int right = numberOfNonWhitePixels(x, image.width() - x, image);
- QVERIFY2(left > 0, msgNotGreaterThan(left, 0).constData());
- QCOMPARE(right, 0);
+ const int x = image.width() - qCeil(text->implicitWidth() * view.devicePixelRatio());
+ const int left = numberOfNonWhitePixels(0, x, image);
+ const int right = numberOfNonWhitePixels(x, image.width() - x, image);
+ QCOMPARE(left, 0);
+ QVERIFY2(right > 0, msgNotGreaterThan(left, 0).constData());
}
{
// HCenter Align
- text->setHAlign(QQuickText::AlignHCenter);
+ text->setHAlign(QQuickTextEdit::AlignHCenter);
QImage image = view.grabWindow();
- int x1 = qFloor(image.width() - text->implicitWidth() * view.devicePixelRatio()) / 2;
- int x2 = image.width() - x1;
- int left = numberOfNonWhitePixels(0, x1, image);
- int mid = numberOfNonWhitePixels(x1, x2 - x1, image);
- int right = numberOfNonWhitePixels(x2, image.width() - x2, image);
+ const int x1 = qFloor(image.width() - text->implicitWidth() * view.devicePixelRatio()) / 2;
+ const int x2 = image.width() - x1;
+ const int left = numberOfNonWhitePixels(0, x1, image);
+ const int mid = numberOfNonWhitePixels(x1, x2 - x1, image);
+ const int right = numberOfNonWhitePixels(x2, image.width(), image);
QCOMPARE(left, 0);
QVERIFY2(mid > 0, msgNotGreaterThan(left, 0).constData());
QCOMPARE(right, 0);
}
{
- // Right Align
- text->setHAlign(QQuickText::AlignRight);
+ // Left Align
+ text->setHAlign(QQuickTextEdit::AlignLeft);
QImage image = view.grabWindow();
- int x = image.width() - qCeil(text->implicitWidth() * view.devicePixelRatio());
- int left = numberOfNonWhitePixels(0, x, image);
- int right = numberOfNonWhitePixels(x, image.width() - x, image);
- QCOMPARE(left, 0);
- QVERIFY2(right > 0, msgNotGreaterThan(left, 0).constData());
+ const int x = qCeil(text->implicitWidth() * view.devicePixelRatio());
+ const int left = numberOfNonWhitePixels(0, x, image);
+ const int right = numberOfNonWhitePixels(x, image.width() - x, image);
+ QVERIFY2(left > 0, msgNotGreaterThan(left, 0).constData());
+ QCOMPARE(right, 0);
}
}
@@ -3385,11 +3390,6 @@ bool tst_qquicktextedit::isMainFontFixed()
return ret;
}
-bool tst_qquicktextedit::hasWindowActivation()
-{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
-}
-
void tst_qquicktextedit::textInput()
{
QQuickView view(testFileUrl("inputMethodEvent.qml"));
@@ -3951,6 +3951,105 @@ void tst_qquicktextedit::renderingAroundSelection()
QTRY_COMPARE(textItem->sortedLinePositions, sortedLinePositions);
}
+struct OffsetAndExpectedBlocks {
+ int tableIndex; // which nested frame
+ qreal tableOffset; // fraction of that frame's height to scroll to
+ int minExpectedBlockCount;
+
+ OffsetAndExpectedBlocks(int i, qreal o, int c)
+ : tableIndex(i), tableOffset(o), minExpectedBlockCount(c) {}
+};
+
+typedef QList<OffsetAndExpectedBlocks> OffsetAndExpectedBlocksList;
+
+void tst_qquicktextedit::largeTextTables_data()
+{
+ QTest::addColumn<int>("tables");
+ QTest::addColumn<int>("tableCols");
+ QTest::addColumn<int>("tableRows");
+ QTest::addColumn<OffsetAndExpectedBlocksList>("steps");
+
+ QTest::newRow("one big table") << 1 << 3 << 70
+ << OffsetAndExpectedBlocksList{
+ OffsetAndExpectedBlocks(1, 0.75, 150),
+ OffsetAndExpectedBlocks(1, 0.5, 150)};
+ QTest::newRow("short tables") << 5 << 3 << 10
+ << OffsetAndExpectedBlocksList{
+ OffsetAndExpectedBlocks(4, 0.75, 35),
+ OffsetAndExpectedBlocks(3, 0.25, 50),
+ OffsetAndExpectedBlocks(2, 0.75, 50)};
+}
+
+void tst_qquicktextedit::largeTextTables() // QTBUG-118636
+{
+ QFETCH(int, tables);
+ QFETCH(int, tableCols);
+ QFETCH(int, tableRows);
+ QFETCH(OffsetAndExpectedBlocksList, steps);
+
+ QStringList lines;
+
+ lines << QLatin1String("<h1>") + QTest::currentDataTag() + "</h1>";
+ for (int t = 0; t < tables; ++t) {
+ if (t > 0)
+ lines << QString("<p>table %1</p>").arg(t);
+ lines << "<table border='1'>";
+ for (int r = 0; r < tableRows; ++r) {
+ lines << " <tr>";
+ for (int c = 0; c < tableCols; ++c)
+ lines << QString(" <td>table %1 cell %2, %3</td>").arg(t).arg(c).arg(r);
+ lines << " </tr>";
+ }
+ lines << "</table>";
+ }
+ lines << "<p>here endeth the tables</p>";
+ QString html = lines.join('\n');
+
+#ifdef DEBUG_WRITE_INPUT
+ QFile f(QLatin1String("/tmp/") + QTest::currentDataTag() + ".html");
+ f.open(QFile::WriteOnly);
+ f.write(html.toUtf8());
+ f.close();
+#endif
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("inFlickable.qml")));
+ QQuickFlickable *flick = qmlobject_cast<QQuickFlickable *>(window.rootObject());
+ QVERIFY(flick);
+ QQuickTextEdit *te = window.rootObject()->findChild<QQuickTextEdit *>();
+ QVERIFY(te);
+ auto *tePriv = QQuickTextEditPrivate::get(te);
+ auto font = te->font();
+ font.setPixelSize(10);
+ te->setFont(font);
+
+ te->setTextFormat(QQuickTextEdit::RichText);
+ te->setText(html);
+ te->setFlag(QQuickItem::ItemObservesViewport); // this isn't "large text", but test viewporting anyway
+
+ QTextDocument *doc = te->textDocument()->textDocument();
+ QList<QTextFrame *> frames = doc->rootFrame()->childFrames();
+ frames.prepend(doc->rootFrame());
+ qCDebug(lcTests) << "blocks" << doc->blockCount() << "chars" << doc->characterCount() << "frames" << frames;
+
+ for (const OffsetAndExpectedBlocks &oeb : steps) {
+ QCOMPARE_GT(frames.size(), oeb.tableIndex);
+ const QTextFrame *textFrame = frames.at(oeb.tableIndex);
+ const QTextCursor top = textFrame->firstCursorPosition();
+ const qreal yTop = te->positionToRectangle(top.position()).top();
+ const QTextCursor bottom = textFrame->lastCursorPosition();
+ const qreal yBottom = te->positionToRectangle(bottom.position()).bottom();
+ const qreal y = yTop + (yBottom - yTop) * oeb.tableOffset;
+ qCDebug(lcTests) << "frame" << textFrame << "goes from pos" << top.position() << "y" << yTop
+ << "to pos" << bottom.position() << "y" << yBottom << "; scrolling to" << y
+ << "which is at" << oeb.tableOffset << "of table height" << (yBottom - yTop);
+ flick->setContentY(y);
+ qCDebug(lcTests) << tePriv->renderedRegion << "rendered blocks" << tePriv->renderedBlockCount << ":"
+ << tePriv->firstBlockInViewport << "to" << tePriv->firstBlockPastViewport;
+ QTRY_COMPARE_GE(tePriv->renderedBlockCount, oeb.minExpectedBlockCount);
+ }
+}
+
void tst_qquicktextedit::signal_editingfinished()
{
QQuickView *window = new QQuickView(nullptr);
@@ -6483,8 +6582,8 @@ void tst_qquicktextedit::touchscreenDoesNotSelect()
void tst_qquicktextedit::touchscreenSetsFocusAndMovesCursor()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
+
QQuickView window;
QVERIFY(QQuickTest::showView(window, testFileUrl("twoInAColumn.qml")));
window.requestActivate();
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index 5e2d49afb8..c944406e10 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -5,6 +5,7 @@
#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuickTestUtils/private/testhttpserver_p.h>
#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <private/qinputmethod_p.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
@@ -212,7 +213,6 @@ private:
#if QT_CONFIG(shortcut)
void simulateKeys(QWindow *window, const QKeySequence &sequence);
#endif
- static bool hasWindowActivation();
QQmlEngine engine;
QStringList standard;
@@ -238,11 +238,6 @@ void tst_qquicktextinput::simulateKeys(QWindow *window, const QList<Key> &keys)
}
}
-bool tst_qquicktextinput::hasWindowActivation()
-{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
-}
-
#if QT_CONFIG(shortcut)
void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequence)
@@ -7191,17 +7186,15 @@ void tst_qquicktextinput::touchscreenDoesNotSelect()
QTest::touchEvent(&window, touchscreen.data()).press(0, QPoint(x2,y), &window);
QTest::touchEvent(&window, touchscreen.data()).release(0, QPoint(x2,y), &window);
QQuickTouchUtils::flush(&window);
- QCOMPARE(textInputObject->selectedText().isEmpty(), !expectDefaultSelectByMouse);
- if (expectDefaultSelectByMouse)
- QCOMPARE(textInputObject->cursorPosition(), cursorPos);
- else
- QCOMPARE_NE(textInputObject->cursorPosition(), cursorPos);
+ QCOMPARE(textInputObject->selectedText().isEmpty(), true);
+ QCOMPARE_NE(textInputObject->cursorPosition(), cursorPos);
+ QVERIFY(textInputObject->selectedText().isEmpty());
}
void tst_qquicktextinput::touchscreenSetsFocusAndMovesCursor()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
+
QQuickView window;
QVERIFY(QQuickTest::showView(window, testFileUrl("twoInAColumn.qml")));
window.requestActivate();
diff --git a/tests/auto/quick/qquickview_extra/data/qtbug_87228.qml b/tests/auto/quick/qquickview_extra/data/qtbug_87228.qml
index ff10eba23d..9327daae6b 100644
--- a/tests/auto/quick/qquickview_extra/data/qtbug_87228.qml
+++ b/tests/auto/quick/qquickview_extra/data/qtbug_87228.qml
@@ -15,6 +15,8 @@ Item {
Rectangle {
ListView {
objectName: "listView"
+ width: 100
+ height: 100
delegate: Text {
required property string desc
text: desc
diff --git a/tests/auto/quick/softwarerenderer/tst_softwarerenderer.cpp b/tests/auto/quick/softwarerenderer/tst_softwarerenderer.cpp
index 2d2581a3fa..2124a8ee8f 100644
--- a/tests/auto/quick/softwarerenderer/tst_softwarerenderer.cpp
+++ b/tests/auto/quick/softwarerenderer/tst_softwarerenderer.cpp
@@ -56,10 +56,8 @@ void tst_SoftwareRenderer::renderTarget()
rc.polishItems();
- rc.beginFrame();
rc.sync();
rc.render();
- rc.endFrame();
QImage content = window->grabWindow();
QString errorMessage;
@@ -74,10 +72,8 @@ void tst_SoftwareRenderer::renderTarget()
rc.polishItems();
- rc.beginFrame();
rc.sync();
rc.render();
- rc.endFrame();
content = window->grabWindow();
QVERIFY2(QQuickVisualTestUtils::compareImages(content, renderTarget2, &errorMessage),
diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
index d7820996be..179acbc728 100644
--- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp
+++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
@@ -244,6 +244,8 @@ private slots:
void strayTouchDoesntAutograb();
+ void noDoubleClickWithInterveningTouch();
+
protected:
bool eventFilter(QObject *, QEvent *event) override
{
@@ -1303,7 +1305,7 @@ void tst_TouchMouse::touchGrabCausesMouseUngrab()
QVERIFY(leftItem);
EventItem *rightItem = window.rootObject()->findChild<EventItem*>("rightItem");
- QVERIFY(leftItem);
+ QVERIFY(rightItem);
// Send a touch to the leftItem. But leftItem accepts only mouse events, thus
// a mouse event will be synthesized out of this touch and will get accepted by
@@ -1660,6 +1662,58 @@ void tst_TouchMouse::strayTouchDoesntAutograb() // QTBUG-107867
QTest::touchEvent(&window, device).release(0, p1).release(1, p1);
}
+void tst_TouchMouse::noDoubleClickWithInterveningTouch() // QTBUG-116442
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("twosiblingitems.qml")));
+
+ EventItem *leftItem = window.rootObject()->findChild<EventItem*>("leftItem");
+ QVERIFY(leftItem);
+ // simulate a MouseArea: don't accept touch
+ leftItem->setAcceptedMouseButtons(Qt::LeftButton);
+ leftItem->acceptMouse = true;
+
+ EventItem *rightItem = window.rootObject()->findChild<EventItem*>("rightItem");
+ QVERIFY(rightItem);
+ // simulate an item that reacts to either touch or mouse
+ rightItem->setAcceptedMouseButtons(Qt::LeftButton);
+ rightItem->acceptMouse = true;
+ rightItem->setAcceptTouchEvents(true);
+ rightItem->acceptTouch = true;
+
+ const QPoint pLeft(80, 200);
+ const QPoint pRight(240, 200);
+
+ // tap left
+ QTest::touchEvent(&window, device).press(1, pLeft, &window);
+ QTest::touchEvent(&window, device).release(1, pLeft, &window);
+ QQuickTouchUtils::flush(&window);
+ qCDebug(lcTests) << "left tap" << leftItem->eventList;
+ QCOMPARE(leftItem->eventList.size(), 3);
+ QCOMPARE(leftItem->eventList.at(0).type, QEvent::MouseButtonPress);
+ leftItem->eventList.clear();
+
+ // tap right
+ QTest::touchEvent(&window, device).press(1, pRight, &window);
+ QTest::touchEvent(&window, device).release(1, pRight, &window);
+ QQuickTouchUtils::flush(&window);
+ qCDebug(lcTests) << "right tap" << rightItem->eventList;
+ QCOMPARE(rightItem->eventList.size(), 2);
+ QCOMPARE(rightItem->eventList.at(0).type, QEvent::TouchBegin);
+ rightItem->eventList.clear();
+
+ // tap left again: this is NOT a double-click, even though it's within time and space limits
+ QTest::touchEvent(&window, device).press(3, pLeft, &window);
+ QTest::touchEvent(&window, device).release(3, pLeft, &window);
+ QQuickTouchUtils::flush(&window);
+ qCDebug(lcTests) << "left tap again" << leftItem->eventList;
+ QCOMPARE(leftItem->eventList.size(), 3);
+ QCOMPARE(leftItem->eventList.at(0).type, QEvent::MouseButtonPress);
+ QCOMPARE(leftItem->eventList.at(1).type, QEvent::MouseButtonRelease);
+ QCOMPARE(leftItem->eventList.at(2).type, QEvent::UngrabMouse);
+ leftItem->eventList.clear();
+}
+
QTEST_MAIN(tst_TouchMouse)
#include "tst_touchmouse.moc"