From ebf07c3f68415099132856b2831633c310bc3395 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 14 Apr 2015 14:55:24 +0200 Subject: Flickable: avoid infinite velocity during release after drag It sometimes happens on touchscreens that mouse events occur too close together. We cannot calculate velocity based on zero elapsed time, so just ignore the event. Task-number: QTBUG-45527 Change-Id: I120e73cfa60e2fcc594cb1f3b69f530e746abddd Reviewed-by: Timur Pocheptsov --- tests/auto/qmltest/listview/tst_listview.qml | 4 ++++ tests/auto/quick/qquickflickable/tst_qquickflickable.cpp | 1 + .../tst_qquickmultipointtoucharea.cpp | 8 ++++++++ tests/auto/quick/touchmouse/tst_touchmouse.cpp | 13 +++++++++++++ 4 files changed, 26 insertions(+) (limited to 'tests/auto') diff --git a/tests/auto/qmltest/listview/tst_listview.qml b/tests/auto/qmltest/listview/tst_listview.qml index a3cae7fce2..ef9f73e005 100644 --- a/tests/auto/qmltest/listview/tst_listview.qml +++ b/tests/auto/qmltest/listview/tst_listview.qml @@ -304,9 +304,13 @@ Item { function test_listInteractiveCurrentIndexEnforce() { mousePress(listInteractiveCurrentIndexEnforce, 10, 50); + wait(1); // because Flickable pays attention to velocity, we need some time between movements mouseMove(listInteractiveCurrentIndexEnforce, 10, 40); + wait(1); mouseMove(listInteractiveCurrentIndexEnforce, 10, 30); + wait(1); mouseMove(listInteractiveCurrentIndexEnforce, 10, 20); + wait(1); mouseMove(listInteractiveCurrentIndexEnforce, 10, 10); compare(listInteractiveCurrentIndexEnforce.interactive, false); mouseRelease(listInteractiveCurrentIndexEnforce, 10, 10); diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 2e134ff5ad..294f7069c0 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -1466,6 +1466,7 @@ void tst_qquickflickable::flickWithTouch(QQuickWindow *window, QTouchDevice *tou for (int i = 1; i <= 8; ++i) { QTest::touchEvent(window, touchDevice).move(0, from + i*diff/8, window); QQuickTouchUtils::flush(window); + QTest::qWait(1); // because Flickable pays attention to velocity, we need some time between movements } QTest::touchEvent(window, touchDevice).release(0, to, window); QQuickTouchUtils::flush(window); diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp index 2f432e57bc..d3b576e092 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp +++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -601,18 +601,22 @@ void tst_QQuickMultiPointTouchArea::inFlickable() QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); + QTest::qWait(1); // because Flickable pays attention to velocity, we need some time between movements QTest::touchEvent(window.data(), device).move(0, p1); QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); + QTest::qWait(1); QTest::touchEvent(window.data(), device).move(0, p1); QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); + QTest::qWait(1); QTest::touchEvent(window.data(), device).move(0, p1); QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); + QTest::qWait(1); QTest::touchEvent(window.data(), device).move(0, p1); QQuickTouchUtils::flush(window.data()); @@ -788,18 +792,22 @@ void tst_QQuickMultiPointTouchArea::inFlickable2() QCOMPARE(point11->pressed(), true); p1 += QPoint(0,15); + QTest::qWait(1); QTest::touchEvent(window.data(), device).move(0, p1); QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); + QTest::qWait(1); QTest::touchEvent(window.data(), device).move(0, p1); QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); + QTest::qWait(1); QTest::touchEvent(window.data(), device).move(0, p1); QQuickTouchUtils::flush(window.data()); p1 += QPoint(0,15); + QTest::qWait(1); QTest::touchEvent(window.data(), device).move(0, p1); QQuickTouchUtils::flush(window.data()); diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index e14b7d7c84..0608af7cd4 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -591,10 +591,13 @@ void tst_TouchMouse::buttonOnFlickable() QPoint p2 = p1 + QPoint(0, -10); QPoint p3 = p2 + QPoint(0, -10); QQuickTouchUtils::flush(window); + QTest::qWait(1); // because Flickable pays attention to velocity, we need some time between movements QTest::touchEvent(window, device).move(0, p1, window); QQuickTouchUtils::flush(window); + QTest::qWait(1); QTest::touchEvent(window, device).move(0, p2, window); QQuickTouchUtils::flush(window); + QTest::qWait(1); QTest::touchEvent(window, device).move(0, p3, window); QQuickTouchUtils::flush(window); @@ -676,10 +679,13 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() QPoint p2 = p1 + QPoint(0, -10); QPoint p3 = p2 + QPoint(0, -10); QQuickTouchUtils::flush(window); + QTest::qWait(1); QTest::touchEvent(window, device).move(0, p1, window); QQuickTouchUtils::flush(window); + QTest::qWait(1); QTest::touchEvent(window, device).move(0, p2, window); QQuickTouchUtils::flush(window); + QTest::qWait(1); QTest::touchEvent(window, device).move(0, p3, window); QQuickTouchUtils::flush(window); QVERIFY(flickable->isMovingVertically()); @@ -871,15 +877,19 @@ void tst_TouchMouse::pinchOnFlickable() QQuickTouchUtils::flush(window); QCOMPARE(rect->position(), QPointF(200.0, 200.0)); p -= QPoint(10, 0); + QTest::qWait(1); QTest::touchEvent(window, device).move(0, p, window); QQuickTouchUtils::flush(window); p -= QPoint(10, 0); + QTest::qWait(1); QTest::touchEvent(window, device).move(0, p, window); QQuickTouchUtils::flush(window); p -= QPoint(10, 0); + QTest::qWait(1); QTest::touchEvent(window, device).move(0, p, window); QQuickTouchUtils::flush(window); p -= QPoint(10, 0); + QTest::qWait(1); QTest::touchEvent(window, device).move(0, p, window); QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).release(0, p, window); @@ -1092,13 +1102,16 @@ void tst_TouchMouse::mouseOnFlickableOnPinch() QQuickTouchUtils::flush(window); QCOMPARE(rect->position(), QPointF(200.0, 200.0)); p -= QPoint(10, 0); + QTest::qWait(1); pinchSequence.move(0, p, window).commit(); QQuickTouchUtils::flush(window); p -= QPoint(10, 0); + QTest::qWait(1); pinchSequence.move(0, p, window).commit(); QQuickTouchUtils::flush(window); QGuiApplication::processEvents(); p -= QPoint(10, 0); + QTest::qWait(1); pinchSequence.move(0, p, window).commit(); QQuickTouchUtils::flush(window); -- cgit v1.2.3 From 68bfc9332cd65c1eb88d1ec87164447b0db43237 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 25 Jul 2016 16:07:16 +0200 Subject: Fix crash with Component.onDestruction A call to a handler of Component.onDestruction may end up causing WeakValues such as QQmlData::jsWrapper to be set again, even though they've been set to undefined in an earlier iteration of the loop that walks through the weak references. That in turn may result in invalid object references to objects that are scheduled for destruction by the collector. So after calling all destroy handlers for QObjects, reset all of the weak values again. Task-number: QTBUG-54939 Change-Id: I00ebabb76274e296fb1bd90d8d3e21dbbb920b57 Reviewed-by: Lars Knoll --- .../qml/qqmlecmascript/data/DestructionHelper.qml | 3 + .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 102 +++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 tests/auto/qml/qqmlecmascript/data/DestructionHelper.qml (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlecmascript/data/DestructionHelper.qml b/tests/auto/qml/qqmlecmascript/data/DestructionHelper.qml new file mode 100644 index 0000000000..8bb0a3554e --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/DestructionHelper.qml @@ -0,0 +1,3 @@ +import Test 1.0 +WeakReferenceMutator { +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index b3b31e1a73..d65cec843c 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -49,6 +49,8 @@ #include #include #include +#include +#include #ifdef Q_CC_MSVC #define NO_INLINE __declspec(noinline) @@ -287,6 +289,7 @@ private slots: void replaceBinding(); void deleteRootObjectInCreation(); void onDestruction(); + void onDestructionViaGC(); void bindingSuppression(); void signalEmitted(); void threadSignal(); @@ -7157,6 +7160,105 @@ void tst_qqmlecmascript::onDestruction() } } +class WeakReferenceMutator : public QObject +{ + Q_OBJECT +public: + WeakReferenceMutator() + : resultPtr(Q_NULLPTR) + , weakRef(Q_NULLPTR) + {} + + void init(QV4::ExecutionEngine *v4, QV4::WeakValue *weakRef, bool *resultPtr) + { + QV4::QObjectWrapper::wrap(v4, this); + QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); + + this->resultPtr = resultPtr; + this->weakRef = weakRef; + + QObject::connect(QQmlComponent::qmlAttachedProperties(this), &QQmlComponentAttached::destruction, this, &WeakReferenceMutator::reviveFirstWeakReference); + } + +private slots: + void reviveFirstWeakReference() { + *resultPtr = weakRef->valueRef() && weakRef->isNullOrUndefined(); + if (!*resultPtr) + return; + QV4::ExecutionEngine *v4 = QV8Engine::getV4(qmlEngine(this)); + weakRef->set(v4, v4->newObject()); + *resultPtr = weakRef->valueRef() && !weakRef->isNullOrUndefined(); + } + +public: + bool *resultPtr; + + QV4::WeakValue *weakRef; +}; + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +namespace Heap { +struct WeakReferenceSentinel : public Object { + WeakReferenceSentinel(WeakValue *weakRef, bool *resultPtr) + : weakRef(weakRef) + , resultPtr(resultPtr) { + + } + + ~WeakReferenceSentinel() { + *resultPtr = weakRef->isNullOrUndefined(); + } + + WeakValue *weakRef; + bool *resultPtr; +}; +} // namespace Heap + +struct WeakReferenceSentinel : public Object { + V4_OBJECT2(WeakReferenceSentinel, Object) + V4_NEEDS_DESTROY +}; + +} // namespace QV4 + +QT_END_NAMESPACE + +DEFINE_OBJECT_VTABLE(QV4::WeakReferenceSentinel); + +void tst_qqmlecmascript::onDestructionViaGC() +{ + qmlRegisterType("Test", 1, 0, "WeakReferenceMutator"); + + QQmlEngine engine; + QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine); + + QQmlComponent component(&engine, testFileUrl("DestructionHelper.qml")); + + QScopedPointer weakRef; + + bool mutatorResult = false; + bool sentinelResult = false; + + { + weakRef.reset(new QV4::WeakValue); + weakRef->set(v4, v4->newObject()); + QVERIFY(!weakRef->isNullOrUndefined()); + + QPointer weakReferenceMutator = qobject_cast(component.create()); + QVERIFY2(!weakReferenceMutator.isNull(), qPrintable(component.errorString())); + weakReferenceMutator->init(v4, weakRef.data(), &mutatorResult); + + v4->memoryManager->allocObject(weakRef.data(), &sentinelResult); + } + gc(engine); + + QVERIFY2(mutatorResult, "We failed to re-assign the weak reference a new value during GC"); + QVERIFY2(sentinelResult, "The weak reference was not cleared properly"); +} + struct EventProcessor : public QObject { Q_OBJECT -- cgit v1.2.3 From 35597f301480ffc59f598be4de2c2074543725be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Thu, 2 Jun 2016 12:08:29 +0200 Subject: Fix char conversions in QML This is a partial revert of 90b06e2773842, as it had unwanted side effects. The original intention was to make assignment from char to string possible, or more specifically, we wanted a solution where a QChar could be assigned to a QString, as a character and not a string representation of its value. While this behavior is desirable for QChar, we most likely want the opposite for the regular character types. Task-number: QTBUG-49232 Change-Id: I82d5f72b900fe984c4db1478fd52a9eb69ad2ee6 Reviewed-by: Michael Brasser Reviewed-by: Simon Hausmann --- tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp | 29 ++++++++++++++++ tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 42 ++---------------------- 2 files changed, 32 insertions(+), 39 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index d338e6f5ad..739af3782e 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -66,6 +66,7 @@ private slots: void qtbug_22535(); void evalAfterInvalidate(); void qobjectDerived(); + void qtbug_49232(); private: QQmlEngine engine; @@ -205,6 +206,8 @@ class TestObject : public QObject Q_PROPERTY(int a READ a NOTIFY aChanged) Q_PROPERTY(int b READ b NOTIFY bChanged) Q_PROPERTY(int c READ c NOTIFY cChanged) + Q_PROPERTY(char d READ d NOTIFY dChanged) + Q_PROPERTY(uchar e READ e NOTIFY eChanged) public: TestObject() : _a(10), _b(10), _c(10) {} @@ -218,15 +221,25 @@ public: int c() const { return _c; } void setC(int c) { _c = c; emit cChanged(); } + char d() const { return _d; } + void setD(char d) { _d = d; emit dChanged(); } + + uchar e() const { return _e; } + void setE(uchar e) { _e = e; emit eChanged(); } + signals: void aChanged(); void bChanged(); void cChanged(); + void dChanged(); + void eChanged(); private: int _a; int _b; int _c; + char _d; + uchar _e; }; #define TEST_CONTEXT_PROPERTY(ctxt, name, value) \ @@ -699,6 +712,22 @@ void tst_qqmlcontext::qobjectDerived() QCOMPARE(command.count, 2); } +void tst_qqmlcontext::qtbug_49232() +{ + TestObject testObject; + testObject.setD('a'); + testObject.setE(97); + + QQmlEngine engine; + engine.rootContext()->setContextProperty("TestObject", &testObject); + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0; QtObject { property int valueOne: TestObject.d; property int valueTwo: TestObject.e }", QUrl()); + QScopedPointer obj(component.create()); + + QCOMPARE(obj->property("valueOne"), QVariant('a')); + QCOMPARE(obj->property("valueTwo"), QVariant(97)); +} + QTEST_MAIN(tst_qqmlcontext) #include "tst_qqmlcontext.moc" diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 6ada14ce79..86c13065fa 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -329,11 +329,8 @@ class PropertyObject : public QObject Q_PROPERTY(MyQmlObject *qmlObject READ qmlObject) Q_PROPERTY(MyQObject *qObject READ qObject WRITE setQObject NOTIFY qObjectChanged) Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty) - Q_PROPERTY(char charProperty READ charProperty WRITE setCharProperty) Q_PROPERTY(QChar qcharProperty READ qcharProperty WRITE setQcharProperty) Q_PROPERTY(QChar constQChar READ constQChar STORED false CONSTANT FINAL) - Q_PROPERTY(char constChar READ constChar STORED false CONSTANT FINAL) - Q_PROPERTY(int constInt READ constInt STORED false CONSTANT FINAL) Q_CLASSINFO("DefaultProperty", "defaultProperty") public: @@ -370,15 +367,11 @@ public: } QString stringProperty() const { return m_stringProperty;} - char charProperty() const { return m_charProperty; } QChar qcharProperty() const { return m_qcharProperty; } QChar constQChar() const { return 0x25cf; /* Unicode: black circle */ } - char constChar() const { return 'A'; } - int constInt() const { return 123456; } void setStringProperty(QString arg) { m_stringProperty = arg; } - void setCharProperty(char arg) { m_charProperty = arg; } void setQcharProperty(QChar arg) { m_qcharProperty = arg; } signals: @@ -395,7 +388,6 @@ private: MyQmlObject m_qmlObject; MyQObject *m_qObject; QString m_stringProperty; - char m_charProperty; QChar m_qcharProperty; }; @@ -1408,23 +1400,14 @@ void tst_qqmlproperty::write() // Char/string-property { PropertyObject o; - QQmlProperty charProperty(&o, "charProperty"); QQmlProperty qcharProperty(&o, "qcharProperty"); QQmlProperty stringProperty(&o, "stringProperty"); const int black_circle = 0x25cf; - QCOMPARE(charProperty.write(QString("foo")), false); - QCOMPARE(charProperty.write('Q'), true); - QCOMPARE(charProperty.read(), QVariant('Q')); - QCOMPARE(charProperty.write(QString("t")), true); - QCOMPARE(charProperty.read(), QVariant('t')); - QCOMPARE(qcharProperty.write(QString("foo")), false); QCOMPARE(qcharProperty.write('Q'), true); QCOMPARE(qcharProperty.read(), QVariant('Q')); - QCOMPARE(qcharProperty.write(QString("t")), true); - QCOMPARE(qcharProperty.read(), QVariant('t')); QCOMPARE(qcharProperty.write(QChar(black_circle)), true); QCOMPARE(qcharProperty.read(), QVariant(QChar(black_circle))); @@ -1433,19 +1416,10 @@ void tst_qqmlproperty::write() QCOMPARE(o.stringProperty(), QString("bar")); QCOMPARE(stringProperty.write(QVariant(1234)), true); QCOMPARE(stringProperty.read().toString(), QString::number(1234)); + QCOMPARE(stringProperty.write('A'), true); + QCOMPARE(stringProperty.read().toString(), QString::number('A')); QCOMPARE(stringProperty.write(QChar(black_circle)), true); - QCOMPARE(stringProperty.read(), QVariant(QString(QChar(black_circle)))); - - { // char -> QString - QQmlComponent component(&engine); - component.setData("import Test 1.0\nPropertyObject { stringProperty: constChar }", QUrl()); - PropertyObject *obj = qobject_cast(component.create()); - QVERIFY(obj != 0); - if (obj) { - QQmlProperty stringProperty(obj, "stringProperty"); - QCOMPARE(stringProperty.read(), QVariant(QString(obj->constChar()))); - } - } + QCOMPARE(stringProperty.read(), QVariant(QChar(black_circle))); { // QChar -> QString QQmlComponent component(&engine); @@ -1458,16 +1432,6 @@ void tst_qqmlproperty::write() } } - { // int -> QString - QQmlComponent component(&engine); - component.setData("import Test 1.0\nPropertyObject { stringProperty: constInt }", QUrl()); - PropertyObject *obj = qobject_cast(component.create()); - QVERIFY(obj != 0); - if (obj) { - QQmlProperty stringProperty(obj, "stringProperty"); - QCOMPARE(stringProperty.read(), QVariant(QString::number(obj->constInt()))); - } - } } // VariantMap-property -- cgit v1.2.3 From 273e5b0bdc1239df77e2e5694fdd5ad068595be3 Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Tue, 24 May 2016 12:21:39 +0300 Subject: PathView: fix item creation First call of QQuickPathView::refill() did not use currentIndex for item prepending and there was situation when items were not created, e.g.: PathView with current item in center and currentIndex was set so that item with index 0 was after current item and before path end. The result of this situation: items from path begin to current item were not created. The reason was that idx always equaled (modelCount-1) for item prepending. Now first filling uses currentIndex to calculate valid idx. Task-number: QTBUG-53464 Change-Id: I7e343b0712c9c5c5cd56b1d8e020cf8c0f6e6301 Reviewed-by: Shawn Rutledge --- .../auto/quick/qquickpathview/data/qtbug53464.qml | 77 ++++++++++++++++++++++ .../quick/qquickpathview/tst_qquickpathview.cpp | 24 +++++++ 2 files changed, 101 insertions(+) create mode 100644 tests/auto/quick/qquickpathview/data/qtbug53464.qml (limited to 'tests/auto') diff --git a/tests/auto/quick/qquickpathview/data/qtbug53464.qml b/tests/auto/quick/qquickpathview/data/qtbug53464.qml new file mode 100644 index 0000000000..d30d404e68 --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/qtbug53464.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Netris +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + width: 600 + height: 400 + PathView { + objectName: "pathView" + model: 10 + anchors.fill: parent + pathItemCount: 5 + highlightRangeMode: PathView.StrictlyEnforceRange + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + currentIndex: 8 + + path: Path { + startX: 0 + startY: 50 + PathLine { + x: 600 + y: 50 + } + } + + delegate: Component { + Text { + width: 50 + height: 50 + text: index + objectName: "delegate" + index + font.pixelSize: 24 + color: PathView.isCurrentItem ? "green" : "black" + } + } + } +} + diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index fc5dd3bbca..2046391d02 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -141,6 +141,7 @@ private slots: void flickableDelegate(); void jsArrayChange(); void qtbug42716(); + void qtbug53464(); void addCustomAttribute(); }; @@ -2381,6 +2382,29 @@ void tst_QQuickPathView::qtbug42716() QVERIFY(!itemMiss); } +void tst_QQuickPathView::qtbug53464() +{ + QScopedPointer window(createView()); + + window->setSource(testFileUrl("qtbug53464.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + QQuickPathView *pathView = findItem(window->rootObject(), "pathView"); + QVERIFY(pathView != Q_NULLPTR); + const int currentIndex = pathView->currentIndex(); + QCOMPARE(currentIndex, 8); + + const int pathItemCount = pathView->pathItemCount(); + int totalCount = 0; + foreach (QQuickItem *item, pathView->childItems()) { + if (item->objectName().startsWith(QLatin1String("delegate"))) + ++totalCount; + } + QCOMPARE(pathItemCount, totalCount); +} + void tst_QQuickPathView::addCustomAttribute() { const QScopedPointer window(createView()); -- cgit v1.2.3 From 9010dd0e767c407f107aacfe6be145229e3ba793 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Fri, 12 Aug 2016 13:38:54 +0200 Subject: Fix test failure: wait between mouse events the proper way Apparently, QTest::mouseEvent() disregards the wall time for the time stamps for events, but synthesizes the timestamps instead. The proper way is to specify the waiting time in the delay argument. This will adjust both the timestamp and perform a qWait() before the event handler is called. Without this patch, the qWait(doubleClickInterval) was disregarded, which lead to that a doubleclick event was generated, and it failed with the following message: Actual (((window->rootObject()->property("doubleClicks").toInt()))): 2 Expected (1) : 1 tst_qquickmousearea.cpp(1105) : failure location Change-Id: Ieda3b670d3cda0bd522db2f9677dad5745c88a21 Reviewed-by: Shawn Rutledge --- .../quick/qquickmousearea/tst_qquickmousearea.cpp | 31 +++++++++------------- 1 file changed, 12 insertions(+), 19 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index 9cdfd21f9c..d51c228b7c 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -1032,17 +1032,17 @@ void tst_QQuickMouseArea::clickThrough() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QVERIFY(window->rootObject() != 0); + // to avoid generating a double click. + const int doubleClickInterval = qApp->styleHints()->mouseDoubleClickInterval() + 10; + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QTRY_COMPARE(window->rootObject()->property("presses").toInt(), 0); QTRY_COMPARE(window->rootObject()->property("clicks").toInt(), 1); - // to avoid generating a double click. - int doubleClickInterval = qApp->styleHints()->mouseDoubleClickInterval() + 10; - QTest::qWait(doubleClickInterval); - - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QCOMPARE(window->rootObject()->property("doubleClicks").toInt(), 0); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); @@ -1072,9 +1072,7 @@ void tst_QQuickMouseArea::clickThrough() QCOMPARE(window->rootObject()->property("presses").toInt(), 0); QCOMPARE(window->rootObject()->property("clicks").toInt(), 0); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QTest::qWait(100); @@ -1093,15 +1091,13 @@ void tst_QQuickMouseArea::clickThrough() window->rootObject()->setProperty("letThrough", QVariant(true)); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QCOMPARE(window->rootObject()->property("presses").toInt(), 0); QTRY_COMPARE(window->rootObject()->property("clicks").toInt(), 1); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QTest::qWait(100); @@ -1120,12 +1116,10 @@ void tst_QQuickMouseArea::clickThrough() window->rootObject()->setProperty("noPropagation", QVariant(true)); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QTest::qWait(100); @@ -1146,7 +1140,7 @@ void tst_QQuickMouseArea::clickThrough() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QVERIFY(window->rootObject() != 0); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QCOMPARE(window->rootObject()->property("clicksEnabled").toInt(), 1); @@ -1154,8 +1148,7 @@ void tst_QQuickMouseArea::clickThrough() window->rootObject()->setProperty("disableLower", QVariant(true)); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QCOMPARE(window->rootObject()->property("clicksEnabled").toInt(), 2); -- cgit v1.2.3 From 6f15de1d2da9c83d7fca1d5c8243c0d69a1390ee Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Thu, 26 May 2016 14:45:31 +0300 Subject: PathView: fix infinite construction/destruction loop ... when all (or almost all) items are in the cache. When all items are in cache, check lower bound is equal to upper_bound. In rare cases, especially when almost all items are in cache, the inserting code was used (not only appending and prepending). In this code there was not bound check before creation of item and there was such situation: 1. Create item by inserting code (without bound check) 2. At the next call of refill() remove this item by life cycle because this item does not meet the conditions. And go to step 1. In other words at the first call we create some item, at the second remove this item. And again. So we had infinite construction/destruction loop. To break it we should check position of new item before creation in inserting code too (like we do in appending and prepending code). Task-number: QTBUG-37815 Change-Id: I015cdeb67ca5fcd06c34b3145b49cbd3e38d4078 Reviewed-by: Shawn Rutledge --- .../auto/quick/qquickpathview/data/qtbug37815.qml | 77 ++++++++++++++++++++++ .../quick/qquickpathview/tst_qquickpathview.cpp | 26 ++++++++ 2 files changed, 103 insertions(+) create mode 100644 tests/auto/quick/qquickpathview/data/qtbug37815.qml (limited to 'tests/auto') diff --git a/tests/auto/quick/qquickpathview/data/qtbug37815.qml b/tests/auto/quick/qquickpathview/data/qtbug37815.qml new file mode 100644 index 0000000000..3fd4daca63 --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/qtbug37815.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Netris +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Rectangle { + width: 600 + height: 400 + PathView { + objectName: "pathView" + model: 10 + anchors.fill: parent + pathItemCount: 5 + cacheItemCount: 5 + highlightRangeMode: PathView.StrictlyEnforceRange + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + + path: Path { + startX: 0 + startY: 50 + PathLine { + x: 600 + y: 50 + } + } + + delegate: Component { + Text { + width: 50 + height: 50 + text: index + objectName: "delegate" + index + font.pixelSize: 24 + color: PathView.isCurrentItem ? "green" : "black" + } + } + } +} + diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index 2046391d02..493af97521 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -140,6 +140,7 @@ private slots: void nestedinFlickable(); void flickableDelegate(); void jsArrayChange(); + void qtbug37815(); void qtbug42716(); void qtbug53464(); void addCustomAttribute(); @@ -2334,6 +2335,31 @@ void tst_QQuickPathView::jsArrayChange() QCOMPARE(spy.count(), 1); } +void tst_QQuickPathView::qtbug37815() +{ + QScopedPointer window(createView()); + + window->setSource(testFileUrl("qtbug37815.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + // cache items will be created async. Let's wait... + QTest::qWait(1000); + + QQuickPathView *pathView = findItem(window->rootObject(), "pathView"); + QVERIFY(pathView != Q_NULLPTR); + + const int pathItemCount = pathView->pathItemCount(); + const int cacheItemCount = pathView->cacheItemCount(); + int totalCount = 0; + foreach (QQuickItem *item, pathView->childItems()) { + if (item->objectName().startsWith(QLatin1String("delegate"))) + ++totalCount; + } + QCOMPARE(pathItemCount + cacheItemCount, totalCount); +} + /* This bug was one where if you jump the list such that the sole missing item needed to be * added in the middle of the list, it would instead move an item somewhere else in the list * to the middle (messing it up very badly). -- cgit v1.2.3