From 51102228258ed107a255b79606ef855bfa0e460d Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Thu, 1 Sep 2011 15:24:34 +1000 Subject: [PATCH] Use QDeclarativeChangeSet to communicate changes to views. 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 Reviewed-by: Bea Lam Reviewed-by: Alan Alpert --- src/declarative/items/qsgitemview.cpp | 179 ++++++-------------- src/declarative/items/qsgitemview_p.h | 8 +- src/declarative/items/qsgitemview_p_p.h | 5 +- src/declarative/items/qsgpathview.cpp | 158 +++++++---------- src/declarative/items/qsgpathview_p.h | 7 +- src/declarative/items/qsgrepeater.cpp | 120 ++++++------- src/declarative/items/qsgrepeater_p.h | 7 +- src/declarative/items/qsgvisualdatamodel.cpp | 53 ++++-- src/declarative/items/qsgvisualitemmodel.cpp | 5 +- src/declarative/items/qsgvisualitemmodel_p.h | 7 +- .../qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp | 33 +++- 11 files changed, 255 insertions(+), 327 deletions(-) diff --git a/src/declarative/items/qsgitemview.cpp b/src/declarative/items/qsgitemview.cpp index 2b3f51b..291592b 100644 --- a/src/declarative/items/qsgitemview.cpp +++ b/src/declarative/items/qsgitemview.cpp @@ -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) diff --git a/src/declarative/items/qsgitemview_p.h b/src/declarative/items/qsgitemview_p.h index b1093ff..9d25eab 100644 --- a/src/declarative/items/qsgitemview_p.h +++ b/src/declarative/items/qsgitemview_p.h @@ -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) diff --git a/src/declarative/items/qsgitemview_p_p.h b/src/declarative/items/qsgitemview_p_p.h index afa50af..73cb68c 100644 --- a/src/declarative/items/qsgitemview_p_p.h +++ b/src/declarative/items/qsgitemview_p_p.h @@ -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; diff --git a/src/declarative/items/qsgpathview.cpp b/src/declarative/items/qsgpathview.cpp index 11733df..a1038ad 100644 --- a/src/declarative/items/qsgpathview.cpp +++ b/src/declarative/items/qsgpathview.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -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; iitems.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 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) diff --git a/src/declarative/items/qsgpathview_p.h b/src/declarative/items/qsgpathview_p.h index fa00294..b70745e 100644 --- a/src/declarative/items/qsgpathview_p.h +++ b/src/declarative/items/qsgpathview_p.h @@ -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(); diff --git a/src/declarative/items/qsgrepeater.cpp b/src/declarative/items/qsgrepeater.cpp index 4e2fa63..0037ea1 100644 --- a/src/declarative/items/qsgrepeater.cpp +++ b/src/declarative/items/qsgrepeater.cpp @@ -46,6 +46,7 @@ #include #include #include +#include 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 > > 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 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 > 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 diff --git a/src/declarative/items/qsgrepeater_p.h b/src/declarative/items/qsgrepeater_p.h index 497f54c..2094d94 100644 --- a/src/declarative/items/qsgrepeater_p.h +++ b/src/declarative/items/qsgrepeater_p.h @@ -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) diff --git a/src/declarative/items/qsgvisualdatamodel.cpp b/src/declarative/items/qsgvisualdatamodel.cpp index 219d1dc..09f5d5d 100644 --- a/src/declarative/items/qsgvisualdatamodel.cpp +++ b/src/declarative/items/qsgvisualdatamodel.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include @@ -90,6 +91,8 @@ public: void emitDestroyingPackage(QDeclarativePackage *package) { emit q_func()->destroyingPackage(package); } + void emitChanges(); + QSGVisualAdaptorModel *m_adaptorModel; QDeclarativeComponent *m_delegate; QDeclarativeGuard 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 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*)), diff --git a/src/declarative/items/qsgvisualitemmodel.cpp b/src/declarative/items/qsgvisualitemmodel.cpp index fbc8a1a..90d008e 100644 --- a/src/declarative/items/qsgvisualitemmodel.cpp +++ b/src/declarative/items/qsgvisualitemmodel.cpp @@ -46,6 +46,7 @@ #include #include +#include #include #include @@ -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(); } diff --git a/src/declarative/items/qsgvisualitemmodel_p.h b/src/declarative/items/qsgvisualitemmodel_p.h index 2eeff3c..6e8606c 100644 --- a/src/declarative/items/qsgvisualitemmodel_p.h +++ b/src/declarative/items/qsgvisualitemmodel_p.h @@ -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); diff --git a/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp index a2e6d95..bd17deb 100644 --- a/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp +++ b/tests/auto/declarative/qsgvisualdatamodel/tst_qsgvisualdatamodel.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -138,8 +139,12 @@ private: template T *findItem(QSGItem *parent, const QString &objectName, int index); }; + +Q_DECLARE_METATYPE(QDeclarativeChangeSet) + void tst_qsgvisualdatamodel::initTestCase() { + qRegisterMetaType(); } void tst_qsgvisualdatamodel::cleanupTestCase() @@ -566,14 +571,28 @@ void tst_qsgvisualdatamodel::qaimRowsMoved() QSGVisualDataModel *obj = qobject_cast(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(); + 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; } -- 1.7.2.5