From 2e64e9e3d4bff0d93dd2671ef4aee72c566c55e1 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 1 Nov 2017 12:48:12 +0100 Subject: Prevent the QML engine from registering circular dependencies Change-Id: Ic4fd2bde745e7dfaf0909e8cc575441bb04cefa3 Task-number: QTBUG-64017 Reviewed-by: Lars Knoll Reviewed-by: Marco Martin Reviewed-by: Bhushan Shah --- src/qml/qml/qqmltypeloader.cpp | 10 +++++++++- src/qml/qml/qqmltypeloader_p.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 193acb04be..d9d7c19312 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -316,7 +316,8 @@ Returns true if the status is WaitingForDependencies. */ bool QQmlDataBlob::isWaiting() const { - return status() == WaitingForDependencies; + return status() == WaitingForDependencies || + status() == ResolvingDependencies; } /*! @@ -608,6 +609,7 @@ The default implementation does nothing. */ void QQmlDataBlob::allDependenciesDone() { + m_data.setStatus(QQmlDataBlob::ResolvingDependencies); } /*! @@ -2499,6 +2501,8 @@ void QQmlTypeData::continueLoadFromIR() void QQmlTypeData::allDependenciesDone() { + QQmlTypeLoader::Blob::allDependenciesDone(); + if (!m_typesResolved) { // Check that all imports were resolved QList errors; @@ -2618,6 +2622,10 @@ void QQmlTypeData::resolveTypes() if (ref.type.isCompositeSingleton()) { ref.typeData = typeLoader()->getType(ref.type.sourceUrl()); + if (ref.typeData->status() == QQmlDataBlob::ResolvingDependencies) { + // TODO: give an error message? If so, we should record and show the path of the cycle. + continue; + } addDependency(ref.typeData); ref.prefix = csRef.prefix; diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index ef63e02b4f..22ac61968f 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -98,6 +98,7 @@ public: Null, // Prior to QQmlTypeLoader::load() Loading, // Prior to data being received and dataReceived() being called WaitingForDependencies, // While there are outstanding addDependency()s + ResolvingDependencies, // While resolving outstanding dependencies, to detect cycles Complete, // Finished Error // Error }; -- cgit v1.2.3 From 5fc892ef86870021ad11d0be6981aa9630c1c01c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 6 Nov 2017 08:22:03 +0100 Subject: Fix coverity reported warning The variable wasn't initialized in any constructor. This didn't cause issues in practice, as it always got set in optimizeRenderList(). Change-Id: I37459bb2d51bbe2bb881aaefffd6972a5345c75d Reviewed-by: Andy Nichols --- .../scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h index c68a933384..f20c2cf977 100644 --- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h @@ -104,7 +104,7 @@ private: QRegion m_dirtyRegion; QRegion m_obscuredRegion; - bool m_isOpaque; + bool m_isOpaque = false; QSGSoftwareRenderableNodeUpdater *m_nodeUpdater; }; -- cgit v1.2.3 From 37d25a5112cdf13620715c03d6bdbd1bc3cde515 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 2 Dec 2015 09:51:35 +0100 Subject: QQuickWidget: pass enter and leave events to the offscreen window By passing the enter and leave events to the offscreen window it will enable mouse areas inside a QQuickWidget to know when the mouse has actually entered or left the area if it is covering the whole item. Task-number: QTBUG-45557 Change-Id: I670ebe30e367e919c73fed449bf2bed7ca42b5fd Reviewed-by: Gatis Paeglis --- src/quickwidgets/qquickwidget.cpp | 9 ++++++++ .../quickwidgets/qquickwidget/data/enterleave.qml | 12 +++++++++++ .../quickwidgets/qquickwidget/tst_qquickwidget.cpp | 25 ++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 tests/auto/quickwidgets/qquickwidget/data/enterleave.qml diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 4c4f5fa9f3..9e18ac2270 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -1398,6 +1398,7 @@ bool QQuickWidget::event(QEvent *e) switch (e->type()) { + case QEvent::Leave: case QEvent::TouchBegin: case QEvent::TouchEnd: case QEvent::TouchUpdate: @@ -1451,6 +1452,14 @@ bool QQuickWidget::event(QEvent *e) case QEvent::ShortcutOverride: return QCoreApplication::sendEvent(d->offscreenWindow, e); + case QEvent::Enter: { + QEnterEvent *enterEvent = static_cast(e); + QEnterEvent mappedEvent(enterEvent->localPos(), enterEvent->windowPos(), + enterEvent->screenPos()); + const bool ret = QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent); + e->setAccepted(mappedEvent.isAccepted()); + return ret; + } default: break; } diff --git a/tests/auto/quickwidgets/qquickwidget/data/enterleave.qml b/tests/auto/quickwidgets/qquickwidget/data/enterleave.qml new file mode 100644 index 0000000000..b3057e30ad --- /dev/null +++ b/tests/auto/quickwidgets/qquickwidget/data/enterleave.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +Rectangle { + property bool hasMouse: mouseArea.containsMouse + height: 200 + width: 200 + MouseArea { + id: mouseArea + hoverEnabled: true + anchors.fill: parent + } +} diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp index ee49c9c7ad..e4991a5f26 100644 --- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp +++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp @@ -61,6 +61,7 @@ private slots: void nullEngine(); void keyEvents(); void shortcuts(); + void enterLeave(); }; @@ -408,6 +409,30 @@ void tst_qquickwidget::shortcuts() QTRY_VERIFY(filter.shortcutOk); } +void tst_qquickwidget::enterLeave() +{ + QQuickWidget view; + view.setSource(testFileUrl("enterleave.qml")); + + // Ensure it is not inside the window first + QCursor::setPos(QPoint(50, 50)); + QTRY_VERIFY(QCursor::pos() == QPoint(50, 50)); + + view.move(100, 100); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view, 5000)); + QQuickItem *rootItem = view.rootObject(); + QVERIFY(rootItem); + + QTRY_VERIFY(!rootItem->property("hasMouse").toBool()); + // Check the enter + QCursor::setPos(view.pos() + QPoint(50, 50)); + QTRY_VERIFY(rootItem->property("hasMouse").toBool()); + // Now check the leave + QCursor::setPos(view.pos() - QPoint(50, 50)); + QTRY_VERIFY(!rootItem->property("hasMouse").toBool()); +} + QTEST_MAIN(tst_qquickwidget) #include "tst_qquickwidget.moc" -- cgit v1.2.3 From 75cc5fdc219c42ae26ec8497647eda5440c324f2 Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Mon, 6 Nov 2017 14:20:59 +0100 Subject: Never create pointer events from mouseGrabberItem() Normally, this was not a problem, but it is problematic during QQuickWindow destruction: The list of pointer event instances are destroyed, but later the grabber is removed (through call to removeGrabber()). This queries the mouseGrabberItem(), which would create a new pointer event instance. It also has the benefit that d->pointerEventInstances are now only populated due to actual incoming events. Task-number: QTBUG-61434 Change-Id: I4e7b6f5643f3b971138a1f7c7237ee734d29783c Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 38 +++++++++++++++++++++++--------------- src/quick/items/qquickwindow_p.h | 1 + 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index b58caa061a..112a338920 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -823,12 +823,13 @@ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool to if (Q_LIKELY(touch)) { const auto touchDevices = QQuickPointerDevice::touchDevices(); for (auto device : touchDevices) { - auto pointerEvent = pointerEventInstance(device); - for (int i = 0; i < pointerEvent->pointCount(); ++i) { - if (pointerEvent->point(i)->grabber() == grabber) { - pointerEvent->point(i)->setGrabber(nullptr); - // FIXME send ungrab event only once - grabber->touchUngrabEvent(); + if (auto pointerEvent = queryPointerEventInstance(device)) { + for (int i = 0; i < pointerEvent->pointCount(); ++i) { + if (pointerEvent->point(i)->grabber() == grabber) { + pointerEvent->point(i)->setGrabber(nullptr); + // FIXME send ungrab event only once + grabber->touchUngrabEvent(); + } } } } @@ -1492,14 +1493,15 @@ QQuickItem *QQuickWindow::mouseGrabberItem() const Q_D(const QQuickWindow); if (d->touchMouseId != -1 && d->touchMouseDevice) { - QQuickPointerEvent *event = d->pointerEventInstance(d->touchMouseDevice); - auto point = event->pointById(d->touchMouseId); - return point ? point->grabber() : nullptr; + if (QQuickPointerEvent *event = d->queryPointerEventInstance(d->touchMouseDevice)) { + auto point = event->pointById(d->touchMouseId); + return point ? point->grabber() : nullptr; + } + } else if (QQuickPointerEvent *event = d->queryPointerEventInstance(QQuickPointerDevice::genericMouseDevice())) { + Q_ASSERT(event->pointCount()); + return event->point(0)->grabber(); } - - QQuickPointerEvent *event = d->pointerEventInstance(QQuickPointerDevice::genericMouseDevice()); - Q_ASSERT(event->pointCount()); - return event->point(0)->grabber(); + return nullptr; } @@ -2111,15 +2113,21 @@ void QQuickWindowPrivate::flushFrameSynchronousEvents() } } -QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevice *device) const +QQuickPointerEvent *QQuickWindowPrivate::queryPointerEventInstance(QQuickPointerDevice *device) const { // the list of devices should be very small so a linear search should be ok for (QQuickPointerEvent *e: pointerEventInstances) { if (e->device() == device) return e; } + return nullptr; +} - QQuickPointerEvent *ev = nullptr; +QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevice *device) const +{ + QQuickPointerEvent *ev = queryPointerEventInstance(device); + if (ev) + return ev; QQuickWindow *q = const_cast(q_func()); switch (device->type()) { case QQuickPointerDevice::Mouse: diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index b3ff5a2b35..e47dde6464 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -164,6 +164,7 @@ public: // the device-specific event instances which are reused during event delivery mutable QVector pointerEventInstances; + QQuickPointerEvent *queryPointerEventInstance(QQuickPointerDevice *device) const; QQuickPointerEvent *pointerEventInstance(QQuickPointerDevice *device) const; // delivery of pointer events: -- cgit v1.2.3 From 4331ccd4b735d9d721a384193a3d42ee2ce6c805 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 14 Jul 2017 16:37:22 +0200 Subject: QQuickWindow: cleanup pointer event instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pointer event instances are QObject-children of QQuickWindow, meaning that they remain alive after ~QQuickWindow(), until execution reaches ~QObject(). Make sure the pointer event instances are cleaned up in ~QQuickWindow() to avoid accessing them later during the destruction phase. Task-number: QTBUG-61434 Change-Id: Icd4576e7581524773a3eb33864fdd64df821e0e8 Reviewed-by: Jan Arve Sæther Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 112a338920..70c8590ae7 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1292,6 +1292,8 @@ QQuickWindow::~QQuickWindow() delete d->dragGrabber; d->dragGrabber = 0; #endif delete d->contentItem; d->contentItem = 0; + qDeleteAll(d->pointerEventInstances); + d->pointerEventInstances.clear(); d->renderJobMutex.lock(); qDeleteAll(d->beforeSynchronizingJobs); -- cgit v1.2.3 From 54f15f5df5cf545bf4d675ccbafecd482b4a2b0b Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Mon, 23 Oct 2017 13:51:43 +0300 Subject: Fix ListView::positionViewAtIndex with ListView.Contain mode Sticky headers and footers weren't accounted for when calculating new view position causing the requested item to be left behind them. Task-number: QTBUG-63974 Change-Id: Id69579643a942e8558960b2c8b0fee980fa86947 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickitemview.cpp | 27 ++++++++------ .../auto/quick/qquicklistview/data/qtbug63974.qml | 34 ++++++++++++++++++ .../quick/qquicklistview/tst_qquicklistview.cpp | 41 ++++++++++++++++++++++ 3 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 tests/auto/quick/qquicklistview/data/qtbug63974.qml diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 478499e209..c203f389ae 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -952,11 +952,16 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) item = visibleItem(idx); } if (item) { + const bool stickyHeader = hasStickyHeader(); + const bool stickyFooter = hasStickyFooter(); + const qreal stickyHeaderSize = stickyHeader ? headerSize() : 0; + const qreal stickyFooterSize = stickyFooter ? footerSize() : 0; + const qreal itemPos = item->position(); switch (mode) { case QQuickItemView::Beginning: pos = itemPos; - if (header && (index < 0 || hasStickyHeader())) + if (header && (index < 0 || stickyHeader)) pos -= headerSize(); break; case QQuickItemView::Center: @@ -964,23 +969,23 @@ void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) break; case QQuickItemView::End: pos = itemPos - viewSize + item->size(); - if (footer && (index >= modelCount || hasStickyFooter())) + if (footer && (index >= modelCount || stickyFooter)) pos += footerSize(); break; case QQuickItemView::Visible: - if (itemPos > pos + viewSize) - pos = itemPos - viewSize + item->size(); - else if (item->endPosition() <= pos) - pos = itemPos; + if (itemPos > pos + viewSize - stickyFooterSize) + pos = item->endPosition() - viewSize + stickyFooterSize; + else if (item->endPosition() <= pos - stickyHeaderSize) + pos = itemPos - stickyHeaderSize; break; case QQuickItemView::Contain: - if (item->endPosition() >= pos + viewSize) - pos = itemPos - viewSize + item->size(); - if (itemPos < pos) - pos = itemPos; + if (item->endPosition() >= pos + viewSize + stickyFooterSize) + pos = itemPos - viewSize + item->size() + stickyFooterSize; + if (itemPos - stickyHeaderSize < pos) + pos = itemPos - stickyHeaderSize; break; case QQuickItemView::SnapPosition: - pos = itemPos - highlightRangeStart; + pos = itemPos - highlightRangeStart - stickyHeaderSize; break; } pos = qMin(pos, maxExtent); diff --git a/tests/auto/quick/qquicklistview/data/qtbug63974.qml b/tests/auto/quick/qquicklistview/data/qtbug63974.qml new file mode 100644 index 0000000000..1e0afa54f8 --- /dev/null +++ b/tests/auto/quick/qquicklistview/data/qtbug63974.qml @@ -0,0 +1,34 @@ +import QtQuick 2.6 + +ListView { + id: table + height: 200 + width: 100 + + headerPositioning: ListView.OverlayHeader + header: Rectangle { + width: table.width + height: 20 + color: "red" + z: 100 + } + + footerPositioning: ListView.OverlayFooter + footer: Rectangle { + width: table.width + height: 20 + color: "blue" + z: 200 + } + + model: 30 + delegate: Rectangle { + height: 20 + width: table.width + color: "lightgray" + Text { + text: "Item " + index + anchors.centerIn: parent + } + } +} diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index a31cb37c16..c08d5d31b4 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -256,6 +256,7 @@ private slots: void keyNavigationEnabled(); void QTBUG_61269_appendDuringScrollDown(); void QTBUG_50097_stickyHeader_positionViewAtIndex(); + void QTBUG_63974_stickyHeader_positionViewAtIndex_Contain(); void itemFiltered(); void releaseItems(); @@ -8561,6 +8562,46 @@ void tst_QQuickListView::QTBUG_50097_stickyHeader_positionViewAtIndex() QTRY_COMPARE(listview->contentY(), -100.0); // back to the same position: header visible, items not under the header. } +void tst_QQuickListView::QTBUG_63974_stickyHeader_positionViewAtIndex_Contain() +{ + QScopedPointer window(createView()); + window->setSource(testFileUrl("qtbug63974.qml")); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QQuickListView *listview = qobject_cast(window->rootObject()); + QVERIFY(listview != 0); + + const qreal headerSize = 20; + const qreal footerSize = 20; + const qreal itemSize = 20; + const int itemCount = 30; + const qreal contentHeight = itemCount * itemSize; + + const qreal initialY = listview->contentY(); + const qreal endPosition = contentHeight + footerSize - listview->height(); + + QVERIFY(qFuzzyCompare(initialY, -headerSize)); + + listview->positionViewAtIndex(itemCount - 1, QQuickListView::Contain); + QTRY_COMPARE(listview->contentY(), endPosition); + + listview->positionViewAtIndex(0, QQuickListView::Contain); + QTRY_COMPARE(listview->contentY(), -headerSize); + + listview->positionViewAtIndex(itemCount - 1, QQuickListView::Visible); + QTRY_COMPARE(listview->contentY(), endPosition); + + listview->positionViewAtIndex(0, QQuickListView::Visible); + QTRY_COMPARE(listview->contentY(), -headerSize); + + listview->positionViewAtIndex(itemCount - 1, QQuickListView::SnapPosition); + QTRY_COMPARE(listview->contentY(), endPosition); + + listview->positionViewAtIndex(0, QQuickListView::SnapPosition); + QTRY_COMPARE(listview->contentY(), -headerSize); +} + void tst_QQuickListView::itemFiltered() { QStringListModel model(QStringList() << "one" << "two" << "three" << "four" << "five" << "six"); -- cgit v1.2.3 From 87253cb04612a3f97c779c0111c0e635e6c910ab Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 8 Nov 2017 11:51:02 +0100 Subject: stabilize and optimize tst_QQuickListView::QTBUG_34576_velocityZero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - don't use QTRY_VERIFY or QTRY_COMPARE if there's nothing to wait for, because it will always wait a short time and add needless delay to the test - QVERIFY(QSignalSpy::wait())'s should perhaps not be done in sequence, in case the second signal already happened while we were waiting for the first. QTRY_VERIFY(QSignalSpy::count() > 0) should be more reliable in such a case, as long as we are sure the count started at zero before the behavior which was supposed to make the signal be emitted. - 1000ms is probably not long enough to wait for ListView velocity change on a slow CI system. - according to the comment "verify that currentIndexChanged is triggered" we need another spy for that signal. Change-Id: I99d93a849b674ce6c81acbe91639f03933025117 Reviewed-by: Jan Arve Sæther --- tests/auto/quick/qquicklistview/tst_qquicklistview.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index c08d5d31b4..f06a118976 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -8658,9 +8658,9 @@ void tst_QQuickListView::QTBUG_34576_velocityZero() QVERIFY(QTest::qWaitForWindowExposed(window)); QQuickListView *listview = findItem(window->rootObject(), "list"); - QTRY_VERIFY(listview != 0); + QVERIFY(listview); QQuickItem *contentItem = listview->contentItem(); - QTRY_VERIFY(contentItem != 0); + QVERIFY(contentItem); QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false); QSignalSpy horizontalVelocitySpy(listview, SIGNAL(horizontalVelocityChanged())); @@ -8672,20 +8672,21 @@ void tst_QQuickListView::QTBUG_34576_velocityZero() window->rootObject()->setProperty("horizontalVelocityZeroCount", QVariant(0)); listview->setCurrentIndex(2); QTRY_COMPARE(window->rootObject()->property("current").toInt(), 2); - QTRY_COMPARE(horizontalVelocitySpy.count(), 0); - QTRY_COMPARE(window->rootObject()->property("horizontalVelocityZeroCount").toInt(), 0); + QCOMPARE(horizontalVelocitySpy.count(), 0); + QCOMPARE(window->rootObject()->property("horizontalVelocityZeroCount").toInt(), 0); + + QSignalSpy currentIndexChangedSpy(listview, SIGNAL(currentIndexChanged())); // click button which increases currentIndex QTest::mousePress(window, Qt::LeftButton, 0, QPoint(295,215)); QTest::mouseRelease(window, Qt::LeftButton, 0, QPoint(295,215)); // verify that currentIndexChanged is triggered - QVERIFY(horizontalVelocitySpy.wait()); + QTRY_VERIFY(currentIndexChangedSpy.count() > 0); - // set currentIndex to item out of view to cause listview scroll + // since we have set currentIndex to an item out of view, the listview will scroll QTRY_COMPARE(window->rootObject()->property("current").toInt(), 3); - QTRY_COMPARE(horizontalVelocitySpy.count() > 0, true); - QVERIFY(horizontalVelocitySpy.wait(1000)); + QTRY_VERIFY(horizontalVelocitySpy.count() > 0); // velocity should be always > 0.0 QTRY_COMPARE(window->rootObject()->property("horizontalVelocityZeroCount").toInt(), 0); -- cgit v1.2.3 From 9cb3bc655a42f386607316d228a64422d453b201 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 2 Nov 2017 13:56:52 +0100 Subject: docs and example: clarify the usage of Flickable contentX/contentY It's such a common mistake to observe that they normally go to zero at the top-left corner, but fail to realize that they won't always do that. Task-number: QTBUG-64219 Task-number: QTBUG-22894 Task-number: QTBUG-27884 Change-Id: I6bc81d4761debdaff8fb3366bf1e944241207157 Reviewed-by: J-P Nurmi --- examples/quick/demos/photosurface/photosurface.qml | 4 ++-- src/quick/items/qquickflickable.cpp | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/examples/quick/demos/photosurface/photosurface.qml b/examples/quick/demos/photosurface/photosurface.qml index 8057bb8400..5d1445d776 100644 --- a/examples/quick/demos/photosurface/photosurface.qml +++ b/examples/quick/demos/photosurface/photosurface.qml @@ -181,7 +181,7 @@ Window { radius: 2 antialiasing: true height: flick.height * (flick.height / flick.contentHeight) - (width - anchors.margins) * 2 - y: flick.contentY * (flick.height / flick.contentHeight) + y: (flick.contentY - flick.originY) * (flick.height / flick.contentHeight) NumberAnimation on opacity { id: vfade; to: 0; duration: 500 } onYChanged: { opacity = 1.0; scrollFadeTimer.restart() } } @@ -197,7 +197,7 @@ Window { radius: 2 antialiasing: true width: flick.width * (flick.width / flick.contentWidth) - (height - anchors.margins) * 2 - x: flick.contentX * (flick.width / flick.contentWidth) + x: (flick.contentX - flick.originY) * (flick.width / flick.contentWidth) NumberAnimation on opacity { id: hfade; to: 0; duration: 500 } onXChanged: { opacity = 1.0; scrollFadeTimer.restart() } } diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index e0f8b6de00..3662827973 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -734,7 +734,19 @@ QQuickFlickable::~QQuickFlickable() These properties hold the surface coordinate currently at the top-left corner of the Flickable. For example, if you flick an image up 100 pixels, - \c contentY will be 100. + \c contentY will increase by 100. + + \note If you flick back to the origin (the top-left corner), after the + rebound animation, \c contentX will settle to the same value as \c originX, + and \c contentY to \c originY. These are usually (0,0), however ListView + and GridView may have an arbitrary origin due to delegate size variation, + or item insertion/removal outside the visible region. So if you want to + implement something like a vertical scrollbar, one way is to use + \c {y: (contentY - originY) * (height / contentHeight)} + for the position; another way is to use the normalized values in + \l {QtQuick::Flickable::visibleArea}{visibleArea}. + + \sa originX, originY */ qreal QQuickFlickable::contentX() const { @@ -2153,6 +2165,8 @@ void QQuickFlickable::setRightMargin(qreal m) This is usually (0,0), however ListView and GridView may have an arbitrary origin due to delegate size variation, or item insertion/removal outside the visible region. + + \sa contentX, contentY */ qreal QQuickFlickable::originY() const -- cgit v1.2.3 From 05220b707b1bd901adb61ecae77177b88ed832ca Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 7 Nov 2017 13:06:34 +0100 Subject: Fix tst_qquickshadereffect The expected signal counts were not matching. Since the test has not been run in the CI, it went unnoticed. Furthermore, the test crashed due to a missing null pointer check. Change-Id: Iff80a2ea17832eb7bc531ac9eb2fc482f2c69e38 Reviewed-by: Laszlo Agocs --- src/quick/items/qquickopenglshadereffect.cpp | 2 +- tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp index 4fcfe04b55..193478484e 100644 --- a/src/quick/items/qquickopenglshadereffect.cpp +++ b/src/quick/items/qquickopenglshadereffect.cpp @@ -890,7 +890,7 @@ QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuic bool geometryUsesTextureSubRect = false; if (m_supportsAtlasTextures && material->textureProviders.size() == 1) { QSGTextureProvider *provider = material->textureProviders.at(0); - if (provider->texture()) { + if (provider && provider->texture()) { srcRect = provider->texture()->normalizedTextureSubRect(); geometryUsesTextureSubRect = true; } diff --git a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp index fe33dbd4d8..1731253da6 100644 --- a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp +++ b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp @@ -52,8 +52,8 @@ public: int signalsConnected = 0; protected: - void connectNotify(const QMetaMethod &) { ++signalsConnected; } - void disconnectNotify(const QMetaMethod &) { --signalsConnected; } + void connectNotify(const QMetaMethod &) override { ++signalsConnected; } + void disconnectNotify(const QMetaMethod &) override { --signalsConnected; } signals: void dummyChanged(); @@ -257,7 +257,7 @@ void tst_qquickshadereffect::lookThroughShaderCode() QQmlComponent component(&engine); component.setData("import QtQuick 2.0\nimport ShaderEffectTest 1.0\nTestShaderEffect {}", QUrl()); QScopedPointer item(qobject_cast(component.create())); - QCOMPARE(item->signalsConnected, 1); + QCOMPARE(item->signalsConnected, 0); QString expected; if ((presenceFlags & VertexPresent) == 0) @@ -274,7 +274,7 @@ void tst_qquickshadereffect::lookThroughShaderCode() QCOMPARE(item->parseLog(), expected); // If the uniform was successfully parsed, the notify signal has been connected to an update slot. - QCOMPARE(item->signalsConnected, (presenceFlags & SourcePresent) ? 2 : 1); + QCOMPARE(item->signalsConnected, (presenceFlags & SourcePresent) ? 1 : 0); } void tst_qquickshadereffect::deleteSourceItem() -- cgit v1.2.3 From e08c42e9fdb83367e7ea77f5ff91c6f665fcea15 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 28 Jul 2017 14:42:56 +0200 Subject: Fix tests/auto/quick/quick.pro The following auto tests have not been run in the CI at all: - tst_qquickanimatedsprite - tst_qquickframebufferobject - tst_qquickopenglinfo - tst_qquickspritesequence - tst_qquickshadereffect Change-Id: Iacc832563fd2c002eef480fa4d42469d852adc0f Reviewed-by: Frederik Gladhorn --- tests/auto/quick/quick.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index 00be8240e5..4c1c667489 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -46,7 +46,7 @@ PRIVATETESTS += \ # This test requires the xmlpatterns module !qtHaveModule(xmlpatterns): PRIVATETESTS -= qquickxmllistmodel -QUICKTESTS = \ +QUICKTESTS += \ qquickaccessible \ qquickanchors \ qquickanimatedimage \ -- cgit v1.2.3 From 8cf186cc7c56144b02d5b40d8f4832ff3021e68a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 8 Nov 2017 10:58:46 +0100 Subject: Make tst_qquickframebufferobject pass on macOS The test has not been run in the CI, so the problem went unnoticed for a long time. Change-Id: I42a44a5fb89c0bd78e8997d4841e85672c73acdb Reviewed-by: Laszlo Agocs Reviewed-by: Shawn Rutledge --- .../quick/qquickframebufferobject/tst_qquickframebufferobject.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp index d4922599be..363064aa31 100644 --- a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp +++ b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp @@ -192,7 +192,8 @@ void tst_QQuickFramebufferObject::testThatStuffWorks() item->setMsaa(msaa); view.show(); - QTest::qWaitForWindowExposed(&view); + view.requestActivate(); + QTest::qWaitForWindowActive(&view); QImage result = view.grabWindow(); @@ -231,7 +232,8 @@ void tst_QQuickFramebufferObject::testInvalidate() item->setTextureSize(QSize(200, 200)); view.show(); - QTest::qWaitForWindowExposed(&view); + view.requestActivate(); + QTest::qWaitForWindowActive(&view); QCOMPARE(frameInfo.fboSize, QSize(200, 200)); -- cgit v1.2.3 From 5f16aa795d39969d93b520861a1e86729c7db90e Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 9 Nov 2017 13:01:08 +0100 Subject: Blacklist tst_qquickwidget::enterLeave() on Mac Task-number: QTBUG-64397 Change-Id: I28268ea87b81dd1f7dbf8bb5a8eb421962cc5f31 Reviewed-by: Gatis Paeglis --- tests/auto/quickwidgets/qquickwidget/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/auto/quickwidgets/qquickwidget/BLACKLIST diff --git a/tests/auto/quickwidgets/qquickwidget/BLACKLIST b/tests/auto/quickwidgets/qquickwidget/BLACKLIST new file mode 100644 index 0000000000..6594a22472 --- /dev/null +++ b/tests/auto/quickwidgets/qquickwidget/BLACKLIST @@ -0,0 +1,2 @@ +[enterLeave] +osx -- cgit v1.2.3 From 6990ae6c1bad32952e371fa72bee65a7af11c313 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 23 Oct 2017 15:03:05 +0200 Subject: Make sure we remove stopped animators from the list of roots Change-Id: I89b36ee7d03ac6b8d07b24c656d3311728e8f9c3 Reviewed-by: J-P Nurmi --- src/quick/util/qquickanimatorcontroller.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp index 3f7347c01d..5cf8051922 100644 --- a/src/quick/util/qquickanimatorcontroller.cpp +++ b/src/quick/util/qquickanimatorcontroller.cpp @@ -123,8 +123,10 @@ static void qquickanimator_sync_before_start(QAbstractAnimationJob *job) void QQuickAnimatorController::beforeNodeSync() { - for (const QSharedPointer &toStop : qAsConst(m_rootsPendingStop)) + for (const QSharedPointer &toStop : qAsConst(m_rootsPendingStop)) { toStop->stop(); + m_animationRoots.remove(toStop.data()); + } m_rootsPendingStop.clear(); -- cgit v1.2.3