diff options
-rw-r--r-- | src/declarative/items/qsggridview.cpp | 16 | ||||
-rw-r--r-- | src/declarative/items/qsglistview.cpp | 13 | ||||
-rw-r--r-- | tests/auto/declarative/qsggridview/tst_qsggridview.cpp | 163 | ||||
-rw-r--r-- | tests/auto/declarative/qsglistview/tst_qsglistview.cpp | 189 |
4 files changed, 274 insertions, 107 deletions
diff --git a/src/declarative/items/qsggridview.cpp b/src/declarative/items/qsggridview.cpp index 1aa7292060..8559379d20 100644 --- a/src/declarative/items/qsggridview.cpp +++ b/src/declarative/items/qsggridview.cpp @@ -1500,10 +1500,18 @@ void QSGGridView::itemsMoved(int from, int to, int count) d->moveReason = QSGGridViewPrivate::Other; FxGridItemSG *firstVisible = static_cast<FxGridItemSG*>(d->firstVisibleItem()); QHash<int,FxGridItemSG*> moved; + int moveByCount = 0; bool movingBackwards = from > to; int firstItemIndex = firstVisible ? firstVisible->index : -1; + // if visibleItems.first() is above the content start pos, and the items + // beneath it are moved, ensure this first item is later repositioned correctly + // (to above the next visible item) so that subsequent layout() is correct + bool repositionFirstItem = firstVisible + && d->visibleItems.first()->position() < firstVisible->position() + && from > d->visibleItems.first()->index; + QList<FxViewItem*>::Iterator it = d->visibleItems.begin(); while (it != d->visibleItems.end()) { FxViewItem *item = *it; @@ -1511,6 +1519,8 @@ void QSGGridView::itemsMoved(int from, int to, int count) // take the items that are moving item->index += (to-from); moved.insert(item->index, static_cast<FxGridItemSG*>(item)); + if (repositionFirstItem) + moveByCount++; it = d->visibleItems.erase(it); } else { if (item->index > from && item->index != -1) { @@ -1594,6 +1604,12 @@ void QSGGridView::itemsMoved(int from, int to, int count) d->releaseItem(item); } + // Ensure we don't cause an ugly list scroll. + if (d->visibleItems.count() && moveByCount > 0) { + FxGridItemSG *first = static_cast<FxGridItemSG*>(d->visibleItems.first()); + first->setPosition(first->colPos(), first->rowPos() + ((moveByCount / d->columns) * d->rowSize())); + } + d->layout(); } diff --git a/src/declarative/items/qsglistview.cpp b/src/declarative/items/qsglistview.cpp index 0d6a4947f4..abfb4fe9a0 100644 --- a/src/declarative/items/qsglistview.cpp +++ b/src/declarative/items/qsglistview.cpp @@ -1815,13 +1815,19 @@ void QSGListView::itemsMoved(int from, int to, int count) d->moveReason = QSGListViewPrivate::Other; FxViewItem *firstVisible = d->firstVisibleItem(); - qreal firstItemPos = firstVisible->position(); QHash<int,FxViewItem*> moved; int moveBy = 0; bool movingBackwards = from > to; int firstItemIndex = firstVisible ? firstVisible->index : -1; + // if visibleItems.first() is above the content start pos, and the items + // beneath it are moved, ensure this first item is later repositioned correctly + // (to above the next visible item) so that subsequent layout() is correct + bool repositionFirstItem = firstVisible + && d->visibleItems.first()->position() < firstVisible->position() + && from > d->visibleItems.first()->index; + QList<FxViewItem*>::Iterator it = d->visibleItems.begin(); while (it != d->visibleItems.end()) { FxViewItem *item = *it; @@ -1829,7 +1835,7 @@ void QSGListView::itemsMoved(int from, int to, int count) // take the items that are moving item->index += (to-from); moved.insert(item->index, item); - if (item->position() < firstItemPos) + if (repositionFirstItem) moveBy += item->size(); it = d->visibleItems.erase(it); } else { @@ -1913,7 +1919,8 @@ void QSGListView::itemsMoved(int from, int to, int count) } // Ensure we don't cause an ugly list scroll. - static_cast<FxListItemSG*>(d->visibleItems.first())->setPosition(d->visibleItems.first()->position() + moveBy); + if (d->visibleItems.count()) + static_cast<FxListItemSG*>(d->visibleItems.first())->setPosition(d->visibleItems.first()->position() + moveBy); d->updateSections(); d->layout(); diff --git a/tests/auto/declarative/qsggridview/tst_qsggridview.cpp b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp index 76b30322c6..d2115e123d 100644 --- a/tests/auto/declarative/qsggridview/tst_qsggridview.cpp +++ b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp @@ -77,6 +77,7 @@ private slots: void removed(); void clear(); void moved(); + void moved_data(); void swapWithFirstItem(); void changeFlow(); void currentIndex(); @@ -115,6 +116,29 @@ private: QList<T*> findItems(QSGItem *parent, const QString &objectName); void dumpTree(QSGItem *parent, int depth = 0); }; + +template<typename T> +void tst_qsggridview_move(int from, int to, int n, T *items) +{ + if (n == 1) { + items->move(from, to); + } else { + T replaced; + int i=0; + typename T::ConstIterator it=items->begin(); it += from+n; + for (; i<to-from; ++i,++it) + replaced.append(*it); + i=0; + it=items->begin(); it += from; + for (; i<n; ++i,++it) + replaced.append(*it); + typename T::ConstIterator f=replaced.begin(); + typename T::Iterator t=items->begin(); t += from; + for (; f != replaced.end(); ++f, ++t) + *t = *f; + } +} + void tst_QSGGridView::initTestCase() { QSGView canvas; @@ -191,6 +215,12 @@ public: emit endMoveRows(); } + void moveItems(int from, int to, int count) { + emit beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to); + tst_qsggridview_move(from, to, count, &list); + emit endMoveRows(); + } + void modifyItem(int idx, const QString &name, const QString &number) { list[idx] = QPair<QString,QString>(name, number); emit dataChanged(index(idx,0), index(idx,0)); @@ -566,7 +596,16 @@ void tst_QSGGridView::clear() void tst_QSGGridView::moved() { + QFETCH(qreal, contentY); + QFETCH(int, from); + QFETCH(int, to); + QFETCH(int, count); + QFETCH(qreal, itemsOffsetAfterMove); + + QSGText *name; + QSGText *number; QSGView *canvas = createView(); + canvas->show(); TestModel model; for (int i = 0; i < 30; i++) @@ -586,74 +625,93 @@ void tst_QSGGridView::moved() QSGItem *contentItem = gridview->contentItem(); QTRY_VERIFY(contentItem != 0); - model.moveItem(1, 8); - - QSGText *name = findItem<QSGText>(contentItem, "textName", 1); - QTRY_VERIFY(name != 0); - QTRY_COMPARE(name->text(), model.name(1)); - QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1); - QTRY_VERIFY(number != 0); - QTRY_COMPARE(number->text(), model.number(1)); + QSGItem *currentItem = gridview->currentItem(); + QTRY_VERIFY(currentItem != 0); - name = findItem<QSGText>(contentItem, "textName", 8); - QTRY_VERIFY(name != 0); - QTRY_COMPARE(name->text(), model.name(8)); - number = findItem<QSGText>(contentItem, "textNumber", 8); - QTRY_VERIFY(number != 0); - QTRY_COMPARE(number->text(), model.number(8)); + gridview->setContentY(contentY); + model.moveItems(from, to, count); - // Confirm items positioned correctly + // Confirm items positioned correctly and indexes correct + int firstVisibleIndex = qCeil(contentY / 60.0) * 3; int itemCount = findItems<QSGItem>(contentItem, "wrapper").count(); - for (int i = 0; i < model.count() && i < itemCount; ++i) { - QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i); - if (!item) qWarning() << "Item" << i << "not found"; - QTRY_VERIFY(item); - QTRY_VERIFY(item->x() == (i%3)*80); - QTRY_VERIFY(item->y() == (i/3)*60); - } - gridview->setContentY(120); - - // move outside visible area - model.moveItem(1, 25); - - // Confirm items positioned correctly and indexes correct - itemCount = findItems<QSGItem>(contentItem, "wrapper").count()-1; - for (int i = 6; i < model.count()-6 && i < itemCount+6; ++i) { + for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) { + if (i >= firstVisibleIndex + 18) // index has moved out of view + continue; QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i); - if (!item) qWarning() << "Item" << i << "not found"; - QTRY_VERIFY(item); - QTRY_COMPARE(item->x(), qreal((i%3)*80)); - QTRY_COMPARE(item->y(), qreal((i/3)*60)); - name = findItem<QSGText>(contentItem, "textName", i); - QTRY_VERIFY(name != 0); - QTRY_COMPARE(name->text(), model.name(i)); - number = findItem<QSGText>(contentItem, "textNumber", i); - QTRY_VERIFY(number != 0); - QTRY_COMPARE(number->text(), model.number(i)); - } + QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); - // move from outside visible into visible - model.moveItem(28, 8); - - // Confirm items positioned correctly and indexes correct - for (int i = 6; i < model.count()-6 && i < itemCount+6; ++i) { - QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i); - if (!item) qWarning() << "Item" << i << "not found"; - QTRY_VERIFY(item); QTRY_VERIFY(item->x() == (i%3)*80); - QTRY_VERIFY(item->y() == (i/3)*60); + QTRY_VERIFY(item->y() == (i/3)*60 + itemsOffsetAfterMove); + name = findItem<QSGText>(contentItem, "textName", i); - QTRY_VERIFY(name != 0); + QVERIFY(name != 0); QTRY_COMPARE(name->text(), model.name(i)); number = findItem<QSGText>(contentItem, "textNumber", i); - QTRY_VERIFY(number != 0); + QVERIFY(number != 0); QTRY_COMPARE(number->text(), model.number(i)); + + // current index should have been updated + if (item == currentItem) + QTRY_COMPARE(gridview->currentIndex(), i); } delete canvas; } +void tst_QSGGridView::moved_data() +{ + QTest::addColumn<qreal>("contentY"); + QTest::addColumn<int>("from"); + QTest::addColumn<int>("to"); + QTest::addColumn<int>("count"); + QTest::addColumn<qreal>("itemsOffsetAfterMove"); + + // model starts with 30 items, each 80x60, in area 240x320 + // 18 items should be visible at a time + + QTest::newRow("move 1 forwards, within visible items") + << 0.0 + << 1 << 8 << 1 + << 0.0; + + QTest::newRow("move 1 forwards, from non-visible -> visible") + << 120.0 // show 6-23 + << 1 << 23 << 1 + << 0.0; + + QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)") + << 120.0 // // show 6-23 + << 0 << 6 << 1 + << 0.0; + + QTest::newRow("move 1 forwards, from visible -> non-visible") + << 0.0 + << 1 << 20 << 1 + << 0.0; + + QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)") + << 0.0 + << 0 << 20 << 1 + << 0.0; + + + QTest::newRow("move 1 backwards, within visible items") + << 0.0 + << 10 << 5 << 1 + << 0.0; + + QTest::newRow("move 1 backwards, from non-visible -> visible") + << 0.0 + << 28 << 8 << 1 + << 0.0; + + QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)") + << 0.0 + << 29 << 14 << 1 + << 0.0; +} + void tst_QSGGridView::swapWithFirstItem() { // QTBUG_9697 @@ -2395,3 +2453,4 @@ void tst_QSGGridView::dumpTree(QSGItem *parent, int depth) QTEST_MAIN(tst_QSGGridView) #include "tst_qsggridview.moc" + diff --git a/tests/auto/declarative/qsglistview/tst_qsglistview.cpp b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp index 19bc0f0e8a..30daeb85ef 100644 --- a/tests/auto/declarative/qsglistview/tst_qsglistview.cpp +++ b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp @@ -86,7 +86,9 @@ private slots: void qAbstractItemModel_removed(); void qListModelInterface_moved(); + void qListModelInterface_moved_data(); void qAbstractItemModel_moved(); + void qAbstractItemModel_moved_data(); void qListModelInterface_clear(); void qAbstractItemModel_clear(); @@ -141,6 +143,8 @@ private: template<typename T> QList<T*> findItems(QSGItem *parent, const QString &objectName); void dumpTree(QSGItem *parent, int depth = 0); + + void moved_data(); }; void tst_QSGListView::initTestCase() @@ -193,6 +197,36 @@ public: int mCacheBuffer; }; +template<typename T> +void tst_qsglistview_move(int from, int to, int n, T *items) +{ + if (from > to) { + // Only move forwards - flip if backwards moving + int tfrom = from; + int tto = to; + from = tto; + to = tto+n; + n = tfrom-tto; + } + if (n == 1) { + items->move(from, to); + } else { + T replaced; + int i=0; + typename T::ConstIterator it=items->begin(); it += from+n; + for (; i<to-from; ++i,++it) + replaced.append(*it); + i=0; + it=items->begin(); it += from; + for (; i<n; ++i,++it) + replaced.append(*it); + typename T::ConstIterator f=replaced.begin(); + typename T::Iterator t=items->begin(); t += from; + for (; f != replaced.end(); ++f, ++t) + *t = *f; + } +} + class TestModel : public QListModelInterface { Q_OBJECT @@ -275,6 +309,11 @@ public: emit itemsMoved(from, to, 1); } + void moveItems(int from, int to, int count) { + tst_qsglistview_move(from, to, count, &list); + emit itemsMoved(from, to, count); + } + void modifyItem(int index, const QString &name, const QString &number) { list[index] = QPair<QString,QString>(name, number); emit itemsChanged(index, 1, roles()); @@ -356,6 +395,12 @@ public: emit endMoveRows(); } + void moveItems(int from, int to, int count) { + emit beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to); + tst_qsglistview_move(from, to, count, &list); + emit endMoveRows(); + } + void modifyItem(int idx, const QString &name, const QString &number) { list[idx] = QPair<QString,QString>(name, number); emit dataChanged(index(idx,0), index(idx,0)); @@ -592,7 +637,6 @@ void tst_QSGListView::removed(bool animated) ctxt->setContextProperty("testModel", &model); TestObject *testObject = new TestObject; - testObject->setAnimate(animated); ctxt->setContextProperty("testObject", testObject); canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml")); @@ -790,11 +834,19 @@ void tst_QSGListView::clear() delete testObject; } - template <class T> void tst_QSGListView::moved() { + QFETCH(qreal, contentY); + QFETCH(int, from); + QFETCH(int, to); + QFETCH(int, count); + QFETCH(qreal, itemsOffsetAfterMove); + + QSGText *name; + QSGText *number; QSGView *canvas = createView(); + canvas->show(); T model; for (int i = 0; i < 30; i++) @@ -815,71 +867,93 @@ void tst_QSGListView::moved() QSGItem *contentItem = listview->contentItem(); QTRY_VERIFY(contentItem != 0); - model.moveItem(1, 4); + QSGItem *currentItem = listview->currentItem(); + QTRY_VERIFY(currentItem != 0); - QSGText *name = findItem<QSGText>(contentItem, "textName", 1); - QTRY_VERIFY(name != 0); - QTRY_COMPARE(name->text(), model.name(1)); - QSGText *number = findItem<QSGText>(contentItem, "textNumber", 1); - QTRY_VERIFY(number != 0); - QTRY_COMPARE(number->text(), model.number(1)); - - name = findItem<QSGText>(contentItem, "textName", 4); - QTRY_VERIFY(name != 0); - QTRY_COMPARE(name->text(), model.name(4)); - number = findItem<QSGText>(contentItem, "textNumber", 4); - QTRY_VERIFY(number != 0); - QTRY_COMPARE(number->text(), model.number(4)); + listview->setContentY(contentY); + model.moveItems(from, to, count); + qApp->processEvents(); - // Confirm items positioned correctly + // Confirm items positioned correctly and indexes correct + int firstVisibleIndex = qCeil(contentY / 20.0); int itemCount = findItems<QSGItem>(contentItem, "wrapper").count(); - for (int i = 0; i < model.count() && i < itemCount; ++i) { - QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i); - if (!item) qWarning() << "Item" << i << "not found"; - QTRY_VERIFY(item); - QTRY_VERIFY(item->y() == i*20); - } - - listview->setContentY(80); - - // move outside visible area - model.moveItem(1, 18); - // Confirm items positioned correctly and indexes correct - for (int i = 3; i < model.count() && i < itemCount; ++i) { + for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) { + if (i >= firstVisibleIndex + 16) // index has moved out of view + continue; QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i); - if (!item) qWarning() << "Item" << i << "not found"; - QTRY_VERIFY(item); - QTRY_COMPARE(item->y(), i*20.0 + 20); + QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i))); + QTRY_COMPARE(item->y(), i*20.0 + itemsOffsetAfterMove); name = findItem<QSGText>(contentItem, "textName", i); - QTRY_VERIFY(name != 0); + QVERIFY(name != 0); QTRY_COMPARE(name->text(), model.name(i)); number = findItem<QSGText>(contentItem, "textNumber", i); - QTRY_VERIFY(number != 0); + QVERIFY(number != 0); QTRY_COMPARE(number->text(), model.number(i)); - } - - // move from outside visible into visible - model.moveItem(20, 4); - // Confirm items positioned correctly and indexes correct - for (int i = 3; i < model.count() && i < itemCount; ++i) { - QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i); - if (!item) qWarning() << "Item" << i << "not found"; - QTRY_VERIFY(item); - QTRY_COMPARE(item->y(), i*20.0 + 20); - name = findItem<QSGText>(contentItem, "textName", i); - QTRY_VERIFY(name != 0); - QTRY_COMPARE(name->text(), model.name(i)); - number = findItem<QSGText>(contentItem, "textNumber", i); - QTRY_VERIFY(number != 0); - QTRY_COMPARE(number->text(), model.number(i)); + // current index should have been updated + if (item == currentItem) + QTRY_COMPARE(listview->currentIndex(), i); } delete canvas; delete testObject; } +void tst_QSGListView::moved_data() +{ + QTest::addColumn<qreal>("contentY"); + QTest::addColumn<int>("from"); + QTest::addColumn<int>("to"); + QTest::addColumn<int>("count"); + QTest::addColumn<qreal>("itemsOffsetAfterMove"); + + // model starts with 30 items, each 20px high, in area 320px high + // 16 items should be visible at a time + // itemsOffsetAfterMove should be > 0 whenever items above the visible pos have moved + + QTest::newRow("move 1 forwards, within visible items") + << 0.0 + << 1 << 4 << 1 + << 0.0; + + QTest::newRow("move 1 forwards, from non-visible -> visible") + << 80.0 // show 4-19 + << 1 << 18 << 1 + << 20.0; + + QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)") + << 80.0 // show 4-19 + << 0 << 4 << 1 + << 20.0; + + QTest::newRow("move 1 forwards, from visible -> non-visible") + << 0.0 + << 1 << 16 << 1 + << 0.0; + + QTest::newRow("move 1 forwards, from visible -> non-visible (move first item)") + << 0.0 + << 0 << 16 << 1 + << 20.0; + + + QTest::newRow("move 1 backwards, within visible items") + << 0.0 + << 4 << 1 << 1 + << 0.0; + + QTest::newRow("move 1 backwards, from non-visible -> visible") + << 0.0 + << 20 << 4 << 1 + << 0.0; + + QTest::newRow("move 1 backwards, from non-visible -> visible (move last item)") + << 0.0 + << 29 << 15 << 1 + << 0.0; +} + void tst_QSGListView::swapWithFirstItem() { QSGView *canvas = createView(); @@ -903,7 +977,7 @@ void tst_QSGListView::swapWithFirstItem() // ensure content position is stable listview->setContentY(0); - model.moveItem(10, 0); + model.moveItem(1, 0); QTRY_VERIFY(listview->contentY() == 0); delete testObject; @@ -2848,11 +2922,21 @@ void tst_QSGListView::qListModelInterface_moved() moved<TestModel>(); } +void tst_QSGListView::qListModelInterface_moved_data() +{ + moved_data(); +} + void tst_QSGListView::qAbstractItemModel_moved() { moved<TestModel2>(); } +void tst_QSGListView::qAbstractItemModel_moved_data() +{ + moved_data(); +} + void tst_QSGListView::qListModelInterface_clear() { clear<TestModel>(); @@ -2937,3 +3021,4 @@ void tst_QSGListView::dumpTree(QSGItem *parent, int depth) QTEST_MAIN(tst_QSGListView) #include "tst_qsglistview.moc" + |