From ded29009f766a8373193d94bcb8309270f66a266 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 20 May 2009 14:42:44 +1000 Subject: Make VisualItemModel with packages work properly. The views can all now deal with items that they have not requested appearing, and will lay them out appropriately. --- src/declarative/fx/qfxgridview.cpp | 158 +++++++++++++++----------- src/declarative/fx/qfxgridview.h | 2 + src/declarative/fx/qfxlistview.cpp | 181 +++++++++++++++++------------- src/declarative/fx/qfxlistview.h | 2 + src/declarative/fx/qfxpathview.cpp | 14 ++- src/declarative/fx/qfxpathview.h | 2 +- src/declarative/fx/qfxpathview_p.h | 3 + src/declarative/fx/qfxvisualitemmodel.cpp | 178 ++++++++++++++++++----------- src/declarative/fx/qfxvisualitemmodel.h | 13 ++- src/declarative/util/qmlpackage.cpp | 5 + 10 files changed, 339 insertions(+), 219 deletions(-) diff --git a/src/declarative/fx/qfxgridview.cpp b/src/declarative/fx/qfxgridview.cpp index 876172d..c14408a 100644 --- a/src/declarative/fx/qfxgridview.cpp +++ b/src/declarative/fx/qfxgridview.cpp @@ -121,9 +121,9 @@ public: qreal rowPos() const { return (view->flow() == QFxGridView::LeftToRight ? item->y() : item->x()); } qreal colPos() const { return (view->flow() == QFxGridView::LeftToRight ? item->x() : item->y()); } qreal endRowPos() const { - return (view->flow() == QFxGridView::LeftToRight - ? item->y() + (item->height() > 0 ? item->height() : 1) - : item->x() + (item->width() > 0 ? item->width() : 1)) - 1; + return view->flow() == QFxGridView::LeftToRight + ? item->y() + view->cellHeight() - 1 + : item->x() + view->cellWidth() - 1; } void setPosition(qreal col, qreal row) { if (view->flow() == QFxGridView::LeftToRight) { @@ -149,7 +149,7 @@ public: QFxGridViewPrivate() : model(0), currentItem(0), tmpCurrent(0), flow(QFxGridView::LeftToRight) , visiblePos(0), visibleIndex(0) , currentIndex(-1) - , cellWidth(100), cellHeight(100), columns(1) + , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1) , highlightComponent(0), highlight(0), trackedItem(0) , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0) , keyPressed(false), ownModel(false), wrap(false), autoHighlight(true) @@ -157,13 +157,14 @@ public: void init(); void clear(); - FxGridItem *getItem(int modelIndex); FxGridItem *createItem(int modelIndex); void releaseItem(FxGridItem *item); void refill(qreal from, qreal to); void updateGrid(); void layout(bool removed=false); + void updateUnrequestedIndexes(); + void updateUnrequestedPositions(); void updateTrackedItem(); void createHighlight(); void updateHighlight(); @@ -290,6 +291,7 @@ public: QFxVisualItemModel *model; QVariant modelVariant; QList visibleItems; + QHash unrequestedItems; FxGridItem *currentItem; QFxItem *tmpCurrent; QFxGridView::Flow flow; @@ -299,6 +301,7 @@ public: int cellWidth; int cellHeight; int columns; + int requestedIndex; QmlComponent *highlightComponent; FxGridItem *highlight; FxGridItem *trackedItem; @@ -330,29 +333,18 @@ void QFxGridViewPrivate::clear() visibleItems.clear(); visiblePos = 0; visibleIndex = 0; - if (currentItem) { - FxGridItem *tmpItem = currentItem; - currentItem = 0; - currentIndex = -1; - releaseItem(tmpItem); - } + releaseItem(currentItem); + currentItem = 0; + currentIndex = -1; createHighlight(); trackedItem = 0; } -FxGridItem *QFxGridViewPrivate::getItem(int modelIndex) -{ - if (currentItem && modelIndex == currentIndex) - return currentItem; - if (FxGridItem *listItem = visibleItem(modelIndex)) - return listItem; - return createItem(modelIndex); -} - FxGridItem *QFxGridViewPrivate::createItem(int modelIndex) { Q_Q(QFxGridView); // create object + requestedIndex = modelIndex; FxGridItem *listItem = 0; if (QFxItem *item = model->item(modelIndex, false)) { listItem = new FxGridItem(item, q); @@ -362,6 +354,7 @@ FxGridItem *QFxGridViewPrivate::createItem(int modelIndex) listItem->item->setZ(modelIndex + 1); listItem->item->setParent(q->viewport()); } + requestedIndex = 0; return listItem; } @@ -369,15 +362,18 @@ FxGridItem *QFxGridViewPrivate::createItem(int modelIndex) void QFxGridViewPrivate::releaseItem(FxGridItem *item) { Q_Q(QFxGridView); - if (item != currentItem) { - if (trackedItem == item) { - QObject::disconnect(trackedItem->item, SIGNAL(topChanged()), q, SLOT(trackedPositionChanged())); - QObject::disconnect(trackedItem->item, SIGNAL(leftChanged()), q, SLOT(trackedPositionChanged())); - trackedItem = 0; - } - model->release(item->item); - delete item; + if (!item) + return; + if (trackedItem == item) { + QObject::disconnect(trackedItem->item, SIGNAL(topChanged()), q, SLOT(trackedPositionChanged())); + QObject::disconnect(trackedItem->item, SIGNAL(leftChanged()), q, SLOT(trackedPositionChanged())); + trackedItem = 0; } + if (model->release(item->item) == 0) { + // item was not destroyed, and we no longer reference it. + unrequestedItems.insert(item->item, model->indexOf(item->item, q)); + } + delete item; } void QFxGridViewPrivate::refill(qreal from, qreal to) @@ -409,7 +405,7 @@ void QFxGridViewPrivate::refill(qreal from, qreal to) FxGridItem *item = 0; while (modelIndex < model->count() && rowPos <= to) { //qDebug() << "refill: append item" << modelIndex; - if (!(item = getItem(modelIndex))) + if (!(item = createItem(modelIndex))) break; item->setPosition(colPos, rowPos); visibleItems.append(item); @@ -432,7 +428,7 @@ void QFxGridViewPrivate::refill(qreal from, qreal to) } while (visibleIndex > 0 && rowPos + rowSize() - 1 >= from){ //qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos; - if (!(item = getItem(visibleIndex-1))) + if (!(item = createItem(visibleIndex-1))) break; --visibleIndex; item->setPosition(colPos, rowPos); @@ -518,6 +514,28 @@ void QFxGridViewPrivate::layout(bool removed) q->setViewportWidth(endPosition() - startPosition()); fixupX(); } + updateUnrequestedPositions(); +} + +void QFxGridViewPrivate::updateUnrequestedIndexes() +{ + Q_Q(QFxGridView); + QHash::iterator it; + for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) + *it = model->indexOf(it.key(), q); +} + +void QFxGridViewPrivate::updateUnrequestedPositions() +{ + QHash::const_iterator it; + for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) { + qDebug() << "pos of" << (*it) << colPosAt(*it) << rowPosAt(*it); + if (flow == QFxGridView::LeftToRight) { + it.key()->setPos(QPointF(colPosAt(*it), rowPosAt(*it))); + } else { + it.key()->setPos(QPointF(rowPosAt(*it), colPosAt(*it))); + } + } } void QFxGridViewPrivate::updateTrackedItem() @@ -606,11 +624,11 @@ void QFxGridViewPrivate::updateCurrent(int modelIndex) Q_Q(QFxGridView); if (!isValid() || modelIndex < 0 || modelIndex >= model->count()) { if (currentItem) { - FxGridItem *item = currentItem; + currentItem->attached->setIsCurrentItem(false); + releaseItem(currentItem); currentItem = 0; - currentIndex = 0; + currentIndex = -1; updateHighlight(); - releaseItem(item); emit q->currentIndexChanged(); } return; @@ -625,28 +643,21 @@ void QFxGridViewPrivate::updateCurrent(int modelIndex) delete tmpCurrent; tmpCurrent = 0; } - int oldCurrentIndex = currentIndex; FxGridItem *oldCurrentItem = currentItem; - currentIndex = -1; - currentItem = visibleItem(modelIndex); - if (!currentItem) { - currentItem = getItem(modelIndex); - if (currentItem) - currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex)); - } currentIndex = modelIndex; + currentItem = createItem(modelIndex); + qDebug() << "got current" << currentItem->item; fixCurrentVisibility = true; if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item)) oldCurrentItem->attached->setIsCurrentItem(false); if (currentItem) { + currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex)); currentItem->item->setFocus(true); currentItem->attached->setIsCurrentItem(true); } updateHighlight(); emit q->currentIndexChanged(); - // Release the old current item - if (oldCurrentItem && !visibleItem(oldCurrentIndex)) - releaseItem(oldCurrentItem); + releaseItem(oldCurrentItem); } //---------------------------------------------------------------------------- @@ -711,6 +722,8 @@ void QFxGridView::setModel(const QVariant &model) 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(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); + disconnect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*))); } d->clear(); d->modelVariant = model; @@ -736,6 +749,8 @@ void QFxGridView::setModel(const QVariant &model) d->updateCurrent(d->currentIndex); 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(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); + connect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*))); refill(); emit countChanged(); } @@ -1182,7 +1197,7 @@ void QFxGridView::itemsInserted(int modelIndex, int count) d->visibleIndex += count; for (int i = 0; i < d->visibleItems.count(); ++i) { FxGridItem *listItem = d->visibleItems.at(i); - if (listItem->index != -1 && listItem != d->currentItem) + if (listItem->index != -1) listItem->index += count; } } @@ -1258,10 +1273,8 @@ void QFxGridView::itemsInserted(int modelIndex, int count) // Update the indexes of the following visible items. for (; index < d->visibleItems.count(); ++index) { FxGridItem *listItem = d->visibleItems.at(index); - if (listItem != d->currentItem) { - if (listItem->index != -1) - listItem->index += count; - } + if (listItem->index != -1) + listItem->index += count; } } // everything is in order now - emit add() signal @@ -1274,7 +1287,7 @@ void QFxGridView::itemsInserted(int modelIndex, int count) void QFxGridView::itemsRemoved(int modelIndex, int count) { Q_D(QFxGridView); - + qDebug() << "QFxGridView::itemsRemoved"; int index = d->mapFromModel(modelIndex); if (index == -1) { if (modelIndex + count - 1 < d->visibleIndex) { @@ -1282,7 +1295,7 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) d->visibleIndex -= count; for (int i = 0; i < d->visibleItems.count(); ++i) { FxGridItem *listItem = d->visibleItems.at(i); - if (listItem->index != -1 && listItem != d->currentItem) + if (listItem->index != -1) listItem->index -= count; } } @@ -1292,11 +1305,8 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) d->currentItem->index -= count; } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { // current item has been removed. - if (d->currentItem) { - FxGridItem *item = d->currentItem; - d->currentItem = 0; - d->releaseItem(item); - } + d->releaseItem(d->currentItem); + d->currentItem = 0; d->currentIndex = -1; d->updateCurrent(qMin(modelIndex, d->model->count()-1)); } @@ -1305,6 +1315,8 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) return; } + qDebug() << "release gridview"; + // Remove the items from the visible list, skipping anything already marked for removal QList::Iterator it = d->visibleItems.begin(); while (it != d->visibleItems.end()) { @@ -1314,8 +1326,7 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) ++it; } else if (item->index >= modelIndex + count) { // after removed items - if (item != d->currentItem) - item->index -= count; + item->index -= count; ++it; } else { // removed item @@ -1338,11 +1349,9 @@ void QFxGridView::itemsRemoved(int modelIndex, int count) d->currentItem->index -= count; } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { // current item has been removed. - if (d->currentItem && !d->currentItem->attached->delayRemove()) { - FxGridItem *item = d->currentItem; - d->currentItem = 0; - d->releaseItem(item); - } + qDebug() << "release current" << d->currentItem; + d->releaseItem(d->currentItem); + qDebug() << "done"; d->currentItem = 0; d->currentIndex = -1; d->updateCurrent(qMin(modelIndex, d->model->count()-1)); @@ -1385,6 +1394,29 @@ void QFxGridView::destroyRemoved() d->layout(); } +void QFxGridView::createdItem(int index, QFxItem *item) +{ + Q_D(QFxGridView); + item->setItemParent(this); + if (d->requestedIndex != index) { + qDebug() << "Added unrequested" << index; + item->setItemParent(this); + d->unrequestedItems.insert(item, index); + if (d->flow == QFxGridView::LeftToRight) { + item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index))); + } else { + item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index))); + } + } +} + +void QFxGridView::destroyingItem(QFxItem *item) +{ + Q_D(QFxGridView); + d->unrequestedItems.remove(item); +} + + void QFxGridView::refill() { Q_D(QFxGridView); diff --git a/src/declarative/fx/qfxgridview.h b/src/declarative/fx/qfxgridview.h index 2bbfc40..90bf1ce 100644 --- a/src/declarative/fx/qfxgridview.h +++ b/src/declarative/fx/qfxgridview.h @@ -131,6 +131,8 @@ private Q_SLOTS: void itemsInserted(int index, int count); void itemsRemoved(int index, int count); void destroyRemoved(); + void createdItem(int index, QFxItem *item); + void destroyingItem(QFxItem *item); void sizeChange(); private: diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp index 46166e2..27f7ff1 100644 --- a/src/declarative/fx/qfxlistview.cpp +++ b/src/declarative/fx/qfxlistview.cpp @@ -171,15 +171,14 @@ public: QFxListViewPrivate() : model(0), currentItem(0), tmpCurrent(0), orient(Qt::Vertical) , visiblePos(0), visibleIndex(0) - , averageSize(100), currentIndex(-1), currItemMode(QFxListView::Free) - , snapPos(0), highlightComponent(0), highlight(0), trackedItem(0) + , averageSize(100), currentIndex(-1), requestedIndex(-1) + , currItemMode(QFxListView::Free), snapPos(0), highlightComponent(0), highlight(0), trackedItem(0) , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0) , keyPressed(false), ownModel(false), wrap(false), autoHighlight(true) , fixCurrentVisibility(false) {} void init(); void clear(); - FxListItem *getItem(int modelIndex); FxListItem *createItem(int modelIndex); void releaseItem(FxListItem *item); @@ -333,6 +332,8 @@ public: void refill(qreal from, qreal to); void layout(); + void updateUnrequestedIndexes(); + void updateUnrequestedPositions(); void updateTrackedItem(); void createHighlight(); void updateHighlight(); @@ -347,6 +348,7 @@ public: QFxVisualItemModel *model; QVariant modelVariant; QList visibleItems; + QHash unrequestedItems; FxListItem *currentItem; QFxItem *tmpCurrent; Qt::Orientation orient; @@ -354,6 +356,7 @@ public: int visibleIndex; qreal averageSize; int currentIndex; + int requestedIndex; QFxListView::CurrentItemPositioning currItemMode; int snapPos; QmlComponent *highlightComponent; @@ -390,29 +393,18 @@ void QFxListViewPrivate::clear() visibleItems.clear(); visiblePos = 0; visibleIndex = 0; - if (currentItem) { - FxListItem *tmpItem = currentItem; - currentItem = 0; - currentIndex = -1; - releaseItem(tmpItem); - } + releaseItem(currentItem); + currentItem = 0; + currentIndex = -1; createHighlight(); trackedItem = 0; } -FxListItem *QFxListViewPrivate::getItem(int modelIndex) -{ - if (currentItem && modelIndex == currentIndex) - return currentItem; - if (FxListItem *listItem = visibleItem(modelIndex)) - return listItem; - return createItem(modelIndex); -} - FxListItem *QFxListViewPrivate::createItem(int modelIndex) { Q_Q(QFxListView); // create object + requestedIndex = modelIndex; FxListItem *listItem = 0; if (QFxItem *item = model->item(modelIndex, false)) { listItem = new FxListItem(item, q); @@ -438,6 +430,7 @@ FxListItem *QFxListViewPrivate::createItem(int modelIndex) else QObject::connect(listItem->item, SIGNAL(widthChanged()), q, SLOT(itemResized())); } + requestedIndex = -1; return listItem; } @@ -445,21 +438,24 @@ FxListItem *QFxListViewPrivate::createItem(int modelIndex) void QFxListViewPrivate::releaseItem(FxListItem *item) { Q_Q(QFxListView); - if (item != currentItem) { - if (orient == Qt::Vertical) - QObject::disconnect(item->item, SIGNAL(heightChanged()), q, SLOT(itemResized())); - else - QObject::disconnect(item->item, SIGNAL(widthChanged()), q, SLOT(itemResized())); - if (trackedItem == item) { - const char *notifier1 = orient == Qt::Vertical ? SIGNAL(topChanged()) : SIGNAL(leftChanged()); - const char *notifier2 = orient == Qt::Vertical ? SIGNAL(heightChanged()) : SIGNAL(widthChanged()); - QObject::disconnect(trackedItem->item, notifier1, q, SLOT(trackedPositionChanged())); - QObject::disconnect(trackedItem->item, notifier2, q, SLOT(trackedPositionChanged())); - trackedItem = 0; - } - model->release(item->item); - delete item; + if (!item) + return; + if (orient == Qt::Vertical) + QObject::disconnect(item->item, SIGNAL(heightChanged()), q, SLOT(itemResized())); + else + QObject::disconnect(item->item, SIGNAL(widthChanged()), q, SLOT(itemResized())); + if (trackedItem == item) { + const char *notifier1 = orient == Qt::Vertical ? SIGNAL(topChanged()) : SIGNAL(leftChanged()); + const char *notifier2 = orient == Qt::Vertical ? SIGNAL(heightChanged()) : SIGNAL(widthChanged()); + QObject::disconnect(trackedItem->item, notifier1, q, SLOT(trackedPositionChanged())); + QObject::disconnect(trackedItem->item, notifier2, q, SLOT(trackedPositionChanged())); + trackedItem = 0; } + if (model->release(item->item) == 0) { + // item was not destroyed, and we no longer reference it. + unrequestedItems.insert(item->item, model->indexOf(item->item, q)); + } + delete item; } void QFxListViewPrivate::refill(qreal from, qreal to) @@ -485,7 +481,7 @@ void QFxListViewPrivate::refill(qreal from, qreal to) int pos = itemEnd + 1; while (modelIndex < model->count() && pos <= to) { //qDebug() << "refill: append item" << modelIndex; - if (!(item = getItem(modelIndex))) + if (!(item = createItem(modelIndex))) break; item->setPosition(pos); pos += item->size(); @@ -495,7 +491,7 @@ void QFxListViewPrivate::refill(qreal from, qreal to) } while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > from) { //qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos; - if (!(item = getItem(visibleIndex-1))) + if (!(item = createItem(visibleIndex-1))) break; --visibleIndex; visiblePos -= item->size(); @@ -562,6 +558,29 @@ void QFxListViewPrivate::layout() fixupX(); q->setViewportWidth(endPosition() - startPosition()); } + updateUnrequestedPositions(); +} + +void QFxListViewPrivate::updateUnrequestedIndexes() +{ + Q_Q(QFxListView); + QHash::iterator it; + for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) + *it = model->indexOf(it.key(), q); +} + +void QFxListViewPrivate::updateUnrequestedPositions() +{ + QHash::const_iterator it; + for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) { + qDebug() << "pos of" << (*it) << positionAt(*it); + if (visibleItem(*it)) + continue; + if (orient == Qt::Vertical) + it.key()->setY(positionAt(*it)); + else + it.key()->setX(positionAt(*it)); + } } void QFxListViewPrivate::updateTrackedItem() @@ -695,13 +714,11 @@ void QFxListViewPrivate::updateCurrent(int modelIndex) Q_Q(QFxListView); if (!isValid() || modelIndex < 0 || modelIndex >= model->count()) { if (currentItem) { - FxListItem *item = currentItem; - int index = currentIndex; + currentItem->attached->setIsCurrentItem(false); + releaseItem(currentItem); currentItem = 0; - currentIndex = 0; + currentIndex = -1; updateHighlight(); - if (!visibleItem(index)) - releaseItem(item); emit q->currentIndexChanged(); } return; @@ -716,40 +733,28 @@ void QFxListViewPrivate::updateCurrent(int modelIndex) delete tmpCurrent; tmpCurrent = 0; } - int oldCurrentIndex = currentIndex; FxListItem *oldCurrentItem = currentItem; - currentIndex = -1; - currentItem = visibleItem(modelIndex); - if (!currentItem) { - currentItem = getItem(modelIndex); - if (currentItem) { - if (modelIndex == visibleIndex - 1) { - // We can calculate exact postion in this case - currentItem->setPosition(visibleItems.first()->position() - currentItem->size()); - } else { - // Create current item now and position as best we can. - // Its position will be corrected when it becomes visible. - currentItem->setPosition(positionAt(modelIndex)); - } - } - } currentIndex = modelIndex; + currentItem = createItem(modelIndex); fixCurrentVisibility = true; if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item)) oldCurrentItem->attached->setIsCurrentItem(false); if (currentItem) { + if (modelIndex == visibleIndex - 1) { + // We can calculate exact postion in this case + currentItem->setPosition(visibleItems.first()->position() - currentItem->size()); + } else { + // Create current item now and position as best we can. + // Its position will be corrected when it becomes visible. + currentItem->setPosition(positionAt(modelIndex)); + } currentItem->item->setFocus(true); currentItem->attached->setIsCurrentItem(true); } updateHighlight(); emit q->currentIndexChanged(); // Release the old current item - if (oldCurrentItem && !visibleItem(oldCurrentIndex)) { - if (!currentItem || oldCurrentItem->item == currentItem->item) - delete oldCurrentItem; - else - releaseItem(oldCurrentItem); - } + releaseItem(oldCurrentItem); } void QFxListViewPrivate::updateAverage() @@ -884,6 +889,8 @@ void QFxListView::setModel(const QVariant &model) 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(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); + disconnect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*))); } d->clear(); d->modelVariant = model; @@ -909,6 +916,8 @@ void QFxListView::setModel(const QVariant &model) d->updateCurrent(d->currentIndex); 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(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); + connect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*))); refill(); emit countChanged(); } @@ -1417,6 +1426,7 @@ void QFxListView::itemResized() void QFxListView::itemsInserted(int modelIndex, int count) { Q_D(QFxListView); + d->updateUnrequestedIndexes(); if (!d->visibleItems.count() || d->model->count() <= 1) { d->layout(); d->updateCurrent(qMax(0, qMin(d->currentIndex, d->model->count()-1))); @@ -1437,7 +1447,7 @@ void QFxListView::itemsInserted(int modelIndex, int count) d->visibleIndex += count; for (int i = 0; i < d->visibleItems.count(); ++i) { FxListItem *listItem = d->visibleItems.at(i); - if (listItem->index != -1 && listItem != d->currentItem) + if (listItem->index != -1) listItem->index += count; } } @@ -1487,29 +1497,29 @@ void QFxListView::itemsInserted(int modelIndex, int count) // Update the indexes of the following visible items. for (; index < d->visibleItems.count(); ++index) { FxListItem *listItem = d->visibleItems.at(index); - if (listItem != d->currentItem) { - listItem->setPosition(listItem->position() + (pos - initialPos)); - if (listItem->index != -1) - listItem->index += count; - } + listItem->setPosition(listItem->position() + (pos - initialPos)); + if (listItem->index != -1) + listItem->index += count; } } // everything is in order now - emit add() signal for (int j = 0; j < added.count(); ++j) added.at(j)->attached->emitAdd(); + d->updateUnrequestedPositions(); emit countChanged(); } void QFxListView::itemsRemoved(int modelIndex, int count) { Q_D(QFxListView); + d->updateUnrequestedIndexes(); if (!d->mapRangeFromModel(modelIndex, count)) { if (modelIndex + count - 1 < d->visibleIndex) { // Items removed before our visible items. d->visibleIndex -= count; for (int i = 0; i < d->visibleItems.count(); ++i) { FxListItem *listItem = d->visibleItems.at(i); - if (listItem->index != -1 && listItem != d->currentItem) + if (listItem->index != -1) listItem->index -= count; } } @@ -1519,11 +1529,8 @@ void QFxListView::itemsRemoved(int modelIndex, int count) d->currentItem->index -= count; } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { // current item has been removed. - if (d->currentItem) { - FxListItem *item = d->currentItem; - d->currentItem = 0; - d->releaseItem(item); - } + d->releaseItem(d->currentItem); + d->currentItem = 0; d->currentIndex = -1; d->updateCurrent(qMin(modelIndex, d->model->count()-1)); } @@ -1541,8 +1548,7 @@ void QFxListView::itemsRemoved(int modelIndex, int count) ++it; } else if (item->index >= modelIndex + count) { // after removed items - if (item != d->currentItem) - item->index -= count; + item->index -= count; ++it; } else { // removed item @@ -1565,11 +1571,7 @@ void QFxListView::itemsRemoved(int modelIndex, int count) d->currentItem->index -= count; } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) { // current item has been removed. - if (d->currentItem && !d->currentItem->attached->delayRemove()) { - FxListItem *item = d->currentItem; - d->currentItem = 0; - d->releaseItem(item); - } + d->releaseItem(d->currentItem); d->currentItem = 0; d->currentIndex = -1; d->updateCurrent(qMin(modelIndex, d->model->count()-1)); @@ -1618,6 +1620,25 @@ void QFxListView::destroyRemoved() d->layout(); } +void QFxListView::createdItem(int index, QFxItem *item) +{ + Q_D(QFxListView); + if (d->requestedIndex != index) { + item->setItemParent(viewport()); + d->unrequestedItems.insert(item, index); + if (d->orient == Qt::Vertical) + item->setY(d->positionAt(index)); + else + item->setX(d->positionAt(index)); + } +} + +void QFxListView::destroyingItem(QFxItem *item) +{ + Q_D(QFxListView); + d->unrequestedItems.remove(item); +} + QObject *QFxListView::qmlAttachedProperties(QObject *obj) { return QFxListViewAttached::properties(obj); diff --git a/src/declarative/fx/qfxlistview.h b/src/declarative/fx/qfxlistview.h index 40c2496..42f7773 100644 --- a/src/declarative/fx/qfxlistview.h +++ b/src/declarative/fx/qfxlistview.h @@ -141,6 +141,8 @@ private Q_SLOTS: void itemsInserted(int index, int count); void itemsRemoved(int index, int count); void destroyRemoved(); + void createdItem(int index, QFxItem *item); + void destroyingItem(QFxItem *item); }; QML_DECLARE_TYPE(QFxListView); diff --git a/src/declarative/fx/qfxpathview.cpp b/src/declarative/fx/qfxpathview.cpp index b7215cf..b1c78e9 100644 --- a/src/declarative/fx/qfxpathview.cpp +++ b/src/declarative/fx/qfxpathview.cpp @@ -159,7 +159,7 @@ void QFxPathView::setModel(const QVariant &model) 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(itemCreated(int, QFxItem*)), this, SLOT(itemCreated(int,QFxItem*))); + disconnect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); for (int i=0; iitems.count(); i++){ QFxItem *p = d->items[i]; d->model->release(p); @@ -186,7 +186,7 @@ void QFxPathView::setModel(const QVariant &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(itemCreated(int, QFxItem*)), this, SLOT(itemCreated(int,QFxItem*))); + connect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*))); } d->firstIndex = 0; d->pathOffset = 0; @@ -559,9 +559,10 @@ bool QFxPathView::mouseFilter(QGraphicsSceneMouseEvent *e) void QFxPathViewPrivate::regenerate() { Q_Q(QFxPathView); + qDebug() << "relaease all pathview"; for (int i=0; irelease(p); + releaseItem(p); } items.clear(); @@ -634,7 +635,7 @@ void QFxPathView::refill() while(wrapIndex-- >= 0){ QFxItem* p = d->items.takeFirst(); d->updateItem(p, 0.0); - d->model->release(p); + d->releaseItem(p); d->firstIndex++; d->firstIndex %= d->model->count(); int index = (d->firstIndex + d->items.count())%d->model->count(); @@ -647,7 +648,7 @@ void QFxPathView::refill() while(wrapIndex++ < d->items.count()-1){ QFxItem* p = d->items.takeLast(); d->updateItem(p, 1.0); - d->model->release(p); + d->releaseItem(p); d->firstIndex--; if (d->firstIndex < 0) d->firstIndex = d->model->count() - 1; @@ -698,6 +699,7 @@ void QFxPathView::itemsInserted(int modelIndex, int count) void QFxPathView::itemsRemoved(int modelIndex, int count) { + qDebug() << "QFxPathView::itemsRemoved"; //XXX support animated removal Q_D(QFxPathView); if (!d->isValid()) @@ -733,7 +735,7 @@ void QFxPathView::itemsRemoved(int modelIndex, int count) d->moveOffset.setValue(targetOffset); } -void QFxPathView::itemCreated(int index, QFxItem *item) +void QFxPathView::createdItem(int index, QFxItem *item) { Q_D(QFxPathView); if (d->requestedIndex != index) { diff --git a/src/declarative/fx/qfxpathview.h b/src/declarative/fx/qfxpathview.h index 2ecd04e..04804b7 100644 --- a/src/declarative/fx/qfxpathview.h +++ b/src/declarative/fx/qfxpathview.h @@ -115,7 +115,7 @@ private Q_SLOTS: void ticked(); void itemsInserted(int index, int count); void itemsRemoved(int index, int count); - void itemCreated(int index, QFxItem *item); + void createdItem(int index, QFxItem *item); void destroyingItem(QFxItem *item); protected: diff --git a/src/declarative/fx/qfxpathview_p.h b/src/declarative/fx/qfxpathview_p.h index 358daf6..b5c5ba2 100644 --- a/src/declarative/fx/qfxpathview_p.h +++ b/src/declarative/fx/qfxpathview_p.h @@ -101,6 +101,9 @@ public: requestedIndex = -1; return item; } + void releaseItem(QFxItem *item) { + model->release(item); + } bool isValid() const { return model && model->count() > 0 && model->delegate() && path; diff --git a/src/declarative/fx/qfxvisualitemmodel.cpp b/src/declarative/fx/qfxvisualitemmodel.cpp index 533917e..c631d33 100644 --- a/src/declarative/fx/qfxvisualitemmodel.cpp +++ b/src/declarative/fx/qfxvisualitemmodel.cpp @@ -73,9 +73,53 @@ public: QList m_roles; QHash m_roleNames; - QHash m_cache; + struct ObjectRef { + ObjectRef(QObject *object=0) : obj(object), ref(1) {} + QObject *obj; + int ref; + }; + class Cache : public QHash { + public: + QObject *getItem(int index) { + QObject *item = 0; + QHash::iterator it = find(index); + if (it != end()) { + (*it).ref++; + item = (*it).obj; + qDebug() << "ref" << item << (*it).ref; + } + return item; + } + QObject *item(int index) { + QObject *item = 0; + QHash::const_iterator it = find(index); + if (it != end()) + item = (*it).obj; + return item; + } + void insertItem(int index, QObject *obj) { + insert(index, ObjectRef(obj)); + } + bool releaseItem(QObject *obj) { + QHash::iterator it = begin(); + for (; it != end(); ++it) { + ObjectRef &objRef = *it; + if (objRef.obj == obj) { + if (--objRef.ref == 0) { + erase(it); + qDebug() << "released item" << obj << "item count" << count(); + return true; + } + qDebug() << "not releasing" << obj << "ref" << objRef.ref; + break; + } + } + return false; + } + }; + + Cache m_cache; QHash m_packaged; - QHash m_packageRef; QFxVisualItemModelParts *m_parts; friend class QFxVisualItemParts; @@ -337,8 +381,8 @@ void QFxVisualItemModel::setModel(const QVariant &model) this, SIGNAL(itemsRemoved(int,int))); QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)), this, SIGNAL(itemsMoved(int,int,int))); - QObject::disconnect(d->m_visualItemModel, SIGNAL(packageCreated(int,QmlPackage*)), - this, SLOT(_q_packageCreated(int,QmlPackage*))); + QObject::disconnect(d->m_visualItemModel, SIGNAL(createdPackage(int,QmlPackage*)), + this, SLOT(_q_createdPackage(int,QmlPackage*))); QObject::disconnect(d->m_visualItemModel, SIGNAL(destroyingPackage(QmlPackage*)), this, SLOT(_q_destroyingPackage(QmlPackage*))); d->m_visualItemModel = 0; @@ -390,8 +434,8 @@ void QFxVisualItemModel::setModel(const QVariant &model) this, SIGNAL(itemsRemoved(int,int))); QObject::connect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)), this, SIGNAL(itemsMoved(int,int,int))); - QObject::connect(d->m_visualItemModel, SIGNAL(packageCreated(int,QmlPackage*)), - this, SLOT(_q_packageCreated(int,QmlPackage*))); + QObject::connect(d->m_visualItemModel, SIGNAL(createdPackage(int,QmlPackage*)), + this, SLOT(_q_createdPackage(int,QmlPackage*))); QObject::connect(d->m_visualItemModel, SIGNAL(destroyingPackage(QmlPackage*)), this, SLOT(_q_destroyingPackage(QmlPackage*))); return; @@ -445,41 +489,39 @@ QFxItem *QFxVisualItemModel::item(int index, bool complete) return item(index, QByteArray(), complete); } -void QFxVisualItemModel::release(QFxItem *item) +/* + Returns ReleaseStatus flags. +*/ +QFxVisualItemModel::ReleaseFlags QFxVisualItemModel::release(QFxItem *item) { Q_D(QFxVisualItemModel); - if (d->m_visualItemModel) { - d->m_visualItemModel->release(item); - return; - } - item->setItemParent(0); - QObject *obj = item; + if (d->m_visualItemModel) + return d->m_visualItemModel->release(item); + ReleaseFlags stat = 0; + QObject *obj = item; bool inPackage = false; - if (QmlPackage *package = d->m_packaged.value(item)) { - static_cast(item)->setParent(package); - d->m_packaged.remove(item); - //XXX Inefficient - for (QHash::Iterator iter = d->m_packaged.begin(); - iter != d->m_packaged.end(); ++iter) { - if (*iter == package) - return; - } + + QHash::iterator it = d->m_packaged.find(item); + if (it != d->m_packaged.end()) { + QmlPackage *package = *it; + d->m_packaged.erase(it); + if (d->m_packaged.contains(item)) + stat |= Referenced; inPackage = true; obj = package; // fall through and delete } - //XXX Inefficient - for (QHash::Iterator iter = d->m_cache.begin(); - iter != d->m_cache.end(); ++iter) { - if (*iter == obj) { - if (inPackage) - emit destroyingPackage(qobject_cast(obj)); - delete obj; - d->m_cache.erase(iter); - return; - } + if (d->m_cache.releaseItem(obj)) { + if (inPackage) + emit destroyingPackage(qobject_cast(obj)); + stat |= Destroyed; + delete obj; + } else if (!inPackage) { + stat |= Referenced; } + + return stat; } QObject *QFxVisualItemModel::parts() @@ -499,10 +541,8 @@ QFxItem *QFxVisualItemModel::item(int index, const QByteArray &viewId, bool comp if (d->modelCount() <= 0 || !d->m_delegate) return 0; - QObject *nobj = 0; - if (d->m_cache.contains(index)) { - nobj = d->m_cache[index]; - } else { + QObject *nobj = d->m_cache.getItem(index); + if (!nobj) { QmlContext *ccontext = d->m_context; if (!ccontext) ccontext = qmlContext(this); QmlContext *ctxt = new QmlContext(ccontext); @@ -515,8 +555,9 @@ QFxItem *QFxVisualItemModel::item(int index, const QByteArray &viewId, bool comp if (nobj) { ctxt->setParent(nobj); data->setParent(nobj); - - d->m_cache.insert(index, nobj); + d->m_cache.insertItem(index, nobj); + if (QmlPackage *package = qobject_cast(nobj)) + emit createdPackage(index, package); } else { delete data; delete ctxt; @@ -529,8 +570,7 @@ QFxItem *QFxVisualItemModel::item(int index, const QByteArray &viewId, bool comp if (package) { QObject *o = package->part(QLatin1String(viewId)); item = qobject_cast(o); - d->m_packaged[o] = package; - emit packageCreated(index, package); + d->m_packaged.insertMulti(item, package); } } @@ -558,8 +598,8 @@ QVariant QFxVisualItemModel::evaluate(int index, const QString &expression, QObj return QVariant(); QVariant value; - if (d->m_cache.contains(index)) { - QObject *nobj = d->m_cache[index]; + QObject *nobj = d->m_cache.item(index); + if (nobj) { QFxItem *item = qobject_cast(nobj); if (item) { QmlExpression e(qmlContext(item), expression, objectContext); @@ -582,6 +622,16 @@ QVariant QFxVisualItemModel::evaluate(int index, const QString &expression, QObj return value; } +int QFxVisualItemModel::indexOf(QFxItem *item, QObject *objectContext) const +{ + QmlExpression e(qmlContext(item), "index", objectContext); + e.setTrackChange(false); + QVariant value = e.value(); + if (value.isValid()) + return value.toInt(); + return -1; +} + void QFxVisualItemModel::_q_itemsChanged(int index, int count, const QList &roles) { @@ -589,9 +639,7 @@ void QFxVisualItemModel::_q_itemsChanged(int index, int count, // XXX - highly inefficient for (int ii = index; ii < index + count; ++ii) { - if (d->m_cache.contains(ii)) { - - QObject *item = d->m_cache[ii]; + if (QObject *item = d->m_cache.item(ii)) { QFxVisualItemModelData *data = d->data(item); for (int prop = 0; prop < data->count(); ++prop) { @@ -615,18 +663,18 @@ void QFxVisualItemModel::_q_itemsInserted(int index, int count) { Q_D(QFxVisualItemModel); // XXX - highly inefficient - QHash items; - for (QHash::Iterator iter = d->m_cache.begin(); + QHash items; + for (QHash::Iterator iter = d->m_cache.begin(); iter != d->m_cache.end(); ) { if (iter.key() >= index) { - QObject *item = *iter; + QFxVisualItemModelPrivate::ObjectRef objRef = *iter; int index = iter.key() + count; iter = d->m_cache.erase(iter); - items.insert(index, item); + items.insert(index, objRef); - QFxVisualItemModelData *data = d->data(item); + QFxVisualItemModelData *data = d->data(objRef.obj); data->setIndex(index); } else { ++iter; @@ -641,21 +689,21 @@ void QFxVisualItemModel::_q_itemsRemoved(int index, int count) { Q_D(QFxVisualItemModel); // XXX - highly inefficient - QHash items; - for (QHash::Iterator iter = d->m_cache.begin(); + QHash items; + for (QHash::Iterator iter = d->m_cache.begin(); iter != d->m_cache.end(); ) { if (iter.key() >= index && iter.key() < index + count) { - QObject *item = *iter; + QFxVisualItemModelPrivate::ObjectRef objRef = *iter; iter = d->m_cache.erase(iter); - items.insertMulti(-1, item); //XXX perhaps better to maintain separately - QFxVisualItemModelData *data = d->data(item); + items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately + QFxVisualItemModelData *data = d->data(objRef.obj); data->setIndex(-1); } else if (iter.key() >= index + count) { - QObject *item = *iter; + QFxVisualItemModelPrivate::ObjectRef objRef = *iter; int index = iter.key() - count; iter = d->m_cache.erase(iter); - items.insert(index, item); - QFxVisualItemModelData *data = d->data(item); + items.insert(index, objRef); + QFxVisualItemModelData *data = d->data(objRef.obj); data->setIndex(index); } else { ++iter; @@ -670,18 +718,18 @@ void QFxVisualItemModel::_q_itemsMoved(int from, int to, int count) { Q_D(QFxVisualItemModel); // XXX - highly inefficient - QHash items; - for (QHash::Iterator iter = d->m_cache.begin(); + QHash items; + for (QHash::Iterator iter = d->m_cache.begin(); iter != d->m_cache.end(); ) { if (iter.key() >= from && iter.key() < from + count) { - QObject *item = *iter; + QFxVisualItemModelPrivate::ObjectRef objRef = *iter; int index = iter.key() - from + to; iter = d->m_cache.erase(iter); - items.insert(index, item); + items.insert(index, objRef); - QFxVisualItemModelData *data = d->data(item); + QFxVisualItemModelData *data = d->data(objRef.obj); data->setIndex(index); } else { ++iter; @@ -708,10 +756,10 @@ void QFxVisualItemModel::_q_dataChanged(const QModelIndex &begin, const QModelIn _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles); } -void QFxVisualItemModel::_q_packageCreated(int index, QmlPackage *package) +void QFxVisualItemModel::_q_createdPackage(int index, QmlPackage *package) { Q_D(QFxVisualItemModel); - emit itemCreated(index, qobject_cast(package->part(d->m_part))); + emit createdItem(index, qobject_cast(package->part(d->m_part))); } void QFxVisualItemModel::_q_destroyingPackage(QmlPackage *package) diff --git a/src/declarative/fx/qfxvisualitemmodel.h b/src/declarative/fx/qfxvisualitemmodel.h index 33017e2..7156d70 100644 --- a/src/declarative/fx/qfxvisualitemmodel.h +++ b/src/declarative/fx/qfxvisualitemmodel.h @@ -86,21 +86,26 @@ public: QString part() const; void setPart(const QString &); + enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02 }; + Q_DECLARE_FLAGS(ReleaseFlags, ReleaseFlag) + int count() const; QFxItem *item(int index, bool complete=true); QFxItem *item(int index, const QByteArray &, bool complete=true); - void release(QFxItem *item); + ReleaseFlags release(QFxItem *item); void completeItem(); QVariant evaluate(int index, const QString &expression, QObject *objectContext); + int indexOf(QFxItem *item, QObject *objectContext) const; + QObject *parts(); Q_SIGNALS: void itemsInserted(int index, int count); void itemsRemoved(int index, int count); void itemsMoved(int from, int to, int count); - void itemCreated(int index, QFxItem *item); - void packageCreated(int index, QmlPackage *package); + void createdItem(int index, QFxItem *item); + void createdPackage(int index, QmlPackage *package); void destroyingItem(QFxItem *item); void destroyingPackage(QmlPackage *package); @@ -112,7 +117,7 @@ private Q_SLOTS: void _q_rowsInserted(const QModelIndex &,int,int); void _q_rowsRemoved(const QModelIndex &,int,int); void _q_dataChanged(const QModelIndex&,const QModelIndex&); - void _q_packageCreated(int index, QmlPackage *package); + void _q_createdPackage(int index, QmlPackage *package); void _q_destroyingPackage(QmlPackage *package); private: diff --git a/src/declarative/util/qmlpackage.cpp b/src/declarative/util/qmlpackage.cpp index aa7ed38..bfad44c 100644 --- a/src/declarative/util/qmlpackage.cpp +++ b/src/declarative/util/qmlpackage.cpp @@ -98,6 +98,11 @@ QmlPackage::QmlPackage(QObject *parent) QmlPackage::~QmlPackage() { + Q_D(QmlPackage); + for (int ii = 0; ii < d->dataList.count(); ++ii) { + QObject *obj = d->dataList.at(ii); + delete obj; + } } QmlList *QmlPackage::data() -- cgit v0.12