86 |
86 |
87 if (!index.isValid()) |
87 if (!index.isValid()) |
88 return; |
88 return; |
89 |
89 |
90 int bufferIndex = 0; |
90 int bufferIndex = 0; |
91 if (d->mItems.count() != 0) { |
91 QModelIndex firstInBuffer; |
92 bufferIndex = qMax(0, index.row() - d->mItems.first()->modelIndex().row()); |
92 int firstInBufferPosition = -1; |
|
93 int indexPosition = d->mItemView->modelIterator()->indexPosition(index); |
|
94 if (!d->mItems.isEmpty()) { |
|
95 firstInBuffer = d->mItems.first()->modelIndex(); |
|
96 firstInBufferPosition = d->mItemView->modelIterator()->indexPosition(firstInBuffer); |
|
97 bufferIndex = qMax(0, indexPosition - firstInBufferPosition); |
93 } |
98 } |
94 // inserting new item because of buffer size |
99 // inserting new item because of buffer size |
95 if (d->mItems.count() == 0 |
100 if (d->mItems.isEmpty() |
96 || d->mItems.count() < maxItemCount()) { |
101 || d->mItems.count() < maxItemCount()) { |
97 insertItem(bufferIndex, index, animate); |
102 insertItem(bufferIndex, index, animate); |
98 viewLayout()->invalidate(); |
103 viewLayout()->invalidate(); |
99 } |
104 } |
100 // special case - only for grid, if added item is above the |
105 // special case - only for grid, if added item is above the |
101 // visible region we need to shift all visible items by one! |
106 // visible region we need to shift all visible items by one! |
102 else if (d->mItems.count() > 0 |
107 else if (!d->mItems.isEmpty() |
103 && d->mItems.first()->modelIndex().row() > index.row()) { |
108 && firstInBufferPosition > indexPosition) { |
104 d->shiftUpItem(animate); // shift up in this case always return something |
109 d->shiftUpItem(animate); // shift up in this case always return something |
105 viewLayout()->invalidate(); |
110 viewLayout()->invalidate(); |
106 } |
111 } |
107 // new item is in visible range |
112 // new item is in visible range |
108 else if (bufferIndex < d->mItems.count()) { |
113 else if (bufferIndex < d->mItems.count()) { |
|
114 // new added item comes to buffer - it will be |
|
115 // recycled from last item in buffer (it is also ok |
|
116 // when that last item was invalid) |
109 HbAbstractViewItem *last = d->mItems.last(); |
117 HbAbstractViewItem *last = d->mItems.last(); |
110 if (animate) { |
118 if (animate) { |
111 last->setOpacity(0.0); |
119 last->setOpacity(0.0); |
112 } |
120 } |
113 setItemModelIndex(last, index); |
121 setItemModelIndex(last, index); |
158 |
166 |
159 if (!d->mItemView || !d->mItemView->model()) { |
167 if (!d->mItemView || !d->mItemView->model()) { |
160 return; |
168 return; |
161 } |
169 } |
162 |
170 |
|
171 HbModelIterator *modelIterator = d->mItemView->modelIterator(); |
163 QModelIndex index = startIndex; |
172 QModelIndex index = startIndex; |
164 if (!index.isValid()) { |
173 if (!index.isValid()) { |
165 index = d->mItemView->model()->index(0, 0); |
174 index = modelIterator->nextIndex(QModelIndex()); |
166 if (!index.isValid()) |
175 if (!index.isValid()) { |
|
176 // this mean model is empty |
167 return; |
177 return; |
168 } |
178 } |
169 index = d->mItemView->model()->index( |
179 } |
170 d->alignIndexToClosestFirstInRow(index.row()), 0); |
180 |
171 |
181 int indexPosition = modelIterator->indexPosition(index); |
172 int modelItemsCount = d->mItemView->model()->rowCount(); |
182 indexPosition = d->alignIndexToClosestFirstInRow(indexPosition); |
|
183 index = modelIterator->index(indexPosition); |
|
184 |
|
185 int modelItemsCount = modelIterator->indexCount(); |
173 int itemsCount = d->mItems.count(); |
186 int itemsCount = d->mItems.count(); |
174 int diff = index.row() + itemsCount - modelItemsCount; |
187 int diff = indexPosition + itemsCount - modelItemsCount; |
175 if (diff >= d->mItemsPerRow) { |
188 if (diff >= d->mItemsPerRow) { |
176 diff = modelItemsCount - itemsCount; |
189 // starting from index do not fill the buffer |
177 if (diff % d->mItemsPerRow) diff = diff + d->mItemsPerRow - diff % d->mItemsPerRow; |
190 // so new starting index need to be calculated |
178 index = d->mItemView->model()->index(diff, 0); |
191 // to fill the buffer with items |
179 if (!index.isValid()) |
192 int newStartIndex = modelItemsCount - itemsCount; |
180 index = d->mItemView->model()->index(0, 0); |
193 int remainder = newStartIndex % d->mItemsPerRow;; |
|
194 if (remainder) { |
|
195 // move newStartIndex forward to contain |
|
196 // last row and empty items |
|
197 newStartIndex += d->mItemsPerRow - remainder; |
|
198 } |
|
199 index = modelIterator->index(newStartIndex); |
|
200 if (!index.isValid()) { |
|
201 // if invalid get first item from model |
|
202 index = modelIterator->nextIndex(QModelIndex()); |
|
203 } |
|
204 indexPosition = modelIterator->indexPosition(index); |
|
205 } |
|
206 |
|
207 if (d->mItems.first()->modelIndex() == index) { |
|
208 // container already contain right items |
|
209 return; |
181 } |
210 } |
182 |
211 |
183 int i = 0; |
212 int i = 0; |
184 for (; i < itemsCount && index.isValid(); ++i) { |
213 for (; i < itemsCount && index.isValid(); ++i) { |
185 setItemModelIndex(d->mItems.at(i), index); |
214 setItemModelIndex(d->mItems.at(i), index); |
186 index = d->mItemView->modelIterator()->nextIndex(index); |
215 index = modelIterator->nextIndex(index); |
187 } |
216 } |
188 |
217 |
189 if (i < itemsCount) { |
218 if (i < itemsCount) { |
190 for (; i % d->mItemsPerRow != 0; i++) { |
219 for (; i % d->mItemsPerRow != 0; i++) { |
191 setItemModelIndex(d->mItems.at(i), index); |
220 setItemModelIndex(d->mItems.at(i), index); |
192 } |
221 } |
193 if (i < itemsCount) { |
222 if (i < itemsCount) { |
|
223 // somehow model size was change |
|
224 // this is almost impossible do get there - |
|
225 // means that items were removed but view |
|
226 // was not noticed about that - or setModelIndexes |
|
227 // was call before model has noticed view |
194 while (i > d->mItems.count()) { |
228 while (i > d->mItems.count()) { |
195 d->mItems.removeLast(); |
229 d->mItems.removeLast(); |
196 } |
230 } |
197 } |
231 } |
198 } |
232 } |
248 } |
274 } |
249 |
275 |
250 /*! |
276 /*! |
251 \reimp |
277 \reimp |
252 */ |
278 */ |
253 |
|
254 QPointF HbGridItemContainer::recycleItems(const QPointF &delta) |
279 QPointF HbGridItemContainer::recycleItems(const QPointF &delta) |
255 { |
280 { |
256 Q_D(HbGridItemContainer); |
281 Q_D(HbGridItemContainer); |
257 |
282 |
258 if (!d->mItemRecycling || d->mItemsPerRow <=0) { |
283 if (d->mPrototypes.count() != 1) { |
259 return delta; |
284 return delta; |
260 } |
285 } |
261 |
286 |
262 QRectF viewRect(d->itemBoundingRect(d->mItemView)); |
287 // current invisible space can be scrolled by base class |
263 QSizeF itemsCanvas(layout()->preferredSize()); |
288 // recycling need only do the rest |
264 qreal invisibleArea = 0; |
289 const qreal diff = d->getDiffWithoutScrollareaCompensation(delta); |
265 |
290 |
266 qreal diff = 0.0; |
291 if (diff != 0.0) { |
267 if (Qt::Vertical == d->mScrollDirection) { |
292 HbModelIterator *modelIterator = d->mItemView->modelIterator(); |
268 invisibleArea = itemsCanvas.height() - viewRect.height(); |
293 qreal result = 0.0; |
269 diff = pos().y() - delta.y(); |
294 qreal containerSize = (d->mScrollDirection == Qt::Vertical) |
270 if ((delta.y() < 0.0 && diff > 0) |
295 ? size().height() : size().width(); |
271 || (delta.y() > 0.0 && invisibleArea + diff < 0)) { |
296 bool doFarJump = false; |
272 diff = delta.y(); |
297 if (qAbs(diff) > containerSize) { |
|
298 // if huge diff - current buffer does not containt any item that should |
|
299 // be there after jump - because of that use setModelIndexes instead of |
|
300 // recycling items - faster |
|
301 // but it is possible that even if far jump was requested (huge delta) |
|
302 // it can't be done because of model size and current position (at the end) |
|
303 if (diff > 0) { |
|
304 // scrolling down |
|
305 int indexPos = modelIterator->indexPosition(d->lastValidItemIndex()) |
|
306 + d->mItems.count(); |
|
307 doFarJump = (indexPos < modelIterator->indexCount()); |
|
308 } else { |
|
309 // scrolling up |
|
310 int indexPos = modelIterator->indexPosition(d->mItems.first()->modelIndex()) |
|
311 - d->mItems.count(); |
|
312 doFarJump = (indexPos >= 0); |
|
313 } |
|
314 } |
|
315 if (doFarJump) { |
|
316 // start calculations for far jump |
|
317 // take back into account real delta (do jump as far as possible |
|
318 // without leaving it for scroll area) |
|
319 result = d->farRecycling(delta); |
273 } |
320 } |
274 else { |
321 else { |
275 diff = 0.0; |
322 result = d->recycling(diff); |
276 } |
323 } |
277 } |
|
278 else { |
|
279 invisibleArea = itemsCanvas.width() - viewRect.width(); |
|
280 diff = pos().x() - delta.x(); |
|
281 if ((delta.x() < 0.0 && diff > 0) |
|
282 || (delta.x() > 0.0 && invisibleArea + diff < 0)) { |
|
283 diff = delta.x(); |
|
284 } |
|
285 else { |
|
286 diff = 0.0; |
|
287 } |
|
288 } |
|
289 |
|
290 if (diff != 0.0) { |
|
291 if (HbAbstractItemViewPrivate::d_ptr(d->mItemView)->mOptions & HbAbstractItemViewPrivate::PanningActive) { |
|
292 // jump is almost in the middle of fetched buffer - in most of cases |
|
293 // after scrolling was stopped panning should be done without fetching |
|
294 // items |
|
295 // in case when buffer == 1 below lines do not change diff |
|
296 qreal extraDiff = invisibleArea/2 - d->mCachedItemHeight; |
|
297 if (extraDiff < 0.0) { |
|
298 extraDiff = 0.0; // impossible because this mean that bufferSize == 0 |
|
299 } |
|
300 |
|
301 if (diff < 0.0) { |
|
302 diff -= extraDiff; |
|
303 } |
|
304 else { |
|
305 diff += extraDiff; |
|
306 } |
|
307 } |
|
308 |
|
309 qreal result = (d->recycling(diff)); |
|
310 |
324 |
311 QPointF newDelta(Qt::Vertical == d->mScrollDirection |
325 QPointF newDelta(Qt::Vertical == d->mScrollDirection |
312 ?QPointF(0.0, delta.y() - result) |
326 ? QPointF(0.0, delta.y() - result) |
313 : QPointF(delta.x() - result, 0.0)); |
327 : QPointF(delta.x() - result, 0.0)); |
314 |
328 |
315 return newDelta; |
329 return newDelta; |
316 } |
330 } |
317 |
331 |
318 return delta; |
332 return delta; |
319 } |
333 } |