Use QDeclarativeChangeSet to communicate changes to views.
authorAndrew den Exter <andrew.den-exter@nokia.com>
Thu, 1 Sep 2011 05:24:34 +0000 (15:24 +1000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 21 Sep 2011 06:23:52 +0000 (08:23 +0200)
Allows QSGVisualDataModel to send multiple changes at a time. Changes
sets with multiple changes will be generated by VisualDataModels with
items that have been re-ordered or filtered.

Task-number: QTBUG-20107
Change-Id: I28f2620431cc89c61e1061635ffb68dc5801675c
Reviewed-on: http://codereview.qt-project.org/4034
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Bea Lam <bea.lam@nokia.com>
Reviewed-by: Alan Alpert <alan.alpert@nokia.com>
src/declarative/items/qsgitemview.cpp
src/declarative/items/qsgitemview_p.h
src/declarative/items/qsgitemview_p_p.h
src/declarative/items/qsgpathview.cpp
src/declarative/items/qsgpathview_p.h
src/declarative/items/qsgrepeater.cpp
src/declarative/items/qsgrepeater_p.h
src/declarative/items/qsgvisualdatamodel.cpp
src/declarative/items/qsgvisualitemmodel.cpp
src/declarative/items/qsgvisualitemmodel_p.h
tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp

index 2b3f51b..291592b 100644 (file)
@@ -70,68 +70,48 @@ bool QSGItemViewChangeSet::hasPendingChanges() const
     return !pendingChanges.isEmpty();
 }
 
-void QSGItemViewChangeSet::doInsert(int index, int count)
-{
-    pendingChanges.insert(index, count);
-
-    if (newCurrentIndex >= index) {
-        // adjust current item index
-        newCurrentIndex += count;
-        currentChanged = true;
-    } else if (newCurrentIndex < 0) {
-        newCurrentIndex = 0;
-        currentChanged = true;
-    }
-
-    itemCount += count;
-}
-
-void QSGItemViewChangeSet::doRemove(int index, int count)
-{
-    itemCount -= count;
-    pendingChanges.remove(index, count);
-
-    if (newCurrentIndex >= index + count) {
-        newCurrentIndex -= count;
-        currentChanged = true;
-    } else if (newCurrentIndex >= index && newCurrentIndex < index + count) {
-        // current item has been removed.
-        currentRemoved = true;
-        newCurrentIndex = -1;
-        if (itemCount)
-            newCurrentIndex = qMin(index, itemCount-1);
-        currentChanged = true;
-    }
-}
-
-void QSGItemViewChangeSet::doMove(int from, int to, int count)
-{
-    pendingChanges.move(from, to, count);
-
-    if (to > from) {
-        if (newCurrentIndex >= from) {
-            if (newCurrentIndex < from + count)
-                newCurrentIndex += (to-from);
-            else if (newCurrentIndex < to + count)
-                newCurrentIndex -= count;
+void QSGItemViewChangeSet::applyChanges(const QDeclarativeChangeSet &changeSet)
+{
+    pendingChanges.apply(changeSet);
+
+    int moveId = -1;
+    int moveOffset;
+
+    foreach (const QDeclarativeChangeSet::Remove &r, changeSet.removes()) {
+        itemCount -= r.count;
+        if (moveId == -1 && newCurrentIndex >= r.index + r.count) {
+            newCurrentIndex -= r.count;
+            currentChanged = true;
+        } else if (moveId == -1 && newCurrentIndex >= r.index && newCurrentIndex < r.index + r.count) {
+            // current item has been removed.
+            if (r.isMove()) {
+                moveId = r.moveId;
+                moveOffset = newCurrentIndex - r.index;
+            } else {
+                currentRemoved = true;
+                newCurrentIndex = -1;
+                if (itemCount)
+                    newCurrentIndex = qMin(r.index, itemCount - 1);
+            }
+            currentChanged = true;
         }
-        currentChanged = true;
-    } else if (to < from) {
-        if (newCurrentIndex >= to) {
-            if (newCurrentIndex >= from && newCurrentIndex < from + count)
-                newCurrentIndex -= (from-to);
-            else if (newCurrentIndex < from)
-                newCurrentIndex += count;
+    }
+    foreach (const QDeclarativeChangeSet::Insert &i, changeSet.inserts()) {
+        itemCount += i.count;
+        if (moveId == -1) {
+            if (newCurrentIndex >= i.index) {
+                newCurrentIndex += i.count;
+                currentChanged = true;
+            } else if (newCurrentIndex < 0) {
+                newCurrentIndex = 0;
+                currentChanged = true;
+            }
+        } else if (moveId == i.moveId) {
+            newCurrentIndex = i.index + moveOffset;
         }
-        currentChanged = true;
     }
 }
 
-void QSGItemViewChangeSet::QSGItemViewChangeSet::doChange(int index, int count)
-{
-    pendingChanges.change(index, count);
-}
-
 void QSGItemViewChangeSet::prepare(int currentIndex, int count)
 {
     if (active)
@@ -193,11 +173,8 @@ void QSGItemView::setModel(const QVariant &model)
     if (d->modelVariant == model)
         return;
     if (d->model) {
-        disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
-        disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
-        disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
-        disconnect(d->model, SIGNAL(itemsChanged(int,int)), this, SLOT(itemsChanged(int,int)));
-        disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+        disconnect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
+                this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
         disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
         disconnect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
     }
@@ -247,11 +224,8 @@ void QSGItemView::setModel(const QVariant &model)
             }
             d->updateViewport();
         }
-        connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
-        connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
-        connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
-        connect(d->model, SIGNAL(itemsChanged(int,int)), this, SLOT(itemsChanged(int,int)));
-        connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+        connect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
+                this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
         connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
         connect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
         emit countChanged();
@@ -788,66 +762,25 @@ void QSGItemView::destroyRemoved()
     d->layout();
 }
 
-void QSGItemView::itemsInserted(int index, int count)
-{
-    Q_D(QSGItemView);
-    if (!isComponentComplete() || !d->model || !d->model->isValid())
-        return;
-
-    d->currentChanges.prepare(d->currentIndex, d->itemCount);
-    d->currentChanges.doInsert(index, count);
-    polish();
-}
-
-void QSGItemView::itemsRemoved(int index, int count)
+void QSGItemView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
 {
     Q_D(QSGItemView);
-    if (!isComponentComplete() || !d->model || !d->model->isValid())
-        return;
-
-    d->currentChanges.prepare(d->currentIndex, d->itemCount);
-    d->currentChanges.doRemove(index, count);
-    polish();
-}
-
-void QSGItemView::itemsMoved(int from, int to, int count)
-{
-    Q_D(QSGItemView);
-    if (!isComponentComplete() || !d->model || !d->model->isValid())
-        return;
-
-    if (from == to || count <= 0 || from < 0 || to < 0)
-        return;
-
-    d->currentChanges.prepare(d->currentIndex, d->itemCount);
-    d->currentChanges.doMove(from, to, count);
-    polish();
-}
-
-void QSGItemView::itemsChanged(int index, int count)
-{
-    Q_D(QSGItemView);
-    if (!isComponentComplete() || !d->model || !d->model->isValid())
-        return;
-
-    d->currentChanges.prepare(d->currentIndex, d->itemCount);
-    d->currentChanges.doChange(index, count);
-    polish();
-}
+    if (reset) {
+        d->moveReason = QSGItemViewPrivate::SetIndex;
+        d->regenerate();
+        if (d->highlight && d->currentItem) {
+            if (d->autoHighlight)
+                d->resetHighlightPosition();
+            d->updateTrackedItem();
+        }
+        d->moveReason = QSGItemViewPrivate::Other;
 
-void QSGItemView::modelReset()
-{
-    Q_D(QSGItemView);
-    d->moveReason = QSGItemViewPrivate::SetIndex;
-    d->regenerate();
-    if (d->highlight && d->currentItem) {
-        if (d->autoHighlight)
-            d->resetHighlightPosition();
-        d->updateTrackedItem();
+        emit countChanged();
+    } else {
+        d->currentChanges.prepare(d->currentIndex, d->itemCount);
+        d->currentChanges.applyChanges(changeSet);
+        polish();
     }
-    d->moveReason = QSGItemViewPrivate::Other;
-
-    emit countChanged();
 }
 
 void QSGItemView::createdItem(int index, QSGItem *item)
index b1093ff..9d25eab 100644 (file)
@@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE
 
 QT_MODULE(Declarative)
 
+class QDeclarativeChangeSet;
 
 class QSGItemViewPrivate;
 
@@ -192,15 +193,12 @@ protected slots:
     virtual void updateSections() {}
     void destroyRemoved();
     void createdItem(int index, QSGItem *item);
-    void modelReset();
+    void modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
     void destroyingItem(QSGItem *item);
     void animStopped();
     void trackedPositionChanged();
 
-    void itemsInserted(int index, int count);
-    void itemsRemoved(int index, int count);
-    void itemsMoved(int from, int to, int count);
-    void itemsChanged(int index, int count);
+
 
 private:
     Q_DECLARE_PRIVATE(QSGItemView)
index afa50af..73cb68c 100644 (file)
@@ -83,10 +83,7 @@ public:
     void prepare(int currentIndex, int count);
     void reset();
 
-    void doInsert(int index, int count);
-    void doRemove(int index, int count);
-    void doMove(int from, int to, int count);
-    void doChange(int index, int count);
+    void applyChanges(const QDeclarativeChangeSet &changeSet);
 
     int itemCount;
     int newCurrentIndex;
index 11733df..a1038ad 100644 (file)
@@ -46,6 +46,7 @@
 #include <private/qdeclarativestate_p.h>
 #include <private/qdeclarativeopenmetaobject_p.h>
 #include <private/qlistmodelinterface_p.h>
+#include <private/qdeclarativechangeset_p.h>
 
 #include <QtGui/qevent.h>
 #include <QtGui/qevent.h>
@@ -493,10 +494,8 @@ void QSGPathView::setModel(const QVariant &model)
         return;
 
     if (d->model) {
-        disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
-        disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
-        disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
-        disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+        disconnect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
+                this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
         disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
         for (int i=0; i<d->items.count(); i++){
             QSGItem *p = d->items[i];
@@ -524,10 +523,8 @@ void QSGPathView::setModel(const QVariant &model)
     }
     d->modelCount = 0;
     if (d->model) {
-        connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
-        connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
-        connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
-        connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+        connect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
+                this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
         connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
         d->modelCount = d->model->count();
         if (d->model->count())
@@ -1479,121 +1476,98 @@ void QSGPathView::refill()
         d->releaseItem(d->itemCache.takeLast());
 }
 
-void QSGPathView::itemsInserted(int modelIndex, int count)
+void QSGPathView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
 {
-    //XXX support animated insertion
     Q_D(QSGPathView);
-    if (!d->isValid() || !isComponentComplete())
+    if (!d->model || !d->model->isValid() || !d->path || !isComponentComplete())
         return;
 
-    if (d->modelCount) {
-        d->itemCache += d->items;
-        d->items.clear();
-        if (modelIndex <= d->currentIndex) {
-            d->currentIndex += count;
-            emit currentIndexChanged();
-        } else if (d->offset != 0) {
-            d->offset += count;
-            d->offsetAdj += count;
-        }
-    }
-
-    d->modelCount += count;
-    if (d->flicking || d->moving) {
+    if (reset) {
+        d->modelCount = d->model->count();
         d->regenerate();
-        d->updateCurrent();
-    } else {
-        d->firstIndex = -1;
-        d->updateMappedRange();
-        d->scheduleLayout();
+        emit countChanged();
+        return;
     }
-    emit countChanged();
-}
 
-void QSGPathView::itemsRemoved(int modelIndex, int count)
-{
-    //XXX support animated removal
-    Q_D(QSGPathView);
-    if (!d->model || !d->modelCount || !d->model->isValid() || !d->path || !isComponentComplete())
+    if (changeSet.removes().isEmpty() && changeSet.inserts().isEmpty())
         return;
 
-    // fix current
+    const int modelCount = d->modelCount;
+    int moveId = -1;
+    int moveOffset;
     bool currentChanged = false;
-    if (d->currentIndex >= modelIndex + count) {
-        d->currentIndex -= count;
-        currentChanged = true;
-    } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
-        // current item has been removed.
-        d->currentIndex = qMin(modelIndex, d->modelCount-count-1);
-        if (d->currentItem) {
-            if (QSGPathViewAttached *att = d->attached(d->currentItem))
-                att->setIsCurrentItem(true);
-            d->releaseItem(d->currentItem);
-            d->currentItem = 0;
+    bool changedOffset = false;
+    bool removed = false;
+    bool inserted = false;
+    foreach (const QDeclarativeChangeSet::Remove &r, changeSet.removes()) {
+        removed = true;
+        if (moveId == -1 && d->currentIndex >= r.index + r.count) {
+            d->currentIndex -= r.count;
+            currentChanged = true;
+        } else if (moveId == -1 && d->currentIndex >= r.index && d->currentIndex < r.index + r.count) {
+            // current item has been removed.
+            d->currentIndex = qMin(r.index, d->modelCount - r.count - 1);
+            if (r.isMove()) {
+                moveId = r.moveId;
+                moveOffset = d->currentIndex - r.index;
+            } else if (d->currentItem) {
+                if (QSGPathViewAttached *att = d->attached(d->currentItem))
+                    att->setIsCurrentItem(true);
+                d->releaseItem(d->currentItem);
+                d->currentItem = 0;
+            }
+            currentChanged = true;
+        }
+
+        if (r.index > d->currentIndex) {
+            if (d->offset >= r.count) {
+                changedOffset = true;
+                d->offset -= r.count;
+                d->offsetAdj -= r.count;
+            }
+        }
+        d->modelCount -= r.count;
+    }
+    foreach (const QDeclarativeChangeSet::Insert &i, changeSet.inserts()) {
+        inserted = true;
+        if (d->modelCount) {
+            if (moveId == -1 && i.index <= d->currentIndex) {
+                d->currentIndex += i.count;
+            } else if (d->offset != 0) {
+                if (moveId != -1 && moveId == i.moveId)
+                    d->currentIndex = i.index + moveOffset;
+                d->offset += i.count;
+                d->offsetAdj += i.count;
+            }
         }
-        currentChanged = true;
+        d->modelCount += i.count;
     }
 
     d->itemCache += d->items;
     d->items.clear();
 
-    bool changedOffset = false;
-    if (modelIndex > d->currentIndex) {
-        if (d->offset >= count) {
-            changedOffset = true;
-            d->offset -= count;
-            d->offsetAdj -= count;
-        }
-    }
-
-    d->modelCount -= count;
     if (!d->modelCount) {
         while (d->itemCache.count())
             d->releaseItem(d->itemCache.takeLast());
         d->offset = 0;
         changedOffset = true;
         d->tl.reset(d->moveOffset);
-    } else {
+    } else if (removed) {
         d->regenerate();
         d->updateCurrent();
         if (!d->flicking && !d->moving && d->haveHighlightRange && d->highlightRangeMode == QSGPathView::StrictlyEnforceRange)
             d->snapToCurrent();
+    } else if (inserted) {
+        d->firstIndex = -1;
+        d->updateMappedRange();
+        d->scheduleLayout();
     }
     if (changedOffset)
         emit offsetChanged();
     if (currentChanged)
         emit currentIndexChanged();
-    emit countChanged();
-}
-
-void QSGPathView::itemsMoved(int /*from*/, int /*to*/, int /*count*/)
-{
-    Q_D(QSGPathView);
-    if (!d->isValid() || !isComponentComplete())
-        return;
-
-    QList<QSGItem *> removedItems = d->items;
-    d->items.clear();
-    d->regenerate();
-    while (removedItems.count())
-        d->releaseItem(removedItems.takeLast());
-
-    // Fix current index
-    if (d->currentIndex >= 0 && d->currentItem) {
-        int oldCurrent = d->currentIndex;
-        d->currentIndex = d->model->indexOf(d->currentItem, this);
-        if (oldCurrent != d->currentIndex)
-            emit currentIndexChanged();
-    }
-    d->updateCurrent();
-}
-
-void QSGPathView::modelReset()
-{
-    Q_D(QSGPathView);
-    d->modelCount = d->model->count();
-    d->regenerate();
-    emit countChanged();
+    if (d->modelCount != modelCount)
+        emit countChanged();
 }
 
 void QSGPathView::createdItem(int index, QSGItem *item)
index fa00294..b70745e 100644 (file)
@@ -53,6 +53,8 @@ QT_BEGIN_NAMESPACE
 
 QT_MODULE(Declarative)
 
+class QDeclarativeChangeSet;
+
 class QSGPathViewPrivate;
 class QSGPathViewAttached;
 class Q_AUTOTEST_EXPORT QSGPathView : public QSGItem
@@ -186,10 +188,7 @@ private Q_SLOTS:
     void refill();
     void ticked();
     void movementEnding();
-    void itemsInserted(int index, int count);
-    void itemsRemoved(int index, int count);
-    void itemsMoved(int,int,int);
-    void modelReset();
+    void modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
     void createdItem(int index, QSGItem *item);
     void destroyingItem(QSGItem *item);
     void pathUpdated();
index 4e2fa63..0037ea1 100644 (file)
@@ -46,6 +46,7 @@
 #include <private/qdeclarativeglobal_p.h>
 #include <private/qdeclarativelistaccessor_p.h>
 #include <private/qlistmodelinterface_p.h>
+#include <private/qdeclarativechangeset_p.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -185,10 +186,8 @@ void QSGRepeater::setModel(const QVariant &model)
 
     clear();
     if (d->model) {
-        disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
-        disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
-        disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
-        disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+        disconnect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
+                this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
         /*
         disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
         disconnect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
@@ -212,10 +211,8 @@ void QSGRepeater::setModel(const QVariant &model)
             dataModel->setModel(model);
     }
     if (d->model) {
-        connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
-        connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
-        connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
-        connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
+        connect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
+                this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
         /*
         connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
         connect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
@@ -368,72 +365,67 @@ void QSGRepeater::regenerate()
     }
 }
 
-void QSGRepeater::itemsInserted(int index, int count)
+void QSGRepeater::modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
 {
     Q_D(QSGRepeater);
+
     if (!isComponentComplete())
         return;
-    for (int i = 0; i < count; ++i) {
-        int modelIndex = index + i;
-        QSGItem *item = d->model->item(modelIndex);
-        if (item) {
-            QDeclarative_setParent_noEvent(item, parentItem());
-            item->setParentItem(parentItem());
-            if (modelIndex < d->deletables.count())
-                item->stackBefore(d->deletables.at(modelIndex));
-            else
-                item->stackBefore(this);
-            d->deletables.insert(modelIndex, item);
-            emit itemAdded(modelIndex, item);
-        }
-    }
-    emit countChanged();
-}
 
-void QSGRepeater::itemsRemoved(int index, int count)
-{
-    Q_D(QSGRepeater);
-    if (!isComponentComplete() || count <= 0)
-        return;
-    while (count--) {
-        QSGItem *item = d->deletables.takeAt(index);
-        emit itemRemoved(index, item);
-        if (item)
-            d->model->release(item);
-        else
-            break;
+    if (reset) {
+        regenerate();
+        emit countChanged();
     }
-    emit countChanged();
-}
 
-void QSGRepeater::itemsMoved(int from, int to, int count)
-{
-    Q_D(QSGRepeater);
-    if (!isComponentComplete() || count <= 0)
-        return;
-    if (from + count > d->deletables.count()) {
-        regenerate();
-        return;
+    int difference = 0;
+    QHash<int, QList<QPointer<QSGItem> > > moved;
+    foreach (const QDeclarativeChangeSet::Remove &remove, changeSet.removes()) {
+        int index = qMin(remove.index, d->deletables.count());
+        int count = qMin(remove.index + remove.count, d->deletables.count()) - index;
+        if (remove.isMove()) {
+            moved.insert(remove.moveId, d->deletables.mid(index, count));
+            d->deletables.erase(
+                    d->deletables.begin() + index,
+                    d->deletables.begin() + index + count);
+        } else while (count--) {
+            QSGItem *item = d->deletables.takeAt(index);
+            emit itemRemoved(index, item);
+            if (item)
+                d->model->release(item);
+        }
+
+        difference -= remove.count;
     }
-    QList<QSGItem*> removed;
-    int removedCount = count;
-    while (removedCount--)
-        removed << d->deletables.takeAt(from);
-    for (int i = 0; i < count; ++i)
-        d->deletables.insert(to + i, removed.at(i));
-    d->deletables.last()->stackBefore(this);
-    for (int i = d->model->count()-1; i > 0; --i) {
-        QSGItem *item = d->deletables.at(i-1);
-        item->stackBefore(d->deletables.at(i));
+
+    foreach (const QDeclarativeChangeSet::Insert &insert, changeSet.inserts()) {
+        int index = qMin(insert.index, d->deletables.count());
+        if (insert.isMove()) {
+            QList<QPointer<QSGItem> > items = moved.value(insert.moveId);
+            d->deletables = d->deletables.mid(0, index) + items + d->deletables.mid(index);
+            QSGItem *stackBefore = index + items.count() < d->deletables.count()
+                    ? d->deletables.at(index + items.count())
+                    : this;
+            for (int i = index; i < index + items.count(); ++i)
+                d->deletables.at(i)->stackBefore(stackBefore);
+        } else for (int i = 0; i < insert.count; ++i) {
+            int modelIndex = index + i;
+            QSGItem *item = d->model->item(modelIndex);
+            if (item) {
+                QDeclarative_setParent_noEvent(item, parentItem());
+                item->setParentItem(parentItem());
+                if (modelIndex < d->deletables.count())
+                    item->stackBefore(d->deletables.at(modelIndex));
+                else
+                    item->stackBefore(this);
+                d->deletables.insert(modelIndex, item);
+                emit itemAdded(modelIndex, item);
+            }
+        }
+        difference += insert.count;
     }
-}
 
-void QSGRepeater::modelReset()
-{
-    if (!isComponentComplete())
-        return;
-    regenerate();
-    emit countChanged();
+    if (difference != 0)
+        emit countChanged();
 }
 
 QT_END_NAMESPACE
index 497f54c..2094d94 100644 (file)
@@ -51,6 +51,8 @@ QT_BEGIN_NAMESPACE
 
 QT_MODULE(Declarative)
 
+class QDeclarativeChangeSet;
+
 class QSGRepeaterPrivate;
 class Q_AUTOTEST_EXPORT QSGRepeater : public QSGItem
 {
@@ -92,10 +94,7 @@ protected:
     void itemChange(ItemChange change, const ItemChangeData &value);
 
 private Q_SLOTS:
-    void itemsInserted(int,int);
-    void itemsRemoved(int,int);
-    void itemsMoved(int,int,int);
-    void modelReset();
+    void modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
 
 private:
     Q_DISABLE_COPY(QSGRepeater)
index 219d1dc..09f5d5d 100644 (file)
@@ -58,6 +58,7 @@
 #include <private/qdeclarativeglobal_p.h>
 #include <private/qmetaobjectbuilder_p.h>
 #include <private/qdeclarativeproperty_p.h>
+#include <private/qdeclarativechangeset_p.h>
 #include <private/qsgvisualadaptormodel_p.h>
 #include <private/qobject_p.h>
 
@@ -90,6 +91,8 @@ public:
     void emitDestroyingPackage(QDeclarativePackage *package) {
         emit q_func()->destroyingPackage(package); }
 
+    void emitChanges();
+
     QSGVisualAdaptorModel *m_adaptorModel;
     QDeclarativeComponent *m_delegate;
     QDeclarativeGuard<QDeclarativeContext> m_context;
@@ -145,6 +148,9 @@ public:
     friend class QSGVisualDataModelData;
     bool m_delegateValidated : 1;
     bool m_completePending : 1;
+    bool m_reset : 1;
+
+    QDeclarativeChangeSet m_absoluteChangeSet;
 
     QList<QByteArray> watchedRoles;
 };
@@ -229,6 +235,7 @@ QSGVisualDataModelPrivate::QSGVisualDataModelPrivate(QDeclarativeContext *ctxt)
     , m_parts(0)
     , m_delegateValidated(false)
     , m_completePending(false)
+    , m_reset(false)
 {
 }
 
@@ -340,14 +347,10 @@ void QSGVisualDataModel::setDelegate(QDeclarativeComponent *delegate)
     bool wasValid = d->m_delegate != 0;
     d->m_delegate = delegate;
     d->m_delegateValidated = false;
-    if (!wasValid && d->m_adaptorModel->count() && d->m_delegate) {
-        emit itemsInserted(0, d->m_adaptorModel->count());
-        emit countChanged();
-    }
-    if (wasValid && !d->m_delegate && d->m_adaptorModel->count()) {
+    if (!wasValid && d->m_adaptorModel->count() && d->m_delegate)
+        _q_itemsInserted(0, d->m_adaptorModel->count());
+    if (wasValid && !d->m_delegate && d->m_adaptorModel->count())
         _q_itemsRemoved(0, d->m_adaptorModel->count());
-        emit countChanged();
-    }
 }
 
 /*!
@@ -620,7 +623,8 @@ void QSGVisualDataModel::_q_itemsChanged(int index, int count)
     Q_D(QSGVisualDataModel);
     if (!d->m_delegate)
         return;
-    emit itemsChanged(index, count);
+    d->m_absoluteChangeSet.change(index, count);
+    d->emitChanges();
 }
 
 void QSGVisualDataModel::_q_itemsInserted(int index, int count)
@@ -646,7 +650,8 @@ void QSGVisualDataModel::_q_itemsInserted(int index, int count)
     }
     d->m_cache.unite(items);
 
-    emit itemsInserted(index, count);
+    d->m_absoluteChangeSet.insert(index, count);
+    d->emitChanges();
     emit countChanged();
 }
 
@@ -674,7 +679,8 @@ void QSGVisualDataModel::_q_itemsRemoved(int index, int count)
     }
     d->m_cache.unite(items);
 
-    emit itemsRemoved(index, count);
+    d->m_absoluteChangeSet.remove(index, count);
+    d->emitChanges();
     emit countChanged();
 }
 
@@ -710,15 +716,29 @@ void QSGVisualDataModel::_q_itemsMoved(int from, int to, int count)
         }
     }
     d->m_cache.unite(items);
-    emit itemsMoved(from, to, count);
+    d->m_absoluteChangeSet.move(from, to, count);
+    d->emitChanges();
+}
+
+void QSGVisualDataModelPrivate::emitChanges()
+{
+    Q_Q(QSGVisualDataModel);
+    if (!m_absoluteChangeSet.isEmpty()) {
+        emit q->modelUpdated(m_absoluteChangeSet, m_reset);
+        m_absoluteChangeSet.clear();
+        m_reset = false;
+    }
 }
 
-void QSGVisualDataModel::_q_modelReset(int, int)
+void QSGVisualDataModel::_q_modelReset(int oldCount, int newCount)
 {
     Q_D(QSGVisualDataModel);
     if (!d->m_delegate)
         return;
-    emit modelReset();
+    d->m_absoluteChangeSet.remove(0, oldCount);
+    d->m_absoluteChangeSet.insert(0, newCount);
+    d->m_reset = true;
+    d->emitChanges();
     emit countChanged();
 }
 
@@ -729,11 +749,8 @@ QSGVisualPartsModel::QSGVisualPartsModel(QSGVisualDataModel *model, const QStrin
     , m_model(model)
     , m_part(part)
 {
-    connect(m_model, SIGNAL(modelReset()), this, SIGNAL(modelReset()));
-    connect(m_model, SIGNAL(itemsInserted(int,int)), this, SIGNAL(itemsInserted(int,int)));
-    connect(m_model, SIGNAL(itemsRemoved(int,int)), this, SIGNAL(itemsRemoved(int,int)));
-    connect(m_model, SIGNAL(itemsChanged(int,int)), this, SIGNAL(itemsChanged(int,int)));
-    connect(m_model, SIGNAL(itemsMoved(int,int,int)), this, SIGNAL(itemsMoved(int,int,int)));
+    connect(m_model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
+            this, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)));
     connect(m_model, SIGNAL(createdPackage(int,QDeclarativePackage*)),
             this, SLOT(createdPackage(int,QDeclarativePackage*)));
     connect(m_model, SIGNAL(destroyingPackage(QDeclarativePackage*)),
index fbc8a1a..90d008e 100644 (file)
@@ -46,6 +46,7 @@
 #include <QtDeclarative/qdeclarativecontext.h>
 #include <QtDeclarative/qdeclarativeengine.h>
 
+#include <private/qdeclarativechangeset_p.h>
 #include <private/qdeclarativeglobal_p.h>
 #include <private/qobject_p.h>
 
@@ -82,7 +83,9 @@ public:
         Q_Q(QSGVisualItemModel);
         QSGVisualItemModelAttached *attached = QSGVisualItemModelAttached::properties(children.last().item);
         attached->setIndex(children.count()-1);
-        emit q->itemsInserted(children.count()-1, 1);
+        QDeclarativeChangeSet changeSet;
+        changeSet.insert(children.count() - 1, 1);
+        emit q->modelUpdated(changeSet, false);
         emit q->countChanged();
     }
 
index 2eeff3c..6e8606c 100644 (file)
@@ -53,6 +53,7 @@ QT_BEGIN_NAMESPACE
 QT_MODULE(Declarative)
 
 class QSGItem;
+class QDeclarativeChangeSet;
 
 class Q_DECLARATIVE_EXPORT QSGVisualModel : public QObject
 {
@@ -79,11 +80,7 @@ public:
 
 Q_SIGNALS:
     void countChanged();
-    void itemsInserted(int index, int count);
-    void itemsRemoved(int index, int count);
-    void itemsMoved(int from, int to, int count);
-    void itemsChanged(int index, int count);
-    void modelReset();
+    void modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset);
     void createdItem(int index, QSGItem *item);
     void destroyingItem(QSGItem *item);
 
index a2e6d95..bd17deb 100644 (file)
@@ -51,6 +51,7 @@
 #include <private/qsgtext_p.h>
 #include <private/qsgvisualdatamodel_p.h>
 #include <private/qdeclarativevaluetype_p.h>
+#include <private/qdeclarativechangeset_p.h>
 #include <math.h>
 #include <QtOpenGL/QGLShaderProgram>
 
@@ -138,8 +139,12 @@ private:
     template<typename T>
     T *findItem(QSGItem *parent, const QString &objectName, int index);
 };
+
+Q_DECLARE_METATYPE(QDeclarativeChangeSet)
+
 void tst_qsgvisualdatamodel::initTestCase()
 {
+    qRegisterMetaType<QDeclarativeChangeSet>();
 }
 
 void tst_qsgvisualdatamodel::cleanupTestCase()
@@ -566,14 +571,28 @@ void tst_qsgvisualdatamodel::qaimRowsMoved()
     QSGVisualDataModel *obj = qobject_cast<QSGVisualDataModel*>(c.create());
     QVERIFY(obj != 0);
 
-    QSignalSpy spy(obj, SIGNAL(itemsMoved(int,int,int)));
+    QSignalSpy spy(obj, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)));
     model.emitMove(sourceFirst, sourceLast, destinationChild);
-    QTRY_COMPARE(spy.count(), 1);
-
-    QCOMPARE(spy[0].count(), 3);
-    QCOMPARE(spy[0][0].toInt(), expectFrom);
-    QCOMPARE(spy[0][1].toInt(), expectTo);
-    QCOMPARE(spy[0][2].toInt(), expectCount);
+    // QAbstractItemModel also emits the changed signal when items are moved.
+    QCOMPARE(spy.count(), 2);
+
+    bool move = false;
+    for (int i = 0; i < 2; ++i) {
+        QCOMPARE(spy[1].count(), 2);
+        QDeclarativeChangeSet changeSet = spy[i][0].value<QDeclarativeChangeSet>();
+        if (!changeSet.changes().isEmpty())
+            continue;
+        move = true;
+        QCOMPARE(changeSet.removes().count(), 1);
+        QCOMPARE(changeSet.removes().at(0).index, expectFrom);
+        QCOMPARE(changeSet.removes().at(0).count, expectCount);
+        QCOMPARE(changeSet.inserts().count(), 1);
+        QCOMPARE(changeSet.inserts().at(0).index, expectTo);
+        QCOMPARE(changeSet.inserts().at(0).count, expectCount);
+        QCOMPARE(changeSet.removes().at(0).moveId, changeSet.inserts().at(0).moveId);
+        QCOMPARE(spy[i][1].toBool(), false);
+    }
+    QVERIFY(move);
 
     delete obj;
 }