From c2c19f2b8f1feb2d6785800c69f9f351bc317a05 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 9 Nov 2011 15:34:01 +1000 Subject: [PATCH] PathView element's current item changes on insertion. When inserting an item before the current item update the offset to ensure the current item doesn't change. Task-number: QTBUG-21320 Change-Id: I2375bc5098e7f83c33e7a0b123ed1b82f607055f Reviewed-by: Bea Lam --- src/declarative/items/qquickpathview.cpp | 23 ++++- .../declarative/qquickpathview/data/pathline.qml | 48 +++++++++++ .../qquickpathview/tst_qquickpathview.cpp | 89 ++++++++++++++++++++ 3 files changed, 155 insertions(+), 5 deletions(-) create mode 100644 tests/auto/declarative/qquickpathview/data/pathline.qml diff --git a/src/declarative/items/qquickpathview.cpp b/src/declarative/items/qquickpathview.cpp index dc73bf2..c4da6f5 100644 --- a/src/declarative/items/qquickpathview.cpp +++ b/src/declarative/items/qquickpathview.cpp @@ -494,7 +494,7 @@ void QQuickPathView::setModel(const QVariant &model) disconnect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*))); for (int i=0; iitems.count(); i++){ QQuickItem *p = d->items[i]; - d->model->release(p); + d->releaseItem(p); } d->items.clear(); } @@ -1537,9 +1537,12 @@ void QQuickPathView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool r if (d->modelCount) { if (moveId == -1 && i.index <= d->currentIndex) { d->currentIndex += i.count; + currentChanged = true; } else if (d->offset != 0) { - if (moveId != -1 && moveId == i.moveId) + if (moveId != -1 && moveId == i.moveId) { d->currentIndex = i.index + moveOffset; + currentChanged = true; + } d->offset += i.count; d->offsetAdj += i.count; } @@ -1558,13 +1561,20 @@ void QQuickPathView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool r d->tl.reset(d->moveOffset); } else if (removed) { d->regenerate(); - d->updateCurrent(); - if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) - d->snapToCurrent(); + if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) { + qreal targetOffset = qmlMod(d->modelCount - d->currentIndex, d->modelCount); + if (targetOffset != d->offset) + d->tl.set(d->moveOffset, targetOffset); + } } else if (inserted) { d->firstIndex = -1; d->updateMappedRange(); d->scheduleLayout(); + if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange) { + qreal targetOffset = qmlMod(d->modelCount - d->currentIndex, d->modelCount); + if (targetOffset != d->offset) + d->tl.set(d->moveOffset, targetOffset); + } } if (changedOffset) emit offsetChanged(); @@ -1698,6 +1708,9 @@ void QQuickPathViewPrivate::snapToCurrent() qreal targetOffset = qmlMod(modelCount - currentIndex, modelCount); + if (offset == targetOffset) + return; + moveReason = Other; offsetAdj = 0.0; tl.reset(moveOffset); diff --git a/tests/auto/declarative/qquickpathview/data/pathline.qml b/tests/auto/declarative/qquickpathview/data/pathline.qml new file mode 100644 index 0000000..4c1c785 --- /dev/null +++ b/tests/auto/declarative/qquickpathview/data/pathline.qml @@ -0,0 +1,48 @@ +import QtQuick 2.0 + +Rectangle { + id: app + width: 360 + height: 360 + + PathView { + id: pathView + objectName: "view" + x: (app.width-pathView.width)/2 + y: 100 + width: 240 + height: 100 + + model: testModel + + Rectangle { + anchors.fill: parent + color: "white" + border.color: "black" + } + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + + delegate: Rectangle { + objectName: "wrapper" + width: 100 + height: 100 + color: PathView.isCurrentItem ? "red" : "yellow" + Text { + text: index + anchors.centerIn: parent + } + z: (PathView.isCurrentItem?1:0) + } + path: Path { + id: path + startX: -100+pathView.width/2 + startY: pathView.height/2 + PathLine { + id: line + x: 100+pathView.width/2 + y: pathView.height/2 + } + } + } +} diff --git a/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp b/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp index dc85f59..5e434b0 100644 --- a/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/declarative/qquickpathview/tst_qquickpathview.cpp @@ -111,6 +111,7 @@ private slots: void changePreferredHighlight(); void missingPercent(); void creationContext(); + void currentOffsetOnInsertion(); private: QQuickView *createView(); @@ -240,6 +241,8 @@ void tst_QQuickPathView::initValues() QCOMPARE(obj->dragMargin(), 0.); QCOMPARE(obj->count(), 0); QCOMPARE(obj->pathItemCount(), -1); + + delete obj; } void tst_QQuickPathView::items() @@ -303,6 +306,8 @@ void tst_QQuickPathView::pathview2() QCOMPARE(obj->dragMargin(), 0.); QCOMPARE(obj->count(), 8); QCOMPARE(obj->pathItemCount(), 10); + + delete obj; } void tst_QQuickPathView::pathview3() @@ -321,6 +326,8 @@ void tst_QQuickPathView::pathview3() QCOMPARE(obj->dragMargin(), 24.); QCOMPARE(obj->count(), 8); QCOMPARE(obj->pathItemCount(), 4); + + delete obj; } void tst_QQuickPathView::path() @@ -366,6 +373,8 @@ void tst_QQuickPathView::path() QCOMPARE(cubic->control1Y(), 90.); QCOMPARE(cubic->control2X(), 210.); QCOMPARE(cubic->control2Y(), 90.); + + delete obj; } void tst_QQuickPathView::dataModel() @@ -1081,6 +1090,86 @@ void tst_QQuickPathView::creationContext() QCOMPARE(item->property("text").toString(), QString("Hello!")); } +// QTBUG-21320 +void tst_QQuickPathView::currentOffsetOnInsertion() +{ + QQuickView *canvas = createView(); + canvas->show(); + + TestModel model; + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->setSource(QUrl::fromLocalFile(TESTDATA("pathline.qml"))); + qApp->processEvents(); + + QQuickPathView *pathview = findItem(canvas->rootObject(), "view"); + QVERIFY(pathview != 0); + + pathview->setPreferredHighlightBegin(0.5); + pathview->setPreferredHighlightEnd(0.5); + + QCOMPARE(pathview->count(), model.count()); + + model.addItem("item0", "0"); + + QCOMPARE(pathview->count(), model.count()); + + QQuickRectangle *item = 0; + QTRY_VERIFY(item = findItem(pathview, "wrapper", 0)); + + QDeclarativePath *path = qobject_cast(pathview->path()); + QVERIFY(path); + + QPointF start = path->pointAt(0.5); + start = QPointF(qRound(start.x()), qRound(start.y())); + QPointF offset;//Center of item is at point, but pos is from corner + offset.setX(item->width()/2); + offset.setY(item->height()/2); + QCOMPARE(item->pos() + offset, start); + + QSignalSpy currentIndexSpy(pathview, SIGNAL(currentIndexChanged())); + + // insert an item at the beginning + model.insertItem(0, "item1", "1"); + qApp->processEvents(); + + QCOMPARE(currentIndexSpy.count(), 1); + + // currentIndex is now 1 + QVERIFY(item = findItem(pathview, "wrapper", 1)); + + // verify that current item (item 1) is still at offset 0.5 + QCOMPARE(item->pos() + offset, start); + + // insert another item at the beginning + model.insertItem(0, "item2", "2"); + qApp->processEvents(); + + QCOMPARE(currentIndexSpy.count(), 2); + + // currentIndex is now 2 + QVERIFY(item = findItem(pathview, "wrapper", 2)); + + // verify that current item (item 2) is still at offset 0.5 + QCOMPARE(item->pos() + offset, start); + + // verify that remove before current maintains current item + model.removeItem(0); + qApp->processEvents(); + + QCOMPARE(currentIndexSpy.count(), 3); + + // currentIndex is now 1 + QVERIFY(item = findItem(pathview, "wrapper", 1)); + + // verify that current item (item 1) is still at offset 0.5 + QCOMPARE(item->pos() + offset, start); + + delete canvas; +} + QQuickView *tst_QQuickPathView::createView() { QQuickView *canvas = new QQuickView(0); -- 1.7.2.5