From 162f9d19231612f2b5ae55156ecfd449d3f2f8d7 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 4 Nov 2009 10:33:45 +1000 Subject: Fix moving items in visual item model. --- .../graphicsitems/qmlgraphicsvisualitemmodel.cpp | 32 ++++-- .../graphicsitems/qmlgraphicsvisualitemmodel_p.h | 1 + tests/auto/declarative/listview/data/listview.qml | 4 +- tests/auto/declarative/listview/tst_listview.cpp | 120 +++++++++++++++++++++ 4 files changed, 149 insertions(+), 8 deletions(-) diff --git a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp index 686c0da..80b2458 100644 --- a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp @@ -617,6 +617,8 @@ void QmlGraphicsVisualDataModel::setModel(const QVariant &model) this, SLOT(_q_rowsRemoved(const QModelIndex &,int,int))); QObject::disconnect(d->m_abstractItemModel, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)), this, SLOT(_q_dataChanged(const QModelIndex&,const QModelIndex&))); + QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int)), + this, SLOT(_q_rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int))); } else if (d->m_visualItemModel) { QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)), this, SIGNAL(itemsInserted(int,int))); @@ -654,6 +656,8 @@ void QmlGraphicsVisualDataModel::setModel(const QVariant &model) this, SLOT(_q_rowsRemoved(const QModelIndex &,int,int))); QObject::connect(d->m_abstractItemModel, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)), this, SLOT(_q_dataChanged(const QModelIndex&,const QModelIndex&))); + QObject::connect(d->m_abstractItemModel, SIGNAL(rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int)), + this, SLOT(_q_rowsMoved(const QModelIndex&,int,int,const QModelIndex&,int))); return; } if ((d->m_visualItemModel = qvariant_cast(model))) { @@ -978,9 +982,10 @@ void QmlGraphicsVisualDataModel::_q_itemsMoved(int from, int to, int count) for (QHash::Iterator iter = d->m_cache.begin(); iter != d->m_cache.end(); ) { + int diff = from > to ? count : -count; if (iter.key() >= qMin(from,to) && iter.key() < qMax(from+count,to+count)) { QmlGraphicsVisualDataModelPrivate::ObjectRef objRef = *iter; - int index = iter.key() + from - to; + int index = iter.key() + diff; iter = d->m_cache.erase(iter); items.insert(index, objRef); @@ -996,20 +1001,35 @@ void QmlGraphicsVisualDataModel::_q_itemsMoved(int from, int to, int count) emit itemsMoved(from, to, count); } -void QmlGraphicsVisualDataModel::_q_rowsInserted(const QModelIndex &, int begin, int end) +void QmlGraphicsVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end) { - _q_itemsInserted(begin, end - begin + 1); + if (!parent.isValid()) + _q_itemsInserted(begin, end - begin + 1); } -void QmlGraphicsVisualDataModel::_q_rowsRemoved(const QModelIndex &, int begin, int end) +void QmlGraphicsVisualDataModel::_q_rowsRemoved(const QModelIndex &parent, int begin, int end) { - _q_itemsRemoved(begin, end - begin + 1); + if (!parent.isValid()) + _q_itemsRemoved(begin, end - begin + 1); +} + +void QmlGraphicsVisualDataModel::_q_rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow) +{ + const int count = sourceEnd - sourceStart + 1; + if (!destinationParent.isValid() && !sourceParent.isValid()) { + _q_itemsMoved(sourceStart, destinationRow, count); + } else if (!sourceParent.isValid()) { + _q_itemsRemoved(sourceStart, count); + } else if (!destinationParent.isValid()) { + _q_itemsInserted(destinationRow, count); + } } void QmlGraphicsVisualDataModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end) { Q_D(QmlGraphicsVisualDataModel); - _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles); + if (!begin.parent().isValid()) + _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles); } void QmlGraphicsVisualDataModel::_q_createdPackage(int index, QmlPackage *package) diff --git a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h index 8b0a8f5..3ff2a74 100644 --- a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h +++ b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel_p.h @@ -183,6 +183,7 @@ private Q_SLOTS: void _q_itemsMoved(int from, int to, int count); void _q_rowsInserted(const QModelIndex &,int,int); void _q_rowsRemoved(const QModelIndex &,int,int); + void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int); void _q_dataChanged(const QModelIndex&,const QModelIndex&); void _q_createdPackage(int index, QmlPackage *package); void _q_destroyingPackage(QmlPackage *package); diff --git a/tests/auto/declarative/listview/data/listview.qml b/tests/auto/declarative/listview/data/listview.qml index 9039b55..b7b838b 100644 --- a/tests/auto/declarative/listview/data/listview.qml +++ b/tests/auto/declarative/listview/data/listview.qml @@ -6,7 +6,7 @@ Rectangle { color: "#ffffff" resources: [ Component { - id: Delegate + id: myDelegate Rectangle { id: wrapper objectName: "wrapper" @@ -41,6 +41,6 @@ Rectangle { width: 240 height: 320 model: testModel - delegate: Delegate + delegate: myDelegate } } diff --git a/tests/auto/declarative/listview/tst_listview.cpp b/tests/auto/declarative/listview/tst_listview.cpp index 42d4900..441138b 100644 --- a/tests/auto/declarative/listview/tst_listview.cpp +++ b/tests/auto/declarative/listview/tst_listview.cpp @@ -66,11 +66,15 @@ private slots: void qListModelInterface_removed(); void qAbstractItemModel_removed(); + void qListModelInterface_moved(); + void qAbstractItemModel_moved(); + private: template void items(); template void changed(); template void inserted(); template void removed(); + template void moved(); QmlView *createView(const QString &filename); template T *findItem(QmlGraphicsItem *parent, const QString &id, int index=-1); @@ -140,6 +144,11 @@ public: emit itemsRemoved(index, 1); } + void moveItem(int from, int to) { + list.move(from, to); + emit itemsMoved(from, to, 1); + } + void modifyItem(int index, const QString &name, const QString &number) { list[index] = QPair(name, number); emit itemsChanged(index, 1, roles()); @@ -195,6 +204,12 @@ public: emit endRemoveRows(); } + void moveItem(int from, int to) { + emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to); + list.move(from, to); + emit endMoveRows(); + } + void modifyItem(int idx, const QString &name, const QString &number) { list[idx] = QPair(name, number); emit dataChanged(index(idx,0), index(idx,0)); @@ -454,6 +469,100 @@ void tst_QmlGraphicsListView::removed() delete canvas; } +template +void tst_QmlGraphicsListView::moved() +{ + QmlView *canvas = createView(SRCDIR "/data/listview.qml"); + + T model; + for (int i = 0; i < 30; i++) + model.addItem("Item" + QString::number(i), ""); + + QmlContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + canvas->execute(); + qApp->processEvents(); + + QmlGraphicsListView *listview = findItem(canvas->root(), "list"); + QVERIFY(listview != 0); + + QmlGraphicsItem *viewport = listview->viewport(); + QVERIFY(viewport != 0); + + model.moveItem(1, 4); + + // let transitions settle. + QTest::qWait(1000); + + QmlGraphicsText *name = findItem(viewport, "textName", 1); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(1)); + QmlGraphicsText *number = findItem(viewport, "textNumber", 1); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(1)); + + name = findItem(viewport, "textName", 4); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(4)); + number = findItem(viewport, "textNumber", 4); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(4)); + + // Confirm items positioned correctly + int itemCount = findItems(viewport, "wrapper").count(); + for (int i = 0; i < model.count() && i < itemCount; ++i) { + QmlGraphicsItem *item = findItem(viewport, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QVERIFY(item); + QVERIFY(item->y() == i*20); + } + + listview->setViewportY(80); + + // move outside visible area + model.moveItem(1, 18); + + // let transitions settle. + QTest::qWait(1000); + + // Confirm items positioned correctly and indexes correct + for (int i = 3; i < model.count() && i < itemCount; ++i) { + QmlGraphicsItem *item = findItem(viewport, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QVERIFY(item); + QVERIFY(item->y() == i*20 + 20); + name = findItem(viewport, "textName", i); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(i)); + number = findItem(viewport, "textNumber", i); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(i)); + } + + // move from outside visible into visible + model.moveItem(20, 4); + + // let transitions settle. + QTest::qWait(1000); + + // Confirm items positioned correctly and indexes correct + for (int i = 3; i < model.count() && i < itemCount; ++i) { + QmlGraphicsItem *item = findItem(viewport, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QVERIFY(item); + QVERIFY(item->y() == i*20 + 20); + name = findItem(viewport, "textName", i); + QVERIFY(name != 0); + QCOMPARE(name->text(), model.name(i)); + number = findItem(viewport, "textNumber", i); + QVERIFY(number != 0); + QCOMPARE(number->text(), model.number(i)); + } + + delete canvas; +} + void tst_QmlGraphicsListView::qListModelInterface_items() { items(); @@ -494,6 +603,17 @@ void tst_QmlGraphicsListView::qAbstractItemModel_removed() removed(); } +void tst_QmlGraphicsListView::qListModelInterface_moved() +{ + moved(); +} + +void tst_QmlGraphicsListView::qAbstractItemModel_moved() +{ + moved(); +} + + QmlView *tst_QmlGraphicsListView::createView(const QString &filename) { QmlView *canvas = new QmlView(0); -- cgit v0.12