Merge remote-tracking branch 'origin/4.7' into qt-4.8-from-4.7
[qt:qt.git] / src / declarative / graphicsitems / qdeclarativegridview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativegridview_p.h"
43
44 #include "private/qdeclarativevisualitemmodel_p.h"
45 #include "private/qdeclarativeflickable_p_p.h"
46
47 #include "private/qdeclarativesmoothedanimation_p_p.h"
48 #include <qdeclarativeguard_p.h>
49
50 #include <qlistmodelinterface_p.h>
51 #include <QKeyEvent>
52
53 #include <qmath.h>
54 #include <math.h>
55 #include "qplatformdefs.h"
56
57 QT_BEGIN_NAMESPACE
58
59 #ifndef QML_FLICK_SNAPONETHRESHOLD
60 #define QML_FLICK_SNAPONETHRESHOLD 30
61 #endif
62
63 //----------------------------------------------------------------------------
64
65 class FxGridItem
66 {
67 public:
68     FxGridItem(QDeclarativeItem *i, QDeclarativeGridView *v) : item(i), view(v) {
69         attached = static_cast<QDeclarativeGridViewAttached*>(qmlAttachedPropertiesObject<QDeclarativeGridView>(item));
70         if (attached)
71             attached->setView(view);
72     }
73     ~FxGridItem() {}
74
75     qreal rowPos() const {
76         qreal rowPos = 0;
77         if (view->flow() == QDeclarativeGridView::LeftToRight) {
78             rowPos = item->y();
79         } else {
80             if (view->effectiveLayoutDirection() == Qt::RightToLeft)
81                 rowPos = -view->cellWidth()-item->x();
82             else
83                 rowPos = item->x();
84         }
85         return rowPos;
86     }
87     qreal colPos() const {
88         qreal colPos = 0;
89         if (view->flow() == QDeclarativeGridView::LeftToRight) {
90             if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
91                 int colSize = view->cellWidth();
92                 int columns = view->width()/colSize;
93                 colPos = colSize * (columns-1) - item->x();
94             } else {
95                 colPos = item->x();
96             }
97         } else {
98             colPos = item->y();
99         }
100
101         return colPos;
102     }
103
104     qreal endRowPos() const {
105         if (view->flow() == QDeclarativeGridView::LeftToRight) {
106             return item->y() + view->cellHeight() - 1;
107         } else {
108             if (view->effectiveLayoutDirection() == Qt::RightToLeft)
109                 return -item->x() - 1;
110             else
111                 return item->x() + view->cellWidth() - 1;
112         }
113     }
114     void setPosition(qreal col, qreal row) {
115         if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
116             if (view->flow() == QDeclarativeGridView::LeftToRight) {
117                 int columns = view->width()/view->cellWidth();
118                 item->setPos(QPointF((view->cellWidth() * (columns-1) - col), row));
119             } else {
120                 item->setPos(QPointF(-view->cellWidth()-row, col));
121             }
122         } else {
123             if (view->flow() == QDeclarativeGridView::LeftToRight)
124                 item->setPos(QPointF(col, row));
125             else
126                 item->setPos(QPointF(row, col));
127         }
128
129     }
130     bool contains(qreal x, qreal y) const {
131         return (x >= item->x() && x < item->x() + view->cellWidth() &&
132                 y >= item->y() && y < item->y() + view->cellHeight());
133     }
134
135     QDeclarativeItem *item;
136     QDeclarativeGridView *view;
137     QDeclarativeGridViewAttached *attached;
138     int index;
139 };
140
141 //----------------------------------------------------------------------------
142
143 class QDeclarativeGridViewPrivate : public QDeclarativeFlickablePrivate
144 {
145     Q_DECLARE_PUBLIC(QDeclarativeGridView)
146
147 public:
148     QDeclarativeGridViewPrivate()
149     : currentItem(0), layoutDirection(Qt::LeftToRight), flow(QDeclarativeGridView::LeftToRight)
150     , visibleIndex(0) , currentIndex(-1)
151     , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1), itemCount(0)
152     , highlightRangeStart(0), highlightRangeEnd(0)
153     , highlightRangeStartValid(false), highlightRangeEndValid(false)
154     , highlightRange(QDeclarativeGridView::NoHighlightRange)
155     , highlightComponent(0), highlight(0), trackedItem(0)
156     , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0)
157     , highlightMoveDuration(150)
158     , footerComponent(0), footer(0), headerComponent(0), header(0)
159     , bufferMode(BufferBefore | BufferAfter), snapMode(QDeclarativeGridView::NoSnap)
160     , ownModel(false), wrap(false), autoHighlight(true)
161     , fixCurrentVisibility(false), lazyRelease(false), layoutScheduled(false)
162     , deferredRelease(false), haveHighlightRange(false), currentIndexCleared(false) {}
163
164     void init();
165     void clear();
166     FxGridItem *createItem(int modelIndex);
167     void releaseItem(FxGridItem *item);
168     void refill(qreal from, qreal to, bool doBuffer=false);
169
170     void updateGrid();
171     void scheduleLayout();
172     void layout();
173     void updateUnrequestedIndexes();
174     void updateUnrequestedPositions();
175     void updateTrackedItem();
176     void createHighlight();
177     void updateHighlight();
178     void updateCurrent(int modelIndex);
179     void updateHeader();
180     void updateFooter();
181     void fixupPosition();
182
183     FxGridItem *visibleItem(int modelIndex) const {
184         if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
185             for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
186                 FxGridItem *item = visibleItems.at(i);
187                 if (item->index == modelIndex)
188                     return item;
189             }
190         }
191         return 0;
192     }
193
194     bool isRightToLeftTopToBottom() const {
195         Q_Q(const QDeclarativeGridView);
196         return flow == QDeclarativeGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft;
197     }
198
199     void regenerate() {
200         Q_Q(QDeclarativeGridView);
201         if (q->isComponentComplete()) {
202             clear();
203             updateGrid();
204             setPosition(0);
205             q->refill();
206             updateCurrent(currentIndex);
207         }
208     }
209
210     void mirrorChange() {
211         Q_Q(QDeclarativeGridView);
212         regenerate();
213     }
214
215     qreal position() const {
216         Q_Q(const QDeclarativeGridView);
217         return flow == QDeclarativeGridView::LeftToRight ? q->contentY() : q->contentX();
218     }
219     void setPosition(qreal pos) {
220         Q_Q(QDeclarativeGridView);
221         if (flow == QDeclarativeGridView::LeftToRight) {
222             q->QDeclarativeFlickable::setContentY(pos);
223             q->QDeclarativeFlickable::setContentX(0);
224         } else {
225             if (q->effectiveLayoutDirection() == Qt::LeftToRight)
226                 q->QDeclarativeFlickable::setContentX(pos);
227             else
228                 q->QDeclarativeFlickable::setContentX(-pos-size());
229             q->QDeclarativeFlickable::setContentY(0);
230         }
231     }
232     int size() const {
233         Q_Q(const QDeclarativeGridView);
234         return flow == QDeclarativeGridView::LeftToRight ? q->height() : q->width();
235     }
236     qreal originPosition() const {
237         qreal pos = 0;
238         if (!visibleItems.isEmpty())
239             pos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
240         return pos;
241     }
242
243     qreal lastPosition() const {
244         qreal pos = 0;
245         if (model && model->count())
246             pos = rowPosAt(model->count() - 1) + rowSize();
247         return pos;
248     }
249
250     qreal startPosition() const {
251         return isRightToLeftTopToBottom() ? -lastPosition()+1 : originPosition();
252     }
253
254     qreal endPosition() const {
255         return isRightToLeftTopToBottom() ? -originPosition()+1 : lastPosition();
256
257     }
258
259     bool isValid() const {
260         return model && model->count() && model->isValid();
261     }
262
263     int rowSize() const {
264         return flow == QDeclarativeGridView::LeftToRight ? cellHeight : cellWidth;
265     }
266     int colSize() const {
267         return flow == QDeclarativeGridView::LeftToRight ? cellWidth : cellHeight;
268     }
269
270     qreal colPosAt(int modelIndex) const {
271         if (FxGridItem *item = visibleItem(modelIndex))
272             return item->colPos();
273         if (!visibleItems.isEmpty()) {
274             if (modelIndex < visibleIndex) {
275                 int count = (visibleIndex - modelIndex) % columns;
276                 int col = visibleItems.first()->colPos() / colSize();
277                 col = (columns - count + col) % columns;
278                 return col * colSize();
279             } else {
280                 int count = columns - 1 - (modelIndex - visibleItems.last()->index - 1) % columns;
281                 return visibleItems.last()->colPos() - count * colSize();
282             }
283         } else {
284             return (modelIndex % columns) * colSize();
285         }
286         return 0;
287     }
288     qreal rowPosAt(int modelIndex) const {
289         if (FxGridItem *item = visibleItem(modelIndex))
290             return item->rowPos();
291         if (!visibleItems.isEmpty()) {
292             if (modelIndex < visibleIndex) {
293                 int firstCol = visibleItems.first()->colPos() / colSize();
294                 int col = visibleIndex - modelIndex + (columns - firstCol - 1);
295                 int rows = col / columns;
296                 return visibleItems.first()->rowPos() - rows * rowSize();
297             } else {
298                 int count = modelIndex - visibleItems.last()->index;
299                 int col = visibleItems.last()->colPos() + count * colSize();
300                 int rows = col / (columns * colSize());
301                 return visibleItems.last()->rowPos() + rows * rowSize();
302             }
303         } else {
304             qreal pos = (modelIndex / columns) * rowSize();
305             if (header)
306                 pos += headerSize();
307             return pos;
308         }
309         return 0;
310     }
311
312     FxGridItem *firstVisibleItem() const {
313         const qreal pos = isRightToLeftTopToBottom() ? -position()-size() : position();
314         for (int i = 0; i < visibleItems.count(); ++i) {
315             FxGridItem *item = visibleItems.at(i);
316             if (item->index != -1 && item->endRowPos() > pos)
317                 return item;
318         }
319         return visibleItems.count() ? visibleItems.first() : 0;
320     }
321
322     int lastVisibleIndex() const {
323         for (int i = 0; i < visibleItems.count(); ++i) {
324             FxGridItem *item = visibleItems.at(i);
325             if (item->index != -1)
326                 return item->index;
327         }
328         return -1;
329     }
330
331     // Map a model index to visibleItems list index.
332     // These may differ if removed items are still present in the visible list,
333     // e.g. doing a removal animation
334     int mapFromModel(int modelIndex) const {
335         if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
336             return -1;
337         for (int i = 0; i < visibleItems.count(); ++i) {
338             FxGridItem *listItem = visibleItems.at(i);
339             if (listItem->index == modelIndex)
340                 return i + visibleIndex;
341             if (listItem->index > modelIndex)
342                 return -1;
343         }
344         return -1; // Not in visibleList
345     }
346
347     qreal snapPosAt(qreal pos) const {
348         Q_Q(const QDeclarativeGridView);
349         qreal snapPos = 0;
350         if (!visibleItems.isEmpty()) {
351             qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
352             pos += highlightStart;
353             pos += rowSize()/2;
354             snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
355             snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
356             snapPos -= highlightStart;
357             qreal maxExtent;
358             qreal minExtent;
359             if (isRightToLeftTopToBottom()) {
360                 maxExtent = q->minXExtent();
361                 minExtent = q->maxXExtent();
362             } else {
363                 maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
364                 minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
365             }
366             if (snapPos > maxExtent)
367                 snapPos = maxExtent;
368             if (snapPos < minExtent)
369                 snapPos = minExtent;
370         }
371         return snapPos;
372     }
373
374     FxGridItem *snapItemAt(qreal pos) {
375         for (int i = 0; i < visibleItems.count(); ++i) {
376             FxGridItem *item = visibleItems[i];
377             if (item->index == -1)
378                 continue;
379             qreal itemTop = item->rowPos();
380             if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
381                 return item;
382         }
383         return 0;
384     }
385
386     int snapIndex() {
387         int index = currentIndex;
388         for (int i = 0; i < visibleItems.count(); ++i) {
389             FxGridItem *item = visibleItems[i];
390             if (item->index == -1)
391                 continue;
392             qreal itemTop = item->rowPos();
393             if (itemTop >= highlight->rowPos()-rowSize()/2 && itemTop < highlight->rowPos()+rowSize()/2) {
394                 index = item->index;
395                 if (item->colPos() >= highlight->colPos()-colSize()/2 && item->colPos() < highlight->colPos()+colSize()/2)
396                     return item->index;
397             }
398         }
399         return index;
400     }
401
402     qreal headerSize() const {
403         if (!header)
404             return 0.0;
405
406         return flow == QDeclarativeGridView::LeftToRight
407                        ? header->item->height()
408                        : header->item->width();
409     }
410
411
412     virtual void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
413         Q_Q(const QDeclarativeGridView);
414         QDeclarativeFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
415         if (item == q) {
416             if (newGeometry.height() != oldGeometry.height()
417                 || newGeometry.width() != oldGeometry.width()) {
418                 if (q->isComponentComplete()) {
419                     updateGrid();
420                     scheduleLayout();
421                 }
422             }
423         } else if ((header && header->item == item) || (footer && footer->item == item)) {
424             if (header)
425                 updateHeader();
426             if (footer)
427                 updateFooter();
428         }
429     }
430
431     void positionViewAtIndex(int index, int mode);
432     virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
433     virtual void flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
434                 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
435
436     // for debugging only
437     void checkVisible() const {
438         int skip = 0;
439         for (int i = 0; i < visibleItems.count(); ++i) {
440             FxGridItem *listItem = visibleItems.at(i);
441             if (listItem->index == -1) {
442                 ++skip;
443             } else if (listItem->index != visibleIndex + i - skip) {
444                 for (int j = 0; j < visibleItems.count(); j++)
445                     qDebug() << " index" << j << "item index" << visibleItems.at(j)->index;
446                 qFatal("index %d %d %d", visibleIndex, i, listItem->index);
447             }
448         }
449     }
450
451     QDeclarativeGuard<QDeclarativeVisualModel> model;
452     QVariant modelVariant;
453     QList<FxGridItem*> visibleItems;
454     QHash<QDeclarativeItem*,int> unrequestedItems;
455     FxGridItem *currentItem;
456     Qt::LayoutDirection layoutDirection;
457     QDeclarativeGridView::Flow flow;
458     int visibleIndex;
459     int currentIndex;
460     int cellWidth;
461     int cellHeight;
462     int columns;
463     int requestedIndex;
464     int itemCount;
465     qreal highlightRangeStart;
466     qreal highlightRangeEnd;
467     bool highlightRangeStartValid;
468     bool highlightRangeEndValid;
469     QDeclarativeGridView::HighlightRangeMode highlightRange;
470     QDeclarativeComponent *highlightComponent;
471     FxGridItem *highlight;
472     FxGridItem *trackedItem;
473     enum MovementReason { Other, SetIndex, Mouse };
474     MovementReason moveReason;
475     int buffer;
476     QSmoothedAnimation *highlightXAnimator;
477     QSmoothedAnimation *highlightYAnimator;
478     int highlightMoveDuration;
479     QDeclarativeComponent *footerComponent;
480     FxGridItem *footer;
481     QDeclarativeComponent *headerComponent;
482     FxGridItem *header;
483     enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
484     int bufferMode;
485     QDeclarativeGridView::SnapMode snapMode;
486
487     bool ownModel : 1;
488     bool wrap : 1;
489     bool autoHighlight : 1;
490     bool fixCurrentVisibility : 1;
491     bool lazyRelease : 1;
492     bool layoutScheduled : 1;
493     bool deferredRelease : 1;
494     bool haveHighlightRange : 1;
495     bool currentIndexCleared : 1;
496 };
497
498 void QDeclarativeGridViewPrivate::init()
499 {
500     Q_Q(QDeclarativeGridView);
501     QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
502     q->setFlag(QGraphicsItem::ItemIsFocusScope);
503     q->setFlickableDirection(QDeclarativeFlickable::VerticalFlick);
504     addItemChangeListener(this, Geometry);
505 }
506
507 void QDeclarativeGridViewPrivate::clear()
508 {
509     for (int i = 0; i < visibleItems.count(); ++i)
510         releaseItem(visibleItems.at(i));
511     visibleItems.clear();
512     visibleIndex = 0;
513     releaseItem(currentItem);
514     currentItem = 0;
515     createHighlight();
516     trackedItem = 0;
517     itemCount = 0;
518 }
519
520 FxGridItem *QDeclarativeGridViewPrivate::createItem(int modelIndex)
521 {
522     Q_Q(QDeclarativeGridView);
523     // create object
524     requestedIndex = modelIndex;
525     FxGridItem *listItem = 0;
526     if (QDeclarativeItem *item = model->item(modelIndex, false)) {
527         listItem = new FxGridItem(item, q);
528         listItem->index = modelIndex;
529         if (model->completePending()) {
530             // complete
531             listItem->item->setZValue(1);
532             listItem->item->setParentItem(q->contentItem());
533             model->completeItem();
534         } else {
535             listItem->item->setParentItem(q->contentItem());
536         }
537         unrequestedItems.remove(listItem->item);
538     }
539     requestedIndex = -1;
540     return listItem;
541 }
542
543
544 void QDeclarativeGridViewPrivate::releaseItem(FxGridItem *item)
545 {
546     Q_Q(QDeclarativeGridView);
547     if (!item || !model)
548         return;
549     if (trackedItem == item) {
550         QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
551         QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
552         trackedItem = 0;
553     }
554     if (model->release(item->item) == 0) {
555         // item was not destroyed, and we no longer reference it.
556         unrequestedItems.insert(item->item, model->indexOf(item->item, q));
557     }
558     delete item;
559 }
560
561 void QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer)
562 {
563     Q_Q(QDeclarativeGridView);
564     if (!isValid() || !q->isComponentComplete())
565         return;
566     itemCount = model->count();
567     qreal bufferFrom = from - buffer;
568     qreal bufferTo = to + buffer;
569     qreal fillFrom = from;
570     qreal fillTo = to;
571     if (doBuffer && (bufferMode & BufferAfter))
572         fillTo = bufferTo;
573     if (doBuffer && (bufferMode & BufferBefore))
574         fillFrom = bufferFrom;
575
576     bool changed = false;
577
578     int colPos = colPosAt(visibleIndex);
579     int rowPos = rowPosAt(visibleIndex);
580     int modelIndex = visibleIndex;
581     if (visibleItems.count()) {
582         rowPos = visibleItems.last()->rowPos();
583         colPos = visibleItems.last()->colPos() + colSize();
584         if (colPos > colSize() * (columns-1)) {
585             colPos = 0;
586             rowPos += rowSize();
587         }
588         int i = visibleItems.count() - 1;
589         while (i > 0 && visibleItems.at(i)->index == -1)
590             --i;
591         modelIndex = visibleItems.at(i)->index + 1;
592     }
593
594     if (visibleItems.count() && (fillFrom > rowPos + rowSize()*2
595         || fillTo < rowPosAt(visibleIndex) - rowSize())) {
596         // We've jumped more than a page.  Estimate which items are now
597         // visible and fill from there.
598         int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
599         for (int i = 0; i < visibleItems.count(); ++i)
600             releaseItem(visibleItems.at(i));
601         visibleItems.clear();
602         modelIndex += count;
603         if (modelIndex >= model->count())
604             modelIndex = model->count() - 1;
605         else if (modelIndex < 0)
606             modelIndex = 0;
607         modelIndex = modelIndex / columns * columns;
608         visibleIndex = modelIndex;
609         colPos = colPosAt(visibleIndex);
610         rowPos = rowPosAt(visibleIndex);
611     }
612
613     int colNum = colPos / colSize();
614
615     FxGridItem *item = 0;
616
617     // Item creation and release is staggered in order to avoid
618     // creating/releasing multiple items in one frame
619     // while flicking (as much as possible).
620     while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
621 //        qDebug() << "refill: append item" << modelIndex;
622         if (!(item = createItem(modelIndex)))
623             break;
624         item->setPosition(colPos, rowPos);
625         visibleItems.append(item);
626         colPos += colSize();
627         colNum++;
628         if (colPos > colSize() * (columns-1)) {
629             colPos = 0;
630             colNum = 0;
631             rowPos += rowSize();
632         }
633         ++modelIndex;
634         changed = true;
635         if (doBuffer) // never buffer more than one item per frame
636             break;
637     }
638
639     if (visibleItems.count()) {
640         rowPos = visibleItems.first()->rowPos();
641         colPos = visibleItems.first()->colPos() - colSize();
642         if (colPos < 0) {
643             colPos = colSize() * (columns - 1);
644             rowPos -= rowSize();
645         }
646     }
647     colNum = colPos / colSize();
648     while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
649 //        qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
650         if (!(item = createItem(visibleIndex-1)))
651             break;
652         --visibleIndex;
653         item->setPosition(colPos, rowPos);
654         visibleItems.prepend(item);
655         colPos -= colSize();
656         colNum--;
657         if (colPos < 0) {
658             colPos = colSize() * (columns - 1);
659             colNum = columns-1;
660             rowPos -= rowSize();
661         }
662         changed = true;
663         if (doBuffer) // never buffer more than one item per frame
664             break;
665     }
666
667     if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
668         while (visibleItems.count() > 1
669                && (item = visibleItems.first())
670                     && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
671             if (item->attached->delayRemove())
672                 break;
673 //            qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
674             if (item->index != -1)
675                 visibleIndex++;
676             visibleItems.removeFirst();
677             releaseItem(item);
678             changed = true;
679         }
680         while (visibleItems.count() > 1
681                && (item = visibleItems.last())
682                     && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
683             if (item->attached->delayRemove())
684                 break;
685 //            qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
686             visibleItems.removeLast();
687             releaseItem(item);
688             changed = true;
689         }
690         deferredRelease = false;
691     } else {
692         deferredRelease = true;
693     }
694     if (changed) {
695         if (header)
696             updateHeader();
697         if (footer)
698             updateFooter();
699         if (flow == QDeclarativeGridView::LeftToRight)
700             q->setContentHeight(endPosition() - startPosition());
701         else
702             q->setContentWidth(endPosition() - startPosition());
703     } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
704         refill(from, to, true);
705     }
706     lazyRelease = false;
707 }
708
709 void QDeclarativeGridViewPrivate::updateGrid()
710 {
711     Q_Q(QDeclarativeGridView);
712
713     columns = (int)qMax((flow == QDeclarativeGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.));
714     if (isValid()) {
715         if (flow == QDeclarativeGridView::LeftToRight)
716             q->setContentHeight(endPosition() - startPosition());
717         else
718             q->setContentWidth(lastPosition() - originPosition());
719     }
720 }
721
722 void QDeclarativeGridViewPrivate::scheduleLayout()
723 {
724     Q_Q(QDeclarativeGridView);
725     if (!layoutScheduled) {
726         layoutScheduled = true;
727         QCoreApplication::postEvent(q, new QEvent(QEvent::User), Qt::HighEventPriority);
728     }
729 }
730
731 void QDeclarativeGridViewPrivate::layout()
732 {
733     Q_Q(QDeclarativeGridView);
734     layoutScheduled = false;
735     if (!isValid() && !visibleItems.count()) {
736         clear();
737         return;
738     }
739     if (visibleItems.count()) {
740         qreal rowPos = visibleItems.first()->rowPos();
741         qreal colPos = visibleItems.first()->colPos();
742         int col = visibleIndex % columns;
743         if (colPos != col * colSize()) {
744             colPos = col * colSize();
745             visibleItems.first()->setPosition(colPos, rowPos);
746         }
747         for (int i = 1; i < visibleItems.count(); ++i) {
748             FxGridItem *item = visibleItems.at(i);
749             colPos += colSize();
750             if (colPos > colSize() * (columns-1)) {
751                 colPos = 0;
752                 rowPos += rowSize();
753             }
754             item->setPosition(colPos, rowPos);
755         }
756     }
757     if (header)
758         updateHeader();
759     if (footer)
760         updateFooter();
761     q->refill();
762     updateHighlight();
763     moveReason = Other;
764     if (flow == QDeclarativeGridView::LeftToRight) {
765         q->setContentHeight(endPosition() - startPosition());
766         fixupY();
767     } else {
768         q->setContentWidth(endPosition() - startPosition());
769         fixupX();
770     }
771     updateUnrequestedPositions();
772 }
773
774 void QDeclarativeGridViewPrivate::updateUnrequestedIndexes()
775 {
776     Q_Q(QDeclarativeGridView);
777     QHash<QDeclarativeItem*,int>::iterator it;
778     for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
779         *it = model->indexOf(it.key(), q);
780 }
781
782 void QDeclarativeGridViewPrivate::updateUnrequestedPositions()
783 {
784     QHash<QDeclarativeItem*,int>::const_iterator it;
785     for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
786         QDeclarativeItem *item = it.key();
787         if (flow == QDeclarativeGridView::LeftToRight) {
788             item->setPos(QPointF(colPosAt(*it), rowPosAt(*it)));
789         } else {
790             if (isRightToLeftTopToBottom())
791                 item->setPos(QPointF(-rowPosAt(*it)-item->width(), colPosAt(*it)));
792             else
793                 item->setPos(QPointF(rowPosAt(*it), colPosAt(*it)));
794         }
795     }
796 }
797
798 void QDeclarativeGridViewPrivate::updateTrackedItem()
799 {
800     Q_Q(QDeclarativeGridView);
801     FxGridItem *item = currentItem;
802     if (highlight)
803         item = highlight;
804
805     if (trackedItem && item != trackedItem) {
806         QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
807         QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
808         trackedItem = 0;
809     }
810
811     if (!trackedItem && item) {
812         trackedItem = item;
813         QObject::connect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
814         QObject::connect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
815     }
816     if (trackedItem)
817         q->trackedPositionChanged();
818 }
819
820 void QDeclarativeGridViewPrivate::createHighlight()
821 {
822     Q_Q(QDeclarativeGridView);
823     bool changed = false;
824     if (highlight) {
825         if (trackedItem == highlight)
826             trackedItem = 0;
827         if (highlight->item->scene())
828             highlight->item->scene()->removeItem(highlight->item);
829         highlight->item->deleteLater();
830         delete highlight;
831         highlight = 0;
832         delete highlightXAnimator;
833         delete highlightYAnimator;
834         highlightXAnimator = 0;
835         highlightYAnimator = 0;
836         changed = true;
837     }
838
839     if (currentItem) {
840         QDeclarativeItem *item = 0;
841         if (highlightComponent) {
842             QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q));
843             QObject *nobj = highlightComponent->create(highlightContext);
844             if (nobj) {
845                 QDeclarative_setParent_noEvent(highlightContext, nobj);
846                 item = qobject_cast<QDeclarativeItem *>(nobj);
847                 if (!item)
848                     delete nobj;
849             } else {
850                 delete highlightContext;
851             }
852         } else {
853             item = new QDeclarativeItem;
854             QDeclarative_setParent_noEvent(item, q->contentItem());
855             item->setParentItem(q->contentItem());
856         }
857         if (item) {
858             QDeclarative_setParent_noEvent(item, q->contentItem());
859             item->setParentItem(q->contentItem());
860             highlight = new FxGridItem(item, q);
861             if (currentItem && autoHighlight)
862                 highlight->setPosition(currentItem->colPos(), currentItem->rowPos());
863             highlightXAnimator = new QSmoothedAnimation(q);
864             highlightXAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("x"));
865             highlightXAnimator->userDuration = highlightMoveDuration;
866             highlightYAnimator = new QSmoothedAnimation(q);
867             highlightYAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("y"));
868             highlightYAnimator->userDuration = highlightMoveDuration;
869             if (autoHighlight) {
870                 highlightXAnimator->restart();
871                 highlightYAnimator->restart();
872             }
873             changed = true;
874         }
875     }
876     if (changed)
877         emit q->highlightItemChanged();
878 }
879
880 void QDeclarativeGridViewPrivate::updateHighlight()
881 {
882     if ((!currentItem && highlight) || (currentItem && !highlight))
883         createHighlight();
884     if (currentItem && autoHighlight && highlight && !hData.moving && !vData.moving) {
885         // auto-update highlight
886         highlightXAnimator->to = currentItem->item->x();
887         highlightYAnimator->to = currentItem->item->y();
888         highlight->item->setWidth(currentItem->item->width());
889         highlight->item->setHeight(currentItem->item->height());
890         highlightXAnimator->restart();
891         highlightYAnimator->restart();
892     }
893     updateTrackedItem();
894 }
895
896 void QDeclarativeGridViewPrivate::updateCurrent(int modelIndex)
897 {
898     Q_Q(QDeclarativeGridView);
899     if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
900         if (currentItem) {
901             currentItem->attached->setIsCurrentItem(false);
902             releaseItem(currentItem);
903             currentItem = 0;
904             currentIndex = modelIndex;
905             emit q->currentIndexChanged();
906             updateHighlight();
907         } else if (currentIndex != modelIndex) {
908             currentIndex = modelIndex;
909             emit q->currentIndexChanged();
910         }
911         return;
912     }
913
914     if (currentItem && currentIndex == modelIndex) {
915         updateHighlight();
916         return;
917     }
918
919     FxGridItem *oldCurrentItem = currentItem;
920     currentIndex = modelIndex;
921     currentItem = createItem(modelIndex);
922     fixCurrentVisibility = true;
923     if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
924         oldCurrentItem->attached->setIsCurrentItem(false);
925     if (currentItem) {
926         currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex));
927         currentItem->item->setFocus(true);
928         currentItem->attached->setIsCurrentItem(true);
929     }
930     updateHighlight();
931     emit q->currentIndexChanged();
932     releaseItem(oldCurrentItem);
933 }
934
935 void QDeclarativeGridViewPrivate::updateFooter()
936 {
937     Q_Q(QDeclarativeGridView);
938     if (!footer && footerComponent) {
939         QDeclarativeItem *item = 0;
940         QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
941         QObject *nobj = footerComponent->create(context);
942         if (nobj) {
943             QDeclarative_setParent_noEvent(context, nobj);
944             item = qobject_cast<QDeclarativeItem *>(nobj);
945             if (!item)
946                 delete nobj;
947         } else {
948             delete context;
949         }
950         if (item) {
951             QDeclarative_setParent_noEvent(item, q->contentItem());
952             item->setParentItem(q->contentItem());
953             item->setZValue(1);
954             QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
955             itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
956             footer = new FxGridItem(item, q);
957         }
958     }
959     if (footer) {
960         qreal colOffset = 0;
961         qreal rowOffset;
962         if (isRightToLeftTopToBottom()) {
963             rowOffset = footer->item->width()-cellWidth;
964         } else {
965             rowOffset = 0;
966             if (q->effectiveLayoutDirection() == Qt::RightToLeft)
967                 colOffset = footer->item->width()-cellWidth;
968         }
969         if (visibleItems.count()) {
970             qreal endPos = lastPosition();
971             if (lastVisibleIndex() == model->count()-1) {
972                 footer->setPosition(colOffset, endPos + rowOffset);
973             } else {
974                 qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size();
975                 if (endPos <= visiblePos || footer->endRowPos() < endPos + rowOffset)
976                     footer->setPosition(colOffset, endPos + rowOffset);
977             }
978         } else {
979             qreal endPos = 0;
980             if (header) {
981                 endPos += flow == QDeclarativeGridView::LeftToRight ? header->item->height() : header->item->width();
982             }
983             footer->setPosition(colOffset, endPos);
984         }
985     }
986 }
987
988 void QDeclarativeGridViewPrivate::updateHeader()
989 {
990     Q_Q(QDeclarativeGridView);
991     if (!header && headerComponent) {
992         QDeclarativeItem *item = 0;
993         QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
994         QObject *nobj = headerComponent->create(context);
995         if (nobj) {
996             QDeclarative_setParent_noEvent(context, nobj);
997             item = qobject_cast<QDeclarativeItem *>(nobj);
998             if (!item)
999                 delete nobj;
1000         } else {
1001             delete context;
1002         }
1003         if (item) {
1004             QDeclarative_setParent_noEvent(item, q->contentItem());
1005             item->setParentItem(q->contentItem());
1006             item->setZValue(1);
1007             QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
1008             itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
1009             header = new FxGridItem(item, q);
1010         }
1011     }
1012     if (header) {
1013         qreal colOffset = 0;
1014         qreal rowOffset;
1015         if (isRightToLeftTopToBottom()) {
1016             rowOffset = -cellWidth;
1017         } else {
1018             rowOffset = -headerSize();
1019             if (q->effectiveLayoutDirection() == Qt::RightToLeft)
1020                 colOffset = header->item->width()-cellWidth;
1021         }
1022         if (visibleItems.count()) {
1023             qreal startPos = originPosition();
1024             if (visibleIndex == 0) {
1025                 header->setPosition(colOffset, startPos + rowOffset);
1026             } else {
1027                 qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position();
1028                 qreal headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
1029                 if (tempPos <= startPos || headerPos > startPos + rowOffset)
1030                     header->setPosition(colOffset, startPos + rowOffset);
1031             }
1032         } else {
1033             header->setPosition(colOffset, 0);
1034         }
1035     }
1036 }
1037
1038 void QDeclarativeGridViewPrivate::fixupPosition()
1039 {
1040     moveReason = Other;
1041     if (flow == QDeclarativeGridView::LeftToRight)
1042         fixupY();
1043     else
1044         fixupX();
1045 }
1046
1047 void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
1048 {
1049     if ((flow == QDeclarativeGridView::TopToBottom && &data == &vData)
1050         || (flow == QDeclarativeGridView::LeftToRight && &data == &hData))
1051         return;
1052
1053     fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1054
1055     qreal highlightStart;
1056     qreal highlightEnd;
1057     qreal viewPos;
1058     if (isRightToLeftTopToBottom()) {
1059         // Handle Right-To-Left exceptions
1060         viewPos = -position()-size();
1061         highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
1062         highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd;
1063     } else {
1064         viewPos = position();
1065         highlightStart = highlightRangeStart;
1066         highlightEnd = highlightRangeEnd;
1067     }
1068
1069     bool strictHighlightRange = haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange;
1070
1071     if (snapMode != QDeclarativeGridView::NoSnap) {
1072         qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
1073         if (snapMode == QDeclarativeGridView::SnapOneRow && moveReason == Mouse) {
1074             // if we've been dragged < rowSize()/2 then bias towards the next row
1075             qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1076             qreal bias = 0;
1077             if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < rowSize()/2)
1078                 bias = rowSize()/2;
1079             else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -rowSize()/2)
1080                 bias = -rowSize()/2;
1081             if (isRightToLeftTopToBottom())
1082                 bias = -bias;
1083             tempPosition -= bias;
1084         }
1085         FxGridItem *topItem = snapItemAt(tempPosition+highlightStart);
1086         if (!topItem && strictHighlightRange && currentItem) {
1087             // StrictlyEnforceRange always keeps an item in range
1088             updateHighlight();
1089             topItem = currentItem;
1090         }
1091         FxGridItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
1092         if (!bottomItem && strictHighlightRange && currentItem) {
1093             // StrictlyEnforceRange always keeps an item in range
1094             updateHighlight();
1095             bottomItem = currentItem;
1096         }
1097         qreal pos;
1098         bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1099         if (topItem && (isInBounds || strictHighlightRange)) {
1100             if (topItem->index == 0 && header && tempPosition+highlightStart < header->rowPos()+headerSize()/2 && !strictHighlightRange) {
1101                 pos = isRightToLeftTopToBottom() ? - header->rowPos() + highlightStart - size() : header->rowPos() - highlightStart;
1102             } else {
1103                 if (isRightToLeftTopToBottom())
1104                     pos = qMax(qMin(-topItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
1105                 else
1106                     pos = qMax(qMin(topItem->rowPos() - highlightStart, -maxExtent), -minExtent);
1107             }
1108         } else if (bottomItem && isInBounds) {
1109             if (isRightToLeftTopToBottom())
1110                 pos = qMax(qMin(-bottomItem->rowPos() + highlightEnd - size(), -maxExtent), -minExtent);
1111             else
1112                 pos = qMax(qMin(bottomItem->rowPos() - highlightEnd, -maxExtent), -minExtent);
1113         } else {
1114             QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
1115             return;
1116         }
1117         qreal dist = qAbs(data.move + pos);
1118         if (dist > 0) {
1119             timeline.reset(data.move);
1120             if (fixupMode != Immediate) {
1121                 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1122                 data.fixingUp = true;
1123             } else {
1124                 timeline.set(data.move, -pos);
1125             }
1126             vTime = timeline.time();
1127         }
1128     } else if (haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) {
1129         if (currentItem) {
1130             updateHighlight();
1131             qreal pos = currentItem->rowPos();
1132             if (viewPos < pos + rowSize() - highlightEnd)
1133                 viewPos = pos + rowSize() - highlightEnd;
1134             if (viewPos > pos - highlightStart)
1135                 viewPos = pos - highlightStart;
1136             if (isRightToLeftTopToBottom())
1137                 viewPos = -viewPos-size();
1138             timeline.reset(data.move);
1139             if (viewPos != position()) {
1140                 if (fixupMode != Immediate) {
1141                     timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1142                     data.fixingUp = true;
1143                 } else {
1144                     timeline.set(data.move, -viewPos);
1145                 }
1146             }
1147             vTime = timeline.time();
1148         }
1149     } else {
1150         QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
1151     }
1152     data.inOvershoot = false;
1153     fixupMode = Normal;
1154 }
1155
1156 void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1157                                         QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
1158 {
1159     Q_Q(QDeclarativeGridView);
1160     data.fixingUp = false;
1161     moveReason = Mouse;
1162     if ((!haveHighlightRange || highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1163         && snapMode == QDeclarativeGridView::NoSnap) {
1164         QDeclarativeFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1165         return;
1166     }
1167     qreal maxDistance = 0;
1168     qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value();
1169     // -ve velocity means list is moving up/left
1170     if (velocity > 0) {
1171         if (data.move.value() < minExtent) {
1172             if (snapMode == QDeclarativeGridView::SnapOneRow) {
1173                 // if we've been dragged < averageSize/2 then bias towards the next item
1174                 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1175                 qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0;
1176                 if (isRightToLeftTopToBottom())
1177                     bias = -bias;
1178                 data.flickTarget = -snapPosAt(-dataValue - bias);
1179                 maxDistance = qAbs(data.flickTarget - data.move.value());
1180                 velocity = maxVelocity;
1181             } else {
1182                 maxDistance = qAbs(minExtent - data.move.value());
1183             }
1184         }
1185         if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1186             data.flickTarget = minExtent;
1187     } else {
1188         if (data.move.value() > maxExtent) {
1189             if (snapMode == QDeclarativeGridView::SnapOneRow) {
1190                 // if we've been dragged < averageSize/2 then bias towards the next item
1191                 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1192                 qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0;
1193                 if (isRightToLeftTopToBottom())
1194                     bias = -bias;
1195                 data.flickTarget = -snapPosAt(-dataValue + bias);
1196                 maxDistance = qAbs(data.flickTarget - data.move.value());
1197                 velocity = -maxVelocity;
1198             } else {
1199                 maxDistance = qAbs(maxExtent - data.move.value());
1200             }
1201         }
1202         if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1203             data.flickTarget = maxExtent;
1204     }
1205
1206     bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds;
1207
1208     if (maxDistance > 0 || overShoot) {
1209         // This mode requires the grid to stop exactly on a row boundary.
1210         qreal v = velocity;
1211         if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1212             if (v < 0)
1213                 v = -maxVelocity;
1214             else
1215                 v = maxVelocity;
1216         }
1217         qreal accel = deceleration;
1218         qreal v2 = v * v;
1219         qreal overshootDist = qreal(0.0);
1220         if ((maxDistance > qreal(0.0) && v2 / (2.0f * maxDistance) < accel) || snapMode == QDeclarativeGridView::SnapOneRow) {
1221             // + rowSize()/4 to encourage moving at least one item in the flick direction
1222             qreal dist = v2 / (accel * qreal(2.0)) + rowSize()/4;
1223             dist = qMin(dist, maxDistance);
1224             if (v > 0)
1225                 dist = -dist;
1226             if (snapMode != QDeclarativeGridView::SnapOneRow) {
1227                 qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
1228                 data.flickTarget = -snapPosAt(-dataValue + distTemp);
1229             }
1230             data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
1231             if (overShoot) {
1232                 if (data.flickTarget >= minExtent) {
1233                     overshootDist = overShootDistance(vSize);
1234                     data.flickTarget += overshootDist;
1235                 } else if (data.flickTarget <= maxExtent) {
1236                     overshootDist = overShootDistance(vSize);
1237                     data.flickTarget -= overshootDist;
1238                 }
1239             }
1240             qreal adjDist = -data.flickTarget + data.move.value();
1241             if (qAbs(adjDist) > qAbs(dist)) {
1242                 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1243                 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1244                 if (adjv2 > v2) {
1245                     v2 = adjv2;
1246                     v = qSqrt(v2);
1247                     if (dist > 0)
1248                         v = -v;
1249                 }
1250             }
1251             dist = adjDist;
1252             accel = v2 / (2.0f * qAbs(dist));
1253         } else {
1254             data.flickTarget = velocity > 0 ? minExtent : maxExtent;
1255             overshootDist = overShoot ? overShootDistance(vSize) : 0;
1256         }
1257         timeline.reset(data.move);
1258         timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1259         timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1260         if (!hData.flicking && q->xflick()) {
1261             hData.flicking = true;
1262             emit q->flickingChanged();
1263             emit q->flickingHorizontallyChanged();
1264             emit q->flickStarted();
1265         }
1266         if (!vData.flicking && q->yflick()) {
1267             vData.flicking = true;
1268             emit q->flickingChanged();
1269             emit q->flickingVerticallyChanged();
1270             emit q->flickStarted();
1271         }
1272     } else {
1273         timeline.reset(data.move);
1274         fixup(data, minExtent, maxExtent);
1275     }
1276 }
1277
1278
1279 //----------------------------------------------------------------------------
1280
1281 /*!
1282     \qmlclass GridView QDeclarativeGridView
1283     \since 4.7
1284     \ingroup qml-view-elements
1285
1286     \inherits Flickable
1287     \brief The GridView item provides a grid view of items provided by a model.
1288
1289     A GridView displays data from models created from built-in QML elements like ListModel
1290     and XmlListModel, or custom model classes defined in C++ that inherit from
1291     QAbstractListModel.
1292
1293     A GridView has a \l model, which defines the data to be displayed, and
1294     a \l delegate, which defines how the data should be displayed. Items in a 
1295     GridView are laid out horizontally or vertically. Grid views are inherently flickable
1296     as GridView inherits from \l Flickable.
1297
1298     \section1 Example Usage
1299
1300     The following example shows the definition of a simple list model defined
1301     in a file called \c ContactModel.qml:
1302
1303     \snippet doc/src/snippets/declarative/gridview/ContactModel.qml 0
1304
1305     \div {class="float-right"}
1306     \inlineimage gridview-simple.png
1307     \enddiv
1308
1309     This model can be referenced as \c ContactModel in other QML files. See \l{QML Modules}
1310     for more information about creating reusable components like this.
1311
1312     Another component can display this model data in a GridView, as in the following
1313     example, which creates a \c ContactModel component for its model, and a \l Column element
1314     (containing \l Image and \l Text elements) for its delegate.
1315
1316     \clearfloat
1317     \snippet doc/src/snippets/declarative/gridview/gridview.qml import
1318     \codeline
1319     \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs simple
1320
1321     \div {class="float-right"}
1322     \inlineimage gridview-highlight.png
1323     \enddiv
1324
1325     The view will create a new delegate for each item in the model. Note that the delegate
1326     is able to access the model's \c name and \c portrait data directly.
1327
1328     An improved grid view is shown below. The delegate is visually improved and is moved 
1329     into a separate \c contactDelegate component.
1330
1331     \clearfloat
1332     \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs advanced
1333
1334     The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
1335     and \c focus is set to \c true to enable keyboard navigation for the grid view.
1336     The grid view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
1337
1338     Delegates are instantiated as needed and may be destroyed at any time.
1339     State should \e never be stored in a delegate.
1340
1341     GridView attaches a number of properties to the root item of the delegate, for example
1342     \c {GridView.isCurrentItem}.  In the following example, the root delegate item can access
1343     this attached property directly as \c GridView.isCurrentItem, while the child
1344     \c contactInfo object must refer to this property as \c wrapper.GridView.isCurrentItem.
1345
1346     \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem
1347
1348     \note Views do not set the \l{Item::}{clip} property automatically.
1349     If the view is not clipped by another item or the screen, it will be necessary
1350     to set this property to true in order to clip the items that are partially or
1351     fully outside the view.
1352
1353     \sa {declarative/modelviews/gridview}{GridView example}
1354 */
1355 QDeclarativeGridView::QDeclarativeGridView(QDeclarativeItem *parent)
1356     : QDeclarativeFlickable(*(new QDeclarativeGridViewPrivate), parent)
1357 {
1358     Q_D(QDeclarativeGridView);
1359     d->init();
1360 }
1361
1362 QDeclarativeGridView::~QDeclarativeGridView()
1363 {
1364     Q_D(QDeclarativeGridView);
1365     d->clear();
1366     if (d->ownModel)
1367         delete d->model;
1368     delete d->header;
1369     delete d->footer;
1370 }
1371
1372 /*!
1373     \qmlattachedproperty bool GridView::isCurrentItem
1374     This attached property is true if this delegate is the current item; otherwise false.
1375
1376     It is attached to each instance of the delegate.
1377 */
1378
1379 /*!
1380     \qmlattachedproperty GridView GridView::view
1381     This attached property holds the view that manages this delegate instance.
1382
1383     It is attached to each instance of the delegate.
1384
1385     \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem
1386 */
1387
1388 /*!
1389     \qmlattachedproperty bool GridView::delayRemove
1390     This attached property holds whether the delegate may be destroyed.
1391
1392     It is attached to each instance of the delegate.
1393
1394     It is sometimes necessary to delay the destruction of an item
1395     until an animation completes.
1396
1397     The example below ensures that the animation completes before
1398     the item is removed from the grid.
1399
1400     \snippet doc/src/snippets/declarative/gridview/gridview.qml delayRemove
1401 */
1402
1403 /*!
1404     \qmlattachedsignal GridView::onAdd()
1405     This attached handler is called immediately after an item is added to the view.
1406 */
1407
1408 /*!
1409     \qmlattachedsignal GridView::onRemove()
1410     This attached handler is called immediately before an item is removed from the view.
1411 */
1412
1413
1414 /*!
1415   \qmlproperty model GridView::model
1416   This property holds the model providing data for the grid.
1417
1418     The model provides the set of data that is used to create the items
1419     in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
1420     or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
1421     used, it must be a subclass of \l QAbstractItemModel or a simple list.
1422
1423   \sa {qmlmodels}{Data Models}
1424 */
1425 QVariant QDeclarativeGridView::model() const
1426 {
1427     Q_D(const QDeclarativeGridView);
1428     return d->modelVariant;
1429 }
1430
1431 // For internal use
1432 int QDeclarativeGridView::modelCount() const
1433 {
1434     Q_D(const QDeclarativeGridView);
1435     return d->model->count();
1436 }
1437
1438 void QDeclarativeGridView::setModel(const QVariant &model)
1439 {
1440     Q_D(QDeclarativeGridView);
1441     if (d->modelVariant == model)
1442         return;
1443     if (d->model) {
1444         disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1445         disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1446         disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1447         disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1448         disconnect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
1449         disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
1450     }
1451     d->clear();
1452     d->modelVariant = model;
1453     QObject *object = qvariant_cast<QObject*>(model);
1454     QDeclarativeVisualModel *vim = 0;
1455     if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
1456         if (d->ownModel) {
1457             delete d->model;
1458             d->ownModel = false;
1459         }
1460         d->model = vim;
1461     } else {
1462         if (!d->ownModel) {
1463             d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
1464             d->ownModel = true;
1465         }
1466         if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
1467             dataModel->setModel(model);
1468     }
1469     if (d->model) {
1470         d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore | QDeclarativeGridViewPrivate::BufferAfter;
1471         if (isComponentComplete()) {
1472             refill();
1473             if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
1474                 setCurrentIndex(0);
1475             } else {
1476                 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1477                 d->updateCurrent(d->currentIndex);
1478                 if (d->highlight && d->currentItem) {
1479                     if (d->autoHighlight)
1480                         d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1481                     d->updateTrackedItem();
1482                 }
1483                 d->moveReason = QDeclarativeGridViewPrivate::Other;
1484             }
1485         }
1486         connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1487         connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1488         connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1489         connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1490         connect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
1491         connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
1492         emit countChanged();
1493     }
1494     emit modelChanged();
1495 }
1496
1497 /*!
1498     \qmlproperty Component GridView::delegate
1499
1500     The delegate provides a template defining each item instantiated by the view.
1501     The index is exposed as an accessible \c index property.  Properties of the
1502     model are also available depending upon the type of \l {qmlmodels}{Data Model}.
1503
1504     The number of elements in the delegate has a direct effect on the
1505     flicking performance of the view.  If at all possible, place functionality
1506     that is not needed for the normal display of the delegate in a \l Loader which
1507     can load additional elements when needed.
1508
1509     The GridView will layout the items based on the size of the root item
1510     in the delegate.
1511
1512     \note Delegates are instantiated as needed and may be destroyed at any time.
1513     State should \e never be stored in a delegate.
1514 */
1515 QDeclarativeComponent *QDeclarativeGridView::delegate() const
1516 {
1517     Q_D(const QDeclarativeGridView);
1518     if (d->model) {
1519         if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
1520             return dataModel->delegate();
1521     }
1522
1523     return 0;
1524 }
1525
1526 void QDeclarativeGridView::setDelegate(QDeclarativeComponent *delegate)
1527 {
1528     Q_D(QDeclarativeGridView);
1529     if (delegate == this->delegate())
1530         return;
1531
1532     if (!d->ownModel) {
1533         d->model = new QDeclarativeVisualDataModel(qmlContext(this));
1534         d->ownModel = true;
1535     }
1536     if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model)) {
1537         int oldCount = dataModel->count();
1538         dataModel->setDelegate(delegate);
1539         if (isComponentComplete()) {
1540             for (int i = 0; i < d->visibleItems.count(); ++i)
1541                 d->releaseItem(d->visibleItems.at(i));
1542             d->visibleItems.clear();
1543             d->releaseItem(d->currentItem);
1544             d->currentItem = 0;
1545             refill();
1546             d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1547             d->updateCurrent(d->currentIndex);
1548             if (d->highlight && d->currentItem) {
1549                 if (d->autoHighlight)
1550                     d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1551                 d->updateTrackedItem();
1552             }
1553             d->moveReason = QDeclarativeGridViewPrivate::Other;
1554         }
1555         if (oldCount != dataModel->count())
1556             emit countChanged();
1557         emit delegateChanged();
1558     }
1559 }
1560
1561 /*!
1562   \qmlproperty int GridView::currentIndex
1563   \qmlproperty Item GridView::currentItem
1564
1565     The \c currentIndex property holds the index of the current item, and
1566     \c currentItem holds the current item.  Setting the currentIndex to -1
1567     will clear the highlight and set currentItem to null.
1568
1569     If highlightFollowsCurrentItem is \c true, setting either of these 
1570     properties will smoothly scroll the GridView so that the current 
1571     item becomes visible.
1572     
1573     Note that the position of the current item
1574     may only be approximate until it becomes visible in the view.
1575 */
1576 int QDeclarativeGridView::currentIndex() const
1577 {
1578     Q_D(const QDeclarativeGridView);
1579     return d->currentIndex;
1580 }
1581
1582 void QDeclarativeGridView::setCurrentIndex(int index)
1583 {
1584     Q_D(QDeclarativeGridView);
1585     if (d->requestedIndex >= 0) // currently creating item
1586         return;
1587     d->currentIndexCleared = (index == -1);
1588     if (index == d->currentIndex)
1589         return;
1590     if (isComponentComplete() && d->isValid()) {
1591         if (d->layoutScheduled)
1592             d->layout();
1593         d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1594         d->updateCurrent(index);
1595     } else {
1596         d->currentIndex = index;
1597         emit currentIndexChanged();
1598     }
1599 }
1600
1601 QDeclarativeItem *QDeclarativeGridView::currentItem()
1602 {
1603     Q_D(QDeclarativeGridView);
1604     if (!d->currentItem)
1605         return 0;
1606     return d->currentItem->item;
1607 }
1608
1609 /*!
1610   \qmlproperty Item GridView::highlightItem
1611
1612   This holds the highlight item created from the \l highlight component.
1613
1614   The highlightItem is managed by the view unless
1615   \l highlightFollowsCurrentItem is set to false.
1616
1617   \sa highlight, highlightFollowsCurrentItem
1618 */
1619 QDeclarativeItem *QDeclarativeGridView::highlightItem()
1620 {
1621     Q_D(QDeclarativeGridView);
1622     if (!d->highlight)
1623         return 0;
1624     return d->highlight->item;
1625 }
1626
1627 /*!
1628   \qmlproperty int GridView::count
1629   This property holds the number of items in the view.
1630 */
1631 int QDeclarativeGridView::count() const
1632 {
1633     Q_D(const QDeclarativeGridView);
1634     if (d->model)
1635         return d->model->count();
1636     return 0;
1637 }
1638
1639 /*!
1640   \qmlproperty Component GridView::highlight
1641   This property holds the component to use as the highlight.
1642
1643   An instance of the highlight component is created for each view.
1644   The geometry of the resulting component instance will be managed by the view
1645   so as to stay with the current item, unless the highlightFollowsCurrentItem property is false.
1646
1647   \sa highlightItem, highlightFollowsCurrentItem
1648 */
1649 QDeclarativeComponent *QDeclarativeGridView::highlight() const
1650 {
1651     Q_D(const QDeclarativeGridView);
1652     return d->highlightComponent;
1653 }
1654
1655 void QDeclarativeGridView::setHighlight(QDeclarativeComponent *highlight)
1656 {
1657     Q_D(QDeclarativeGridView);
1658     if (highlight != d->highlightComponent) {
1659         d->highlightComponent = highlight;
1660         d->updateCurrent(d->currentIndex);
1661         emit highlightChanged();
1662     }
1663 }
1664
1665 /*!
1666   \qmlproperty bool GridView::highlightFollowsCurrentItem
1667   This property sets whether the highlight is managed by the view.
1668
1669     If this property is true (the default value), the highlight is moved smoothly
1670     to follow the current item.  Otherwise, the
1671     highlight is not moved by the view, and any movement must be implemented
1672     by the highlight.  
1673     
1674     Here is a highlight with its motion defined by a \l {SpringAnimation} item:
1675
1676     \snippet doc/src/snippets/declarative/gridview/gridview.qml highlightFollowsCurrentItem
1677 */
1678 bool QDeclarativeGridView::highlightFollowsCurrentItem() const
1679 {
1680     Q_D(const QDeclarativeGridView);
1681     return d->autoHighlight;
1682 }
1683
1684 void QDeclarativeGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
1685 {
1686     Q_D(QDeclarativeGridView);
1687     if (d->autoHighlight != autoHighlight) {
1688         d->autoHighlight = autoHighlight;
1689         if (autoHighlight) {
1690             d->updateHighlight();
1691         } else if (d->highlightXAnimator) {
1692             d->highlightXAnimator->stop();
1693             d->highlightYAnimator->stop();
1694         }
1695     }
1696 }
1697
1698 /*!
1699     \qmlproperty int GridView::highlightMoveDuration
1700     This property holds the move animation duration of the highlight delegate.
1701
1702     highlightFollowsCurrentItem must be true for this property
1703     to have effect.
1704
1705     The default value for the duration is 150ms.
1706
1707     \sa highlightFollowsCurrentItem
1708 */
1709 int QDeclarativeGridView::highlightMoveDuration() const
1710 {
1711     Q_D(const QDeclarativeGridView);
1712     return d->highlightMoveDuration;
1713 }
1714
1715 void QDeclarativeGridView::setHighlightMoveDuration(int duration)
1716 {
1717     Q_D(QDeclarativeGridView);
1718     if (d->highlightMoveDuration != duration) {
1719         d->highlightMoveDuration = duration;
1720         if (d->highlightYAnimator) {
1721             d->highlightXAnimator->userDuration = d->highlightMoveDuration;
1722             d->highlightYAnimator->userDuration = d->highlightMoveDuration;
1723         }
1724         emit highlightMoveDurationChanged();
1725     }
1726 }
1727
1728
1729 /*!
1730     \qmlproperty real GridView::preferredHighlightBegin
1731     \qmlproperty real GridView::preferredHighlightEnd
1732     \qmlproperty enumeration GridView::highlightRangeMode
1733
1734     These properties define the preferred range of the highlight (for the current item)
1735     within the view. The \c preferredHighlightBegin value must be less than the
1736     \c preferredHighlightEnd value. 
1737
1738     These properties affect the position of the current item when the view is scrolled.
1739     For example, if the currently selected item should stay in the middle of the
1740     view when it is scrolled, set the \c preferredHighlightBegin and 
1741     \c preferredHighlightEnd values to the top and bottom coordinates of where the middle 
1742     item would be. If the \c currentItem is changed programmatically, the view will
1743     automatically scroll so that the current item is in the middle of the view.
1744     Furthermore, the behavior of the current item index will occur whether or not a
1745     highlight exists.
1746
1747     Valid values for \c highlightRangeMode are:
1748
1749     \list
1750     \o GridView.ApplyRange - the view attempts to maintain the highlight within the range.
1751        However, the highlight can move outside of the range at the ends of the view or due
1752        to mouse interaction.
1753     \o GridView.StrictlyEnforceRange - the highlight never moves outside of the range.
1754        The current item changes if a keyboard or mouse action would cause the highlight to move
1755        outside of the range.
1756     \o GridView.NoHighlightRange - this is the default value.
1757     \endlist
1758 */
1759 qreal QDeclarativeGridView::preferredHighlightBegin() const
1760 {
1761     Q_D(const QDeclarativeGridView);
1762     return d->highlightRangeStart;
1763 }
1764
1765 void QDeclarativeGridView::setPreferredHighlightBegin(qreal start)
1766 {
1767     Q_D(QDeclarativeGridView);
1768     d->highlightRangeStartValid = true;
1769     if (d->highlightRangeStart == start)
1770         return;
1771     d->highlightRangeStart = start;
1772     d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1773     emit preferredHighlightBeginChanged();
1774 }
1775
1776 void QDeclarativeGridView::resetPreferredHighlightBegin()
1777 {
1778     Q_D(QDeclarativeGridView);
1779     d->highlightRangeStartValid = false;
1780     if (d->highlightRangeStart == 0)
1781         return;
1782     d->highlightRangeStart = 0;
1783     emit preferredHighlightBeginChanged();
1784 }
1785
1786 qreal QDeclarativeGridView::preferredHighlightEnd() const
1787 {
1788     Q_D(const QDeclarativeGridView);
1789     return d->highlightRangeEnd;
1790 }
1791
1792 void QDeclarativeGridView::setPreferredHighlightEnd(qreal end)
1793 {
1794     Q_D(QDeclarativeGridView);
1795     d->highlightRangeEndValid = true;
1796     if (d->highlightRangeEnd == end)
1797         return;
1798     d->highlightRangeEnd = end;
1799     d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1800     emit preferredHighlightEndChanged();
1801 }
1802
1803 void QDeclarativeGridView::resetPreferredHighlightEnd()
1804 {
1805     Q_D(QDeclarativeGridView);
1806     d->highlightRangeEndValid = false;
1807     if (d->highlightRangeEnd == 0)
1808         return;
1809     d->highlightRangeEnd = 0;
1810     emit preferredHighlightEndChanged();
1811 }
1812
1813 QDeclarativeGridView::HighlightRangeMode QDeclarativeGridView::highlightRangeMode() const
1814 {
1815     Q_D(const QDeclarativeGridView);
1816     return d->highlightRange;
1817 }
1818
1819 void QDeclarativeGridView::setHighlightRangeMode(HighlightRangeMode mode)
1820 {
1821     Q_D(QDeclarativeGridView);
1822     if (d->highlightRange == mode)
1823         return;
1824     d->highlightRange = mode;
1825     d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1826     emit highlightRangeModeChanged();
1827 }
1828
1829 /*!
1830   \qmlproperty enumeration GridView::layoutDirection
1831   This property holds the layout direction of the grid.
1832
1833     Possible values:
1834
1835   \list
1836   \o Qt.LeftToRight (default) - Items will be laid out starting in the top, left corner. The flow is
1837   dependent on the \l GridView::flow property.
1838   \o Qt.RightToLeft - Items will be laid out starting in the top, right corner. The flow is dependent
1839   on the \l GridView::flow property.
1840   \endlist
1841
1842   When using the attached property \l {LayoutMirroring::enabled} for locale layouts,
1843   the layout direction of the grid view will be mirrored. However, the actual property
1844   \c layoutDirection will remain unchanged. You can use the property
1845   \l {LayoutMirroring::enabled} to determine whether the direction has been mirrored.
1846
1847   \sa {LayoutMirroring}{LayoutMirroring}
1848 */
1849
1850 Qt::LayoutDirection QDeclarativeGridView::layoutDirection() const
1851 {
1852     Q_D(const QDeclarativeGridView);
1853     return d->layoutDirection;
1854 }
1855
1856 void QDeclarativeGridView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1857 {
1858     Q_D(QDeclarativeGridView);
1859     if (d->layoutDirection != layoutDirection) {
1860         d->layoutDirection = layoutDirection;
1861         d->regenerate();
1862         emit layoutDirectionChanged();
1863     }
1864 }
1865
1866 Qt::LayoutDirection QDeclarativeGridView::effectiveLayoutDirection() const
1867 {
1868     Q_D(const QDeclarativeGridView);
1869     if (d->effectiveLayoutMirror)
1870         return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
1871     else
1872         return d->layoutDirection;
1873 }
1874
1875 /*!
1876   \qmlproperty enumeration GridView::flow
1877   This property holds the flow of the grid.
1878
1879     Possible values:
1880
1881     \list
1882     \o GridView.LeftToRight (default) - Items are laid out from left to right, and the view scrolls vertically
1883     \o GridView.TopToBottom - Items are laid out from top to bottom, and the view scrolls horizontally
1884     \endlist
1885 */
1886 QDeclarativeGridView::Flow QDeclarativeGridView::flow() const
1887 {
1888     Q_D(const QDeclarativeGridView);
1889     return d->flow;
1890 }
1891
1892 void QDeclarativeGridView::setFlow(Flow flow)
1893 {
1894     Q_D(QDeclarativeGridView);
1895     if (d->flow != flow) {
1896         d->flow = flow;
1897         if (d->flow == LeftToRight) {
1898             setContentWidth(-1);
1899             setFlickableDirection(QDeclarativeFlickable::VerticalFlick);
1900         } else {
1901             setContentHeight(-1);
1902             setFlickableDirection(QDeclarativeFlickable::HorizontalFlick);
1903         }
1904         setContentX(0);
1905         setContentY(0);
1906         d->regenerate();
1907         emit flowChanged();
1908     }
1909 }
1910
1911 /*!
1912   \qmlproperty bool GridView::keyNavigationWraps
1913   This property holds whether the grid wraps key navigation
1914
1915     If this is true, key navigation that would move the current item selection
1916     past one end of the view instead wraps around and moves the selection to
1917     the other end of the view.
1918
1919     By default, key navigation is not wrapped.
1920 */
1921 bool QDeclarativeGridView::isWrapEnabled() const
1922 {
1923     Q_D(const QDeclarativeGridView);
1924     return d->wrap;
1925 }
1926
1927 void QDeclarativeGridView::setWrapEnabled(bool wrap)
1928 {
1929     Q_D(QDeclarativeGridView);
1930     if (d->wrap == wrap)
1931         return;
1932     d->wrap = wrap;
1933     emit keyNavigationWrapsChanged();
1934 }
1935
1936 /*!
1937     \qmlproperty int GridView::cacheBuffer
1938     This property determines whether delegates are retained outside the
1939     visible area of the view.
1940
1941     If non-zero the view will keep as many delegates
1942     instantiated as will fit within the buffer specified.  For example,
1943     if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
1944     set to 40, then up to 2 delegates above and 2 delegates below the visible
1945     area may be retained.
1946
1947     Note that cacheBuffer is not a pixel buffer - it only maintains additional
1948     instantiated delegates.
1949
1950     Setting this value can make scrolling the list smoother at the expense
1951     of additional memory usage.  It is not a substitute for creating efficient
1952     delegates; the fewer elements in a delegate, the faster a view may be
1953     scrolled.
1954 */
1955 int QDeclarativeGridView::cacheBuffer() const
1956 {
1957     Q_D(const QDeclarativeGridView);
1958     return d->buffer;
1959 }
1960
1961 void QDeclarativeGridView::setCacheBuffer(int buffer)
1962 {
1963     Q_D(QDeclarativeGridView);
1964     if (d->buffer != buffer) {
1965         d->buffer = buffer;
1966         if (isComponentComplete())
1967             refill();
1968         emit cacheBufferChanged();
1969     }
1970 }
1971
1972 /*!
1973   \qmlproperty int GridView::cellWidth
1974   \qmlproperty int GridView::cellHeight
1975
1976   These properties holds the width and height of each cell in the grid.
1977
1978   The default cell size is 100x100.
1979 */
1980 int QDeclarativeGridView::cellWidth() const
1981 {
1982     Q_D(const QDeclarativeGridView);
1983     return d->cellWidth;
1984 }
1985
1986 void QDeclarativeGridView::setCellWidth(int cellWidth)
1987 {
1988     Q_D(QDeclarativeGridView);
1989     if (cellWidth != d->cellWidth && cellWidth > 0) {
1990         d->cellWidth = qMax(1, cellWidth);
1991         d->updateGrid();
1992         emit cellWidthChanged();
1993         d->layout();
1994     }
1995 }
1996
1997 int QDeclarativeGridView::cellHeight() const
1998 {
1999     Q_D(const QDeclarativeGridView);
2000     return d->cellHeight;
2001 }
2002
2003 void QDeclarativeGridView::setCellHeight(int cellHeight)
2004 {
2005     Q_D(QDeclarativeGridView);
2006     if (cellHeight != d->cellHeight && cellHeight > 0) {
2007         d->cellHeight = qMax(1, cellHeight);
2008         d->updateGrid();
2009         emit cellHeightChanged();
2010         d->layout();
2011     }
2012 }
2013 /*!
2014     \qmlproperty enumeration GridView::snapMode
2015
2016     This property determines how the view scrolling will settle following a drag or flick.
2017     The possible values are:
2018
2019     \list
2020     \o GridView.NoSnap (default) - the view stops anywhere within the visible area.
2021     \o GridView.SnapToRow - the view settles with a row (or column for \c GridView.TopToBottom flow)
2022     aligned with the start of the view.
2023     \o GridView.SnapOneRow - the view will settle no more than one row (or column for \c GridView.TopToBottom flow)
2024     away from the first visible row at the time the mouse button is released.
2025     This mode is particularly useful for moving one page at a time.
2026     \endlist
2027
2028 */
2029 QDeclarativeGridView::SnapMode QDeclarativeGridView::snapMode() const
2030 {
2031     Q_D(const QDeclarativeGridView);
2032     return d->snapMode;
2033 }
2034
2035 void QDeclarativeGridView::setSnapMode(SnapMode mode)
2036 {
2037     Q_D(QDeclarativeGridView);
2038     if (d->snapMode != mode) {
2039         d->snapMode = mode;
2040         emit snapModeChanged();
2041     }
2042 }
2043
2044 /*!
2045     \qmlproperty Component GridView::footer
2046     This property holds the component to use as the footer.
2047
2048     An instance of the footer component is created for each view.  The
2049     footer is positioned at the end of the view, after any items.
2050
2051     \sa header
2052 */
2053 QDeclarativeComponent *QDeclarativeGridView::footer() const
2054 {
2055     Q_D(const QDeclarativeGridView);
2056     return d->footerComponent;
2057 }
2058
2059 void QDeclarativeGridView::setFooter(QDeclarativeComponent *footer)
2060 {
2061     Q_D(QDeclarativeGridView);
2062     if (d->footerComponent != footer) {
2063         if (d->footer) {
2064             if (scene())
2065                 scene()->removeItem(d->footer->item);
2066             d->footer->item->deleteLater();
2067             delete d->footer;
2068             d->footer = 0;
2069         }
2070         d->footerComponent = footer;
2071         if (isComponentComplete()) {
2072             d->updateFooter();
2073             d->updateGrid();
2074             d->fixupPosition();
2075         }
2076         emit footerChanged();
2077     }
2078 }
2079
2080 /*!
2081     \qmlproperty Component GridView::header
2082     This property holds the component to use as the header.
2083
2084     An instance of the header component is created for each view.  The
2085     header is positioned at the beginning of the view, before any items.
2086
2087     \sa footer
2088 */
2089 QDeclarativeComponent *QDeclarativeGridView::header() const
2090 {
2091     Q_D(const QDeclarativeGridView);
2092     return d->headerComponent;
2093 }
2094
2095 void QDeclarativeGridView::setHeader(QDeclarativeComponent *header)
2096 {
2097     Q_D(QDeclarativeGridView);
2098     if (d->headerComponent != header) {
2099         if (d->header) {
2100             if (scene())
2101                 scene()->removeItem(d->header->item);
2102             d->header->item->deleteLater();
2103             delete d->header;
2104             d->header = 0;
2105         }
2106         d->headerComponent = header;
2107         if (isComponentComplete()) {
2108             d->updateHeader();
2109             d->updateFooter();
2110             d->updateGrid();
2111             d->fixupPosition();
2112         }
2113         emit headerChanged();
2114     }
2115 }
2116
2117 void QDeclarativeGridView::setContentX(qreal pos)
2118 {
2119     Q_D(QDeclarativeGridView);
2120     // Positioning the view manually should override any current movement state
2121     d->moveReason = QDeclarativeGridViewPrivate::Other;
2122     QDeclarativeFlickable::setContentX(pos);
2123 }
2124
2125 void QDeclarativeGridView::setContentY(qreal pos)
2126 {
2127     Q_D(QDeclarativeGridView);
2128     // Positioning the view manually should override any current movement state
2129     d->moveReason = QDeclarativeGridViewPrivate::Other;
2130     QDeclarativeFlickable::setContentY(pos);
2131 }
2132
2133 bool QDeclarativeGridView::event(QEvent *event)
2134 {
2135     Q_D(QDeclarativeGridView);
2136     if (event->type() == QEvent::User) {
2137         if (d->layoutScheduled)
2138             d->layout();
2139         return true;
2140     }
2141
2142     return QDeclarativeFlickable::event(event);
2143 }
2144
2145 void QDeclarativeGridView::viewportMoved()
2146 {
2147     Q_D(QDeclarativeGridView);
2148     QDeclarativeFlickable::viewportMoved();
2149     if (!d->itemCount)
2150         return;
2151     d->lazyRelease = true;
2152     if (d->hData.flicking || d->vData.flicking) {
2153         if (yflick()) {
2154             if (d->vData.velocity > 0)
2155                 d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore;
2156             else if (d->vData.velocity < 0)
2157                 d->bufferMode = QDeclarativeGridViewPrivate::BufferAfter;
2158         }
2159
2160         if (xflick()) {
2161             if (d->hData.velocity > 0)
2162                 d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore;
2163             else if (d->hData.velocity < 0)
2164                 d->bufferMode = QDeclarativeGridViewPrivate::BufferAfter;
2165         }
2166     }
2167     refill();
2168     if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2169         d->moveReason = QDeclarativeGridViewPrivate::Mouse;
2170     if (d->moveReason != QDeclarativeGridViewPrivate::SetIndex) {
2171         if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2172             // reposition highlight
2173             qreal pos = d->highlight->rowPos();
2174             qreal viewPos;
2175             qreal highlightStart;
2176             qreal highlightEnd;
2177             if (d->isRightToLeftTopToBottom()) {
2178                 highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
2179                 highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
2180                 viewPos = -d->position()-d->size();
2181             } else {
2182                 highlightStart = d->highlightRangeStart;
2183                 highlightEnd = d->highlightRangeEnd;
2184                 viewPos = d->position();
2185             }
2186             if (pos > viewPos + highlightEnd - d->rowSize())
2187                 pos = viewPos + highlightEnd - d->rowSize();
2188             if (pos < viewPos + highlightStart)
2189                 pos = viewPos + highlightStart;
2190
2191             d->highlight->setPosition(d->highlight->colPos(), qRound(pos));
2192
2193             // update current index
2194             int idx = d->snapIndex();
2195             if (idx >= 0 && idx != d->currentIndex) {
2196                 d->updateCurrent(idx);
2197                 if (d->currentItem && d->currentItem->colPos() != d->highlight->colPos() && d->autoHighlight) {
2198                     if (d->flow == LeftToRight)
2199                         d->highlightXAnimator->to = d->currentItem->item->x();
2200                     else
2201                         d->highlightYAnimator->to = d->currentItem->item->y();
2202                 }
2203             }
2204         }
2205     }
2206 }
2207
2208 qreal QDeclarativeGridView::minYExtent() const
2209 {
2210     Q_D(const QDeclarativeGridView);
2211     if (d->flow == QDeclarativeGridView::TopToBottom)
2212         return QDeclarativeFlickable::minYExtent();
2213     qreal extent = -d->startPosition();
2214     if (d->header && d->visibleItems.count())
2215         extent += d->header->item->height();
2216     if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2217         extent += d->highlightRangeStart;
2218         extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd));
2219     }
2220     return extent;
2221 }
2222
2223 qreal QDeclarativeGridView::maxYExtent() const
2224 {
2225     Q_D(const QDeclarativeGridView);
2226     if (d->flow == QDeclarativeGridView::TopToBottom)
2227         return QDeclarativeFlickable::maxYExtent();
2228     qreal extent;
2229     if (!d->model || !d->model->count()) {
2230         extent = 0;
2231     } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2232         extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart);
2233         if (d->highlightRangeEnd != d->highlightRangeStart)
2234             extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1));
2235     } else {
2236         extent = -(d->endPosition() - height());
2237     }
2238     if (d->footer)
2239         extent -= d->footer->item->height();
2240     const qreal minY = minYExtent();
2241     if (extent > minY)
2242         extent = minY;
2243     return extent;
2244 }
2245
2246 qreal QDeclarativeGridView::minXExtent() const
2247 {
2248     Q_D(const QDeclarativeGridView);
2249     if (d->flow == QDeclarativeGridView::LeftToRight)
2250         return QDeclarativeFlickable::minXExtent();
2251     qreal extent = -d->startPosition();
2252     qreal highlightStart;
2253     qreal highlightEnd;
2254     qreal endPositionFirstItem = 0;
2255     if (d->isRightToLeftTopToBottom()) {
2256         if (d->model && d->model->count())
2257             endPositionFirstItem = d->rowPosAt(d->model->count()-1);
2258         highlightStart = d->highlightRangeStartValid
2259                 ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
2260                 : d->size() - (d->lastPosition()-endPositionFirstItem);
2261         highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
2262         if (d->footer && d->visibleItems.count())
2263             extent += d->footer->item->width();
2264     } else {
2265         endPositionFirstItem = d->rowPosAt(0)+d->rowSize();
2266         highlightStart = d->highlightRangeStart;
2267         highlightEnd = d->highlightRangeEnd;
2268         if (d->header && d->visibleItems.count())
2269             extent += d->header->item->width();
2270     }
2271     if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2272         extent += d->isRightToLeftTopToBottom() ? -highlightStart : highlightStart;
2273         extent = qMax(extent, -(endPositionFirstItem - highlightEnd));
2274     }
2275     return extent;
2276 }
2277
2278 qreal QDeclarativeGridView::maxXExtent() const
2279 {
2280     Q_D(const QDeclarativeGridView);
2281     if (d->flow == QDeclarativeGridView::LeftToRight)
2282         return QDeclarativeFlickable::maxXExtent();
2283     qreal extent;
2284     qreal highlightStart;
2285     qreal highlightEnd;
2286     qreal lastItemPosition = 0;
2287     if (d->isRightToLeftTopToBottom()){
2288         highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
2289         highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
2290         lastItemPosition = d->endPosition();
2291     } else {
2292         highlightStart = d->highlightRangeStart;
2293         highlightEnd = d->highlightRangeEnd;
2294         lastItemPosition = 0;
2295         if (d->model && d->model->count())
2296             lastItemPosition = d->rowPosAt(d->model->count()-1);
2297     }
2298     if (!d->model || !d->model->count()) {
2299         extent = 0;
2300     } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2301         extent = -(lastItemPosition - highlightStart);
2302         if (highlightEnd != highlightStart)
2303             extent = d->isRightToLeftTopToBottom()
2304                     ? qMax(extent, -(d->endPosition() - highlightEnd + 1))
2305                     : qMin(extent, -(d->endPosition() - highlightEnd + 1));
2306     } else {
2307         extent = -(d->endPosition() - width());
2308     }
2309     if (d->isRightToLeftTopToBottom()) {
2310         if (d->header)
2311             extent -= d->header->item->width();
2312     } else {
2313         if (d->footer)
2314             extent -= d->footer->item->width();
2315     }
2316
2317     const qreal minX = minXExtent();
2318     if (extent > minX)
2319         extent = minX;
2320     return extent;
2321 }
2322
2323 void QDeclarativeGridView::keyPressEvent(QKeyEvent *event)
2324 {
2325     Q_D(QDeclarativeGridView);
2326     keyPressPreHandler(event);
2327     if (event->isAccepted())
2328         return;
2329     if (d->model && d->model->count() && d->interactive) {
2330         d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
2331         int oldCurrent = currentIndex();
2332         switch (event->key()) {
2333         case Qt::Key_Up:
2334             moveCurrentIndexUp();
2335             break;
2336         case Qt::Key_Down:
2337             moveCurrentIndexDown();
2338             break;
2339         case Qt::Key_Left:
2340             moveCurrentIndexLeft();
2341             break;
2342         case Qt::Key_Right:
2343             moveCurrentIndexRight();
2344             break;
2345         default:
2346             break;
2347         }
2348         if (oldCurrent != currentIndex()) {
2349             event->accept();
2350             return;
2351         }
2352     }
2353     d->moveReason = QDeclarativeGridViewPrivate::Other;
2354     event->ignore();
2355     QDeclarativeFlickable::keyPressEvent(event);
2356 }
2357
2358 /*!
2359     \qmlmethod GridView::moveCurrentIndexUp()
2360
2361     Move the currentIndex up one item in the view.
2362     The current index will wrap if keyNavigationWraps is true and it
2363     is currently at the end. This method has no effect if the \l count is zero.
2364
2365     \bold Note: methods should only be called after the Component has completed.
2366 */
2367 void QDeclarativeGridView::moveCurrentIndexUp()
2368 {
2369     Q_D(QDeclarativeGridView);
2370     const int count = d->model ? d->model->count() : 0;
2371     if (!count)
2372         return;
2373     if (d->flow == QDeclarativeGridView::LeftToRight) {
2374         if (currentIndex() >= d->columns || d->wrap) {
2375             int index = currentIndex() - d->columns;
2376             setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2377         }
2378     } else {
2379         if (currentIndex() > 0 || d->wrap) {
2380             int index = currentIndex() - 1;
2381             setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2382         }
2383     }
2384 }
2385
2386 /*!
2387     \qmlmethod GridView::moveCurrentIndexDown()
2388
2389     Move the currentIndex down one item in the view.
2390     The current index will wrap if keyNavigationWraps is true and it
2391     is currently at the end. This method has no effect if the \l count is zero.
2392
2393     \bold Note: methods should only be called after the Component has completed.
2394 */
2395 void QDeclarativeGridView::moveCurrentIndexDown()
2396 {
2397     Q_D(QDeclarativeGridView);
2398     const int count = d->model ? d->model->count() : 0;
2399     if (!count)
2400         return;
2401     if (d->flow == QDeclarativeGridView::LeftToRight) {
2402         if (currentIndex() < count - d->columns || d->wrap) {
2403             int index = currentIndex()+d->columns;
2404             setCurrentIndex((index >= 0 && index < count) ? index : 0);
2405         }
2406     } else {
2407         if (currentIndex() < count - 1 || d->wrap) {
2408             int index = currentIndex() + 1;
2409             setCurrentIndex((index >= 0 && index < count) ? index : 0);
2410         }
2411     }
2412 }
2413
2414 /*!
2415     \qmlmethod GridView::moveCurrentIndexLeft()
2416
2417     Move the currentIndex left one item in the view.
2418     The current index will wrap if keyNavigationWraps is true and it
2419     is currently at the end. This method has no effect if the \l count is zero.
2420
2421     \bold Note: methods should only be called after the Component has completed.
2422 */
2423 void QDeclarativeGridView::moveCurrentIndexLeft()
2424 {
2425     Q_D(QDeclarativeGridView);
2426     const int count = d->model ? d->model->count() : 0;
2427     if (!count)
2428         return;
2429
2430     if (effectiveLayoutDirection() == Qt::LeftToRight) {
2431         if (d->flow == QDeclarativeGridView::LeftToRight) {
2432             if (currentIndex() > 0 || d->wrap) {
2433                 int index = currentIndex() - 1;
2434                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2435             }
2436         } else {
2437             if (currentIndex() >= d->columns || d->wrap) {
2438                 int index = currentIndex() - d->columns;
2439                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2440             }
2441         }
2442     } else {
2443         if (d->flow == QDeclarativeGridView::LeftToRight) {
2444             if (currentIndex() < count - 1 || d->wrap) {
2445                 int index = currentIndex() + 1;
2446                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2447             }
2448         } else {
2449             if (currentIndex() < count - d->columns || d->wrap) {
2450                 int index = currentIndex() + d->columns;
2451                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2452             }
2453         }
2454     }
2455 }
2456
2457 /*!
2458     \qmlmethod GridView::moveCurrentIndexRight()
2459
2460     Move the currentIndex right one item in the view.
2461     The current index will wrap if keyNavigationWraps is true and it
2462     is currently at the end. This method has no effect if the \l count is zero.
2463
2464     \bold Note: methods should only be called after the Component has completed.
2465 */
2466 void QDeclarativeGridView::moveCurrentIndexRight()
2467 {
2468     Q_D(QDeclarativeGridView);
2469     const int count = d->model ? d->model->count() : 0;
2470     if (!count)
2471         return;
2472
2473     if (effectiveLayoutDirection() == Qt::LeftToRight) {
2474         if (d->flow == QDeclarativeGridView::LeftToRight) {
2475             if (currentIndex() < count - 1 || d->wrap) {
2476                 int index = currentIndex() + 1;
2477                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2478             }
2479         } else {
2480             if (currentIndex() < count - d->columns || d->wrap) {
2481                 int index = currentIndex()+d->columns;
2482                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2483             }
2484         }
2485     } else {
2486         if (d->flow == QDeclarativeGridView::LeftToRight) {
2487             if (currentIndex() > 0 || d->wrap) {
2488                 int index = currentIndex() - 1;
2489                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2490             }
2491         } else {
2492             if (currentIndex() >= d->columns || d->wrap) {
2493                 int index = currentIndex() - d->columns;
2494                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2495             }
2496         }
2497     }
2498 }
2499
2500 void QDeclarativeGridViewPrivate::positionViewAtIndex(int index, int mode)
2501 {
2502     Q_Q(QDeclarativeGridView);
2503     if (!isValid())
2504         return;
2505     if (mode < QDeclarativeGridView::Beginning || mode > QDeclarativeGridView::Contain)
2506         return;
2507
2508     int idx = qMax(qMin(index, model->count()-1), 0);
2509
2510     if (layoutScheduled)
2511         layout();
2512     qreal pos = isRightToLeftTopToBottom() ? -position() - size() : position();
2513     FxGridItem *item = visibleItem(idx);
2514     qreal maxExtent;
2515     if (flow == QDeclarativeGridView::LeftToRight)
2516         maxExtent = -q->maxYExtent();
2517     else
2518         maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2519
2520     if (!item) {
2521         int itemPos = rowPosAt(idx);
2522         // save the currently visible items in case any of them end up visible again
2523         QList<FxGridItem*> oldVisible = visibleItems;
2524         visibleItems.clear();
2525         visibleIndex = idx - idx % columns;
2526         if (flow == QDeclarativeGridView::LeftToRight)
2527             maxExtent = -q->maxYExtent();
2528         else
2529             maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2530         setPosition(qMin(qreal(itemPos), maxExtent));
2531         // now release the reference to all the old visible items.
2532         for (int i = 0; i < oldVisible.count(); ++i)
2533             releaseItem(oldVisible.at(i));
2534         item = visibleItem(idx);
2535     }
2536     if (item) {
2537         qreal itemPos = item->rowPos();
2538         switch (mode) {
2539         case QDeclarativeGridView::Beginning:
2540             pos = itemPos;
2541             if (index < 0 && header) {
2542                 pos -= flow == QDeclarativeGridView::LeftToRight
2543                             ? header->item->height()
2544                             : header->item->width();
2545             }
2546             break;
2547         case QDeclarativeGridView::Center:
2548             pos = itemPos - (size() - rowSize())/2;
2549             break;
2550         case QDeclarativeGridView::End:
2551             pos = itemPos - size() + rowSize();
2552             if (index >= model->count() && footer) {
2553                 pos += flow == QDeclarativeGridView::LeftToRight
2554                             ? footer->item->height()
2555                             : footer->item->width();
2556             }
2557             break;
2558         case QDeclarativeGridView::Visible:
2559             if (itemPos > pos + size())
2560                 pos = itemPos - size() + rowSize();
2561             else if (item->endRowPos() < pos)
2562                 pos = itemPos;
2563             break;
2564         case QDeclarativeGridView::Contain:
2565             if (item->endRowPos() > pos + size())
2566                 pos = itemPos - size() + rowSize();
2567             if (itemPos < pos)
2568                 pos = itemPos;
2569         }
2570
2571         pos = qMin(pos, maxExtent);
2572         qreal minExtent;
2573         if (flow == QDeclarativeGridView::LeftToRight)
2574             minExtent = -q->minYExtent();
2575         else
2576             minExtent = isRightToLeftTopToBottom() ? q->maxXExtent()-size() : -q->minXExtent();
2577         pos = qMax(pos, minExtent);
2578         moveReason = QDeclarativeGridViewPrivate::Other;
2579         q->cancelFlick();
2580         setPosition(pos);
2581     }
2582     fixupPosition();
2583 }
2584
2585 /*!
2586     \qmlmethod GridView::positionViewAtIndex(int index, PositionMode mode)
2587
2588     Positions the view such that the \a index is at the position specified by
2589     \a mode:
2590
2591     \list
2592     \o GridView.Beginning - position item at the top (or left for \c GridView.TopToBottom flow) of the view.
2593     \o GridView.Center - position item in the center of the view.
2594     \o GridView.End - position item at bottom (or right for horizontal orientation) of the view.
2595     \o GridView.Visible - if any part of the item is visible then take no action, otherwise
2596     bring the item into view.
2597     \o GridView.Contain - ensure the entire item is visible.  If the item is larger than
2598     the view the item is positioned at the top (or left for \c GridView.TopToBottom flow) of the view.
2599     \endlist
2600
2601     If positioning the view at the index would cause empty space to be displayed at
2602     the beginning or end of the view, the view will be positioned at the boundary.
2603
2604     It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2605     at a particular index.  This is unreliable since removing items from the start
2606     of the view does not cause all other items to be repositioned.
2607     The correct way to bring an item into view is with \c positionViewAtIndex.
2608
2609     \bold Note: methods should only be called after the Component has completed.  To position
2610     the view at startup, this method should be called by Component.onCompleted.  For
2611     example, to position the view at the end:
2612
2613     \code
2614     Component.onCompleted: positionViewAtIndex(count - 1, GridView.Beginning)
2615     \endcode
2616 */
2617 void QDeclarativeGridView::positionViewAtIndex(int index, int mode)
2618 {
2619     Q_D(QDeclarativeGridView);
2620     if (!d->isValid() || index < 0 || index >= d->model->count())
2621         return;
2622     d->positionViewAtIndex(index, mode);
2623 }
2624
2625 /*!
2626     \qmlmethod GridView::positionViewAtBeginning()
2627     \qmlmethod GridView::positionViewAtEnd()
2628     \since QtQuick 1.1
2629
2630     Positions the view at the beginning or end, taking into account any header or footer.
2631
2632     It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2633     at a particular index.  This is unreliable since removing items from the start
2634     of the list does not cause all other items to be repositioned, and because
2635     the actual start of the view can vary based on the size of the delegates.
2636
2637     \bold Note: methods should only be called after the Component has completed.  To position
2638     the view at startup, this method should be called by Component.onCompleted.  For
2639     example, to position the view at the end on startup:
2640
2641     \code
2642     Component.onCompleted: positionViewAtEnd()
2643     \endcode
2644 */
2645 void QDeclarativeGridView::positionViewAtBeginning()
2646 {
2647     Q_D(QDeclarativeGridView);
2648     if (!d->isValid())
2649         return;
2650     d->positionViewAtIndex(-1, Beginning);
2651 }
2652
2653 void QDeclarativeGridView::positionViewAtEnd()
2654 {
2655     Q_D(QDeclarativeGridView);
2656     if (!d->isValid())
2657         return;
2658     d->positionViewAtIndex(d->model->count(), End);
2659 }
2660
2661 /*!
2662     \qmlmethod int GridView::indexAt(int x, int y)
2663
2664     Returns the index of the visible item containing the point \a x, \a y in content
2665     coordinates.  If there is no item at the point specified, or the item is
2666     not visible -1 is returned.
2667
2668     If the item is outside the visible area, -1 is returned, regardless of
2669     whether an item will exist at that point when scrolled into view.
2670
2671     \bold Note: methods should only be called after the Component has completed.
2672 */
2673 int QDeclarativeGridView::indexAt(qreal x, qreal y) const
2674 {
2675     Q_D(const QDeclarativeGridView);
2676     for (int i = 0; i < d->visibleItems.count(); ++i) {
2677         const FxGridItem *listItem = d->visibleItems.at(i);
2678         if(listItem->contains(x, y))
2679             return listItem->index;
2680     }
2681
2682     return -1;
2683 }
2684
2685 void QDeclarativeGridView::componentComplete()
2686 {
2687     Q_D(QDeclarativeGridView);
2688     QDeclarativeFlickable::componentComplete();
2689     d->updateHeader();
2690     d->updateFooter();
2691     d->updateGrid();
2692     if (d->isValid()) {
2693         refill();
2694         d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
2695         if (d->currentIndex < 0 && !d->currentIndexCleared)
2696             d->updateCurrent(0);
2697         else
2698             d->updateCurrent(d->currentIndex);
2699         if (d->highlight && d->currentItem) {
2700             if (d->autoHighlight)
2701                 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
2702             d->updateTrackedItem();
2703         }
2704         d->moveReason = QDeclarativeGridViewPrivate::Other;
2705         d->fixupPosition();
2706     }
2707 }
2708
2709 void QDeclarativeGridView::trackedPositionChanged()
2710 {
2711     Q_D(QDeclarativeGridView);
2712     if (!d->trackedItem || !d->currentItem)
2713         return;
2714     if (d->moveReason == QDeclarativeGridViewPrivate::SetIndex) {
2715         const qreal trackedPos = d->trackedItem->rowPos();
2716         qreal viewPos;
2717         qreal highlightStart;
2718         qreal highlightEnd;
2719         if (d->isRightToLeftTopToBottom()) {
2720             viewPos = -d->position()-d->size();
2721             highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
2722             highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
2723         } else {
2724             viewPos = d->position();
2725             highlightStart = d->highlightRangeStart;
2726             highlightEnd = d->highlightRangeEnd;
2727         }
2728         qreal pos = viewPos;
2729         if (d->haveHighlightRange) {
2730             if (d->highlightRange == StrictlyEnforceRange) {
2731                 if (trackedPos > pos + highlightEnd - d->rowSize())
2732                     pos = trackedPos - highlightEnd + d->rowSize();
2733                 if (trackedPos < pos + highlightStart)
2734                     pos = trackedPos - highlightStart;
2735             } else {
2736                 if (trackedPos < d->startPosition() + highlightStart) {
2737                     pos = d->startPosition();
2738                 } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + highlightEnd) {
2739                     pos = d->endPosition() - d->size() + 1;
2740                     if (pos < d->startPosition())
2741                         pos = d->startPosition();
2742                 } else {
2743                     if (trackedPos < viewPos + highlightStart) {
2744                         pos = trackedPos - highlightStart;
2745                     } else if (trackedPos > viewPos + highlightEnd - d->rowSize()) {
2746                         pos = trackedPos - highlightEnd + d->rowSize();
2747                     }
2748                 }
2749             }
2750         } else {
2751             if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) {
2752                 pos = qMax(trackedPos, d->currentItem->rowPos());
2753             } else if (d->trackedItem->endRowPos() >= viewPos + d->size()
2754                 && d->currentItem->endRowPos() >= viewPos + d->size()) {
2755                 if (d->trackedItem->endRowPos() <= d->currentItem->endRowPos()) {
2756                     pos = d->trackedItem->endRowPos() - d->size() + 1;
2757                     if (d->rowSize() > d->size())
2758                         pos = trackedPos;
2759                 } else {
2760                     pos = d->currentItem->endRowPos() - d->size() + 1;
2761                     if (d->rowSize() > d->size())
2762                         pos = d->currentItem->rowPos();
2763                 }
2764             }
2765         }
2766         if (viewPos != pos) {
2767             cancelFlick();
2768             d->calcVelocity = true;
2769             d->setPosition(pos);
2770             d->calcVelocity = false;
2771         }
2772     }
2773 }
2774
2775 void QDeclarativeGridView::itemsInserted(int modelIndex, int count)
2776 {
2777     Q_D(QDeclarativeGridView);
2778     if (!isComponentComplete())
2779         return;
2780
2781     int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
2782     if (index < 0) {
2783         int i = d->visibleItems.count() - 1;
2784         while (i > 0 && d->visibleItems.at(i)->index == -1)
2785             --i;
2786         if (d->visibleItems.at(i)->index + 1 == modelIndex) {
2787             // Special case of appending an item to the model.
2788             index = d->visibleIndex + d->visibleItems.count();
2789         } else {
2790             if (modelIndex <= d->visibleIndex) {
2791                 // Insert before visible items
2792                 d->visibleIndex += count;
2793                 for (int i = 0; i < d->visibleItems.count(); ++i) {
2794                     FxGridItem *listItem = d->visibleItems.at(i);
2795                     if (listItem->index != -1 && listItem->index >= modelIndex)
2796                         listItem->index += count;
2797                 }
2798             }
2799             if (d->currentIndex >= modelIndex) {
2800                 // adjust current item index
2801                 d->currentIndex += count;
2802                 if (d->currentItem)
2803                     d->currentItem->index = d->currentIndex;
2804                 emit currentIndexChanged();
2805             }
2806             d->scheduleLayout();
2807             d->itemCount += count;
2808             emit countChanged();
2809             return;
2810         }
2811     }
2812
2813     int insertCount = count;
2814     if (index < d->visibleIndex && d->visibleItems.count()) {
2815         insertCount -= d->visibleIndex - index;
2816         index = d->visibleIndex;
2817         modelIndex = d->visibleIndex;
2818     }
2819
2820     qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+d->width()+1 : d->position();
2821     int to = d->buffer+tempPos+d->size()-1;
2822     int colPos = 0;
2823     int rowPos = 0;
2824     if (d->visibleItems.count()) {
2825         index -= d->visibleIndex;
2826         if (index < d->visibleItems.count()) {
2827             colPos = d->visibleItems.at(index)->colPos();
2828             rowPos = d->visibleItems.at(index)->rowPos();
2829         } else {
2830             // appending items to visible list
2831             colPos = d->visibleItems.at(index-1)->colPos() + d->colSize();
2832             rowPos = d->visibleItems.at(index-1)->rowPos();
2833             if (colPos > d->colSize() * (d->columns-1)) {
2834                 colPos = 0;
2835                 rowPos += d->rowSize();
2836             }
2837         }
2838     } else if (d->itemCount == 0 && d->header) {
2839         rowPos = d->headerSize();
2840     }
2841
2842     // Update the indexes of the following visible items.
2843     for (int i = 0; i < d->visibleItems.count(); ++i) {
2844         FxGridItem *listItem = d->visibleItems.at(i);
2845         if (listItem->index != -1 && listItem->index >= modelIndex)
2846             listItem->index += count;
2847     }
2848
2849     bool addedVisible = false;
2850     QList<FxGridItem*> added;
2851     int i = 0;
2852     while (i < insertCount && rowPos <= to + d->rowSize()*(d->columns - (colPos/d->colSize()))/qreal(d->columns)) {
2853         if (!addedVisible) {
2854             d->scheduleLayout();
2855             addedVisible = true;
2856         }
2857         FxGridItem *item = d->createItem(modelIndex + i);
2858         if (!item) {
2859             // broken or no delegate
2860             d->clear();
2861             return;
2862         }
2863         d->visibleItems.insert(index, item);
2864         item->setPosition(colPos, rowPos);
2865         added.append(item);
2866         colPos += d->colSize();
2867         if (colPos > d->colSize() * (d->columns-1)) {
2868             colPos = 0;
2869             rowPos += d->rowSize();
2870         }
2871         ++index;
2872         ++i;
2873     }
2874     if (i < insertCount) {
2875         // We didn't insert all our new items, which means anything
2876         // beyond the current index is not visible - remove it.
2877         while (d->visibleItems.count() > index) {
2878             d->releaseItem(d->visibleItems.takeLast());
2879         }
2880     }
2881
2882     // update visibleIndex
2883     d->visibleIndex = 0;
2884     for (QList<FxGridItem*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2885         if ((*it)->index != -1) {
2886             d->visibleIndex = (*it)->index;
2887             break;
2888         }
2889     }
2890
2891     if (d->itemCount && d->currentIndex >= modelIndex) {
2892         // adjust current item index
2893         d->currentIndex += count;
2894         if (d->currentItem) {
2895             d->currentItem->index = d->currentIndex;
2896             d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
2897         }
2898         emit currentIndexChanged();
2899     } else if (d->itemCount == 0 && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
2900         setCurrentIndex(0);
2901     }
2902
2903     // everything is in order now - emit add() signal
2904     for (int j = 0; j < added.count(); ++j)
2905         added.at(j)->attached->emitAdd();
2906
2907     d->itemCount += count;
2908     emit countChanged();
2909 }
2910
2911 void QDeclarativeGridView::itemsRemoved(int modelIndex, int count)
2912 {
2913     Q_D(QDeclarativeGridView);
2914     if (!isComponentComplete())
2915         return;
2916
2917     d->itemCount -= count;
2918     bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count;
2919     bool removedVisible = false;
2920     // Remove the items from the visible list, skipping anything already marked for removal
2921     QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
2922     while (it != d->visibleItems.end()) {
2923         FxGridItem *item = *it;
2924         if (item->index == -1 || item->index < modelIndex) {
2925             // already removed, or before removed items
2926             if (item->index < modelIndex && !removedVisible) {
2927                 d->scheduleLayout();
2928                 removedVisible = true;
2929             }
2930             ++it;
2931         } else if (item->index >= modelIndex + count) {
2932             // after removed items
2933             item->index -= count;
2934             ++it;
2935         } else {
2936             // removed item
2937             if (!removedVisible) {
2938                 d->scheduleLayout();
2939                 removedVisible = true;
2940             }
2941             item->attached->emitRemove();
2942             if (item->attached->delayRemove()) {
2943                 item->index = -1;
2944                 connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
2945                 ++it;
2946             } else {
2947                 it = d->visibleItems.erase(it);
2948                 d->releaseItem(item);
2949             }
2950         }
2951     }
2952
2953     // If we removed items before visible items a layout may be
2954     // required to ensure item 0 is in the first column.
2955     if (!removedVisible && modelIndex < d->visibleIndex)
2956         d->scheduleLayout();
2957
2958     // fix current
2959     if (d->currentIndex >= modelIndex + count) {
2960         d->currentIndex -= count;
2961         if (d->currentItem)
2962             d->currentItem->index -= count;
2963         emit currentIndexChanged();
2964     } else if (currentRemoved) {
2965         // current item has been removed.
2966         d->releaseItem(d->currentItem);
2967         d->currentItem = 0;
2968         d->currentIndex = -1;
2969         if (d->itemCount)
2970             d->updateCurrent(qMin(modelIndex, d->itemCount-1));
2971         else
2972             emit currentIndexChanged();
2973     }
2974
2975     // update visibleIndex
2976     d->visibleIndex = 0;
2977     for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2978         if ((*it)->index != -1) {
2979             d->visibleIndex = (*it)->index;
2980             break;
2981         }
2982     }
2983
2984     if (removedVisible && d->visibleItems.isEmpty()) {
2985         d->timeline.clear();
2986         if (d->itemCount == 0) {
2987             d->setPosition(0);
2988             d->updateHeader();
2989             d->updateFooter();
2990             update();
2991         }
2992     }
2993
2994     emit countChanged();
2995 }
2996
2997 void QDeclarativeGridView::destroyRemoved()
2998 {
2999     Q_D(QDeclarativeGridView);
3000     for (QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
3001             it != d->visibleItems.end();) {
3002         FxGridItem *listItem = *it;
3003         if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
3004             d->releaseItem(listItem);
3005             it = d->visibleItems.erase(it);
3006         } else {
3007             ++it;
3008         }
3009     }
3010
3011     // Correct the positioning of the items
3012     d->layout();
3013 }
3014
3015 void QDeclarativeGridView::itemsMoved(int from, int to, int count)
3016 {
3017     Q_D(QDeclarativeGridView);
3018     if (!isComponentComplete())
3019         return;
3020     QHash<int,FxGridItem*> moved;
3021
3022     FxGridItem *firstItem = d->firstVisibleItem();
3023
3024     QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
3025     while (it != d->visibleItems.end()) {
3026         FxGridItem *item = *it;
3027         if (item->index >= from && item->index < from + count) {
3028             // take the items that are moving
3029             item->index += (to-from);
3030             moved.insert(item->index, item);
3031             it = d->visibleItems.erase(it);
3032         } else {
3033             if (item->index > from && item->index != -1) {
3034                 // move everything after the moved items.
3035                 item->index -= count;
3036                 if (item->index < d->visibleIndex)
3037                     d->visibleIndex = item->index;
3038             }
3039             ++it;
3040         }
3041     }
3042
3043     int remaining = count;
3044     int endIndex = d->visibleIndex;
3045     it = d->visibleItems.begin();
3046     while (it != d->visibleItems.end()) {
3047         FxGridItem *item = *it;
3048         if (remaining && item->index >= to && item->index < to + count) {
3049             // place items in the target position, reusing any existing items
3050             FxGridItem *movedItem = moved.take(item->index);
3051             if (!movedItem)
3052                 movedItem = d->createItem(item->index);
3053             if (!movedItem) {
3054                 // broken or no delegate
3055                 d->clear();
3056                 return;
3057             }
3058             it = d->visibleItems.insert(it, movedItem);
3059             if (it == d->visibleItems.begin() && firstItem)
3060                 movedItem->setPosition(firstItem->colPos(), firstItem->rowPos());
3061             ++it;
3062             --remaining;
3063         } else {
3064             if (item->index != -1) {
3065                 if (item->index >= to) {
3066                     // update everything after the moved items.
3067                     item->index += count;
3068                 }
3069                 endIndex = item->index;
3070             }
3071             ++it;
3072         }
3073     }
3074
3075     // If we have moved items to the end of the visible items
3076     // then add any existing moved items that we have
3077     while (FxGridItem *item = moved.take(endIndex+1)) {
3078         d->visibleItems.append(item);
3079         ++endIndex;
3080     }
3081
3082     // update visibleIndex
3083     for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
3084         if ((*it)->index != -1) {
3085             d->visibleIndex = (*it)->index;
3086             break;
3087         }
3088     }
3089
3090     // Fix current index
3091     if (d->currentIndex >= 0 && d->currentItem) {
3092         int oldCurrent = d->currentIndex;
3093         d->currentIndex = d->model->indexOf(d->currentItem->item, this);
3094         if (oldCurrent != d->currentIndex) {
3095             d->currentItem->index = d->currentIndex;
3096             emit currentIndexChanged();
3097         }
3098     }
3099
3100     // Whatever moved items remain are no longer visible items.
3101     while (moved.count()) {
3102         int idx = moved.begin().key();
3103         FxGridItem *item = moved.take(idx);
3104         if (d->currentItem && item->item == d->currentItem->item)
3105             item->setPosition(d->colPosAt(idx), d->rowPosAt(idx));
3106         d->releaseItem(item);
3107     }
3108
3109     d->layout();
3110 }
3111
3112 void QDeclarativeGridView::modelReset()
3113 {
3114     Q_D(QDeclarativeGridView);
3115     d->clear();
3116     refill();
3117     d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
3118     d->updateCurrent(d->currentIndex);
3119     if (d->highlight && d->currentItem) {
3120         if (d->autoHighlight)
3121             d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
3122         d->updateTrackedItem();
3123     }
3124     d->moveReason = QDeclarativeGridViewPrivate::Other;
3125
3126     emit countChanged();
3127 }
3128
3129 void QDeclarativeGridView::createdItem(int index, QDeclarativeItem *item)
3130 {
3131     Q_D(QDeclarativeGridView);
3132     if (d->requestedIndex != index) {
3133         item->setParentItem(this);
3134         d->unrequestedItems.insert(item, index);
3135         if (d->flow == QDeclarativeGridView::LeftToRight) {
3136             item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index)));
3137         } else {
3138             item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index)));
3139         }
3140     }
3141 }
3142
3143 void QDeclarativeGridView::destroyingItem(QDeclarativeItem *item)
3144 {
3145     Q_D(QDeclarativeGridView);
3146     d->unrequestedItems.remove(item);
3147 }
3148
3149 void QDeclarativeGridView::animStopped()
3150 {
3151     Q_D(QDeclarativeGridView);
3152     d->bufferMode = QDeclarativeGridViewPrivate::NoBuffer;
3153     if (d->haveHighlightRange && d->highlightRange == QDeclarativeGridView::StrictlyEnforceRange)
3154         d->updateHighlight();
3155 }
3156
3157 void QDeclarativeGridView::refill()
3158 {
3159     Q_D(QDeclarativeGridView);
3160     if (d->isRightToLeftTopToBottom())
3161         d->refill(-d->position()-d->size()+1, -d->position());
3162     else
3163         d->refill(d->position(), d->position()+d->size()-1);
3164 }
3165
3166
3167 QDeclarativeGridViewAttached *QDeclarativeGridView::qmlAttachedProperties(QObject *obj)
3168 {
3169     return new QDeclarativeGridViewAttached(obj);
3170 }
3171
3172 QT_END_NAMESPACE