Merge remote branch 'origin/4.8' into 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         FxGridItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
1087         qreal pos;
1088         if (topItem && bottomItem && strictHighlightRange) {
1089             qreal topPos = qMin(topItem->rowPos() - highlightStart, -maxExtent);
1090             qreal bottomPos = qMax(bottomItem->rowPos() - highlightEnd, -minExtent);
1091             pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos;
1092         } else if (topItem) {
1093             qreal headerPos = 0;
1094             if (header)
1095                 headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
1096             if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2 && !strictHighlightRange) {
1097                 pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart;
1098             } else {
1099                 if (isRightToLeftTopToBottom())
1100                     pos = qMax(qMin(-topItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
1101                 else
1102                     pos = qMax(qMin(topItem->rowPos() - highlightStart, -maxExtent), -minExtent);
1103             }
1104         } else if (bottomItem) {
1105             if (isRightToLeftTopToBottom())
1106                 pos = qMax(qMin(-bottomItem->rowPos() + highlightEnd - size(), -maxExtent), -minExtent);
1107             else
1108                 pos = qMax(qMin(bottomItem->rowPos() - highlightEnd, -maxExtent), -minExtent);
1109         } else {
1110             QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
1111             return;
1112         }
1113         qreal dist = qAbs(data.move + pos);
1114         if (dist > 0) {
1115             timeline.reset(data.move);
1116             if (fixupMode != Immediate) {
1117                 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1118                 data.fixingUp = true;
1119             } else {
1120                 timeline.set(data.move, -pos);
1121             }
1122             vTime = timeline.time();
1123         }
1124     } else if (haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) {
1125         if (currentItem) {
1126             updateHighlight();
1127             qreal pos = currentItem->rowPos();
1128             if (viewPos < pos + rowSize() - highlightEnd)
1129                 viewPos = pos + rowSize() - highlightEnd;
1130             if (viewPos > pos - highlightStart)
1131                 viewPos = pos - highlightStart;
1132             if (isRightToLeftTopToBottom())
1133                 viewPos = -viewPos-size();
1134             timeline.reset(data.move);
1135             if (viewPos != position()) {
1136                 if (fixupMode != Immediate) {
1137                     timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1138                     data.fixingUp = true;
1139                 } else {
1140                     timeline.set(data.move, -viewPos);
1141                 }
1142             }
1143             vTime = timeline.time();
1144         }
1145     } else {
1146         QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
1147     }
1148     data.inOvershoot = false;
1149     fixupMode = Normal;
1150 }
1151
1152 void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1153                                         QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
1154 {
1155     Q_Q(QDeclarativeGridView);
1156     data.fixingUp = false;
1157     moveReason = Mouse;
1158     if ((!haveHighlightRange || highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1159         && snapMode == QDeclarativeGridView::NoSnap) {
1160         QDeclarativeFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1161         return;
1162     }
1163     qreal maxDistance = 0;
1164     qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value();
1165     // -ve velocity means list is moving up/left
1166     if (velocity > 0) {
1167         if (data.move.value() < minExtent) {
1168             if (snapMode == QDeclarativeGridView::SnapOneRow) {
1169                 // if we've been dragged < averageSize/2 then bias towards the next item
1170                 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1171                 qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0;
1172                 if (isRightToLeftTopToBottom())
1173                     bias = -bias;
1174                 data.flickTarget = -snapPosAt(-dataValue - bias);
1175                 maxDistance = qAbs(data.flickTarget - data.move.value());
1176                 velocity = maxVelocity;
1177             } else {
1178                 maxDistance = qAbs(minExtent - data.move.value());
1179             }
1180         }
1181         if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1182             data.flickTarget = minExtent;
1183     } else {
1184         if (data.move.value() > maxExtent) {
1185             if (snapMode == QDeclarativeGridView::SnapOneRow) {
1186                 // if we've been dragged < averageSize/2 then bias towards the next item
1187                 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1188                 qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0;
1189                 if (isRightToLeftTopToBottom())
1190                     bias = -bias;
1191                 data.flickTarget = -snapPosAt(-dataValue + bias);
1192                 maxDistance = qAbs(data.flickTarget - data.move.value());
1193                 velocity = -maxVelocity;
1194             } else {
1195                 maxDistance = qAbs(maxExtent - data.move.value());
1196             }
1197         }
1198         if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1199             data.flickTarget = maxExtent;
1200     }
1201
1202     bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds;
1203
1204     if (maxDistance > 0 || overShoot) {
1205         // This mode requires the grid to stop exactly on a row boundary.
1206         qreal v = velocity;
1207         if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1208             if (v < 0)
1209                 v = -maxVelocity;
1210             else
1211                 v = maxVelocity;
1212         }
1213         qreal accel = deceleration;
1214         qreal v2 = v * v;
1215         qreal overshootDist = 0.0;
1216         if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QDeclarativeGridView::SnapOneRow) {
1217             // + rowSize()/4 to encourage moving at least one item in the flick direction
1218             qreal dist = v2 / (accel * 2.0) + rowSize()/4;
1219             dist = qMin(dist, maxDistance);
1220             if (v > 0)
1221                 dist = -dist;
1222             if (snapMode != QDeclarativeGridView::SnapOneRow) {
1223                 qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
1224                 data.flickTarget = -snapPosAt(-dataValue + distTemp);
1225             }
1226             data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
1227             if (overShoot) {
1228                 if (data.flickTarget >= minExtent) {
1229                     overshootDist = overShootDistance(vSize);
1230                     data.flickTarget += overshootDist;
1231                 } else if (data.flickTarget <= maxExtent) {
1232                     overshootDist = overShootDistance(vSize);
1233                     data.flickTarget -= overshootDist;
1234                 }
1235             }
1236             qreal adjDist = -data.flickTarget + data.move.value();
1237             if (qAbs(adjDist) > qAbs(dist)) {
1238                 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1239                 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1240                 if (adjv2 > v2) {
1241                     v2 = adjv2;
1242                     v = qSqrt(v2);
1243                     if (dist > 0)
1244                         v = -v;
1245                 }
1246             }
1247             dist = adjDist;
1248             accel = v2 / (2.0f * qAbs(dist));
1249         } else {
1250             data.flickTarget = velocity > 0 ? minExtent : maxExtent;
1251             overshootDist = overShoot ? overShootDistance(vSize) : 0;
1252         }
1253         timeline.reset(data.move);
1254         timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1255         timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1256         if (!hData.flicking && q->xflick()) {
1257             hData.flicking = true;
1258             emit q->flickingChanged();
1259             emit q->flickingHorizontallyChanged();
1260             emit q->flickStarted();
1261         }
1262         if (!vData.flicking && q->yflick()) {
1263             vData.flicking = true;
1264             emit q->flickingChanged();
1265             emit q->flickingVerticallyChanged();
1266             emit q->flickStarted();
1267         }
1268     } else {
1269         timeline.reset(data.move);
1270         fixup(data, minExtent, maxExtent);
1271     }
1272 }
1273
1274
1275 //----------------------------------------------------------------------------
1276
1277 /*!
1278     \qmlclass GridView QDeclarativeGridView
1279     \since 4.7
1280     \ingroup qml-view-elements
1281
1282     \inherits Flickable
1283     \brief The GridView item provides a grid view of items provided by a model.
1284
1285     A GridView displays data from models created from built-in QML elements like ListModel
1286     and XmlListModel, or custom model classes defined in C++ that inherit from
1287     QAbstractListModel.
1288
1289     A GridView has a \l model, which defines the data to be displayed, and
1290     a \l delegate, which defines how the data should be displayed. Items in a 
1291     GridView are laid out horizontally or vertically. Grid views are inherently flickable
1292     as GridView inherits from \l Flickable.
1293
1294     \section1 Example Usage
1295
1296     The following example shows the definition of a simple list model defined
1297     in a file called \c ContactModel.qml:
1298
1299     \snippet doc/src/snippets/declarative/gridview/ContactModel.qml 0
1300
1301     \div {class="float-right"}
1302     \inlineimage gridview-simple.png
1303     \enddiv
1304
1305     This model can be referenced as \c ContactModel in other QML files. See \l{QML Modules}
1306     for more information about creating reusable components like this.
1307
1308     Another component can display this model data in a GridView, as in the following
1309     example, which creates a \c ContactModel component for its model, and a \l Column element
1310     (containing \l Image and \l Text elements) for its delegate.
1311
1312     \clearfloat
1313     \snippet doc/src/snippets/declarative/gridview/gridview.qml import
1314     \codeline
1315     \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs simple
1316
1317     \div {class="float-right"}
1318     \inlineimage gridview-highlight.png
1319     \enddiv
1320
1321     The view will create a new delegate for each item in the model. Note that the delegate
1322     is able to access the model's \c name and \c portrait data directly.
1323
1324     An improved grid view is shown below. The delegate is visually improved and is moved 
1325     into a separate \c contactDelegate component.
1326
1327     \clearfloat
1328     \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs advanced
1329
1330     The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
1331     and \c focus is set to \c true to enable keyboard navigation for the grid view.
1332     The grid view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
1333
1334     Delegates are instantiated as needed and may be destroyed at any time.
1335     State should \e never be stored in a delegate.
1336
1337     GridView attaches a number of properties to the root item of the delegate, for example
1338     \c {GridView.isCurrentItem}.  In the following example, the root delegate item can access
1339     this attached property directly as \c GridView.isCurrentItem, while the child
1340     \c contactInfo object must refer to this property as \c wrapper.GridView.isCurrentItem.
1341
1342     \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem
1343
1344     \note Views do not set the \l{Item::}{clip} property automatically.
1345     If the view is not clipped by another item or the screen, it will be necessary
1346     to set this property to true in order to clip the items that are partially or
1347     fully outside the view.
1348
1349     \sa {declarative/modelviews/gridview}{GridView example}
1350 */
1351 QDeclarativeGridView::QDeclarativeGridView(QDeclarativeItem *parent)
1352     : QDeclarativeFlickable(*(new QDeclarativeGridViewPrivate), parent)
1353 {
1354     Q_D(QDeclarativeGridView);
1355     d->init();
1356 }
1357
1358 QDeclarativeGridView::~QDeclarativeGridView()
1359 {
1360     Q_D(QDeclarativeGridView);
1361     d->clear();
1362     if (d->ownModel)
1363         delete d->model;
1364     delete d->header;
1365     delete d->footer;
1366 }
1367
1368 /*!
1369     \qmlattachedproperty bool GridView::isCurrentItem
1370     This attached property is true if this delegate is the current item; otherwise false.
1371
1372     It is attached to each instance of the delegate.
1373 */
1374
1375 /*!
1376     \qmlattachedproperty GridView GridView::view
1377     This attached property holds the view that manages this delegate instance.
1378
1379     It is attached to each instance of the delegate.
1380
1381     \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem
1382 */
1383
1384 /*!
1385     \qmlattachedproperty bool GridView::delayRemove
1386     This attached property holds whether the delegate may be destroyed.
1387
1388     It is attached to each instance of the delegate.
1389
1390     It is sometimes necessary to delay the destruction of an item
1391     until an animation completes.
1392
1393     The example below ensures that the animation completes before
1394     the item is removed from the grid.
1395
1396     \snippet doc/src/snippets/declarative/gridview/gridview.qml delayRemove
1397 */
1398
1399 /*!
1400     \qmlattachedsignal GridView::onAdd()
1401     This attached handler is called immediately after an item is added to the view.
1402 */
1403
1404 /*!
1405     \qmlattachedsignal GridView::onRemove()
1406     This attached handler is called immediately before an item is removed from the view.
1407 */
1408
1409
1410 /*!
1411   \qmlproperty model GridView::model
1412   This property holds the model providing data for the grid.
1413
1414     The model provides the set of data that is used to create the items
1415     in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
1416     or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
1417     used, it must be a subclass of \l QAbstractItemModel or a simple list.
1418
1419   \sa {qmlmodels}{Data Models}
1420 */
1421 QVariant QDeclarativeGridView::model() const
1422 {
1423     Q_D(const QDeclarativeGridView);
1424     return d->modelVariant;
1425 }
1426
1427 // For internal use
1428 int QDeclarativeGridView::modelCount() const
1429 {
1430     Q_D(const QDeclarativeGridView);
1431     return d->model->count();
1432 }
1433
1434 void QDeclarativeGridView::setModel(const QVariant &model)
1435 {
1436     Q_D(QDeclarativeGridView);
1437     if (d->modelVariant == model)
1438         return;
1439     if (d->model) {
1440         disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1441         disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1442         disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1443         disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1444         disconnect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
1445         disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
1446     }
1447     d->clear();
1448     d->modelVariant = model;
1449     QObject *object = qvariant_cast<QObject*>(model);
1450     QDeclarativeVisualModel *vim = 0;
1451     if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
1452         if (d->ownModel) {
1453             delete d->model;
1454             d->ownModel = false;
1455         }
1456         d->model = vim;
1457     } else {
1458         if (!d->ownModel) {
1459             d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
1460             d->ownModel = true;
1461         }
1462         if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
1463             dataModel->setModel(model);
1464     }
1465     if (d->model) {
1466         d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore | QDeclarativeGridViewPrivate::BufferAfter;
1467         if (isComponentComplete()) {
1468             refill();
1469             if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
1470                 setCurrentIndex(0);
1471             } else {
1472                 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1473                 d->updateCurrent(d->currentIndex);
1474                 if (d->highlight && d->currentItem) {
1475                     if (d->autoHighlight)
1476                         d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1477                     d->updateTrackedItem();
1478                 }
1479                 d->moveReason = QDeclarativeGridViewPrivate::Other;
1480             }
1481         }
1482         connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1483         connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1484         connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1485         connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1486         connect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
1487         connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
1488         emit countChanged();
1489     }
1490     emit modelChanged();
1491 }
1492
1493 /*!
1494     \qmlproperty Component GridView::delegate
1495
1496     The delegate provides a template defining each item instantiated by the view.
1497     The index is exposed as an accessible \c index property.  Properties of the
1498     model are also available depending upon the type of \l {qmlmodels}{Data Model}.
1499
1500     The number of elements in the delegate has a direct effect on the
1501     flicking performance of the view.  If at all possible, place functionality
1502     that is not needed for the normal display of the delegate in a \l Loader which
1503     can load additional elements when needed.
1504
1505     The GridView will layout the items based on the size of the root item
1506     in the delegate.
1507
1508     \note Delegates are instantiated as needed and may be destroyed at any time.
1509     State should \e never be stored in a delegate.
1510 */
1511 QDeclarativeComponent *QDeclarativeGridView::delegate() const
1512 {
1513     Q_D(const QDeclarativeGridView);
1514     if (d->model) {
1515         if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
1516             return dataModel->delegate();
1517     }
1518
1519     return 0;
1520 }
1521
1522 void QDeclarativeGridView::setDelegate(QDeclarativeComponent *delegate)
1523 {
1524     Q_D(QDeclarativeGridView);
1525     if (delegate == this->delegate())
1526         return;
1527
1528     if (!d->ownModel) {
1529         d->model = new QDeclarativeVisualDataModel(qmlContext(this));
1530         d->ownModel = true;
1531     }
1532     if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model)) {
1533         int oldCount = dataModel->count();
1534         dataModel->setDelegate(delegate);
1535         if (isComponentComplete()) {
1536             for (int i = 0; i < d->visibleItems.count(); ++i)
1537                 d->releaseItem(d->visibleItems.at(i));
1538             d->visibleItems.clear();
1539             d->releaseItem(d->currentItem);
1540             d->currentItem = 0;
1541             refill();
1542             d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1543             d->updateCurrent(d->currentIndex);
1544             if (d->highlight && d->currentItem) {
1545                 if (d->autoHighlight)
1546                     d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1547                 d->updateTrackedItem();
1548             }
1549             d->moveReason = QDeclarativeGridViewPrivate::Other;
1550         }
1551         if (oldCount != dataModel->count())
1552             emit countChanged();
1553         emit delegateChanged();
1554     }
1555 }
1556
1557 /*!
1558   \qmlproperty int GridView::currentIndex
1559   \qmlproperty Item GridView::currentItem
1560
1561     The \c currentIndex property holds the index of the current item, and
1562     \c currentItem holds the current item.  Setting the currentIndex to -1
1563     will clear the highlight and set currentItem to null.
1564
1565     If highlightFollowsCurrentItem is \c true, setting either of these 
1566     properties will smoothly scroll the GridView so that the current 
1567     item becomes visible.
1568     
1569     Note that the position of the current item
1570     may only be approximate until it becomes visible in the view.
1571 */
1572 int QDeclarativeGridView::currentIndex() const
1573 {
1574     Q_D(const QDeclarativeGridView);
1575     return d->currentIndex;
1576 }
1577
1578 void QDeclarativeGridView::setCurrentIndex(int index)
1579 {
1580     Q_D(QDeclarativeGridView);
1581     if (d->requestedIndex >= 0) // currently creating item
1582         return;
1583     d->currentIndexCleared = (index == -1);
1584     if (index == d->currentIndex)
1585         return;
1586     if (isComponentComplete() && d->isValid()) {
1587         if (d->layoutScheduled)
1588             d->layout();
1589         d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1590         d->updateCurrent(index);
1591     } else {
1592         d->currentIndex = index;
1593         emit currentIndexChanged();
1594     }
1595 }
1596
1597 QDeclarativeItem *QDeclarativeGridView::currentItem()
1598 {
1599     Q_D(QDeclarativeGridView);
1600     if (!d->currentItem)
1601         return 0;
1602     return d->currentItem->item;
1603 }
1604
1605 /*!
1606   \qmlproperty Item GridView::highlightItem
1607
1608   This holds the highlight item created from the \l highlight component.
1609
1610   The highlightItem is managed by the view unless
1611   \l highlightFollowsCurrentItem is set to false.
1612
1613   \sa highlight, highlightFollowsCurrentItem
1614 */
1615 QDeclarativeItem *QDeclarativeGridView::highlightItem()
1616 {
1617     Q_D(QDeclarativeGridView);
1618     if (!d->highlight)
1619         return 0;
1620     return d->highlight->item;
1621 }
1622
1623 /*!
1624   \qmlproperty int GridView::count
1625   This property holds the number of items in the view.
1626 */
1627 int QDeclarativeGridView::count() const
1628 {
1629     Q_D(const QDeclarativeGridView);
1630     if (d->model)
1631         return d->model->count();
1632     return 0;
1633 }
1634
1635 /*!
1636   \qmlproperty Component GridView::highlight
1637   This property holds the component to use as the highlight.
1638
1639   An instance of the highlight component is created for each view.
1640   The geometry of the resulting component instance will be managed by the view
1641   so as to stay with the current item, unless the highlightFollowsCurrentItem property is false.
1642
1643   \sa highlightItem, highlightFollowsCurrentItem
1644 */
1645 QDeclarativeComponent *QDeclarativeGridView::highlight() const
1646 {
1647     Q_D(const QDeclarativeGridView);
1648     return d->highlightComponent;
1649 }
1650
1651 void QDeclarativeGridView::setHighlight(QDeclarativeComponent *highlight)
1652 {
1653     Q_D(QDeclarativeGridView);
1654     if (highlight != d->highlightComponent) {
1655         d->highlightComponent = highlight;
1656         d->updateCurrent(d->currentIndex);
1657         emit highlightChanged();
1658     }
1659 }
1660
1661 /*!
1662   \qmlproperty bool GridView::highlightFollowsCurrentItem
1663   This property sets whether the highlight is managed by the view.
1664
1665     If this property is true (the default value), the highlight is moved smoothly
1666     to follow the current item.  Otherwise, the
1667     highlight is not moved by the view, and any movement must be implemented
1668     by the highlight.  
1669     
1670     Here is a highlight with its motion defined by a \l {SpringAnimation} item:
1671
1672     \snippet doc/src/snippets/declarative/gridview/gridview.qml highlightFollowsCurrentItem
1673 */
1674 bool QDeclarativeGridView::highlightFollowsCurrentItem() const
1675 {
1676     Q_D(const QDeclarativeGridView);
1677     return d->autoHighlight;
1678 }
1679
1680 void QDeclarativeGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
1681 {
1682     Q_D(QDeclarativeGridView);
1683     if (d->autoHighlight != autoHighlight) {
1684         d->autoHighlight = autoHighlight;
1685         if (autoHighlight) {
1686             d->updateHighlight();
1687         } else if (d->highlightXAnimator) {
1688             d->highlightXAnimator->stop();
1689             d->highlightYAnimator->stop();
1690         }
1691     }
1692 }
1693
1694 /*!
1695     \qmlproperty int GridView::highlightMoveDuration
1696     This property holds the move animation duration of the highlight delegate.
1697
1698     highlightFollowsCurrentItem must be true for this property
1699     to have effect.
1700
1701     The default value for the duration is 150ms.
1702
1703     \sa highlightFollowsCurrentItem
1704 */
1705 int QDeclarativeGridView::highlightMoveDuration() const
1706 {
1707     Q_D(const QDeclarativeGridView);
1708     return d->highlightMoveDuration;
1709 }
1710
1711 void QDeclarativeGridView::setHighlightMoveDuration(int duration)
1712 {
1713     Q_D(QDeclarativeGridView);
1714     if (d->highlightMoveDuration != duration) {
1715         d->highlightMoveDuration = duration;
1716         if (d->highlightYAnimator) {
1717             d->highlightXAnimator->userDuration = d->highlightMoveDuration;
1718             d->highlightYAnimator->userDuration = d->highlightMoveDuration;
1719         }
1720         emit highlightMoveDurationChanged();
1721     }
1722 }
1723
1724
1725 /*!
1726     \qmlproperty real GridView::preferredHighlightBegin
1727     \qmlproperty real GridView::preferredHighlightEnd
1728     \qmlproperty enumeration GridView::highlightRangeMode
1729
1730     These properties define the preferred range of the highlight (for the current item)
1731     within the view. The \c preferredHighlightBegin value must be less than the
1732     \c preferredHighlightEnd value. 
1733
1734     These properties affect the position of the current item when the view is scrolled.
1735     For example, if the currently selected item should stay in the middle of the
1736     view when it is scrolled, set the \c preferredHighlightBegin and 
1737     \c preferredHighlightEnd values to the top and bottom coordinates of where the middle 
1738     item would be. If the \c currentItem is changed programmatically, the view will
1739     automatically scroll so that the current item is in the middle of the view.
1740     Furthermore, the behavior of the current item index will occur whether or not a
1741     highlight exists.
1742
1743     Valid values for \c highlightRangeMode are:
1744
1745     \list
1746     \o GridView.ApplyRange - the view attempts to maintain the highlight within the range.
1747        However, the highlight can move outside of the range at the ends of the view or due
1748        to mouse interaction.
1749     \o GridView.StrictlyEnforceRange - the highlight never moves outside of the range.
1750        The current item changes if a keyboard or mouse action would cause the highlight to move
1751        outside of the range.
1752     \o GridView.NoHighlightRange - this is the default value.
1753     \endlist
1754 */
1755 qreal QDeclarativeGridView::preferredHighlightBegin() const
1756 {
1757     Q_D(const QDeclarativeGridView);
1758     return d->highlightRangeStart;
1759 }
1760
1761 void QDeclarativeGridView::setPreferredHighlightBegin(qreal start)
1762 {
1763     Q_D(QDeclarativeGridView);
1764     d->highlightRangeStartValid = true;
1765     if (d->highlightRangeStart == start)
1766         return;
1767     d->highlightRangeStart = start;
1768     d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1769     emit preferredHighlightBeginChanged();
1770 }
1771
1772 void QDeclarativeGridView::resetPreferredHighlightBegin()
1773 {
1774     Q_D(QDeclarativeGridView);
1775     d->highlightRangeStartValid = false;
1776     if (d->highlightRangeStart == 0)
1777         return;
1778     d->highlightRangeStart = 0;
1779     emit preferredHighlightBeginChanged();
1780 }
1781
1782 qreal QDeclarativeGridView::preferredHighlightEnd() const
1783 {
1784     Q_D(const QDeclarativeGridView);
1785     return d->highlightRangeEnd;
1786 }
1787
1788 void QDeclarativeGridView::setPreferredHighlightEnd(qreal end)
1789 {
1790     Q_D(QDeclarativeGridView);
1791     d->highlightRangeEndValid = true;
1792     if (d->highlightRangeEnd == end)
1793         return;
1794     d->highlightRangeEnd = end;
1795     d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1796     emit preferredHighlightEndChanged();
1797 }
1798
1799 void QDeclarativeGridView::resetPreferredHighlightEnd()
1800 {
1801     Q_D(QDeclarativeGridView);
1802     d->highlightRangeEndValid = false;
1803     if (d->highlightRangeEnd == 0)
1804         return;
1805     d->highlightRangeEnd = 0;
1806     emit preferredHighlightEndChanged();
1807 }
1808
1809 QDeclarativeGridView::HighlightRangeMode QDeclarativeGridView::highlightRangeMode() const
1810 {
1811     Q_D(const QDeclarativeGridView);
1812     return d->highlightRange;
1813 }
1814
1815 void QDeclarativeGridView::setHighlightRangeMode(HighlightRangeMode mode)
1816 {
1817     Q_D(QDeclarativeGridView);
1818     if (d->highlightRange == mode)
1819         return;
1820     d->highlightRange = mode;
1821     d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1822     emit highlightRangeModeChanged();
1823 }
1824
1825 /*!
1826   \qmlproperty enumeration GridView::layoutDirection
1827   This property holds the layout direction of the grid.
1828
1829     Possible values:
1830
1831   \list
1832   \o Qt.LeftToRight (default) - Items will be laid out starting in the top, left corner. The flow is
1833   dependent on the \l GridView::flow property.
1834   \o Qt.RightToLeft - Items will be laid out starting in the top, right corner. The flow is dependent
1835   on the \l GridView::flow property.
1836   \endlist
1837
1838   When using the attached property \l {LayoutMirroring::enabled} for locale layouts,
1839   the layout direction of the grid view will be mirrored. However, the actual property
1840   \c layoutDirection will remain unchanged. You can use the property
1841   \l {LayoutMirroring::enabled} to determine whether the direction has been mirrored.
1842
1843   \sa {LayoutMirroring}{LayoutMirroring}
1844 */
1845
1846 Qt::LayoutDirection QDeclarativeGridView::layoutDirection() const
1847 {
1848     Q_D(const QDeclarativeGridView);
1849     return d->layoutDirection;
1850 }
1851
1852 void QDeclarativeGridView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1853 {
1854     Q_D(QDeclarativeGridView);
1855     if (d->layoutDirection != layoutDirection) {
1856         d->layoutDirection = layoutDirection;
1857         d->regenerate();
1858         emit layoutDirectionChanged();
1859     }
1860 }
1861
1862 Qt::LayoutDirection QDeclarativeGridView::effectiveLayoutDirection() const
1863 {
1864     Q_D(const QDeclarativeGridView);
1865     if (d->effectiveLayoutMirror)
1866         return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
1867     else
1868         return d->layoutDirection;
1869 }
1870
1871 /*!
1872   \qmlproperty enumeration GridView::flow
1873   This property holds the flow of the grid.
1874
1875     Possible values:
1876
1877     \list
1878     \o GridView.LeftToRight (default) - Items are laid out from left to right, and the view scrolls vertically
1879     \o GridView.TopToBottom - Items are laid out from top to bottom, and the view scrolls horizontally
1880     \endlist
1881 */
1882 QDeclarativeGridView::Flow QDeclarativeGridView::flow() const
1883 {
1884     Q_D(const QDeclarativeGridView);
1885     return d->flow;
1886 }
1887
1888 void QDeclarativeGridView::setFlow(Flow flow)
1889 {
1890     Q_D(QDeclarativeGridView);
1891     if (d->flow != flow) {
1892         d->flow = flow;
1893         if (d->flow == LeftToRight) {
1894             setContentWidth(-1);
1895             setFlickableDirection(QDeclarativeFlickable::VerticalFlick);
1896         } else {
1897             setContentHeight(-1);
1898             setFlickableDirection(QDeclarativeFlickable::HorizontalFlick);
1899         }
1900         setContentX(0);
1901         setContentY(0);
1902         d->regenerate();
1903         emit flowChanged();
1904     }
1905 }
1906
1907 /*!
1908   \qmlproperty bool GridView::keyNavigationWraps
1909   This property holds whether the grid wraps key navigation
1910
1911     If this is true, key navigation that would move the current item selection
1912     past one end of the view instead wraps around and moves the selection to
1913     the other end of the view.
1914
1915     By default, key navigation is not wrapped.
1916 */
1917 bool QDeclarativeGridView::isWrapEnabled() const
1918 {
1919     Q_D(const QDeclarativeGridView);
1920     return d->wrap;
1921 }
1922
1923 void QDeclarativeGridView::setWrapEnabled(bool wrap)
1924 {
1925     Q_D(QDeclarativeGridView);
1926     if (d->wrap == wrap)
1927         return;
1928     d->wrap = wrap;
1929     emit keyNavigationWrapsChanged();
1930 }
1931
1932 /*!
1933     \qmlproperty int GridView::cacheBuffer
1934     This property determines whether delegates are retained outside the
1935     visible area of the view.
1936
1937     If non-zero the view will keep as many delegates
1938     instantiated as will fit within the buffer specified.  For example,
1939     if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
1940     set to 40, then up to 2 delegates above and 2 delegates below the visible
1941     area may be retained.
1942
1943     Note that cacheBuffer is not a pixel buffer - it only maintains additional
1944     instantiated delegates.
1945
1946     Setting this value can make scrolling the list smoother at the expense
1947     of additional memory usage.  It is not a substitute for creating efficient
1948     delegates; the fewer elements in a delegate, the faster a view may be
1949     scrolled.
1950 */
1951 int QDeclarativeGridView::cacheBuffer() const
1952 {
1953     Q_D(const QDeclarativeGridView);
1954     return d->buffer;
1955 }
1956
1957 void QDeclarativeGridView::setCacheBuffer(int buffer)
1958 {
1959     Q_D(QDeclarativeGridView);
1960     if (d->buffer != buffer) {
1961         d->buffer = buffer;
1962         if (isComponentComplete())
1963             refill();
1964         emit cacheBufferChanged();
1965     }
1966 }
1967
1968 /*!
1969   \qmlproperty int GridView::cellWidth
1970   \qmlproperty int GridView::cellHeight
1971
1972   These properties holds the width and height of each cell in the grid.
1973
1974   The default cell size is 100x100.
1975 */
1976 int QDeclarativeGridView::cellWidth() const
1977 {
1978     Q_D(const QDeclarativeGridView);
1979     return d->cellWidth;
1980 }
1981
1982 void QDeclarativeGridView::setCellWidth(int cellWidth)
1983 {
1984     Q_D(QDeclarativeGridView);
1985     if (cellWidth != d->cellWidth && cellWidth > 0) {
1986         d->cellWidth = qMax(1, cellWidth);
1987         d->updateGrid();
1988         emit cellWidthChanged();
1989         d->layout();
1990     }
1991 }
1992
1993 int QDeclarativeGridView::cellHeight() const
1994 {
1995     Q_D(const QDeclarativeGridView);
1996     return d->cellHeight;
1997 }
1998
1999 void QDeclarativeGridView::setCellHeight(int cellHeight)
2000 {
2001     Q_D(QDeclarativeGridView);
2002     if (cellHeight != d->cellHeight && cellHeight > 0) {
2003         d->cellHeight = qMax(1, cellHeight);
2004         d->updateGrid();
2005         emit cellHeightChanged();
2006         d->layout();
2007     }
2008 }
2009 /*!
2010     \qmlproperty enumeration GridView::snapMode
2011
2012     This property determines how the view scrolling will settle following a drag or flick.
2013     The possible values are:
2014
2015     \list
2016     \o GridView.NoSnap (default) - the view stops anywhere within the visible area.
2017     \o GridView.SnapToRow - the view settles with a row (or column for \c GridView.TopToBottom flow)
2018     aligned with the start of the view.
2019     \o GridView.SnapOneRow - the view will settle no more than one row (or column for \c GridView.TopToBottom flow)
2020     away from the first visible row at the time the mouse button is released.
2021     This mode is particularly useful for moving one page at a time.
2022     \endlist
2023
2024 */
2025 QDeclarativeGridView::SnapMode QDeclarativeGridView::snapMode() const
2026 {
2027     Q_D(const QDeclarativeGridView);
2028     return d->snapMode;
2029 }
2030
2031 void QDeclarativeGridView::setSnapMode(SnapMode mode)
2032 {
2033     Q_D(QDeclarativeGridView);
2034     if (d->snapMode != mode) {
2035         d->snapMode = mode;
2036         emit snapModeChanged();
2037     }
2038 }
2039
2040 /*!
2041     \qmlproperty Component GridView::footer
2042     This property holds the component to use as the footer.
2043
2044     An instance of the footer component is created for each view.  The
2045     footer is positioned at the end of the view, after any items.
2046
2047     \sa header
2048 */
2049 QDeclarativeComponent *QDeclarativeGridView::footer() const
2050 {
2051     Q_D(const QDeclarativeGridView);
2052     return d->footerComponent;
2053 }
2054
2055 void QDeclarativeGridView::setFooter(QDeclarativeComponent *footer)
2056 {
2057     Q_D(QDeclarativeGridView);
2058     if (d->footerComponent != footer) {
2059         if (d->footer) {
2060             if (scene())
2061                 scene()->removeItem(d->footer->item);
2062             d->footer->item->deleteLater();
2063             delete d->footer;
2064             d->footer = 0;
2065         }
2066         d->footerComponent = footer;
2067         if (isComponentComplete()) {
2068             d->updateFooter();
2069             d->updateGrid();
2070             d->fixupPosition();
2071         }
2072         emit footerChanged();
2073     }
2074 }
2075
2076 /*!
2077     \qmlproperty Component GridView::header
2078     This property holds the component to use as the header.
2079
2080     An instance of the header component is created for each view.  The
2081     header is positioned at the beginning of the view, before any items.
2082
2083     \sa footer
2084 */
2085 QDeclarativeComponent *QDeclarativeGridView::header() const
2086 {
2087     Q_D(const QDeclarativeGridView);
2088     return d->headerComponent;
2089 }
2090
2091 void QDeclarativeGridView::setHeader(QDeclarativeComponent *header)
2092 {
2093     Q_D(QDeclarativeGridView);
2094     if (d->headerComponent != header) {
2095         if (d->header) {
2096             if (scene())
2097                 scene()->removeItem(d->header->item);
2098             d->header->item->deleteLater();
2099             delete d->header;
2100             d->header = 0;
2101         }
2102         d->headerComponent = header;
2103         if (isComponentComplete()) {
2104             d->updateHeader();
2105             d->updateFooter();
2106             d->updateGrid();
2107             d->fixupPosition();
2108         }
2109         emit headerChanged();
2110     }
2111 }
2112
2113 void QDeclarativeGridView::setContentX(qreal pos)
2114 {
2115     Q_D(QDeclarativeGridView);
2116     // Positioning the view manually should override any current movement state
2117     d->moveReason = QDeclarativeGridViewPrivate::Other;
2118     QDeclarativeFlickable::setContentX(pos);
2119 }
2120
2121 void QDeclarativeGridView::setContentY(qreal pos)
2122 {
2123     Q_D(QDeclarativeGridView);
2124     // Positioning the view manually should override any current movement state
2125     d->moveReason = QDeclarativeGridViewPrivate::Other;
2126     QDeclarativeFlickable::setContentY(pos);
2127 }
2128
2129 bool QDeclarativeGridView::event(QEvent *event)
2130 {
2131     Q_D(QDeclarativeGridView);
2132     if (event->type() == QEvent::User) {
2133         if (d->layoutScheduled)
2134             d->layout();
2135         return true;
2136     }
2137
2138     return QDeclarativeFlickable::event(event);
2139 }
2140
2141 void QDeclarativeGridView::viewportMoved()
2142 {
2143     Q_D(QDeclarativeGridView);
2144     QDeclarativeFlickable::viewportMoved();
2145     if (!d->itemCount)
2146         return;
2147     d->lazyRelease = true;
2148     if (d->hData.flicking || d->vData.flicking) {
2149         if (yflick()) {
2150             if (d->vData.velocity > 0)
2151                 d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore;
2152             else if (d->vData.velocity < 0)
2153                 d->bufferMode = QDeclarativeGridViewPrivate::BufferAfter;
2154         }
2155
2156         if (xflick()) {
2157             if (d->hData.velocity > 0)
2158                 d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore;
2159             else if (d->hData.velocity < 0)
2160                 d->bufferMode = QDeclarativeGridViewPrivate::BufferAfter;
2161         }
2162     }
2163     refill();
2164     if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2165         d->moveReason = QDeclarativeGridViewPrivate::Mouse;
2166     if (d->moveReason != QDeclarativeGridViewPrivate::SetIndex) {
2167         if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2168             // reposition highlight
2169             qreal pos = d->highlight->rowPos();
2170             qreal viewPos;
2171             qreal highlightStart;
2172             qreal highlightEnd;
2173             if (d->isRightToLeftTopToBottom()) {
2174                 highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
2175                 highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
2176                 viewPos = -d->position()-d->size();
2177             } else {
2178                 highlightStart = d->highlightRangeStart;
2179                 highlightEnd = d->highlightRangeEnd;
2180                 viewPos = d->position();
2181             }
2182             if (pos > viewPos + highlightEnd - d->rowSize())
2183                 pos = viewPos + highlightEnd - d->rowSize();
2184             if (pos < viewPos + highlightStart)
2185                 pos = viewPos + highlightStart;
2186
2187             d->highlight->setPosition(d->highlight->colPos(), qRound(pos));
2188
2189             // update current index
2190             int idx = d->snapIndex();
2191             if (idx >= 0 && idx != d->currentIndex) {
2192                 d->updateCurrent(idx);
2193                 if (d->currentItem && d->currentItem->colPos() != d->highlight->colPos() && d->autoHighlight) {
2194                     if (d->flow == LeftToRight)
2195                         d->highlightXAnimator->to = d->currentItem->item->x();
2196                     else
2197                         d->highlightYAnimator->to = d->currentItem->item->y();
2198                 }
2199             }
2200         }
2201     }
2202 }
2203
2204 qreal QDeclarativeGridView::minYExtent() const
2205 {
2206     Q_D(const QDeclarativeGridView);
2207     if (d->flow == QDeclarativeGridView::TopToBottom)
2208         return QDeclarativeFlickable::minYExtent();
2209     qreal extent = -d->startPosition();
2210     if (d->header && d->visibleItems.count())
2211         extent += d->header->item->height();
2212     if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2213         extent += d->highlightRangeStart;
2214         extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd));
2215     }
2216     return extent;
2217 }
2218
2219 qreal QDeclarativeGridView::maxYExtent() const
2220 {
2221     Q_D(const QDeclarativeGridView);
2222     if (d->flow == QDeclarativeGridView::TopToBottom)
2223         return QDeclarativeFlickable::maxYExtent();
2224     qreal extent;
2225     if (!d->model || !d->model->count()) {
2226         extent = 0;
2227     } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2228         extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart);
2229         if (d->highlightRangeEnd != d->highlightRangeStart)
2230             extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1));
2231     } else {
2232         extent = -(d->endPosition() - height());
2233     }
2234     if (d->footer)
2235         extent -= d->footer->item->height();
2236     const qreal minY = minYExtent();
2237     if (extent > minY)
2238         extent = minY;
2239     return extent;
2240 }
2241
2242 qreal QDeclarativeGridView::minXExtent() const
2243 {
2244     Q_D(const QDeclarativeGridView);
2245     if (d->flow == QDeclarativeGridView::LeftToRight)
2246         return QDeclarativeFlickable::minXExtent();
2247     qreal extent = -d->startPosition();
2248     qreal highlightStart;
2249     qreal highlightEnd;
2250     qreal endPositionFirstItem;
2251     if (d->isRightToLeftTopToBottom()) {
2252         endPositionFirstItem = d->rowPosAt(d->model->count()-1);
2253         highlightStart = d->highlightRangeStartValid
2254                 ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
2255                 : d->size() - (d->lastPosition()-endPositionFirstItem);
2256         highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
2257         if (d->footer && d->visibleItems.count())
2258             extent += d->footer->item->width();
2259     } else {
2260         endPositionFirstItem = d->rowPosAt(0)+d->rowSize();
2261         highlightStart = d->highlightRangeStart;
2262         highlightEnd = d->highlightRangeEnd;
2263         if (d->header && d->visibleItems.count())
2264             extent += d->header->item->width();
2265     }
2266     if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2267         extent += highlightStart;
2268         extent = qMax(extent, -(endPositionFirstItem - highlightEnd));
2269     }
2270     return extent;
2271 }
2272
2273 qreal QDeclarativeGridView::maxXExtent() const
2274 {
2275     Q_D(const QDeclarativeGridView);
2276     if (d->flow == QDeclarativeGridView::LeftToRight)
2277         return QDeclarativeFlickable::maxXExtent();
2278     qreal extent;
2279     qreal highlightStart;
2280     qreal highlightEnd;
2281     qreal lastItemPosition = 0;
2282     if (d->isRightToLeftTopToBottom()){
2283         highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
2284         highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
2285         lastItemPosition = d->endPosition();
2286     } else {
2287         highlightStart = d->highlightRangeStart;
2288         highlightEnd = d->highlightRangeEnd;
2289         lastItemPosition = 0;
2290         if (d->model && d->model->count())
2291             lastItemPosition = d->rowPosAt(d->model->count()-1);
2292     }
2293     if (!d->model || !d->model->count()) {
2294         extent = 0;
2295     } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2296         extent = -(lastItemPosition - highlightStart);
2297         if (highlightEnd != highlightStart)
2298             extent = d->isRightToLeftTopToBottom()
2299                     ? qMax(extent, -(d->endPosition() - highlightEnd + 1))
2300                     : qMin(extent, -(d->endPosition() - highlightEnd + 1));
2301     } else {
2302         extent = -(d->endPosition() - width());
2303     }
2304     if (d->isRightToLeftTopToBottom()) {
2305         if (d->header)
2306             extent -= d->header->item->width();
2307     } else {
2308         if (d->footer)
2309             extent -= d->footer->item->width();
2310     }
2311
2312     const qreal minX = minXExtent();
2313     if (extent > minX)
2314         extent = minX;
2315     return extent;
2316 }
2317
2318 void QDeclarativeGridView::keyPressEvent(QKeyEvent *event)
2319 {
2320     Q_D(QDeclarativeGridView);
2321     keyPressPreHandler(event);
2322     if (event->isAccepted())
2323         return;
2324     if (d->model && d->model->count() && d->interactive) {
2325         d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
2326         int oldCurrent = currentIndex();
2327         switch (event->key()) {
2328         case Qt::Key_Up:
2329             moveCurrentIndexUp();
2330             break;
2331         case Qt::Key_Down:
2332             moveCurrentIndexDown();
2333             break;
2334         case Qt::Key_Left:
2335             moveCurrentIndexLeft();
2336             break;
2337         case Qt::Key_Right:
2338             moveCurrentIndexRight();
2339             break;
2340         default:
2341             break;
2342         }
2343         if (oldCurrent != currentIndex()) {
2344             event->accept();
2345             return;
2346         }
2347     }
2348     d->moveReason = QDeclarativeGridViewPrivate::Other;
2349     event->ignore();
2350     QDeclarativeFlickable::keyPressEvent(event);
2351 }
2352
2353 /*!
2354     \qmlmethod GridView::moveCurrentIndexUp()
2355
2356     Move the currentIndex up one item in the view.
2357     The current index will wrap if keyNavigationWraps is true and it
2358     is currently at the end. This method has no effect if the \l count is zero.
2359
2360     \bold Note: methods should only be called after the Component has completed.
2361 */
2362 void QDeclarativeGridView::moveCurrentIndexUp()
2363 {
2364     Q_D(QDeclarativeGridView);
2365     const int count = d->model ? d->model->count() : 0;
2366     if (!count)
2367         return;
2368     if (d->flow == QDeclarativeGridView::LeftToRight) {
2369         if (currentIndex() >= d->columns || d->wrap) {
2370             int index = currentIndex() - d->columns;
2371             setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2372         }
2373     } else {
2374         if (currentIndex() > 0 || d->wrap) {
2375             int index = currentIndex() - 1;
2376             setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2377         }
2378     }
2379 }
2380
2381 /*!
2382     \qmlmethod GridView::moveCurrentIndexDown()
2383
2384     Move the currentIndex down one item in the view.
2385     The current index will wrap if keyNavigationWraps is true and it
2386     is currently at the end. This method has no effect if the \l count is zero.
2387
2388     \bold Note: methods should only be called after the Component has completed.
2389 */
2390 void QDeclarativeGridView::moveCurrentIndexDown()
2391 {
2392     Q_D(QDeclarativeGridView);
2393     const int count = d->model ? d->model->count() : 0;
2394     if (!count)
2395         return;
2396     if (d->flow == QDeclarativeGridView::LeftToRight) {
2397         if (currentIndex() < count - d->columns || d->wrap) {
2398             int index = currentIndex()+d->columns;
2399             setCurrentIndex((index >= 0 && index < count) ? index : 0);
2400         }
2401     } else {
2402         if (currentIndex() < count - 1 || d->wrap) {
2403             int index = currentIndex() + 1;
2404             setCurrentIndex((index >= 0 && index < count) ? index : 0);
2405         }
2406     }
2407 }
2408
2409 /*!
2410     \qmlmethod GridView::moveCurrentIndexLeft()
2411
2412     Move the currentIndex left one item in the view.
2413     The current index will wrap if keyNavigationWraps is true and it
2414     is currently at the end. This method has no effect if the \l count is zero.
2415
2416     \bold Note: methods should only be called after the Component has completed.
2417 */
2418 void QDeclarativeGridView::moveCurrentIndexLeft()
2419 {
2420     Q_D(QDeclarativeGridView);
2421     const int count = d->model ? d->model->count() : 0;
2422     if (!count)
2423         return;
2424
2425     if (effectiveLayoutDirection() == Qt::LeftToRight) {
2426         if (d->flow == QDeclarativeGridView::LeftToRight) {
2427             if (currentIndex() > 0 || d->wrap) {
2428                 int index = currentIndex() - 1;
2429                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2430             }
2431         } else {
2432             if (currentIndex() >= d->columns || d->wrap) {
2433                 int index = currentIndex() - d->columns;
2434                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2435             }
2436         }
2437     } else {
2438         if (d->flow == QDeclarativeGridView::LeftToRight) {
2439             if (currentIndex() < count - 1 || d->wrap) {
2440                 int index = currentIndex() + 1;
2441                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2442             }
2443         } else {
2444             if (currentIndex() < count - d->columns || d->wrap) {
2445                 int index = currentIndex() + d->columns;
2446                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2447             }
2448         }
2449     }
2450 }
2451
2452 /*!
2453     \qmlmethod GridView::moveCurrentIndexRight()
2454
2455     Move the currentIndex right one item in the view.
2456     The current index will wrap if keyNavigationWraps is true and it
2457     is currently at the end. This method has no effect if the \l count is zero.
2458
2459     \bold Note: methods should only be called after the Component has completed.
2460 */
2461 void QDeclarativeGridView::moveCurrentIndexRight()
2462 {
2463     Q_D(QDeclarativeGridView);
2464     const int count = d->model ? d->model->count() : 0;
2465     if (!count)
2466         return;
2467
2468     if (effectiveLayoutDirection() == Qt::LeftToRight) {
2469         if (d->flow == QDeclarativeGridView::LeftToRight) {
2470             if (currentIndex() < count - 1 || d->wrap) {
2471                 int index = currentIndex() + 1;
2472                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2473             }
2474         } else {
2475             if (currentIndex() < count - d->columns || d->wrap) {
2476                 int index = currentIndex()+d->columns;
2477                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2478             }
2479         }
2480     } else {
2481         if (d->flow == QDeclarativeGridView::LeftToRight) {
2482             if (currentIndex() > 0 || d->wrap) {
2483                 int index = currentIndex() - 1;
2484                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2485             }
2486         } else {
2487             if (currentIndex() >= d->columns || d->wrap) {
2488                 int index = currentIndex() - d->columns;
2489                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2490             }
2491         }
2492     }
2493 }
2494
2495 void QDeclarativeGridViewPrivate::positionViewAtIndex(int index, int mode)
2496 {
2497     Q_Q(QDeclarativeGridView);
2498     if (!isValid())
2499         return;
2500     if (mode < QDeclarativeGridView::Beginning || mode > QDeclarativeGridView::Contain)
2501         return;
2502
2503     int idx = qMax(qMin(index, model->count()-1), 0);
2504
2505     if (layoutScheduled)
2506         layout();
2507     qreal pos = isRightToLeftTopToBottom() ? -position() - size() : position();
2508     FxGridItem *item = visibleItem(idx);
2509     qreal maxExtent;
2510     if (flow == QDeclarativeGridView::LeftToRight)
2511         maxExtent = -q->maxYExtent();
2512     else
2513         maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2514
2515     if (!item) {
2516         int itemPos = rowPosAt(idx);
2517         // save the currently visible items in case any of them end up visible again
2518         QList<FxGridItem*> oldVisible = visibleItems;
2519         visibleItems.clear();
2520         visibleIndex = idx - idx % columns;
2521         if (flow == QDeclarativeGridView::LeftToRight)
2522             maxExtent = -q->maxYExtent();
2523         else
2524             maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2525         setPosition(qMin(qreal(itemPos), maxExtent));
2526         // now release the reference to all the old visible items.
2527         for (int i = 0; i < oldVisible.count(); ++i)
2528             releaseItem(oldVisible.at(i));
2529         item = visibleItem(idx);
2530     }
2531     if (item) {
2532         qreal itemPos = item->rowPos();
2533         switch (mode) {
2534         case QDeclarativeGridView::Beginning:
2535             pos = itemPos;
2536             if (index < 0 && header) {
2537                 pos -= flow == QDeclarativeGridView::LeftToRight
2538                             ? header->item->height()
2539                             : header->item->width();
2540             }
2541             break;
2542         case QDeclarativeGridView::Center:
2543             pos = itemPos - (size() - rowSize())/2;
2544             break;
2545         case QDeclarativeGridView::End:
2546             pos = itemPos - size() + rowSize();
2547             if (index >= model->count() && footer) {
2548                 pos += flow == QDeclarativeGridView::LeftToRight
2549                             ? footer->item->height()
2550                             : footer->item->width();
2551             }
2552             break;
2553         case QDeclarativeGridView::Visible:
2554             if (itemPos > pos + size())
2555                 pos = itemPos - size() + rowSize();
2556             else if (item->endRowPos() < pos)
2557                 pos = itemPos;
2558             break;
2559         case QDeclarativeGridView::Contain:
2560             if (item->endRowPos() > pos + size())
2561                 pos = itemPos - size() + rowSize();
2562             if (itemPos < pos)
2563                 pos = itemPos;
2564         }
2565
2566         pos = qMin(pos, maxExtent);
2567         qreal minExtent;
2568         if (flow == QDeclarativeGridView::LeftToRight)
2569             minExtent = -q->minYExtent();
2570         else
2571             minExtent = isRightToLeftTopToBottom() ? q->maxXExtent()-size() : -q->minXExtent();
2572         pos = qMax(pos, minExtent);
2573         moveReason = QDeclarativeGridViewPrivate::Other;
2574         q->cancelFlick();
2575         setPosition(pos);
2576     }
2577     fixupPosition();
2578 }
2579
2580 /*!
2581     \qmlmethod GridView::positionViewAtIndex(int index, PositionMode mode)
2582
2583     Positions the view such that the \a index is at the position specified by
2584     \a mode:
2585
2586     \list
2587     \o GridView.Beginning - position item at the top (or left for \c GridView.TopToBottom flow) of the view.
2588     \o GridView.Center - position item in the center of the view.
2589     \o GridView.End - position item at bottom (or right for horizontal orientation) of the view.
2590     \o GridView.Visible - if any part of the item is visible then take no action, otherwise
2591     bring the item into view.
2592     \o GridView.Contain - ensure the entire item is visible.  If the item is larger than
2593     the view the item is positioned at the top (or left for \c GridView.TopToBottom flow) of the view.
2594     \endlist
2595
2596     If positioning the view at the index would cause empty space to be displayed at
2597     the beginning or end of the view, the view will be positioned at the boundary.
2598
2599     It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2600     at a particular index.  This is unreliable since removing items from the start
2601     of the view does not cause all other items to be repositioned.
2602     The correct way to bring an item into view is with \c positionViewAtIndex.
2603
2604     \bold Note: methods should only be called after the Component has completed.  To position
2605     the view at startup, this method should be called by Component.onCompleted.  For
2606     example, to position the view at the end:
2607
2608     \code
2609     Component.onCompleted: positionViewAtIndex(count - 1, GridView.Beginning)
2610     \endcode
2611 */
2612 void QDeclarativeGridView::positionViewAtIndex(int index, int mode)
2613 {
2614     Q_D(QDeclarativeGridView);
2615     if (!d->isValid() || index < 0 || index >= d->model->count())
2616         return;
2617     d->positionViewAtIndex(index, mode);
2618 }
2619
2620 /*!
2621     \qmlmethod GridView::positionViewAtBeginning()
2622     \qmlmethod GridView::positionViewAtEnd()
2623     \since QtQuick 1.1
2624
2625     Positions the view at the beginning or end, taking into account any header or footer.
2626
2627     It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2628     at a particular index.  This is unreliable since removing items from the start
2629     of the list does not cause all other items to be repositioned, and because
2630     the actual start of the view can vary based on the size of the delegates.
2631
2632     \bold Note: methods should only be called after the Component has completed.  To position
2633     the view at startup, this method should be called by Component.onCompleted.  For
2634     example, to position the view at the end on startup:
2635
2636     \code
2637     Component.onCompleted: positionViewAtEnd()
2638     \endcode
2639 */
2640 void QDeclarativeGridView::positionViewAtBeginning()
2641 {
2642     Q_D(QDeclarativeGridView);
2643     if (!d->isValid())
2644         return;
2645     d->positionViewAtIndex(-1, Beginning);
2646 }
2647
2648 void QDeclarativeGridView::positionViewAtEnd()
2649 {
2650     Q_D(QDeclarativeGridView);
2651     if (!d->isValid())
2652         return;
2653     d->positionViewAtIndex(d->model->count(), End);
2654 }
2655
2656 /*!
2657     \qmlmethod int GridView::indexAt(int x, int y)
2658
2659     Returns the index of the visible item containing the point \a x, \a y in content
2660     coordinates.  If there is no item at the point specified, or the item is
2661     not visible -1 is returned.
2662
2663     If the item is outside the visible area, -1 is returned, regardless of
2664     whether an item will exist at that point when scrolled into view.
2665
2666     \bold Note: methods should only be called after the Component has completed.
2667 */
2668 int QDeclarativeGridView::indexAt(qreal x, qreal y) const
2669 {
2670     Q_D(const QDeclarativeGridView);
2671     for (int i = 0; i < d->visibleItems.count(); ++i) {
2672         const FxGridItem *listItem = d->visibleItems.at(i);
2673         if(listItem->contains(x, y))
2674             return listItem->index;
2675     }
2676
2677     return -1;
2678 }
2679
2680 void QDeclarativeGridView::componentComplete()
2681 {
2682     Q_D(QDeclarativeGridView);
2683     QDeclarativeFlickable::componentComplete();
2684     d->updateHeader();
2685     d->updateFooter();
2686     d->updateGrid();
2687     if (d->isValid()) {
2688         refill();
2689         d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
2690         if (d->currentIndex < 0 && !d->currentIndexCleared)
2691             d->updateCurrent(0);
2692         else
2693             d->updateCurrent(d->currentIndex);
2694         if (d->highlight && d->currentItem) {
2695             if (d->autoHighlight)
2696                 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
2697             d->updateTrackedItem();
2698         }
2699         d->moveReason = QDeclarativeGridViewPrivate::Other;
2700         d->fixupPosition();
2701     }
2702 }
2703
2704 void QDeclarativeGridView::trackedPositionChanged()
2705 {
2706     Q_D(QDeclarativeGridView);
2707     if (!d->trackedItem || !d->currentItem)
2708         return;
2709     if (d->moveReason == QDeclarativeGridViewPrivate::SetIndex) {
2710         const qreal trackedPos = d->trackedItem->rowPos();
2711         qreal viewPos;
2712         qreal highlightStart;
2713         qreal highlightEnd;
2714         if (d->isRightToLeftTopToBottom()) {
2715             viewPos = -d->position()-d->size();
2716             highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
2717             highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
2718         } else {
2719             viewPos = d->position();
2720             highlightStart = d->highlightRangeStart;
2721             highlightEnd = d->highlightRangeEnd;
2722         }
2723         qreal pos = viewPos;
2724         if (d->haveHighlightRange) {
2725             if (d->highlightRange == StrictlyEnforceRange) {
2726                 if (trackedPos > pos + highlightEnd - d->rowSize())
2727                     pos = trackedPos - highlightEnd + d->rowSize();
2728                 if (trackedPos < pos + highlightStart)
2729                     pos = trackedPos - highlightStart;
2730             } else {
2731                 if (trackedPos < d->startPosition() + highlightStart) {
2732                     pos = d->startPosition();
2733                 } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + highlightEnd) {
2734                     pos = d->endPosition() - d->size() + 1;
2735                     if (pos < d->startPosition())
2736                         pos = d->startPosition();
2737                 } else {
2738                     if (trackedPos < viewPos + highlightStart) {
2739                         pos = trackedPos - highlightStart;
2740                     } else if (trackedPos > viewPos + highlightEnd - d->rowSize()) {
2741                         pos = trackedPos - highlightEnd + d->rowSize();
2742                     }
2743                 }
2744             }
2745         } else {
2746             if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) {
2747                 pos = qMax(trackedPos, d->currentItem->rowPos());
2748             } else if (d->trackedItem->endRowPos() >= viewPos + d->size()
2749                 && d->currentItem->endRowPos() >= viewPos + d->size()) {
2750                 if (d->trackedItem->endRowPos() <= d->currentItem->endRowPos()) {
2751                     pos = d->trackedItem->endRowPos() - d->size() + 1;
2752                     if (d->rowSize() > d->size())
2753                         pos = trackedPos;
2754                 } else {
2755                     pos = d->currentItem->endRowPos() - d->size() + 1;
2756                     if (d->rowSize() > d->size())
2757                         pos = d->currentItem->rowPos();
2758                 }
2759             }
2760         }
2761         if (viewPos != pos) {
2762             cancelFlick();
2763             d->calcVelocity = true;
2764             d->setPosition(pos);
2765             d->calcVelocity = false;
2766         }
2767     }
2768 }
2769
2770 void QDeclarativeGridView::itemsInserted(int modelIndex, int count)
2771 {
2772     Q_D(QDeclarativeGridView);
2773     if (!isComponentComplete())
2774         return;
2775
2776     int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
2777     if (index < 0) {
2778         int i = d->visibleItems.count() - 1;
2779         while (i > 0 && d->visibleItems.at(i)->index == -1)
2780             --i;
2781         if (d->visibleItems.at(i)->index + 1 == modelIndex) {
2782             // Special case of appending an item to the model.
2783             index = d->visibleIndex + d->visibleItems.count();
2784         } else {
2785             if (modelIndex <= d->visibleIndex) {
2786                 // Insert before visible items
2787                 d->visibleIndex += count;
2788                 for (int i = 0; i < d->visibleItems.count(); ++i) {
2789                     FxGridItem *listItem = d->visibleItems.at(i);
2790                     if (listItem->index != -1 && listItem->index >= modelIndex)
2791                         listItem->index += count;
2792                 }
2793             }
2794             if (d->currentIndex >= modelIndex) {
2795                 // adjust current item index
2796                 d->currentIndex += count;
2797                 if (d->currentItem)
2798                     d->currentItem->index = d->currentIndex;
2799                 emit currentIndexChanged();
2800             }
2801             d->scheduleLayout();
2802             d->itemCount += count;
2803             emit countChanged();
2804             return;
2805         }
2806     }
2807
2808     int insertCount = count;
2809     if (index < d->visibleIndex && d->visibleItems.count()) {
2810         insertCount -= d->visibleIndex - index;
2811         index = d->visibleIndex;
2812         modelIndex = d->visibleIndex;
2813     }
2814
2815     qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+d->width()+1 : d->position();
2816     int to = d->buffer+tempPos+d->size()-1;
2817     int colPos = 0;
2818     int rowPos = 0;
2819     if (d->visibleItems.count()) {
2820         index -= d->visibleIndex;
2821         if (index < d->visibleItems.count()) {
2822             colPos = d->visibleItems.at(index)->colPos();
2823             rowPos = d->visibleItems.at(index)->rowPos();
2824         } else {
2825             // appending items to visible list
2826             colPos = d->visibleItems.at(index-1)->colPos() + d->colSize();
2827             rowPos = d->visibleItems.at(index-1)->rowPos();
2828             if (colPos > d->colSize() * (d->columns-1)) {
2829                 colPos = 0;
2830                 rowPos += d->rowSize();
2831             }
2832         }
2833     } else if (d->itemCount == 0 && d->header) {
2834         rowPos = d->headerSize();
2835     }
2836
2837     // Update the indexes of the following visible items.
2838     for (int i = 0; i < d->visibleItems.count(); ++i) {
2839         FxGridItem *listItem = d->visibleItems.at(i);
2840         if (listItem->index != -1 && listItem->index >= modelIndex)
2841             listItem->index += count;
2842     }
2843
2844     bool addedVisible = false;
2845     QList<FxGridItem*> added;
2846     int i = 0;
2847     while (i < insertCount && rowPos <= to + d->rowSize()*(d->columns - (colPos/d->colSize()))/qreal(d->columns)) {
2848         if (!addedVisible) {
2849             d->scheduleLayout();
2850             addedVisible = true;
2851         }
2852         FxGridItem *item = d->createItem(modelIndex + i);
2853         d->visibleItems.insert(index, item);
2854         item->setPosition(colPos, rowPos);
2855         added.append(item);
2856         colPos += d->colSize();
2857         if (colPos > d->colSize() * (d->columns-1)) {
2858             colPos = 0;
2859             rowPos += d->rowSize();
2860         }
2861         ++index;
2862         ++i;
2863     }
2864     if (i < insertCount) {
2865         // We didn't insert all our new items, which means anything
2866         // beyond the current index is not visible - remove it.
2867         while (d->visibleItems.count() > index) {
2868             d->releaseItem(d->visibleItems.takeLast());
2869         }
2870     }
2871
2872     // update visibleIndex
2873     d->visibleIndex = 0;
2874     for (QList<FxGridItem*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2875         if ((*it)->index != -1) {
2876             d->visibleIndex = (*it)->index;
2877             break;
2878         }
2879     }
2880
2881     if (d->itemCount && d->currentIndex >= modelIndex) {
2882         // adjust current item index
2883         d->currentIndex += count;
2884         if (d->currentItem) {
2885             d->currentItem->index = d->currentIndex;
2886             d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
2887         }
2888         emit currentIndexChanged();
2889     } else if (d->itemCount == 0 && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
2890         setCurrentIndex(0);
2891     }
2892
2893     // everything is in order now - emit add() signal
2894     for (int j = 0; j < added.count(); ++j)
2895         added.at(j)->attached->emitAdd();
2896
2897     d->itemCount += count;
2898     emit countChanged();
2899 }
2900
2901 void QDeclarativeGridView::itemsRemoved(int modelIndex, int count)
2902 {
2903     Q_D(QDeclarativeGridView);
2904     if (!isComponentComplete())
2905         return;
2906
2907     d->itemCount -= count;
2908     bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count;
2909     bool removedVisible = false;
2910     // Remove the items from the visible list, skipping anything already marked for removal
2911     QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
2912     while (it != d->visibleItems.end()) {
2913         FxGridItem *item = *it;
2914         if (item->index == -1 || item->index < modelIndex) {
2915             // already removed, or before removed items
2916             if (item->index < modelIndex && !removedVisible) {
2917                 d->scheduleLayout();
2918                 removedVisible = true;
2919             }
2920             ++it;
2921         } else if (item->index >= modelIndex + count) {
2922             // after removed items
2923             item->index -= count;
2924             ++it;
2925         } else {
2926             // removed item
2927             if (!removedVisible) {
2928                 d->scheduleLayout();
2929                 removedVisible = true;
2930             }
2931             item->attached->emitRemove();
2932             if (item->attached->delayRemove()) {
2933                 item->index = -1;
2934                 connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
2935                 ++it;
2936             } else {
2937                 it = d->visibleItems.erase(it);
2938                 d->releaseItem(item);
2939             }
2940         }
2941     }
2942
2943     // If we removed items before visible items a layout may be
2944     // required to ensure item 0 is in the first column.
2945     if (!removedVisible && modelIndex < d->visibleIndex)
2946         d->scheduleLayout();
2947
2948     // fix current
2949     if (d->currentIndex >= modelIndex + count) {
2950         d->currentIndex -= count;
2951         if (d->currentItem)
2952             d->currentItem->index -= count;
2953         emit currentIndexChanged();
2954     } else if (currentRemoved) {
2955         // current item has been removed.
2956         d->releaseItem(d->currentItem);
2957         d->currentItem = 0;
2958         d->currentIndex = -1;
2959         if (d->itemCount)
2960             d->updateCurrent(qMin(modelIndex, d->itemCount-1));
2961         else
2962             emit currentIndexChanged();
2963     }
2964
2965     // update visibleIndex
2966     d->visibleIndex = 0;
2967     for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2968         if ((*it)->index != -1) {
2969             d->visibleIndex = (*it)->index;
2970             break;
2971         }
2972     }
2973
2974     if (removedVisible && d->visibleItems.isEmpty()) {
2975         d->timeline.clear();
2976         if (d->itemCount == 0) {
2977             d->setPosition(0);
2978             d->updateHeader();
2979             d->updateFooter();
2980             update();
2981         }
2982     }
2983
2984     emit countChanged();
2985 }
2986
2987 void QDeclarativeGridView::destroyRemoved()
2988 {
2989     Q_D(QDeclarativeGridView);
2990     for (QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
2991             it != d->visibleItems.end();) {
2992         FxGridItem *listItem = *it;
2993         if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
2994             d->releaseItem(listItem);
2995             it = d->visibleItems.erase(it);
2996         } else {
2997             ++it;
2998         }
2999     }
3000
3001     // Correct the positioning of the items
3002     d->layout();
3003 }
3004
3005 void QDeclarativeGridView::itemsMoved(int from, int to, int count)
3006 {
3007     Q_D(QDeclarativeGridView);
3008     if (!isComponentComplete())
3009         return;
3010     QHash<int,FxGridItem*> moved;
3011
3012     FxGridItem *firstItem = d->firstVisibleItem();
3013
3014     QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
3015     while (it != d->visibleItems.end()) {
3016         FxGridItem *item = *it;
3017         if (item->index >= from && item->index < from + count) {
3018             // take the items that are moving
3019             item->index += (to-from);
3020             moved.insert(item->index, item);
3021             it = d->visibleItems.erase(it);
3022         } else {
3023             if (item->index > from && item->index != -1) {
3024                 // move everything after the moved items.
3025                 item->index -= count;
3026                 if (item->index < d->visibleIndex)
3027                     d->visibleIndex = item->index;
3028             }
3029             ++it;
3030         }
3031     }
3032
3033     int remaining = count;
3034     int endIndex = d->visibleIndex;
3035     it = d->visibleItems.begin();
3036     while (it != d->visibleItems.end()) {
3037         FxGridItem *item = *it;
3038         if (remaining && item->index >= to && item->index < to + count) {
3039             // place items in the target position, reusing any existing items
3040             FxGridItem *movedItem = moved.take(item->index);
3041             if (!movedItem)
3042                 movedItem = d->createItem(item->index);
3043             it = d->visibleItems.insert(it, movedItem);
3044             if (it == d->visibleItems.begin() && firstItem)
3045                 movedItem->setPosition(firstItem->colPos(), firstItem->rowPos());
3046             ++it;
3047             --remaining;
3048         } else {
3049             if (item->index != -1) {
3050                 if (item->index >= to) {
3051                     // update everything after the moved items.
3052                     item->index += count;
3053                 }
3054                 endIndex = item->index;
3055             }
3056             ++it;
3057         }
3058     }
3059
3060     // If we have moved items to the end of the visible items
3061     // then add any existing moved items that we have
3062     while (FxGridItem *item = moved.take(endIndex+1)) {
3063         d->visibleItems.append(item);
3064         ++endIndex;
3065     }
3066
3067     // update visibleIndex
3068     for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
3069         if ((*it)->index != -1) {
3070             d->visibleIndex = (*it)->index;
3071             break;
3072         }
3073     }
3074
3075     // Fix current index
3076     if (d->currentIndex >= 0 && d->currentItem) {
3077         int oldCurrent = d->currentIndex;
3078         d->currentIndex = d->model->indexOf(d->currentItem->item, this);
3079         if (oldCurrent != d->currentIndex) {
3080             d->currentItem->index = d->currentIndex;
3081             emit currentIndexChanged();
3082         }
3083     }
3084
3085     // Whatever moved items remain are no longer visible items.
3086     while (moved.count()) {
3087         int idx = moved.begin().key();
3088         FxGridItem *item = moved.take(idx);
3089         if (d->currentItem && item->item == d->currentItem->item)
3090             item->setPosition(d->colPosAt(idx), d->rowPosAt(idx));
3091         d->releaseItem(item);
3092     }
3093
3094     d->layout();
3095 }
3096
3097 void QDeclarativeGridView::modelReset()
3098 {
3099     Q_D(QDeclarativeGridView);
3100     d->clear();
3101     refill();
3102     d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
3103     d->updateCurrent(d->currentIndex);
3104     if (d->highlight && d->currentItem) {
3105         if (d->autoHighlight)
3106             d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
3107         d->updateTrackedItem();
3108     }
3109     d->moveReason = QDeclarativeGridViewPrivate::Other;
3110
3111     emit countChanged();
3112 }
3113
3114 void QDeclarativeGridView::createdItem(int index, QDeclarativeItem *item)
3115 {
3116     Q_D(QDeclarativeGridView);
3117     if (d->requestedIndex != index) {
3118         item->setParentItem(this);
3119         d->unrequestedItems.insert(item, index);
3120         if (d->flow == QDeclarativeGridView::LeftToRight) {
3121             item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index)));
3122         } else {
3123             item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index)));
3124         }
3125     }
3126 }
3127
3128 void QDeclarativeGridView::destroyingItem(QDeclarativeItem *item)
3129 {
3130     Q_D(QDeclarativeGridView);
3131     d->unrequestedItems.remove(item);
3132 }
3133
3134 void QDeclarativeGridView::animStopped()
3135 {
3136     Q_D(QDeclarativeGridView);
3137     d->bufferMode = QDeclarativeGridViewPrivate::NoBuffer;
3138     if (d->haveHighlightRange && d->highlightRange == QDeclarativeGridView::StrictlyEnforceRange)
3139         d->updateHighlight();
3140 }
3141
3142 void QDeclarativeGridView::refill()
3143 {
3144     Q_D(QDeclarativeGridView);
3145     if (d->isRightToLeftTopToBottom())
3146         d->refill(-d->position()-d->size()+1, -d->position());
3147     else
3148         d->refill(d->position(), d->position()+d->size()-1);
3149 }
3150
3151
3152 QDeclarativeGridViewAttached *QDeclarativeGridView::qmlAttachedProperties(QObject *obj)
3153 {
3154     return new QDeclarativeGridViewAttached(obj);
3155 }
3156
3157 QT_END_NAMESPACE