From a5e8e81c1d7f3fdf9421cb590de5e4613baa7fa1 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 12 Oct 2011 14:30:18 +1000 Subject: [PATCH] Fix insertions above the visible index The first visible item was repositioned incorrectly after an insertion above the visible index since any insertions above the position + cache buffer were ignored and not considered for repositioning the first item. GridView insertion code has changed to be similar to the ListView implementation to fix various issues when inserting above the visible index and to remove code that crossed indexes from visibleItems with model indexes and visible indexes. Also adds extra insertion tests for ListView and GridView. Change-Id: I5e129c605fdad733b61bd29850465b3b752fb63f Reviewed-on: http://codereview.qt-project.org/6485 Reviewed-by: Bea Lam --- src/declarative/items/qsggridview.cpp | 101 ++++++++---- src/declarative/items/qsgitemview.cpp | 39 ++--- src/declarative/items/qsgitemview_p_p.h | 12 +- src/declarative/items/qsglistview.cpp | 59 +++---- .../declarative/qsggridview/tst_qsggridview.cpp | 174 ++++++++++++++++++++ .../declarative/qsglistview/tst_qsglistview.cpp | 179 +++++++++++++++++++++ 6 files changed, 482 insertions(+), 82 deletions(-) diff --git a/src/declarative/items/qsggridview.cpp b/src/declarative/items/qsggridview.cpp index 099d62e..fd2742c 100644 --- a/src/declarative/items/qsggridview.cpp +++ b/src/declarative/items/qsggridview.cpp @@ -173,7 +173,7 @@ public: virtual void repositionPackageItemAt(QSGItem *item, int index); virtual void resetItemPosition(FxViewItem *item, FxViewItem *toItem); virtual void resetFirstItemPosition(); - virtual void moveItemBy(FxViewItem *item, const QList &items, const QList &movedBackwards); + virtual void moveItemBy(FxViewItem *item, qreal forwards, qreal backwards); virtual void createHighlight(); virtual void updateHighlight(); @@ -181,7 +181,7 @@ public: virtual void setPosition(qreal pos); virtual void layoutVisibleItems(); - bool applyInsertionChange(const QDeclarativeChangeSet::Insert &, QList *, QList*, FxViewItem *); + bool applyInsertionChange(const QDeclarativeChangeSet::Insert &, FxViewItem *, InsertionsResult *); virtual qreal headerSize() const; virtual qreal footerSize() const; @@ -586,9 +586,10 @@ void QSGGridViewPrivate::resetFirstItemPosition() item->setPosition(0, 0); } -void QSGGridViewPrivate::moveItemBy(FxViewItem *item, const QList &forwards, const QList &backwards) +void QSGGridViewPrivate::moveItemBy(FxViewItem *item, qreal forwards, qreal backwards) { - int moveCount = forwards.count() - backwards.count(); + int moveCount = (forwards / rowSize()) - (backwards / rowSize()); + FxGridItemSG *gridItem = static_cast(item); gridItem->setPosition(gridItem->colPos(), gridItem->rowPos() + ((moveCount / columns) * rowSize())); } @@ -1757,7 +1758,7 @@ void QSGGridView::moveCurrentIndexRight() } } -bool QSGGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Insert &change, QList *movedBackwards, QList *addedItems, FxViewItem *firstVisible) +bool QSGGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Insert &change, FxViewItem *firstVisible, InsertionsResult *insertResult) { Q_Q(QSGGridView); @@ -1772,7 +1773,7 @@ bool QSGGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Inser --i; if (visibleItems.at(i)->index + 1 == modelIndex) { // Special case of appending an item to the model. - index = visibleIndex + visibleItems.count(); + index = visibleItems.count(); } else { if (modelIndex <= visibleIndex) { // Insert before visible items @@ -1787,19 +1788,10 @@ bool QSGGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Inser } } - int insertCount = count; - if (index < visibleIndex && visibleItems.count()) { - insertCount -= visibleIndex - index; - index = visibleIndex; - modelIndex = visibleIndex; - } - qreal tempPos = isRightToLeftTopToBottom() ? -position()-size()+q->width()+1 : position(); - int to = buffer+tempPos+size()-1; int colPos = 0; int rowPos = 0; if (visibleItems.count()) { - index -= visibleIndex; if (index < visibleItems.count()) { FxGridItemSG *gridItem = static_cast(visibleItems.at(index)); colPos = gridItem->colPos(); @@ -1823,30 +1815,69 @@ bool QSGGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Inser item->index += count; } - int i = 0; - bool prevAddedCount = addedItems->count(); - while (i < insertCount && rowPos <= to + rowSize()*(columns - (colPos/colSize()))/qreal(columns)) { - FxViewItem *item = 0; - if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i)))) { - if (item->index > modelIndex + i) - movedBackwards->append(item); - item->index = modelIndex + i; + int prevAddedCount = insertResult->addedItems.count(); + if (firstVisible && rowPos < firstVisible->position()) { + // Insert items before the visible item. + int insertionIdx = index; + int i = count - 1; + int from = tempPos - buffer; + + while (i >= 0) { + if (rowPos > from) { + insertResult->sizeAddedBeforeVisible += rowSize(); + } else { + FxViewItem *item = 0; + if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i)))) { + if (item->index > modelIndex + i) + insertResult->movedBackwards.append(item); + item->index = modelIndex + i; + } + if (!item) + item = createItem(modelIndex + i); + + visibleItems.insert(insertionIdx, item); + if (!change.isMove()) { + insertResult->addedItems.append(item); + insertResult->sizeAddedBeforeVisible += rowSize(); + } + } + colPos -= colSize(); + if (colPos < 0) { + colPos = colSize() * (columns - 1); + rowPos -= rowSize(); + } + index++; + i--; } - if (!item) - item = createItem(modelIndex + i); - visibleItems.insert(index, item); - if (!change.isMove()) - addedItems->append(item); - colPos += colSize(); - if (colPos > colSize() * (columns-1)) { - colPos = 0; - rowPos += rowSize(); + } else { + int i = 0; + int to = buffer+tempPos+size()-1; + while (i < count && rowPos <= to + rowSize()*(columns - (colPos/colSize()))/qreal(columns)) { + FxViewItem *item = 0; + if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i)))) { + if (item->index > modelIndex + i) + insertResult->movedBackwards.append(item); + item->index = modelIndex + i; + } + if (!item) + item = createItem(modelIndex + i); + + visibleItems.insert(index, item); + if (!change.isMove()) + insertResult->addedItems.append(item); + colPos += colSize(); + if (colPos > colSize() * (columns-1)) { + colPos = 0; + rowPos += rowSize(); + } + ++index; + ++i; } - ++index; - ++i; } - return addedItems->count() > prevAddedCount; + updateVisibleIndex(); + + return insertResult->addedItems.count() > prevAddedCount; } /*! diff --git a/src/declarative/items/qsgitemview.cpp b/src/declarative/items/qsgitemview.cpp index 9415f9e..075024d 100644 --- a/src/declarative/items/qsgitemview.cpp +++ b/src/declarative/items/qsgitemview.cpp @@ -1437,7 +1437,7 @@ bool QSGItemViewPrivate::applyModelChanges() FxViewItem *firstVisible = firstVisibleItem(); FxViewItem *origVisibleItemsFirst = visibleItems.count() ? visibleItems.first() : 0; int firstItemIndex = firstVisible ? firstVisible->index : -1; - QList removedBeforeFirstVisible; + qreal removedBeforeFirstVisibleBy = 0; const QVector &removals = currentChanges.pendingChanges.removes(); for (int i=0; iposition() < firstVisible->position() && item != visibleItems.first()) - removedBeforeFirstVisible.append(item); + removedBeforeFirstVisibleBy += item->size(); if (removals[i].isMove()) { currentChanges.removedItems.insert(removals[i].moveKey(item->index), item); } else { @@ -1487,38 +1487,38 @@ bool QSGItemViewPrivate::applyModelChanges() const QVector &insertions = currentChanges.pendingChanges.inserts(); bool addedVisible = false; - QList addedItems; - QList movedBackwards; + InsertionsResult insertResult; + bool allInsertionsBeforeVisible = true; for (int i=0; i= visibleIndex) + allInsertionsBeforeVisible = false; if (wasEmpty && !visibleItems.isEmpty()) resetFirstItemPosition(); itemCount += insertions[i].count; - updateVisibleIndex(); } - for (int i=0; iattached->emitAdd(); + for (int i=0; iattached->emitAdd(); // if the first visible item has moved, ensure another one takes its place // so that we avoid shifting all content forwards - // (don't use items from removedBeforeFirstVisible - if an item is removed from - // before the first visible, the first visible should not move upwards) + // (if an item is removed from before the first visible, the first visible should not move upwards) if (firstVisible && firstItemIndex >= 0) { bool found = false; - for (int i=0; iindex == firstItemIndex) { + for (int i=0; iindex == firstItemIndex) { // an item has moved backwards up to the first visible's position - resetItemPosition(movedBackwards[i], firstVisible); - movedBackwards.removeAt(i); + resetItemPosition(insertResult.movedBackwards[i], firstVisible); + insertResult.movedBackwards.removeAt(i); found = true; break; } } - if (!found) { - // first visible item has moved forward, another item takes its place + if (!found && !allInsertionsBeforeVisible) { + // first visible item has moved forward, another visible item takes its place FxViewItem *item = visibleItem(firstItemIndex); if (item) resetItemPosition(item, firstVisible); @@ -1529,9 +1529,12 @@ bool QSGItemViewPrivate::applyModelChanges() if (firstVisible && visibleItems.count() && visibleItems.first() != firstVisible) { // ensure first item is placed at correct postion if moving backward // since it will be used to position all subsequent items - if (movedBackwards.count() && origVisibleItemsFirst) + if (insertResult.movedBackwards.count() && origVisibleItemsFirst) resetItemPosition(visibleItems.first(), origVisibleItemsFirst); - moveItemBy(visibleItems.first(), removedBeforeFirstVisible, movedBackwards); + qreal moveBackwardsBy = insertResult.sizeAddedBeforeVisible; + for (int i=0; isize(); + moveItemBy(visibleItems.first(), removedBeforeFirstVisibleBy, moveBackwardsBy); } // Whatever removed/moved items remain are no longer visible items. diff --git a/src/declarative/items/qsgitemview_p_p.h b/src/declarative/items/qsgitemview_p_p.h index 2d39dce..5eaa84c 100644 --- a/src/declarative/items/qsgitemview_p_p.h +++ b/src/declarative/items/qsgitemview_p_p.h @@ -101,6 +101,14 @@ class QSGItemViewPrivate : public QSGFlickablePrivate public: QSGItemViewPrivate(); + struct InsertionsResult { + QList addedItems; + QList movedBackwards; + qreal sizeAddedBeforeVisible; + + InsertionsResult() : sizeAddedBeforeVisible(0) {} + }; + enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 }; enum MovementReason { Other, SetIndex, Mouse }; @@ -227,11 +235,11 @@ protected: virtual void repositionPackageItemAt(QSGItem *item, int index) = 0; virtual void resetItemPosition(FxViewItem *item, FxViewItem *toItem) = 0; virtual void resetFirstItemPosition() = 0; - virtual void moveItemBy(FxViewItem *item, const QList &, const QList &) = 0; + virtual void moveItemBy(FxViewItem *item, qreal forwards, qreal backwards) = 0; virtual void layoutVisibleItems() = 0; virtual void changedVisibleIndex(int newIndex) = 0; - virtual bool applyInsertionChange(const QDeclarativeChangeSet::Insert &, QList *, QList *, FxViewItem *) = 0; + virtual bool applyInsertionChange(const QDeclarativeChangeSet::Insert &, FxViewItem *, InsertionsResult *) = 0; virtual void initializeViewItem(FxViewItem *) {} virtual void initializeCurrentItem() {} diff --git a/src/declarative/items/qsglistview.cpp b/src/declarative/items/qsglistview.cpp index beeeda4..75472c2 100644 --- a/src/declarative/items/qsglistview.cpp +++ b/src/declarative/items/qsglistview.cpp @@ -95,7 +95,7 @@ public: virtual void repositionPackageItemAt(QSGItem *item, int index); virtual void resetItemPosition(FxViewItem *item, FxViewItem *toItem); virtual void resetFirstItemPosition(); - virtual void moveItemBy(FxViewItem *item, const QList &items, const QList &movedBackwards); + virtual void moveItemBy(FxViewItem *item, qreal forwards, qreal backwards); virtual void createHighlight(); virtual void updateHighlight(); @@ -103,7 +103,7 @@ public: virtual void setPosition(qreal pos); virtual void layoutVisibleItems(); - bool applyInsertionChange(const QDeclarativeChangeSet::Insert &, QList *, QList *, FxViewItem *firstVisible); + bool applyInsertionChange(const QDeclarativeChangeSet::Insert &, FxViewItem *firstVisible, InsertionsResult *); virtual void updateSections(); QSGItem *getSectionItem(const QString §ion); @@ -727,14 +727,10 @@ void QSGListViewPrivate::resetFirstItemPosition() item->setPosition(0); } -void QSGListViewPrivate::moveItemBy(FxViewItem *item, const QList &forwards, const QList &backwards) +void QSGListViewPrivate::moveItemBy(FxViewItem *item, qreal forwards, qreal backwards) { - qreal pos = 0; - for (int i=0; isize(); - for (int i=0; isize(); - static_cast(item)->setPosition(item->position() + pos); + qreal diff = forwards - backwards; + static_cast(item)->setPosition(item->position() + diff); } void QSGListViewPrivate::createHighlight() @@ -2347,7 +2343,7 @@ void QSGListView::updateSections() } } -bool QSGListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Insert &change, QList *movedBackwards, QList *addedItems, FxViewItem *firstVisible) +bool QSGListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Insert &change, FxViewItem *firstVisible, InsertionsResult *insertResult) { Q_Q(QSGListView); @@ -2390,27 +2386,34 @@ bool QSGListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Inser : visibleItems.last()->endPosition()+spacing; } - int prevAddedCount = addedItems->count(); + int prevAddedCount = insertResult->addedItems.count(); if (firstVisible && pos < firstVisible->position()) { // Insert items before the visible item. int insertionIdx = index; int i = 0; int from = tempPos - buffer; - for (i = count-1; i >= 0 && pos > from; --i) { - FxViewItem *item = 0; - if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i)))) { - if (item->index > modelIndex + i) - movedBackwards->append(item); - item->index = modelIndex + i; - } - if (!item) - item = createItem(modelIndex + i); + for (i = count-1; i >= 0; --i) { + if (pos > from) { + insertResult->sizeAddedBeforeVisible += averageSize; + pos -= averageSize; + } else { + FxViewItem *item = 0; + if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i)))) { + if (item->index > modelIndex + i) + insertResult->movedBackwards.append(item); + item->index = modelIndex + i; + } + if (!item) + item = createItem(modelIndex + i); - visibleItems.insert(insertionIdx, item); - if (!change.isMove()) - addedItems->append(item); - pos -= item->size() + spacing; + visibleItems.insert(insertionIdx, item); + if (!change.isMove()) { + insertResult->addedItems.append(item); + insertResult->sizeAddedBeforeVisible += item->size(); + } + pos -= item->size() + spacing; + } index++; } } else { @@ -2420,7 +2423,7 @@ bool QSGListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Inser FxViewItem *item = 0; if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i)))) { if (item->index > modelIndex + i) - movedBackwards->append(item); + insertResult->movedBackwards.append(item); item->index = modelIndex + i; } if (!item) @@ -2428,7 +2431,7 @@ bool QSGListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Inser visibleItems.insert(index, item); if (!change.isMove()) - addedItems->append(item); + insertResult->addedItems.append(item); pos += item->size() + spacing; ++index; } @@ -2440,7 +2443,9 @@ bool QSGListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Inser item->index += count; } - return addedItems->count() > prevAddedCount; + updateVisibleIndex(); + + return insertResult->addedItems.count() > prevAddedCount; } diff --git a/tests/auto/declarative/qsggridview/tst_qsggridview.cpp b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp index 42bd619..03975e2 100644 --- a/tests/auto/declarative/qsggridview/tst_qsggridview.cpp +++ b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp @@ -70,6 +70,8 @@ private slots: void items(); void changed(); void inserted(); + void inserted_more(); + void inserted_more_data(); void removed(); void clear(); void moved(); @@ -417,6 +419,178 @@ void tst_QSGGridView::inserted() delete canvas; } +void tst_QSGGridView::inserted_more() +{ + QFETCH(qreal, contentY); + QFETCH(int, insertIndex); + QFETCH(int, insertCount); + QFETCH(qreal, itemsOffsetAfterMove); + + QSGText *name; + QSGText *number; + QSGView *canvas = createView(); + canvas->show(); + + TestModel model; + for (int i = 0; i < 30; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); + ctxt->setContextProperty("testTopToBottom", QVariant(false)); + + canvas->setSource(QUrl::fromLocalFile(TESTDATA("/data/gridview1.qml"))); + qApp->processEvents(); + + QSGGridView *gridview = findItem(canvas->rootObject(), "grid"); + QTRY_VERIFY(gridview != 0); + QSGItem *contentItem = gridview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + gridview->setContentY(contentY); + + QList > newData; + for (int i=0; iproperty("count").toInt(), model.count()); + + // check visibleItems.first() is in correct position + QSGItem *item0 = findItem(contentItem, "wrapper", 0); + QVERIFY(item0); + QCOMPARE(item0->y(), itemsOffsetAfterMove); + + QList items = findItems(contentItem, "wrapper"); + int firstVisibleIndex = -1; + for (int i=0; iy() >= contentY) { + QDeclarativeExpression e(qmlContext(items[i]), items[i], "index"); + firstVisibleIndex = e.evaluate().toInt(); + break; + } + } + QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); + + // Confirm items positioned correctly and indexes correct + int itemCount = findItems(contentItem, "wrapper").count(); + for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) { + QSGItem *item = findItem(contentItem, "wrapper", i); + QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); + + QCOMPARE(item->x(), (i%3)*80.0); + QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove); + + name = findItem(contentItem, "textName", i); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(i)); + number = findItem(contentItem, "textNumber", i); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(i)); + } + + delete canvas; +} + +void tst_QSGGridView::inserted_more_data() +{ + QTest::addColumn("contentY"); + QTest::addColumn("insertIndex"); + QTest::addColumn("insertCount"); + QTest::addColumn("itemsOffsetAfterMove"); + + QTest::newRow("add 1, before visible items") + << 120.0 // show 6-23 + << 5 << 1 + << 0.0; // insert 1 above first visible, grid is rearranged; first visible moves forward within its row + // new 1st visible item is at 0 + + QTest::newRow("add 2, before visible items") + << 120.0 // show 6-23 + << 5 << 2 + << 0.0; // insert 2 above first visible, grid is rearranged; first visible moves forward within its row + + QTest::newRow("add 3, before visible items") + << 120.0 // show 6-23 + << 5 << 3 + << -60.0; // insert 3 (1 row) above first visible in negative pos, first visible does not move + + QTest::newRow("add 5, before visible items") + << 120.0 // show 6-23 + << 5 << 5 + << -60.0; // insert 1 row + 2 items above first visible, 1 row added at negative pos, + // grid is rearranged and first visible moves forward within its row + + QTest::newRow("add 6, before visible items") + << 120.0 // show 6-23 + << 5 << 6 + << -60.0 * 2; // insert 2 rows above first visible in negative pos, first visible does not move + + + + QTest::newRow("add 1, at start of visible, content at start") + << 0.0 + << 0 << 1 + << 0.0; + + QTest::newRow("add multiple, at start of visible, content at start") + << 0.0 + << 0 << 3 + << 0.0; + + QTest::newRow("add 1, at start of visible, content not at start") + << 120.0 // show 6-23 + << 6 << 1 + << 0.0; + + QTest::newRow("add multiple, at start of visible, content not at start") + << 120.0 // show 6-23 + << 6 << 3 + << 0.0; + + + QTest::newRow("add 1, at end of visible, content at start") + << 0.0 + << 17 << 1 + << 0.0; + + QTest::newRow("add 1, at end of visible, content at start") + << 0.0 + << 17 << 3 + << 0.0; + + QTest::newRow("add 1, at end of visible, content not at start") + << 120.0 // show 6-23 + << 23 << 1 + << 0.0; + + QTest::newRow("add multiple, at end of visible, content not at start") + << 120.0 // show 6-23 + << 23 << 3 + << 0.0; + + + QTest::newRow("add 1, after visible, content at start") + << 0.0 + << 20 << 1 + << 0.0; + + QTest::newRow("add 1, after visible, content at start") + << 0.0 + << 20 << 3 + << 0.0; + + QTest::newRow("add 1, after visible, content not at start") + << 120.0 // show 6-23 + << 24 << 1 + << 0.0; + + QTest::newRow("add multiple, after visible, content not at start") + << 120.0 // show 6-23 + << 24 << 3 + << 0.0; +} + void tst_QSGGridView::removed() { QSGView *canvas = createView(); diff --git a/tests/auto/declarative/qsglistview/tst_qsglistview.cpp b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp index 2b6705f..386a03b 100644 --- a/tests/auto/declarative/qsglistview/tst_qsglistview.cpp +++ b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp @@ -76,7 +76,11 @@ private slots: void qAbstractItemModel_changed(); void qListModelInterface_inserted(); + void qListModelInterface_inserted_more(); + void qListModelInterface_inserted_more_data(); void qAbstractItemModel_inserted(); + void qAbstractItemModel_inserted_more(); + void qAbstractItemModel_inserted_more_data(); void qListModelInterface_removed(); void qAbstractItemModel_removed(); @@ -140,6 +144,7 @@ private: template void items(); template void changed(); template void inserted(); + template void inserted_more(); template void removed(bool animated); template void moved(); template void clear(); @@ -151,6 +156,7 @@ private: QList findItems(QSGItem *parent, const QString &objectName); void dumpTree(QSGItem *parent, int depth = 0); + void inserted_more_data(); void moved_data(); }; @@ -654,6 +660,159 @@ void tst_QSGListView::inserted() } template +void tst_QSGListView::inserted_more() +{ + QFETCH(qreal, contentY); + QFETCH(int, insertIndex); + QFETCH(int, insertCount); + QFETCH(qreal, itemsOffsetAfterMove); + + QSGText *name; + QSGText *number; + QSGView *canvas = createView(); + canvas->show(); + + T model; + for (int i = 0; i < 30; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + TestObject *testObject = new TestObject; + ctxt->setContextProperty("testObject", testObject); + + canvas->setSource(QUrl::fromLocalFile(TESTDATA("/data/listviewtest.qml"))); + qApp->processEvents(); + + QSGListView *listview = findItem(canvas->rootObject(), "list"); + QTRY_VERIFY(listview != 0); + QSGItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + listview->setContentY(contentY); + + QList > newData; + for (int i=0; iproperty("count").toInt(), model.count()); + + // check visibleItems.first() is in correct position + QSGItem *item0 = findItem(contentItem, "wrapper", 0); + QVERIFY(item0); + QCOMPARE(item0->y(), itemsOffsetAfterMove); + + QList items = findItems(contentItem, "wrapper"); + int firstVisibleIndex = -1; + for (int i=0; iy() >= contentY) { + QDeclarativeExpression e(qmlContext(items[i]), items[i], "index"); + firstVisibleIndex = e.evaluate().toInt(); + break; + } + } + QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); + + // Confirm items positioned correctly and indexes correct + int itemCount = findItems(contentItem, "wrapper").count(); + for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) { + QSGItem *item = findItem(contentItem, "wrapper", i); + QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); + QTRY_COMPARE(item->y(), i*20.0 + itemsOffsetAfterMove); + name = findItem(contentItem, "textName", i); + QVERIFY(name != 0); + QTRY_COMPARE(name->text(), model.name(i)); + number = findItem(contentItem, "textNumber", i); + QVERIFY(number != 0); + QTRY_COMPARE(number->text(), model.number(i)); + } + + delete canvas; + delete testObject; +} + +void tst_QSGListView::inserted_more_data() +{ + QTest::addColumn("contentY"); + QTest::addColumn("insertIndex"); + QTest::addColumn("insertCount"); + QTest::addColumn("itemsOffsetAfterMove"); + + QTest::newRow("add 1, before visible items") + << 80.0 // show 4-19 + << 3 << 1 + << -20.0; // insert above first visible i.e. 0 is at -20, first visible should not move + + QTest::newRow("add multiple, before visible") + << 80.0 // show 4-19 + << 3 << 3 + << -20.0 * 3; // again first visible should not move + + QTest::newRow("add 1, at start of visible, content at start") + << 0.0 + << 0 << 1 + << 0.0; + + QTest::newRow("add multiple, start of visible, content at start") + << 0.0 + << 0 << 3 + << 0.0; + + QTest::newRow("add 1, at start of visible, content not at start") + << 80.0 // show 4-19 + << 4 << 1 + << 0.0; + + QTest::newRow("add multiple, at start of visible, content not at start") + << 80.0 // show 4-19 + << 4 << 3 + << 0.0; + + + QTest::newRow("add 1, at end of visible, content at start") + << 0.0 + << 15 << 1 + << 0.0; + + QTest::newRow("add 1, at end of visible, content at start") + << 0.0 + << 15 << 3 + << 0.0; + + QTest::newRow("add 1, at end of visible, content not at start") + << 80.0 // show 4-19 + << 19 << 1 + << 0.0; + + QTest::newRow("add multiple, at end of visible, content not at start") + << 80.0 // show 4-19 + << 19 << 3 + << 0.0; + + + QTest::newRow("add 1, after visible, content at start") + << 0.0 + << 16 << 1 + << 0.0; + + QTest::newRow("add 1, after visible, content at start") + << 0.0 + << 16 << 3 + << 0.0; + + QTest::newRow("add 1, after visible, content not at start") + << 80.0 // show 4-19 + << 20 << 1 + << 0.0; + + QTest::newRow("add multiple, after visible, content not at start") + << 80.0 // show 4-19 + << 20 << 3 + << 0.0; +} + +template void tst_QSGListView::removed(bool animated) { QSGView *canvas = createView(); @@ -3666,11 +3825,31 @@ void tst_QSGListView::qListModelInterface_inserted() inserted(); } +void tst_QSGListView::qListModelInterface_inserted_more() +{ + inserted_more(); +} + +void tst_QSGListView::qListModelInterface_inserted_more_data() +{ + inserted_more_data(); +} + void tst_QSGListView::qAbstractItemModel_inserted() { inserted(); } +void tst_QSGListView::qAbstractItemModel_inserted_more() +{ + inserted_more(); +} + +void tst_QSGListView::qAbstractItemModel_inserted_more_data() +{ + inserted_more_data(); +} + void tst_QSGListView::qListModelInterface_removed() { removed(false); -- 2.7.4