src/hbwidgets/itemviews/hbgriditemcontainer_p.cpp
changeset 1 f7ac710697a9
parent 0 16d8024aca5e
child 2 06ff229162e9
--- a/src/hbwidgets/itemviews/hbgriditemcontainer_p.cpp	Mon Apr 19 14:02:13 2010 +0300
+++ b/src/hbwidgets/itemviews/hbgriditemcontainer_p.cpp	Mon May 03 12:48:33 2010 +0300
@@ -88,24 +88,32 @@
         return;
 
     int bufferIndex = 0;
-    if (d->mItems.count() != 0) {
-        bufferIndex = qMax(0, index.row() - d->mItems.first()->modelIndex().row());
+    QModelIndex firstInBuffer;
+    int firstInBufferPosition = -1;
+    int indexPosition = d->mItemView->modelIterator()->indexPosition(index);
+    if (!d->mItems.isEmpty()) {
+        firstInBuffer = d->mItems.first()->modelIndex();
+        firstInBufferPosition = d->mItemView->modelIterator()->indexPosition(firstInBuffer);
+        bufferIndex = qMax(0, indexPosition - firstInBufferPosition);
     }
     // inserting new item because of buffer size
-    if (d->mItems.count() == 0
+    if (d->mItems.isEmpty()
         || d->mItems.count() < maxItemCount()) {
         insertItem(bufferIndex, index, animate);
         viewLayout()->invalidate();
     }
     // special case - only for grid, if added item is above the 
     // visible region we need to shift all visible items by one!
-    else if (d->mItems.count() > 0
-        && d->mItems.first()->modelIndex().row() > index.row()) {
+    else if (!d->mItems.isEmpty()
+        && firstInBufferPosition > indexPosition) {
         d->shiftUpItem(animate); // shift up in this case always return something
         viewLayout()->invalidate();
     }
     // new item is in visible range
     else if (bufferIndex < d->mItems.count()) {
+        // new added item comes to buffer - it will be
+        // recycled from last item in buffer (it is also ok
+        // when that last item was invalid)
         HbAbstractViewItem *last = d->mItems.last();
         if (animate) {
             last->setOpacity(0.0);
@@ -160,30 +168,51 @@
         return;
     }
 
+    HbModelIterator *modelIterator = d->mItemView->modelIterator();
     QModelIndex index = startIndex;
     if (!index.isValid()) {
-        index = d->mItemView->model()->index(0, 0);
-        if (!index.isValid())
+        index = modelIterator->nextIndex(QModelIndex());
+        if (!index.isValid()) {
+            // this mean model is empty
             return;
+        }
     }
-    index = d->mItemView->model()->index(
-                d->alignIndexToClosestFirstInRow(index.row()), 0);
+
+    int indexPosition = modelIterator->indexPosition(index);
+    indexPosition = d->alignIndexToClosestFirstInRow(indexPosition);
+    index = modelIterator->index(indexPosition);
 
-    int modelItemsCount = d->mItemView->model()->rowCount();
+    int modelItemsCount = modelIterator->indexCount();
     int itemsCount = d->mItems.count();
-    int diff = index.row() + itemsCount - modelItemsCount;
+    int diff = indexPosition + itemsCount - modelItemsCount;
     if (diff >= d->mItemsPerRow) {
-        diff = modelItemsCount - itemsCount;
-        if (diff % d->mItemsPerRow) diff = diff + d->mItemsPerRow - diff % d->mItemsPerRow;
-        index = d->mItemView->model()->index(diff, 0);
-        if (!index.isValid())
-            index = d->mItemView->model()->index(0, 0);
+        // starting from index do not fill the buffer
+        // so new starting index need to be calculated
+        // to fill the buffer with items
+        int newStartIndex = modelItemsCount - itemsCount;
+        int remainder = newStartIndex % d->mItemsPerRow;;
+        if (remainder) {
+            // move newStartIndex forward to contain
+            // last row and empty items
+            newStartIndex += d->mItemsPerRow - remainder;
+        }
+        index = modelIterator->index(newStartIndex);
+        if (!index.isValid()) {
+            // if invalid get first item from model
+            index = modelIterator->nextIndex(QModelIndex());
+        }
+        indexPosition = modelIterator->indexPosition(index);
+    }
+
+    if (d->mItems.first()->modelIndex() == index) {
+        // container already contain right items
+        return;
     }
 
     int i = 0;
     for (; i < itemsCount && index.isValid(); ++i) {
         setItemModelIndex(d->mItems.at(i), index);
-        index = d->mItemView->modelIterator()->nextIndex(index);
+        index = modelIterator->nextIndex(index);
     }
 
     if (i < itemsCount) {
@@ -191,6 +220,11 @@
             setItemModelIndex(d->mItems.at(i), index);
         }
         if (i < itemsCount) {
+            // somehow model size was change
+            // this is almost impossible do get there -
+            // means that items were removed but view 
+            // was not noticed about that - or setModelIndexes
+            // was call before model has noticed view
             while (i > d->mItems.count()) {
                 d->mItems.removeLast();
             }
@@ -210,18 +244,10 @@
 /*!
     \reimp
 */
-void HbGridItemContainer::viewResized(const QSizeF &size)
+void HbGridItemContainer::viewResized(const QSizeF &)
 {
     Q_D(HbGridItemContainer);
-    if (!(qFuzzyCompare(d->mViewSize.height(), size.height())
-            && qFuzzyCompare(d->mViewSize.width(), size.width()))) {
-        QPointF p = pos();
-        p.setY(p.y() *  size.height() / d->mViewSize.height());
-        p.setX(p.x() * size.width() / d->mViewSize.width());
-        setPos(p);
-        d->mViewSize = size;
-        d->resetBuffer();
-    }
+    d->resetBuffer();
 }
 
 /*!
@@ -250,68 +276,56 @@
 /*!
     \reimp
 */
-
 QPointF HbGridItemContainer::recycleItems(const QPointF &delta)
 {
     Q_D(HbGridItemContainer);
 
-    if (!d->mItemRecycling || d->mItemsPerRow <=0) {
+    if (d->mPrototypes.count() != 1) {
         return delta;
     }
 
-    QRectF viewRect(d->itemBoundingRect(d->mItemView));
-    QSizeF itemsCanvas(layout()->preferredSize());
-    qreal invisibleArea = 0;
+    // current invisible space can be scrolled by base class
+    // recycling need only do the rest
+    const qreal diff = d->getDiffWithoutScrollareaCompensation(delta);
 
-    qreal diff = 0.0;
-    if (Qt::Vertical == d->mScrollDirection) {
-        invisibleArea = itemsCanvas.height() - viewRect.height();
-        diff = pos().y() - delta.y();
-        if ((delta.y() < 0.0 && diff > 0) 
-            || (delta.y() > 0.0 && invisibleArea + diff < 0)) {
-            diff = delta.y();
+    if (diff != 0.0) {
+        HbModelIterator *modelIterator = d->mItemView->modelIterator();
+        qreal result = 0.0;
+        qreal containerSize = (d->mScrollDirection == Qt::Vertical)
+            ? size().height() : size().width();
+        bool doFarJump = false;
+        if (qAbs(diff) > containerSize) {
+            // if huge diff - current buffer does not containt any item that should
+            // be there after jump - because of that use setModelIndexes instead of
+            // recycling items - faster
+            // but it is possible that even if far jump was requested (huge delta) 
+            // it can't be done because of model size and current position (at the end)
+            if (diff > 0) {
+                // scrolling down
+                int indexPos = modelIterator->indexPosition(d->lastValidItemIndex())
+                                + d->mItems.count();
+                doFarJump = (indexPos < modelIterator->indexCount());
+            } else {
+                // scrolling up
+                int indexPos = modelIterator->indexPosition(d->mItems.first()->modelIndex())
+                                - d->mItems.count();
+                doFarJump = (indexPos >= 0);
+            }
         }
-        else {
-            diff = 0.0;   
-        }
-    }
-    else {
-        invisibleArea = itemsCanvas.width() - viewRect.width();
-        diff = pos().x() - delta.x();
-        if ((delta.x() < 0.0 && diff > 0) 
-            || (delta.x() > 0.0 && invisibleArea + diff < 0)) {
-            diff = delta.x();
+        if (doFarJump) {
+            // start calculations for far jump
+            // take back into account real delta (do jump as far as possible
+            // without leaving it for scroll area)
+            result = d->farRecycling(delta);
         }
         else {
-            diff = 0.0;   
-        }
-    }
-
-    if (diff != 0.0) {
-        if (HbAbstractItemViewPrivate::d_ptr(d->mItemView)->mOptions & HbAbstractItemViewPrivate::PanningActive) {
-            // jump is almost in the middle of fetched buffer - in most of cases
-            // after scrolling was stopped panning should be done without fetching 
-            // items
-            // in case when buffer == 1 below lines do not change diff
-            qreal extraDiff = invisibleArea/2 - d->mCachedItemHeight;
-            if (extraDiff < 0.0) {
-                extraDiff = 0.0; // impossible because this mean that bufferSize == 0
-            }
-
-            if (diff < 0.0) {
-                diff -= extraDiff; 
-            }
-            else {
-                diff += extraDiff;
-            }   
+            result = d->recycling(diff);
         }
 
-        qreal result = (d->recycling(diff));
+        QPointF newDelta(Qt::Vertical == d->mScrollDirection
+                ? QPointF(0.0, delta.y() - result) 
+                : QPointF(delta.x() - result, 0.0));
 
-        QPointF newDelta(Qt::Vertical == d->mScrollDirection
-                ?QPointF(0.0, delta.y() - result) 
-                : QPointF(delta.x() - result, 0.0));
-        
         return newDelta;
     }
 
@@ -460,7 +474,7 @@
 {
     Q_D(HbGridItemContainer);
 
-    if (!index.isValid() || d->mItems.count() <= 0)
+    if (!index.isValid() || d->mItems.isEmpty())
         return;
     
     switch (hint) {
@@ -512,6 +526,15 @@
     }
 }
 
+/*!
+    \reimp
+    In grid case items are allways same size
+*/
+void HbGridItemContainer::setUniformItemSizes(bool enable)
+{
+    Q_UNUSED(enable);
+    // d->mUniformItemSizes - allways true
+}
 
 #include "moc_hbgriditemcontainer_p.cpp"