aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorBea Lam <bea.lam@nokia.com>2011-08-29 15:33:36 +1000
committerQt by Nokia <qt-info@nokia.com>2011-09-01 01:44:29 +0200
commit6fbc4b7e7e5aed8739ca1143e0fc1e38b8c8e17a (patch)
treec1aa4ec039d731bb40a7669f7d1a4fed4015873d /tests
parent8801dd4f173a4e7676400dd18d76d89dfe3b3791 (diff)
Batch view changes instead of applying them immediately
If there are multiple changes to be applied to a view before the next repaint, collate them using QDeclarativeChangeSet and apply the changes as a group on the next layout(). (Note that changes to the current index are applied in sequence as changes are received, since changing it out of order produces different results.) Previously, any itemsInserted(), itemsRemoved() and itemsMoved() changes were immediately applied and items were repositioned immediately. In this situation if the same indexes changed multiple times between repaints, this could lead to redundant changes and bugs arising from multiple changes to the same items. Functions that will execute differently depending on whether pending view changes have been applied (e.g. count(), currentIndex(), highlight()) now call applyPendingChanges() before proceeding to ensure they are executed on a view that is up to date. Also, itemsMoved() operations that moved item/s backwards will now properly move backwards instead of being adjusted to a forward movement (which was implemented recently with e2b5681b1adab83555c7307b05f508d796a1152b) since backwards movements can be implemented more easily with the batched changes which translates moves into insert/remove actions. Change-Id: If9b39755898e8d2ed7e4bc61288206d5f1d653fd Reviewed-on: http://codereview.qt.nokia.com/3697 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/declarative/qsggridview/tst_qsggridview.cpp297
-rw-r--r--tests/auto/declarative/qsglistview/tst_qsglistview.cpp328
2 files changed, 579 insertions, 46 deletions
diff --git a/tests/auto/declarative/qsggridview/tst_qsggridview.cpp b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp
index 49c3080a1c..ae4ca7d7fa 100644
--- a/tests/auto/declarative/qsggridview/tst_qsggridview.cpp
+++ b/tests/auto/declarative/qsggridview/tst_qsggridview.cpp
@@ -78,6 +78,8 @@ private slots:
void clear();
void moved();
void moved_data();
+ void multipleChanges();
+ void multipleChanges_data();
void swapWithFirstItem();
void changeFlow();
void currentIndex();
@@ -150,6 +152,8 @@ void tst_QSGGridView::cleanupTestCase()
{
}
+
+
class TestModel : public QAbstractListModel
{
public:
@@ -196,6 +200,13 @@ public:
emit endInsertRows();
}
+ void insertItems(int index, const QList<QPair<QString, QString> > &items) {
+ emit beginInsertRows(QModelIndex(), index, index + items.count() - 1);
+ for (int i=0; i<items.count(); i++)
+ list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
+ emit endInsertRows();
+ }
+
void removeItem(int index) {
emit beginRemoveRows(QModelIndex(), index, index);
list.removeAt(index);
@@ -355,8 +366,8 @@ void tst_QSGGridView::inserted()
QTRY_VERIFY(contentItem != 0);
model.insertItem(1, "Will", "9876");
- QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
@@ -434,7 +445,7 @@ void tst_QSGGridView::removed()
QTRY_VERIFY(contentItem != 0);
model.removeItem(1);
- QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
QTRY_VERIFY(name != 0);
@@ -443,6 +454,7 @@ void tst_QSGGridView::removed()
QTRY_VERIFY(number != 0);
QTRY_COMPARE(number->text(), model.number(1));
+
// Checks that onRemove is called
QString removed = canvas->rootObject()->property("removed").toString();
QTRY_COMPARE(removed, QString("Item1"));
@@ -452,13 +464,13 @@ void tst_QSGGridView::removed()
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);
}
// Remove first item (which is the current item);
model.removeItem(0);
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
name = findItem<QSGText>(contentItem, "textName", 0);
QTRY_VERIFY(name != 0);
@@ -467,25 +479,25 @@ void tst_QSGGridView::removed()
QTRY_VERIFY(number != 0);
QTRY_COMPARE(number->text(), model.number(0));
+
// Confirm items positioned correctly
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);
}
// Remove items not visible
model.removeItem(25);
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
// Confirm items positioned correctly
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);
}
@@ -498,12 +510,12 @@ void tst_QSGGridView::removed()
QTRY_COMPARE(gridview->contentY(), 120.0);
model.removeItem(1);
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
// Confirm items positioned correctly
for (int i = 6; i < 18; ++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);
}
@@ -511,20 +523,19 @@ void tst_QSGGridView::removed()
// Remove currentIndex
QSGItem *oldCurrent = gridview->currentItem();
model.removeItem(9);
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
QTRY_COMPARE(gridview->currentIndex(), 9);
QTRY_VERIFY(gridview->currentItem() != oldCurrent);
gridview->setContentY(0);
// let transitions settle.
- QTest::qWait(100);
+ QTest::qWait(300);
// Confirm items positioned correctly
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);
}
@@ -587,7 +598,7 @@ void tst_QSGGridView::clear()
// confirm sanity when adding an item to cleared list
model.addItem("New", "1");
- QVERIFY(gridview->count() == 1);
+ QTRY_COMPARE(gridview->count(), 1);
QVERIFY(gridview->currentItem() != 0);
QVERIFY(gridview->currentIndex() == 0);
@@ -631,10 +642,12 @@ void tst_QSGGridView::moved()
gridview->setContentY(contentY);
model.moveItems(from, to, count);
+ // wait for items to move
+ QTest::qWait(300);
+
// Confirm items positioned correctly and indexes correct
int firstVisibleIndex = qCeil(contentY / 60.0) * 3;
int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
-
for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
if (i >= firstVisibleIndex + 18) // index has moved out of view
continue;
@@ -678,12 +691,12 @@ void tst_QSGGridView::moved_data()
QTest::newRow("move 1 forwards, from non-visible -> visible")
<< 120.0 // show 6-23
<< 1 << 23 << 1
- << 0.0;
+ << 0.0; // only 1 item was removed from the 1st row, so it doesn't move down
QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
<< 120.0 // // show 6-23
<< 0 << 6 << 1
- << 0.0;
+ << 0.0; // only 1 item was removed from the 1st row, so it doesn't move down
QTest::newRow("move 1 forwards, from visible -> non-visible")
<< 0.0
@@ -701,6 +714,11 @@ void tst_QSGGridView::moved_data()
<< 10 << 5 << 1
<< 0.0;
+ QTest::newRow("move 1 backwards, within visible items (to first index)")
+ << 0.0
+ << 10 << 0 << 1
+ << 0.0;
+
QTest::newRow("move 1 backwards, from non-visible -> visible")
<< 0.0
<< 28 << 8 << 1
@@ -714,12 +732,12 @@ void tst_QSGGridView::moved_data()
QTest::newRow("move 1 backwards, from visible -> non-visible")
<< 120.0 // show 6-23
<< 7 << 1 << 1
- << 60.0 * 2; // this results in a forward movement that removes 6 items (2 rows)
+ << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)")
<< 120.0 // show 6-23
<< 7 << 0 << 1
- << 60.0 * 2; // first visible item moved, so all items shift 2 rows down with it
+ << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move
QTest::newRow("move multiple forwards, within visible items")
@@ -730,12 +748,12 @@ void tst_QSGGridView::moved_data()
QTest::newRow("move multiple forwards, from non-visible -> visible")
<< 120.0 // show 6-23
<< 1 << 6 << 3
- << 60.0; // top row moved, all items should shift down by 1 row
+ << 60.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is
QTest::newRow("move multiple forwards, from non-visible -> visible (move first item)")
<< 120.0 // show 6-23
<< 0 << 6 << 3
- << 60.0; // top row moved, all items should shift down by 1 row
+ << 60.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row
QTest::newRow("move multiple forwards, from visible -> non-visible")
<< 0.0
@@ -766,14 +784,248 @@ void tst_QSGGridView::moved_data()
QTest::newRow("move multiple backwards, from visible -> non-visible")
<< 120.0 // show 6-23
<< 16 << 1 << 3
- << 60.0 * 5; // this results in a forward movement that removes 15 items (5 rows)
+ << -60.0; // to minimize movement, items are added above visible area, all items move up by 1 row
QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)")
<< 120.0 // show 6-23
<< 16 << 0 << 3
- << 60.0 * 5; // this results in a forward movement that removes 16 items (5 rows)
+ << -60.0; // 16,17,18 move to above item 0, all items move up by 1 row
}
+struct ListChange {
+ enum { Inserted, Removed, Moved, SetCurrent } type;
+ int index;
+ int count;
+ int to; // Move
+
+ static ListChange insert(int index, int count = 1) { ListChange c = { Inserted, index, count, -1 }; return c; }
+ static ListChange remove(int index, int count = 1) { ListChange c = { Removed, index, count, -1 }; return c; }
+ static ListChange move(int index, int to, int count) { ListChange c = { Moved, index, count, to }; return c; }
+ static ListChange setCurrent(int index) { ListChange c = { SetCurrent, index, -1, -1 }; return c; }
+};
+Q_DECLARE_METATYPE(QList<ListChange>)
+
+void tst_QSGGridView::multipleChanges()
+{
+ QFETCH(int, startCount);
+ QFETCH(QList<ListChange>, changes);
+ QFETCH(int, newCount);
+ QFETCH(int, newCurrentIndex);
+
+ QSGView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ for (int i = 0; i < startCount; 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(SRCDIR "/data/gridview1.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ for (int i=0; i<changes.count(); i++) {
+ switch (changes[i].type) {
+ case ListChange::Inserted:
+ {
+ QList<QPair<QString, QString> > items;
+ for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
+ items << qMakePair(QString("new item " + j), QString::number(j));
+ model.insertItems(changes[i].index, items);
+ break;
+ }
+ case ListChange::Removed:
+ model.removeItems(changes[i].index, changes[i].count);
+ break;
+ case ListChange::Moved:
+ model.moveItems(changes[i].index, changes[i].to, changes[i].count);
+ break;
+ case ListChange::SetCurrent:
+ gridview->setCurrentIndex(changes[i].index);
+ break;
+ }
+ }
+
+ QTRY_COMPARE(gridview->count(), newCount);
+ QCOMPARE(gridview->count(), model.count());
+ QTRY_COMPARE(gridview->currentIndex(), newCurrentIndex);
+
+ QSGText *name;
+ QSGText *number;
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 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);
+ QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
+ name = findItem<QSGText>(contentItem, "textName", i);
+ QVERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ number = findItem<QSGText>(contentItem, "textNumber", i);
+ QVERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+
+ delete canvas;
+}
+
+void tst_QSGGridView::multipleChanges_data()
+{
+ QTest::addColumn<int>("startCount");
+ QTest::addColumn<QList<ListChange> >("changes");
+ QTest::addColumn<int>("newCount");
+ QTest::addColumn<int>("newCurrentIndex");
+
+ QList<ListChange> changes;
+
+ for (int i=1; i<30; i++)
+ changes << ListChange::remove(0);
+ QTest::newRow("remove all but 1, first->last") << 30 << changes << 1 << 0;
+
+ changes << ListChange::remove(0);
+ QTest::newRow("remove all") << 30 << changes << 0 << -1;
+
+ changes.clear();
+ changes << ListChange::setCurrent(29);
+ for (int i=29; i>0; i--)
+ changes << ListChange::remove(i);
+ QTest::newRow("remove last (current) -> first") << 30 << changes << 1 << 0;
+
+ QTest::newRow("remove then insert at 0") << 10 << (QList<ListChange>()
+ << ListChange::remove(0, 1)
+ << ListChange::insert(0, 1)
+ ) << 10 << 1;
+
+ QTest::newRow("remove then insert at non-zero index") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(2)
+ << ListChange::remove(2, 1)
+ << ListChange::insert(2, 1)
+ ) << 10 << 3;
+
+ QTest::newRow("remove current then insert below it") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(1)
+ << ListChange::remove(1, 3)
+ << ListChange::insert(2, 2)
+ ) << 9 << 1;
+
+ QTest::newRow("remove current index then move it down") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(2)
+ << ListChange::remove(1, 3)
+ << ListChange::move(1, 5, 1)
+ ) << 7 << 5;
+
+ QTest::newRow("remove current index then move it up") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(5)
+ << ListChange::remove(4, 3)
+ << ListChange::move(4, 1, 1)
+ ) << 7 << 1;
+
+
+ QTest::newRow("insert multiple times") << 0 << (QList<ListChange>()
+ << ListChange::insert(0, 2)
+ << ListChange::insert(0, 4)
+ << ListChange::insert(0, 6)
+ ) << 12 << 10;
+
+ QTest::newRow("insert multiple times with current index changes") << 0 << (QList<ListChange>()
+ << ListChange::insert(0, 2)
+ << ListChange::insert(0, 4)
+ << ListChange::insert(0, 6)
+ << ListChange::setCurrent(3)
+ << ListChange::insert(3, 2)
+ ) << 14 << 5;
+
+ QTest::newRow("insert and remove all") << 0 << (QList<ListChange>()
+ << ListChange::insert(0, 30)
+ << ListChange::remove(0, 30)
+ ) << 0 << -1;
+
+ QTest::newRow("insert and remove current") << 30 << (QList<ListChange>()
+ << ListChange::insert(1)
+ << ListChange::setCurrent(1)
+ << ListChange::remove(1)
+ ) << 30 << 1;
+
+ QTest::newRow("insert before 0, then remove cross section of new and old items") << 10 << (QList<ListChange>()
+ << ListChange::insert(0, 10)
+ << ListChange::remove(5, 10)
+ ) << 10 << 5;
+
+ QTest::newRow("insert multiple, then move new items to end") << 10 << (QList<ListChange>()
+ << ListChange::insert(0, 3)
+ << ListChange::move(0, 10, 3)
+ ) << 13 << 0;
+
+ QTest::newRow("insert multiple, then move new and some old items to end") << 10 << (QList<ListChange>()
+ << ListChange::insert(0, 3)
+ << ListChange::move(0, 8, 5)
+ ) << 13 << 11;
+
+ QTest::newRow("insert multiple at end, then move new and some old items to start") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(9)
+ << ListChange::insert(10, 3)
+ << ListChange::move(8, 0, 5)
+ ) << 13 << 1;
+
+
+ QTest::newRow("move back and forth to same index") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(1)
+ << ListChange::move(1, 2, 2)
+ << ListChange::move(2, 1, 2)
+ ) << 10 << 1;
+
+ QTest::newRow("move forwards then back") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(2)
+ << ListChange::move(1, 2, 3)
+ << ListChange::move(3, 0, 5)
+ ) << 10 << 0;
+
+ QTest::newRow("move current, then remove it") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(5)
+ << ListChange::move(5, 0, 1)
+ << ListChange::remove(0)
+ ) << 9 << 0;
+
+ QTest::newRow("move current, then insert before it") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(5)
+ << ListChange::move(5, 0, 1)
+ << ListChange::insert(0)
+ ) << 11 << 1;
+
+ QTest::newRow("move multiple, then remove them") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(1)
+ << ListChange::move(5, 1, 3)
+ << ListChange::remove(1, 3)
+ ) << 7 << 1;
+
+ QTest::newRow("move multiple, then insert before them") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(5)
+ << ListChange::move(5, 1, 3)
+ << ListChange::insert(1, 5)
+ ) << 15 << 6;
+
+ QTest::newRow("move multiple, then insert after them") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(3)
+ << ListChange::move(0, 1, 2)
+ << ListChange::insert(3, 5)
+ ) << 15 << 8;
+
+
+ QTest::newRow("clear current") << 0 << (QList<ListChange>()
+ << ListChange::insert(0, 5)
+ << ListChange::setCurrent(-1)
+ << ListChange::remove(0, 5)
+ << ListChange::insert(0, 5)
+ ) << 5 << -1;
+}
+
+
void tst_QSGGridView::swapWithFirstItem()
{
// QTBUG_9697
@@ -2375,10 +2627,11 @@ void tst_QSGGridView::onAdd()
items << qMakePair(QString("value %1").arg(i), QString::number(i));
model.addItems(items);
+ QTRY_COMPARE(model.count(), qobject_cast<QSGGridView*>(canvas->rootObject())->count());
qApp->processEvents();
QVariantList result = object->property("addedDelegates").toList();
- QCOMPARE(result.count(), items.count());
+ QTRY_COMPARE(result.count(), items.count());
for (int i=0; i<items.count(); i++)
QCOMPARE(result[i].toString(), items[i].first);
@@ -2423,10 +2676,8 @@ void tst_QSGGridView::onRemove()
canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
QObject *object = canvas->rootObject();
- qApp->processEvents();
-
model.removeItems(indexToRemove, removeCount);
- qApp->processEvents();
+ QTRY_COMPARE(model.count(), qobject_cast<QSGGridView*>(canvas->rootObject())->count());
QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
delete canvas;
diff --git a/tests/auto/declarative/qsglistview/tst_qsglistview.cpp b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp
index 45a32da768..df4c5bc35b 100644
--- a/tests/auto/declarative/qsglistview/tst_qsglistview.cpp
+++ b/tests/auto/declarative/qsglistview/tst_qsglistview.cpp
@@ -51,6 +51,7 @@
#include <QtDeclarative/private/qsgvisualitemmodel_p.h>
#include <QtDeclarative/private/qdeclarativelistmodel_p.h>
#include <QtDeclarative/private/qlistmodelinterface_p.h>
+#include <QtDeclarative/private/qdeclarativechangeset_p.h>
#include "../../../shared/util.h"
#include "incrementalmodel.h"
#include <QtOpenGL/QGLShaderProgram>
@@ -90,6 +91,9 @@ private slots:
void qAbstractItemModel_moved();
void qAbstractItemModel_moved_data();
+ void multipleChanges();
+ void multipleChanges_data();
+
void qListModelInterface_clear();
void qAbstractItemModel_clear();
@@ -294,6 +298,12 @@ public:
emit itemsInserted(index, 1);
}
+ void insertItems(int index, const QList<QPair<QString, QString> > &items) {
+ for (int i=0; i<items.count(); i++)
+ list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
+ emit itemsInserted(index, items.count());
+ }
+
void removeItem(int index) {
list.removeAt(index);
emit itemsRemoved(index, 1);
@@ -378,6 +388,13 @@ public:
emit endInsertRows();
}
+ void insertItems(int index, const QList<QPair<QString, QString> > &items) {
+ emit beginInsertRows(QModelIndex(), index, index+items.count()-1);
+ for (int i=0; i<items.count(); i++)
+ list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
+ emit endInsertRows();
+ }
+
void removeItem(int index) {
emit beginRemoveRows(QModelIndex(), index, index);
list.removeAt(index);
@@ -544,6 +561,7 @@ template <class T>
void tst_QSGListView::inserted()
{
QSGView *canvas = createView();
+ canvas->show();
T model;
model.addItem("Fred", "12345");
@@ -567,6 +585,7 @@ void tst_QSGListView::inserted()
model.insertItem(1, "Will", "9876");
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
@@ -584,7 +603,7 @@ void tst_QSGListView::inserted()
model.insertItem(0, "Foo", "1111"); // zero index, and current item
- QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
name = findItem<QSGText>(contentItem, "textName", 0);
@@ -625,6 +644,8 @@ void tst_QSGListView::inserted()
// QTBUG-19675
model.clear();
model.insertItem(0, "Hello", "1234");
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
+
QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 0);
QVERIFY(item);
QCOMPARE(item->y(), 0.);
@@ -660,7 +681,7 @@ void tst_QSGListView::removed(bool animated)
QTRY_VERIFY(contentItem != 0);
model.removeItem(1);
- QCOMPARE(canvas->rootObject()->property("count").toInt(), model.count());
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
QSGText *name = findItem<QSGText>(contentItem, "textName", 1);
QTRY_VERIFY(name != 0);
@@ -680,8 +701,7 @@ void tst_QSGListView::removed(bool animated)
// Remove first item (which is the current item);
model.removeItem(0); // post: top item starts at 20
-
- QTest::qWait(300);
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
name = findItem<QSGText>(contentItem, "textName", 0);
QTRY_VERIFY(name != 0);
@@ -701,7 +721,7 @@ void tst_QSGListView::removed(bool animated)
// Remove items not visible
model.removeItem(18);
- qApp->processEvents();
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
// Confirm items positioned correctly
itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
@@ -717,7 +737,7 @@ void tst_QSGListView::removed(bool animated)
listview->setCurrentIndex(10);
model.removeItem(1); // post: top item will be at 40
- qApp->processEvents();
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
// Confirm items positioned correctly
for (int i = 2; i < 18; ++i) {
@@ -769,7 +789,7 @@ void tst_QSGListView::removed(bool animated)
// remove all visible items
model.removeItems(1, 18);
- QTest::qWait(300);
+ QTRY_COMPARE(listview->count() , model.count());
// Confirm items positioned correctly
itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
@@ -781,10 +801,13 @@ void tst_QSGListView::removed(bool animated)
}
model.removeItems(1, 17);
-// QTest::qWait(300);
+ QTRY_COMPARE(listview->count() , model.count());
model.removeItems(2, 1);
+ QTRY_COMPARE(listview->count() , model.count());
+
model.addItem("New", "1");
+ QTRY_COMPARE(listview->count() , model.count());
QTRY_VERIFY(name = findItem<QSGText>(contentItem, "textName", model.count()-1));
QCOMPARE(name->text(), QString("New"));
@@ -889,12 +912,23 @@ void tst_QSGListView::moved()
listview->setContentY(contentY);
model.moveItems(from, to, count);
- qApp->processEvents();
+
+ // wait for items to move
+ QTest::qWait(300);
+
+ QList<QSGItem*> items = findItems<QSGItem>(contentItem, "wrapper");
+ int firstVisibleIndex = -1;
+ for (int i=0; i<items.count(); i++) {
+ if (items[i]->y() >= 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 firstVisibleIndex = qCeil(contentY / 20.0);
int itemCount = findItems<QSGItem>(contentItem, "wrapper").count();
-
for (int i = firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
if (i >= firstVisibleIndex + 16) // index has moved out of view
continue;
@@ -937,12 +971,12 @@ void tst_QSGListView::moved_data()
QTest::newRow("move 1 forwards, from non-visible -> visible")
<< 80.0 // show 4-19
<< 1 << 18 << 1
- << 20.0;
+ << 20.0; // removed 1 item above the first visible, so item 0 should drop down by 1 to minimize movement
QTest::newRow("move 1 forwards, from non-visible -> visible (move first item)")
<< 80.0 // show 4-19
<< 0 << 4 << 1
- << 20.0;
+ << 20.0; // first item has moved to below item4, everything drops down by size of 1 item
QTest::newRow("move 1 forwards, from visible -> non-visible")
<< 0.0
@@ -960,6 +994,11 @@ void tst_QSGListView::moved_data()
<< 4 << 1 << 1
<< 0.0;
+ QTest::newRow("move 1 backwards, within visible items (to first index)")
+ << 0.0
+ << 4 << 0 << 1
+ << 0.0;
+
QTest::newRow("move 1 backwards, from non-visible -> visible")
<< 0.0
<< 20 << 4 << 1
@@ -973,12 +1012,12 @@ void tst_QSGListView::moved_data()
QTest::newRow("move 1 backwards, from visible -> non-visible")
<< 80.0 // show 4-19
<< 16 << 1 << 1
- << 20.0 * 15; // this results in a forward movement that removes 15 items
+ << -20.0; // to minimize movement, item 0 moves to -20, and other items do not move
QTest::newRow("move 1 backwards, from visible -> non-visible (move first item)")
<< 80.0 // show 4-19
<< 16 << 0 << 1
- << 20.0 * 16; // everything should move to after item 16
+ << -20.0; // to minimize movement, item 16 (now at 0) moves to -20, and other items do not move
QTest::newRow("move multiple forwards, within visible items")
@@ -1025,12 +1064,248 @@ void tst_QSGListView::moved_data()
QTest::newRow("move multiple backwards, from visible -> non-visible")
<< 80.0 // show 4-19
<< 16 << 1 << 3
- << 20.0 * 15; // this results in a forward movement that removes 15 items
+ << -20.0 * 3; // to minimize movement, 0 moves by -60, and other items do not move
QTest::newRow("move multiple backwards, from visible -> non-visible (move first item)")
<< 80.0 // show 4-19
<< 16 << 0 << 3
- << 20.0 * 16;
+ << -20.0 * 3; // to minimize movement, 16,17,18 move to above item 0, and other items do not move
+}
+
+
+struct ListChange {
+ enum { Inserted, Removed, Moved, SetCurrent } type;
+ int index;
+ int count;
+ int to; // Move
+
+ static ListChange insert(int index, int count = 1) { ListChange c = { Inserted, index, count, -1 }; return c; }
+ static ListChange remove(int index, int count = 1) { ListChange c = { Removed, index, count, -1 }; return c; }
+ static ListChange move(int index, int to, int count) { ListChange c = { Moved, index, count, to }; return c; }
+ static ListChange setCurrent(int index) { ListChange c = { SetCurrent, index, -1, -1 }; return c; }
+};
+Q_DECLARE_METATYPE(QList<ListChange>)
+
+void tst_QSGListView::multipleChanges()
+{
+ QFETCH(int, startCount);
+ QFETCH(QList<ListChange>, changes);
+ QFETCH(int, newCount);
+ QFETCH(int, newCurrentIndex);
+
+ QSGView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ for (int i = 0; i < startCount; 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(SRCDIR "/data/listviewtest.qml"));
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ for (int i=0; i<changes.count(); i++) {
+ switch (changes[i].type) {
+ case ListChange::Inserted:
+ {
+ QList<QPair<QString, QString> > items;
+ for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j)
+ items << qMakePair(QString("new item " + j), QString::number(j));
+ model.insertItems(changes[i].index, items);
+ break;
+ }
+ case ListChange::Removed:
+ model.removeItems(changes[i].index, changes[i].count);
+ break;
+ case ListChange::Moved:
+ model.moveItems(changes[i].index, changes[i].to, changes[i].count);
+ break;
+ case ListChange::SetCurrent:
+ listview->setCurrentIndex(changes[i].index);
+ break;
+ }
+ }
+
+ QTRY_COMPARE(listview->count(), newCount);
+ QCOMPARE(listview->count(), model.count());
+ QTRY_COMPARE(listview->currentIndex(), newCurrentIndex);
+
+ QSGText *name;
+ QSGText *number;
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 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);
+ QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
+ name = findItem<QSGText>(contentItem, "textName", i);
+ QVERIFY(name != 0);
+ QTRY_COMPARE(name->text(), model.name(i));
+ number = findItem<QSGText>(contentItem, "textNumber", i);
+ QVERIFY(number != 0);
+ QTRY_COMPARE(number->text(), model.number(i));
+ }
+
+ delete testObject;
+ delete canvas;
+}
+
+void tst_QSGListView::multipleChanges_data()
+{
+ QTest::addColumn<int>("startCount");
+ QTest::addColumn<QList<ListChange> >("changes");
+ QTest::addColumn<int>("newCount");
+ QTest::addColumn<int>("newCurrentIndex");
+
+ QList<ListChange> changes;
+
+ for (int i=1; i<30; i++)
+ changes << ListChange::remove(0);
+ QTest::newRow("remove all but 1, first->last") << 30 << changes << 1 << 0;
+
+ changes << ListChange::remove(0);
+ QTest::newRow("remove all") << 30 << changes << 0 << -1;
+
+ changes.clear();
+ changes << ListChange::setCurrent(29);
+ for (int i=29; i>0; i--)
+ changes << ListChange::remove(i);
+ QTest::newRow("remove last (current) -> first") << 30 << changes << 1 << 0;
+
+ QTest::newRow("remove then insert at 0") << 10 << (QList<ListChange>()
+ << ListChange::remove(0, 1)
+ << ListChange::insert(0, 1)
+ ) << 10 << 1;
+
+ QTest::newRow("remove then insert at non-zero index") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(2)
+ << ListChange::remove(2, 1)
+ << ListChange::insert(2, 1)
+ ) << 10 << 3;
+
+ QTest::newRow("remove current then insert below it") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(1)
+ << ListChange::remove(1, 3)
+ << ListChange::insert(2, 2)
+ ) << 9 << 1;
+
+ QTest::newRow("remove current index then move it down") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(2)
+ << ListChange::remove(1, 3)
+ << ListChange::move(1, 5, 1)
+ ) << 7 << 5;
+
+ QTest::newRow("remove current index then move it up") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(5)
+ << ListChange::remove(4, 3)
+ << ListChange::move(4, 1, 1)
+ ) << 7 << 1;
+
+
+ QTest::newRow("insert multiple times") << 0 << (QList<ListChange>()
+ << ListChange::insert(0, 2)
+ << ListChange::insert(0, 4)
+ << ListChange::insert(0, 6)
+ ) << 12 << 10;
+
+ QTest::newRow("insert multiple times with current index changes") << 0 << (QList<ListChange>()
+ << ListChange::insert(0, 2)
+ << ListChange::insert(0, 4)
+ << ListChange::insert(0, 6)
+ << ListChange::setCurrent(3)
+ << ListChange::insert(3, 2)
+ ) << 14 << 5;
+
+ QTest::newRow("insert and remove all") << 0 << (QList<ListChange>()
+ << ListChange::insert(0, 30)
+ << ListChange::remove(0, 30)
+ ) << 0 << -1;
+
+ QTest::newRow("insert and remove current") << 30 << (QList<ListChange>()
+ << ListChange::insert(1)
+ << ListChange::setCurrent(1)
+ << ListChange::remove(1)
+ ) << 30 << 1;
+
+ QTest::newRow("insert before 0, then remove cross section of new and old items") << 10 << (QList<ListChange>()
+ << ListChange::insert(0, 10)
+ << ListChange::remove(5, 10)
+ ) << 10 << 5;
+
+ QTest::newRow("insert multiple, then move new items to end") << 10 << (QList<ListChange>()
+ << ListChange::insert(0, 3)
+ << ListChange::move(0, 10, 3)
+ ) << 13 << 0;
+
+ QTest::newRow("insert multiple, then move new and some old items to end") << 10 << (QList<ListChange>()
+ << ListChange::insert(0, 3)
+ << ListChange::move(0, 8, 5)
+ ) << 13 << 11;
+
+ QTest::newRow("insert multiple at end, then move new and some old items to start") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(9)
+ << ListChange::insert(10, 3)
+ << ListChange::move(8, 0, 5)
+ ) << 13 << 1;
+
+
+ QTest::newRow("move back and forth to same index") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(1)
+ << ListChange::move(1, 2, 2)
+ << ListChange::move(2, 1, 2)
+ ) << 10 << 1;
+
+ QTest::newRow("move forwards then back") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(2)
+ << ListChange::move(1, 2, 3)
+ << ListChange::move(3, 0, 5)
+ ) << 10 << 0;
+
+ QTest::newRow("move current, then remove it") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(5)
+ << ListChange::move(5, 0, 1)
+ << ListChange::remove(0)
+ ) << 9 << 0;
+
+ QTest::newRow("move current, then insert before it") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(5)
+ << ListChange::move(5, 0, 1)
+ << ListChange::insert(0)
+ ) << 11 << 1;
+
+ QTest::newRow("move multiple, then remove them") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(1)
+ << ListChange::move(5, 1, 3)
+ << ListChange::remove(1, 3)
+ ) << 7 << 1;
+
+ QTest::newRow("move multiple, then insert before them") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(5)
+ << ListChange::move(5, 1, 3)
+ << ListChange::insert(1, 5)
+ ) << 15 << 6;
+
+ QTest::newRow("move multiple, then insert after them") << 10 << (QList<ListChange>()
+ << ListChange::setCurrent(3)
+ << ListChange::move(0, 1, 2)
+ << ListChange::insert(3, 5)
+ ) << 15 << 8;
+
+
+ QTest::newRow("clear current") << 0 << (QList<ListChange>()
+ << ListChange::insert(0, 5)
+ << ListChange::setCurrent(-1)
+ << ListChange::remove(0, 5)
+ << ListChange::insert(0, 5)
+ ) << 5 << -1;
}
void tst_QSGListView::swapWithFirstItem()
@@ -1167,6 +1442,7 @@ void tst_QSGListView::enforceRange_withoutHighlight()
void tst_QSGListView::spacing()
{
QSGView *canvas = createView();
+ canvas->show();
TestModel model;
for (int i = 0; i < 30; i++)
@@ -1226,6 +1502,7 @@ void tst_QSGListView::spacing()
void tst_QSGListView::sections()
{
QSGView *canvas = createView();
+ canvas->show();
TestModel model;
for (int i = 0; i < 30; i++)
@@ -1257,6 +1534,7 @@ void tst_QSGListView::sections()
// Remove section boundary
model.removeItem(5);
+ QTRY_COMPARE(listview->count(), model.count());
// New section header created
QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", 5);
@@ -1264,6 +1542,7 @@ void tst_QSGListView::sections()
QTRY_COMPARE(item->height(), 40.0);
model.insertItem(3, "New Item", "0");
+ QTRY_COMPARE(listview->count(), model.count());
// Section header moved
item = findItem<QSGItem>(contentItem, "wrapper", 5);
@@ -1276,6 +1555,7 @@ void tst_QSGListView::sections()
// insert item which will become a section header
model.insertItem(6, "Replace header", "1");
+ QTRY_COMPARE(listview->count(), model.count());
item = findItem<QSGItem>(contentItem, "wrapper", 6);
QTRY_VERIFY(item);
@@ -1304,6 +1584,7 @@ void tst_QSGListView::sections()
// check that headers change when item changes
listview->setContentY(0);
model.modifyItem(0, "changed", "2");
+ QTest::qWait(300);
item = findItem<QSGItem>(contentItem, "wrapper", 1);
QTRY_VERIFY(item);
@@ -1315,6 +1596,7 @@ void tst_QSGListView::sections()
void tst_QSGListView::sectionsDelegate()
{
QSGView *canvas = createView();
+ canvas->show();
TestModel model;
for (int i = 0; i < 30; i++)
@@ -1353,6 +1635,7 @@ void tst_QSGListView::sectionsDelegate()
model.modifyItem(2, "Three", "aaa");
model.modifyItem(3, "Four", "aaa");
model.modifyItem(4, "Five", "aaa");
+ QTest::qWait(300);
for (int i = 0; i < 3; ++i) {
QSGItem *item = findItem<QSGItem>(contentItem,
@@ -1363,7 +1646,7 @@ void tst_QSGListView::sectionsDelegate()
// remove section boundary
model.removeItem(5);
- qApp->processEvents();
+ QTRY_COMPARE(listview->count(), model.count());
for (int i = 0; i < 3; ++i) {
QSGItem *item = findItem<QSGItem>(contentItem,
"sect_" + (i == 0 ? QString("aaa") : QString::number(i)));
@@ -2694,6 +2977,7 @@ void tst_QSGListView::resizeDelegate()
listview->setCurrentIndex(25);
listview->setContentY(0);
+ QTest::qWait(300);
for (int i = 0; i < 16; ++i) {
QSGItem *item = findItem<QSGItem>(contentItem, "wrapper", i);
@@ -2905,8 +3189,7 @@ void tst_QSGListView::onAdd()
for (int i=0; i<itemsToAdd; i++)
items << qMakePair(QString("value %1").arg(i), QString::number(i));
model.addItems(items);
-
- qApp->processEvents();
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
QVariantList result = object->property("addedDelegates").toList();
QCOMPARE(result.count(), items.count());
@@ -2952,10 +3235,9 @@ void tst_QSGListView::onRemove()
canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/attachedSignals.qml"));
QObject *object = canvas->rootObject();
- qApp->processEvents();
-
model.removeItems(indexToRemove, removeCount);
- qApp->processEvents();
+ QTRY_COMPARE(canvas->rootObject()->property("count").toInt(), model.count());
+
QCOMPARE(object->property("removedDelegateCount"), QVariant(removeCount));
delete canvas;