Initial import from qtquick2.
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsggridview.cpp
1 // Commit: cc6408ccd5453d1bed9f98b9caa14861cea5742b
2 /****************************************************************************
3 **
4 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
5 ** All rights reserved.
6 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 **
8 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** No Commercial Usage
12 ** This file contains pre-release code and may not be distributed.
13 ** You may use this file in accordance with the terms and conditions
14 ** contained in the Technology Preview License Agreement accompanying
15 ** this package.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 **
39 ** $QT_END_LICENSE$
40 **
41 ****************************************************************************/
42
43 #include "qsggridview_p.h"
44 #include "qsgvisualitemmodel_p.h"
45 #include "qsgflickable_p_p.h"
46
47 #include <private/qdeclarativesmoothedanimation_p_p.h>
48 #include <private/qlistmodelinterface_p.h>
49
50 #include <QtGui/qevent.h>
51 #include <QtCore/qmath.h>
52 #include <QtCore/qcoreapplication.h>
53 #include <math.h>
54
55 QT_BEGIN_NAMESPACE
56
57 //----------------------------------------------------------------------------
58
59 class FxGridItemSG
60 {
61 public:
62     FxGridItemSG(QSGItem *i, QSGGridView *v) : item(i), view(v) {
63         attached = static_cast<QSGGridViewAttached*>(qmlAttachedPropertiesObject<QSGGridView>(item));
64         if (attached)
65             attached->setView(view);
66     }
67     ~FxGridItemSG() {}
68
69     qreal rowPos() const {
70         qreal rowPos = 0;
71         if (view->flow() == QSGGridView::LeftToRight) {
72             rowPos = item->y();
73         } else {
74             if (view->effectiveLayoutDirection() == Qt::RightToLeft)
75                 rowPos = -view->cellWidth()-item->x();
76             else
77                 rowPos = item->x();
78         }
79         return rowPos;
80     }
81     qreal colPos() const {
82         qreal colPos = 0;
83         if (view->flow() == QSGGridView::LeftToRight) {
84             if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
85                 int colSize = view->cellWidth();
86                 int columns = view->width()/colSize;
87                 colPos = colSize * (columns-1) - item->x();
88             } else {
89                 colPos = item->x();
90             }
91         } else {
92             colPos = item->y();
93         }
94
95         return colPos;
96     }
97     qreal endRowPos() const {
98         if (view->flow() == QSGGridView::LeftToRight) {
99             return item->y() + view->cellHeight() - 1;
100         } else {
101             if (view->effectiveLayoutDirection() == Qt::RightToLeft)
102                 return -item->x() - 1;
103             else
104                 return item->x() + view->cellWidth() - 1;
105         }
106     }
107     void setPosition(qreal col, qreal row) {
108         if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
109             if (view->flow() == QSGGridView::LeftToRight) {
110                 int columns = view->width()/view->cellWidth();
111                 item->setPos(QPointF((view->cellWidth() * (columns-1) - col), row));
112             } else {
113                 item->setPos(QPointF(-view->cellWidth()-row, col));
114             }
115         } else {
116             if (view->flow() == QSGGridView::LeftToRight)
117                 item->setPos(QPointF(col, row));
118             else
119                 item->setPos(QPointF(row, col));
120         }
121     }
122     bool contains(qreal x, qreal y) const {
123         return (x >= item->x() && x < item->x() + view->cellWidth() &&
124                 y >= item->y() && y < item->y() + view->cellHeight());
125     }
126
127     QSGItem *item;
128     QSGGridView *view;
129     QSGGridViewAttached *attached;
130     int index;
131 };
132
133 //----------------------------------------------------------------------------
134
135 class QSGGridViewPrivate : public QSGFlickablePrivate
136 {
137     Q_DECLARE_PUBLIC(QSGGridView)
138
139 public:
140     QSGGridViewPrivate()
141     : currentItem(0), layoutDirection(Qt::LeftToRight), flow(QSGGridView::LeftToRight)
142     , visibleIndex(0) , currentIndex(-1)
143     , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1), itemCount(0)
144     , highlightRangeStart(0), highlightRangeEnd(0)
145     , highlightRange(QSGGridView::NoHighlightRange)
146     , highlightComponent(0), highlight(0), trackedItem(0)
147     , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0)
148     , highlightMoveDuration(150)
149     , footerComponent(0), footer(0), headerComponent(0), header(0)
150     , bufferMode(BufferBefore | BufferAfter), snapMode(QSGGridView::NoSnap)
151     , ownModel(false), wrap(false), autoHighlight(true)
152     , fixCurrentVisibility(false), lazyRelease(false), layoutScheduled(false)
153     , deferredRelease(false), haveHighlightRange(false), currentIndexCleared(false)
154     , highlightRangeStartValid(false), highlightRangeEndValid(false) {}
155
156     void init();
157     void clear();
158     FxGridItemSG *createItem(int modelIndex);
159     void releaseItem(FxGridItemSG *item);
160     void refill(qreal from, qreal to, bool doBuffer=false);
161
162     void updateGrid();
163     void scheduleLayout();
164     void layout();
165     void updateUnrequestedIndexes();
166     void updateUnrequestedPositions();
167     void updateTrackedItem();
168     void createHighlight();
169     void updateHighlight();
170     void updateCurrent(int modelIndex);
171     void updateHeader();
172     void updateFooter();
173     void fixupPosition();
174
175     FxGridItemSG *visibleItem(int modelIndex) const {
176         if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
177             for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
178                 FxGridItemSG *item = visibleItems.at(i);
179                 if (item->index == modelIndex)
180                     return item;
181             }
182         }
183         return 0;
184     }
185
186     bool isRightToLeftTopToBottom() const {
187         Q_Q(const QSGGridView);
188         return flow == QSGGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft;
189     }
190
191     void regenerate() {
192         Q_Q(QSGGridView);
193         if (q->isComponentComplete()) {
194             clear();
195             updateGrid();
196             setPosition(0);
197             q->refill();
198             updateCurrent(currentIndex);
199         }
200     }
201
202     void mirrorChange() {
203         Q_Q(QSGGridView);
204         regenerate();
205         emit q->effectiveLayoutDirectionChanged();
206     }
207
208     qreal position() const {
209         Q_Q(const QSGGridView);
210         return flow == QSGGridView::LeftToRight ? q->contentY() : q->contentX();
211     }
212     void setPosition(qreal pos) {
213         Q_Q(QSGGridView);
214         if (flow == QSGGridView::LeftToRight) {
215             q->QSGFlickable::setContentY(pos);
216             q->QSGFlickable::setContentX(0);
217         } else {
218             if (q->effectiveLayoutDirection() == Qt::LeftToRight)
219                 q->QSGFlickable::setContentX(pos);
220             else
221                 q->QSGFlickable::setContentX(-pos-size());
222             q->QSGFlickable::setContentY(0);
223         }
224     }
225     int size() const {
226         Q_Q(const QSGGridView);
227         return flow == QSGGridView::LeftToRight ? q->height() : q->width();
228     }
229     qreal originPosition() const {
230         qreal pos = 0;
231         if (!visibleItems.isEmpty())
232             pos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
233         return pos;
234     }
235
236     qreal lastPosition() const {
237         qreal pos = 0;
238         if (model && model->count())
239             pos = rowPosAt(model->count() - 1) + rowSize();
240         return pos;
241     }
242
243     qreal startPosition() const {
244         return isRightToLeftTopToBottom() ? -lastPosition()+1 : originPosition();
245     }
246
247     qreal endPosition() const {
248         return isRightToLeftTopToBottom() ? -originPosition()+1 : lastPosition();
249
250     }
251
252     bool isValid() const {
253         return model && model->count() && model->isValid();
254     }
255
256     int rowSize() const {
257         return flow == QSGGridView::LeftToRight ? cellHeight : cellWidth;
258     }
259     int colSize() const {
260         return flow == QSGGridView::LeftToRight ? cellWidth : cellHeight;
261     }
262
263     qreal colPosAt(int modelIndex) const {
264         if (FxGridItemSG *item = visibleItem(modelIndex))
265             return item->colPos();
266         if (!visibleItems.isEmpty()) {
267             if (modelIndex < visibleIndex) {
268                 int count = (visibleIndex - modelIndex) % columns;
269                 int col = visibleItems.first()->colPos() / colSize();
270                 col = (columns - count + col) % columns;
271                 return col * colSize();
272             } else {
273                 int count = columns - 1 - (modelIndex - visibleItems.last()->index - 1) % columns;
274                 return visibleItems.last()->colPos() - count * colSize();
275             }
276         } else {
277             return (modelIndex % columns) * colSize();
278         }
279         return 0;
280     }
281     qreal rowPosAt(int modelIndex) const {
282         if (FxGridItemSG *item = visibleItem(modelIndex))
283             return item->rowPos();
284         if (!visibleItems.isEmpty()) {
285             if (modelIndex < visibleIndex) {
286                 int firstCol = visibleItems.first()->colPos() / colSize();
287                 int col = visibleIndex - modelIndex + (columns - firstCol - 1);
288                 int rows = col / columns;
289                 return visibleItems.first()->rowPos() - rows * rowSize();
290             } else {
291                 int count = modelIndex - visibleItems.last()->index;
292                 int col = visibleItems.last()->colPos() + count * colSize();
293                 int rows = col / (columns * colSize());
294                 return visibleItems.last()->rowPos() + rows * rowSize();
295             }
296         } else {
297             qreal pos = (modelIndex / columns) * rowSize();
298             if (header)
299                 pos += headerSize();
300             return pos;
301         }
302         return 0;
303     }
304
305     FxGridItemSG *firstVisibleItem() const {
306         const qreal pos = isRightToLeftTopToBottom() ? -position()-size() : position();
307         for (int i = 0; i < visibleItems.count(); ++i) {
308             FxGridItemSG *item = visibleItems.at(i);
309             if (item->index != -1 && item->endRowPos() > pos)
310                 return item;
311         }
312         return visibleItems.count() ? visibleItems.first() : 0;
313     }
314
315     int lastVisibleIndex() const {
316         for (int i = 0; i < visibleItems.count(); ++i) {
317             FxGridItemSG *item = visibleItems.at(i);
318             if (item->index != -1)
319                 return item->index;
320         }
321         return -1;
322     }
323
324     // Map a model index to visibleItems list index.
325     // These may differ if removed items are still present in the visible list,
326     // e.g. doing a removal animation
327     int mapFromModel(int modelIndex) const {
328         if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
329             return -1;
330         for (int i = 0; i < visibleItems.count(); ++i) {
331             FxGridItemSG *listItem = visibleItems.at(i);
332             if (listItem->index == modelIndex)
333                 return i + visibleIndex;
334             if (listItem->index > modelIndex)
335                 return -1;
336         }
337         return -1; // Not in visibleList
338     }
339
340     qreal snapPosAt(qreal pos) const {
341         Q_Q(const QSGGridView);
342         qreal snapPos = 0;
343         if (!visibleItems.isEmpty()) {
344             pos += rowSize()/2;
345             snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
346             snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
347             qreal maxExtent;
348             qreal minExtent;
349             if (isRightToLeftTopToBottom()) {
350                 maxExtent = q->minXExtent();
351                 minExtent = q->maxXExtent();
352             } else {
353                 maxExtent = flow == QSGGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
354                 minExtent = flow == QSGGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
355             }
356             if (snapPos > maxExtent)
357                 snapPos = maxExtent;
358             if (snapPos < minExtent)
359                 snapPos = minExtent;
360         }
361         return snapPos;
362     }
363
364     FxGridItemSG *snapItemAt(qreal pos) {
365         for (int i = 0; i < visibleItems.count(); ++i) {
366             FxGridItemSG *item = visibleItems[i];
367             if (item->index == -1)
368                 continue;
369             qreal itemTop = item->rowPos();
370             if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
371                 return item;
372         }
373         return 0;
374     }
375
376     int snapIndex() {
377         int index = currentIndex;
378         for (int i = 0; i < visibleItems.count(); ++i) {
379             FxGridItemSG *item = visibleItems[i];
380             if (item->index == -1)
381                 continue;
382             qreal itemTop = item->rowPos();
383             if (itemTop >= highlight->rowPos()-rowSize()/2 && itemTop < highlight->rowPos()+rowSize()/2) {
384                 index = item->index;
385                 if (item->colPos() >= highlight->colPos()-colSize()/2 && item->colPos() < highlight->colPos()+colSize()/2)
386                     return item->index;
387             }
388         }
389         return index;
390     }
391
392     qreal headerSize() const {
393         if (!header)
394             return 0.0;
395
396         return flow == QSGGridView::LeftToRight
397                        ? header->item->height()
398                        : header->item->width();
399     }
400
401
402     virtual void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
403         Q_Q(const QSGGridView);
404         QSGFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
405         if (item == q) {
406             if (newGeometry.height() != oldGeometry.height()
407                 || newGeometry.width() != oldGeometry.width()) {
408                 if (q->isComponentComplete()) {
409                     updateGrid();
410                     scheduleLayout();
411                 }
412             }
413         } else if ((header && header->item == item) || (footer && footer->item == item)) {
414             if (header)
415                 updateHeader();
416             if (footer)
417                 updateFooter();
418         }
419     }
420
421     void positionViewAtIndex(int index, int mode);
422     virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
423     virtual void flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
424                 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
425
426     // for debugging only
427     void checkVisible() const {
428         int skip = 0;
429         for (int i = 0; i < visibleItems.count(); ++i) {
430             FxGridItemSG *listItem = visibleItems.at(i);
431             if (listItem->index == -1) {
432                 ++skip;
433             } else if (listItem->index != visibleIndex + i - skip) {
434                 for (int j = 0; j < visibleItems.count(); j++)
435                     qDebug() << " index" << j << "item index" << visibleItems.at(j)->index;
436                 qFatal("index %d %d %d", visibleIndex, i, listItem->index);
437             }
438         }
439     }
440
441     QDeclarativeGuard<QSGVisualModel> model;
442     QVariant modelVariant;
443     QList<FxGridItemSG*> visibleItems;
444     QHash<QSGItem*,int> unrequestedItems;
445     FxGridItemSG *currentItem;
446     Qt::LayoutDirection layoutDirection;
447     QSGGridView::Flow flow;
448     int visibleIndex;
449     int currentIndex;
450     int cellWidth;
451     int cellHeight;
452     int columns;
453     int requestedIndex;
454     int itemCount;
455     qreal highlightRangeStart;
456     qreal highlightRangeEnd;
457     QSGGridView::HighlightRangeMode highlightRange;
458     QDeclarativeComponent *highlightComponent;
459     FxGridItemSG *highlight;
460     FxGridItemSG *trackedItem;
461     enum MovementReason { Other, SetIndex, Mouse };
462     MovementReason moveReason;
463     int buffer;
464     QSmoothedAnimation *highlightXAnimator;
465     QSmoothedAnimation *highlightYAnimator;
466     int highlightMoveDuration;
467     QDeclarativeComponent *footerComponent;
468     FxGridItemSG *footer;
469     QDeclarativeComponent *headerComponent;
470     FxGridItemSG *header;
471     enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
472     int bufferMode;
473     QSGGridView::SnapMode snapMode;
474
475     bool ownModel : 1;
476     bool wrap : 1;
477     bool autoHighlight : 1;
478     bool fixCurrentVisibility : 1;
479     bool lazyRelease : 1;
480     bool layoutScheduled : 1;
481     bool deferredRelease : 1;
482     bool haveHighlightRange : 1;
483     bool currentIndexCleared : 1;
484     bool highlightRangeStartValid : 1;
485     bool highlightRangeEndValid : 1;
486 };
487
488 void QSGGridViewPrivate::init()
489 {
490     Q_Q(QSGGridView);
491     QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
492     q->setFlag(QSGItem::ItemIsFocusScope);
493     q->setFlickableDirection(QSGFlickable::VerticalFlick);
494     addItemChangeListener(this, Geometry);
495 }
496
497 void QSGGridViewPrivate::clear()
498 {
499     for (int i = 0; i < visibleItems.count(); ++i)
500         releaseItem(visibleItems.at(i));
501     visibleItems.clear();
502     visibleIndex = 0;
503     releaseItem(currentItem);
504     currentItem = 0;
505     createHighlight();
506     trackedItem = 0;
507     itemCount = 0;
508 }
509
510 FxGridItemSG *QSGGridViewPrivate::createItem(int modelIndex)
511 {
512     Q_Q(QSGGridView);
513     // create object
514     requestedIndex = modelIndex;
515     FxGridItemSG *listItem = 0;
516     if (QSGItem *item = model->item(modelIndex, false)) {
517         listItem = new FxGridItemSG(item, q);
518         listItem->index = modelIndex;
519         if (model->completePending()) {
520             // complete
521             listItem->item->setZ(1);
522             listItem->item->setParentItem(q->contentItem());
523             model->completeItem();
524         } else {
525             listItem->item->setParentItem(q->contentItem());
526         }
527         unrequestedItems.remove(listItem->item);
528     }
529     requestedIndex = -1;
530     return listItem;
531 }
532
533
534 void QSGGridViewPrivate::releaseItem(FxGridItemSG *item)
535 {
536     Q_Q(QSGGridView);
537     if (!item || !model)
538         return;
539     if (trackedItem == item) {
540         QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
541         QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
542         trackedItem = 0;
543     }
544     if (model->release(item->item) == 0) {
545         // item was not destroyed, and we no longer reference it.
546         unrequestedItems.insert(item->item, model->indexOf(item->item, q));
547     }
548     delete item;
549 }
550
551 void QSGGridViewPrivate::refill(qreal from, qreal to, bool doBuffer)
552 {
553     Q_Q(QSGGridView);
554     if (!isValid() || !q->isComponentComplete())
555         return;
556     itemCount = model->count();
557     qreal bufferFrom = from - buffer;
558     qreal bufferTo = to + buffer;
559     qreal fillFrom = from;
560     qreal fillTo = to;
561     if (doBuffer && (bufferMode & BufferAfter))
562         fillTo = bufferTo;
563     if (doBuffer && (bufferMode & BufferBefore))
564         fillFrom = bufferFrom;
565
566     bool changed = false;
567
568     int colPos = colPosAt(visibleIndex);
569     int rowPos = rowPosAt(visibleIndex);
570     int modelIndex = visibleIndex;
571     if (visibleItems.count()) {
572         rowPos = visibleItems.last()->rowPos();
573         colPos = visibleItems.last()->colPos() + colSize();
574         if (colPos > colSize() * (columns-1)) {
575             colPos = 0;
576             rowPos += rowSize();
577         }
578         int i = visibleItems.count() - 1;
579         while (i > 0 && visibleItems.at(i)->index == -1)
580             --i;
581         modelIndex = visibleItems.at(i)->index + 1;
582     }
583     int colNum = colPos / colSize();
584
585     FxGridItemSG *item = 0;
586
587     // Item creation and release is staggered in order to avoid
588     // creating/releasing multiple items in one frame
589     // while flicking (as much as possible).
590     while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
591 //        qDebug() << "refill: append item" << modelIndex;
592         if (!(item = createItem(modelIndex)))
593             break;
594         item->setPosition(colPos, rowPos);
595         visibleItems.append(item);
596         colPos += colSize();
597         colNum++;
598         if (colPos > colSize() * (columns-1)) {
599             colPos = 0;
600             colNum = 0;
601             rowPos += rowSize();
602         }
603         ++modelIndex;
604         changed = true;
605         if (doBuffer) // never buffer more than one item per frame
606             break;
607     }
608
609     if (visibleItems.count()) {
610         rowPos = visibleItems.first()->rowPos();
611         colPos = visibleItems.first()->colPos() - colSize();
612         if (colPos < 0) {
613             colPos = colSize() * (columns - 1);
614             rowPos -= rowSize();
615         }
616     }
617     colNum = colPos / colSize();
618     while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
619 //        qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
620         if (!(item = createItem(visibleIndex-1)))
621             break;
622         --visibleIndex;
623         item->setPosition(colPos, rowPos);
624         visibleItems.prepend(item);
625         colPos -= colSize();
626         colNum--;
627         if (colPos < 0) {
628             colPos = colSize() * (columns - 1);
629             colNum = columns-1;
630             rowPos -= rowSize();
631         }
632         changed = true;
633         if (doBuffer) // never buffer more than one item per frame
634             break;
635     }
636
637     if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
638         while (visibleItems.count() > 1
639                && (item = visibleItems.first())
640                     && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
641             if (item->attached->delayRemove())
642                 break;
643 //            qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
644             if (item->index != -1)
645                 visibleIndex++;
646             visibleItems.removeFirst();
647             releaseItem(item);
648             changed = true;
649         }
650         while (visibleItems.count() > 1
651                && (item = visibleItems.last())
652                     && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
653             if (item->attached->delayRemove())
654                 break;
655 //            qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
656             visibleItems.removeLast();
657             releaseItem(item);
658             changed = true;
659         }
660         deferredRelease = false;
661     } else {
662         deferredRelease = true;
663     }
664     if (changed) {
665         if (header)
666             updateHeader();
667         if (footer)
668             updateFooter();
669         if (flow == QSGGridView::LeftToRight)
670             q->setContentHeight(endPosition() - startPosition());
671         else
672             q->setContentWidth(endPosition() - startPosition());
673     } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
674         refill(from, to, true);
675     }
676     lazyRelease = false;
677 }
678
679 void QSGGridViewPrivate::updateGrid()
680 {
681     Q_Q(QSGGridView);
682     columns = (int)qMax((flow == QSGGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.));
683     if (isValid()) {
684         if (flow == QSGGridView::LeftToRight)
685             q->setContentHeight(endPosition() - startPosition());
686         else
687             q->setContentWidth(lastPosition() - originPosition());
688     }
689 }
690
691 void QSGGridViewPrivate::scheduleLayout()
692 {
693     Q_Q(QSGGridView);
694     if (!layoutScheduled) {
695         layoutScheduled = true;
696         q->polish();
697     }
698 }
699
700 void QSGGridViewPrivate::layout()
701 {
702     Q_Q(QSGGridView);
703     layoutScheduled = false;
704     if (!isValid() && !visibleItems.count()) {
705         clear();
706         return;
707     }
708     if (visibleItems.count()) {
709         qreal rowPos = visibleItems.first()->rowPos();
710         qreal colPos = visibleItems.first()->colPos();
711         int col = visibleIndex % columns;
712         if (colPos != col * colSize()) {
713             colPos = col * colSize();
714             visibleItems.first()->setPosition(colPos, rowPos);
715         }
716         for (int i = 1; i < visibleItems.count(); ++i) {
717             FxGridItemSG *item = visibleItems.at(i);
718             colPos += colSize();
719             if (colPos > colSize() * (columns-1)) {
720                 colPos = 0;
721                 rowPos += rowSize();
722             }
723             item->setPosition(colPos, rowPos);
724         }
725     }
726     if (header)
727         updateHeader();
728     if (footer)
729         updateFooter();
730     q->refill();
731     updateHighlight();
732     moveReason = Other;
733     if (flow == QSGGridView::LeftToRight) {
734         q->setContentHeight(endPosition() - startPosition());
735         fixupY();
736     } else {
737         q->setContentWidth(endPosition() - startPosition());
738         fixupX();
739     }
740     updateUnrequestedPositions();
741 }
742
743 void QSGGridViewPrivate::updateUnrequestedIndexes()
744 {
745     Q_Q(QSGGridView);
746     QHash<QSGItem*,int>::iterator it;
747     for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
748         *it = model->indexOf(it.key(), q);
749 }
750
751 void QSGGridViewPrivate::updateUnrequestedPositions()
752 {
753     QHash<QSGItem*,int>::const_iterator it;
754     for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
755         QSGItem *item = it.key();
756         if (flow == QSGGridView::LeftToRight) {
757             item->setPos(QPointF(colPosAt(*it), rowPosAt(*it)));
758         } else {
759             if (isRightToLeftTopToBottom())
760                 item->setPos(QPointF(-rowPosAt(*it)-item->width(), colPosAt(*it)));
761             else
762                 item->setPos(QPointF(rowPosAt(*it), colPosAt(*it)));
763         }
764     }
765 }
766
767 void QSGGridViewPrivate::updateTrackedItem()
768 {
769     Q_Q(QSGGridView);
770     FxGridItemSG *item = currentItem;
771     if (highlight)
772         item = highlight;
773
774     if (trackedItem && item != trackedItem) {
775         QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
776         QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
777         trackedItem = 0;
778     }
779
780     if (!trackedItem && item) {
781         trackedItem = item;
782         QObject::connect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
783         QObject::connect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
784     }
785     if (trackedItem)
786         q->trackedPositionChanged();
787 }
788
789 void QSGGridViewPrivate::createHighlight()
790 {
791     Q_Q(QSGGridView);
792     bool changed = false;
793     if (highlight) {
794         if (trackedItem == highlight)
795             trackedItem = 0;
796         delete highlight->item;
797         delete highlight;
798         highlight = 0;
799         delete highlightXAnimator;
800         delete highlightYAnimator;
801         highlightXAnimator = 0;
802         highlightYAnimator = 0;
803         changed = true;
804     }
805
806     if (currentItem) {
807         QSGItem *item = 0;
808         if (highlightComponent) {
809             QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q));
810             QObject *nobj = highlightComponent->create(highlightContext);
811             if (nobj) {
812                 QDeclarative_setParent_noEvent(highlightContext, nobj);
813                 item = qobject_cast<QSGItem *>(nobj);
814                 if (!item)
815                     delete nobj;
816             } else {
817                 delete highlightContext;
818             }
819         } else {
820             item = new QSGItem;
821             QDeclarative_setParent_noEvent(item, q->contentItem());
822             item->setParentItem(q->contentItem());
823         }
824         if (item) {
825             QDeclarative_setParent_noEvent(item, q->contentItem());
826             item->setParentItem(q->contentItem());
827             highlight = new FxGridItemSG(item, q);
828             if (currentItem && autoHighlight)
829                 highlight->setPosition(currentItem->colPos(), currentItem->rowPos());
830             highlightXAnimator = new QSmoothedAnimation(q);
831             highlightXAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("x"));
832             highlightXAnimator->userDuration = highlightMoveDuration;
833             highlightYAnimator = new QSmoothedAnimation(q);
834             highlightYAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("y"));
835             highlightYAnimator->userDuration = highlightMoveDuration;
836             if (autoHighlight) {
837                 highlightXAnimator->restart();
838                 highlightYAnimator->restart();
839             }
840             changed = true;
841         }
842     }
843     if (changed)
844         emit q->highlightItemChanged();
845 }
846
847 void QSGGridViewPrivate::updateHighlight()
848 {
849     if ((!currentItem && highlight) || (currentItem && !highlight))
850         createHighlight();
851     if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) {
852         // auto-update highlight
853         highlightXAnimator->to = currentItem->item->x();
854         highlightYAnimator->to = currentItem->item->y();
855         highlight->item->setWidth(currentItem->item->width());
856         highlight->item->setHeight(currentItem->item->height());
857         highlightXAnimator->restart();
858         highlightYAnimator->restart();
859     }
860     updateTrackedItem();
861 }
862
863 void QSGGridViewPrivate::updateCurrent(int modelIndex)
864 {
865     Q_Q(QSGGridView);
866     if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
867         if (currentItem) {
868             currentItem->attached->setIsCurrentItem(false);
869             releaseItem(currentItem);
870             currentItem = 0;
871             currentIndex = modelIndex;
872             emit q->currentIndexChanged();
873             updateHighlight();
874         } else if (currentIndex != modelIndex) {
875             currentIndex = modelIndex;
876             emit q->currentIndexChanged();
877         }
878         return;
879     }
880
881     if (currentItem && currentIndex == modelIndex) {
882         updateHighlight();
883         return;
884     }
885
886     FxGridItemSG *oldCurrentItem = currentItem;
887     currentIndex = modelIndex;
888     currentItem = createItem(modelIndex);
889     fixCurrentVisibility = true;
890     if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
891         oldCurrentItem->attached->setIsCurrentItem(false);
892     if (currentItem) {
893         currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex));
894         currentItem->item->setFocus(true);
895         currentItem->attached->setIsCurrentItem(true);
896     }
897     updateHighlight();
898     emit q->currentIndexChanged();
899     releaseItem(oldCurrentItem);
900 }
901
902 void QSGGridViewPrivate::updateFooter()
903 {
904     Q_Q(QSGGridView);
905     if (!footer && footerComponent) {
906         QSGItem *item = 0;
907         QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
908         QObject *nobj = footerComponent->create(context);
909         if (nobj) {
910             QDeclarative_setParent_noEvent(context, nobj);
911             item = qobject_cast<QSGItem *>(nobj);
912             if (!item)
913                 delete nobj;
914         } else {
915             delete context;
916         }
917         if (item) {
918             QDeclarative_setParent_noEvent(item, q->contentItem());
919             item->setParentItem(q->contentItem());
920             item->setZ(1);
921             QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
922             itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
923             footer = new FxGridItemSG(item, q);
924         }
925     }
926     if (footer) {
927         qreal colOffset = 0;
928         qreal rowOffset;
929         if (isRightToLeftTopToBottom()) {
930             rowOffset = footer->item->width()-cellWidth;
931         } else {
932             rowOffset = 0;
933             if (q->effectiveLayoutDirection() == Qt::RightToLeft)
934                 colOffset = footer->item->width()-cellWidth;
935         }
936         if (visibleItems.count()) {
937             qreal endPos = lastPosition();
938             if (lastVisibleIndex() == model->count()-1) {
939                 footer->setPosition(colOffset, endPos + rowOffset);
940             } else {
941                 qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size();
942                 if (endPos <= visiblePos || footer->endRowPos() < endPos + rowOffset)
943                     footer->setPosition(colOffset, endPos + rowOffset);
944             }
945         } else {
946             qreal endPos = 0;
947             if (header) {
948                 endPos += (flow == QSGGridView::LeftToRight) ? header->item->height() : header->item->width();
949             }
950             footer->setPosition(colOffset, endPos);
951         }
952     }
953 }
954
955 void QSGGridViewPrivate::updateHeader()
956 {
957     Q_Q(QSGGridView);
958     if (!header && headerComponent) {
959         QSGItem *item = 0;
960         QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
961         QObject *nobj = headerComponent->create(context);
962         if (nobj) {
963             QDeclarative_setParent_noEvent(context, nobj);
964             item = qobject_cast<QSGItem *>(nobj);
965             if (!item)
966                 delete nobj;
967         } else {
968             delete context;
969         }
970         if (item) {
971             QDeclarative_setParent_noEvent(item, q->contentItem());
972             item->setParentItem(q->contentItem());
973             item->setZ(1);
974             QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
975             itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
976             header = new FxGridItemSG(item, q);
977         }
978     }
979     if (header) {
980         qreal colOffset = 0;
981         qreal rowOffset;
982         if (isRightToLeftTopToBottom()) {
983             rowOffset = -cellWidth;
984         } else {
985             rowOffset = -headerSize();
986             if (q->effectiveLayoutDirection() == Qt::RightToLeft)
987                 colOffset = header->item->width()-cellWidth;
988         }
989         if (visibleItems.count()) {
990             qreal startPos = originPosition();
991             if (visibleIndex == 0) {
992                 header->setPosition(colOffset, startPos + rowOffset);
993             } else {
994                 qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position();
995                 qreal headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
996                 if (tempPos <= startPos || headerPos > startPos + rowOffset)
997                     header->setPosition(colOffset, startPos + rowOffset);
998             }
999         } else {
1000             header->setPosition(colOffset, 0);
1001         }
1002     }
1003 }
1004
1005 void QSGGridViewPrivate::fixupPosition()
1006 {
1007     moveReason = Other;
1008     if (flow == QSGGridView::LeftToRight)
1009         fixupY();
1010     else
1011         fixupX();
1012 }
1013
1014 void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
1015 {
1016     if ((flow == QSGGridView::TopToBottom && &data == &vData)
1017         || (flow == QSGGridView::LeftToRight && &data == &hData))
1018         return;
1019
1020     fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1021
1022     qreal highlightStart;
1023     qreal highlightEnd;
1024     qreal viewPos;
1025     if (isRightToLeftTopToBottom()) {
1026         // Handle Right-To-Left exceptions
1027         viewPos = -position()-size();
1028         highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
1029         highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd;
1030     } else {
1031         viewPos = position();
1032         highlightStart = highlightRangeStart;
1033         highlightEnd = highlightRangeEnd;
1034     }
1035
1036     if (snapMode != QSGGridView::NoSnap) {
1037         qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
1038         FxGridItemSG *topItem = snapItemAt(tempPosition+highlightStart);
1039         FxGridItemSG *bottomItem = snapItemAt(tempPosition+highlightEnd);
1040         qreal pos;
1041         if (topItem && bottomItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
1042             qreal topPos = qMin(topItem->rowPos() - highlightStart, -maxExtent);
1043             qreal bottomPos = qMax(bottomItem->rowPos() - highlightEnd, -minExtent);
1044             pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos;
1045         } else if (topItem) {
1046             qreal headerPos = 0;
1047             if (header)
1048                 headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
1049             if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2) {
1050                 pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart;
1051             } else {
1052                 if (isRightToLeftTopToBottom())
1053                     pos = qMax(qMin(-topItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
1054                 else
1055                     pos = qMax(qMin(topItem->rowPos() - highlightStart, -maxExtent), -minExtent);
1056             }
1057         } else if (bottomItem) {
1058             if (isRightToLeftTopToBottom())
1059                 pos = qMax(qMin(-bottomItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
1060             else
1061                 pos = qMax(qMin(bottomItem->rowPos() - highlightStart, -maxExtent), -minExtent);
1062         } else {
1063             QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
1064             return;
1065         }
1066         if (currentItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
1067             updateHighlight();
1068             qreal currPos = currentItem->rowPos();
1069             if (isRightToLeftTopToBottom())
1070                 pos = -pos-size(); // Transform Pos if required
1071             if (pos < currPos + rowSize() - highlightEnd)
1072                 pos = currPos + rowSize() - highlightEnd;
1073             if (pos > currPos - highlightStart)
1074                 pos = currPos - highlightStart;
1075             if (isRightToLeftTopToBottom())
1076                 pos = -pos-size(); // Untransform
1077         }
1078
1079         qreal dist = qAbs(data.move + pos);
1080         if (dist > 0) {
1081             timeline.reset(data.move);
1082             if (fixupMode != Immediate) {
1083                 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1084                 data.fixingUp = true;
1085             } else {
1086                 timeline.set(data.move, -pos);
1087             }
1088             vTime = timeline.time();
1089         }
1090     } else if (haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
1091         if (currentItem) {
1092             updateHighlight();
1093             qreal pos = currentItem->rowPos();
1094             if (viewPos < pos + rowSize() - highlightEnd)
1095                 viewPos = pos + rowSize() - highlightEnd;
1096             if (viewPos > pos - highlightStart)
1097                 viewPos = pos - highlightStart;
1098             if (isRightToLeftTopToBottom())
1099                 viewPos = -viewPos-size();
1100             timeline.reset(data.move);
1101             if (viewPos != position()) {
1102                 if (fixupMode != Immediate) {
1103                     timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1104                     data.fixingUp = true;
1105                 } else {
1106                     timeline.set(data.move, -viewPos);
1107                 }
1108             }
1109             vTime = timeline.time();
1110         }
1111     } else {
1112         QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
1113     }
1114     fixupMode = Normal;
1115 }
1116
1117 void QSGGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1118                                         QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
1119 {
1120     Q_Q(QSGGridView);
1121     data.fixingUp = false;
1122     moveReason = Mouse;
1123     if ((!haveHighlightRange || highlightRange != QSGGridView::StrictlyEnforceRange)
1124         && snapMode == QSGGridView::NoSnap) {
1125         QSGFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1126         return;
1127     }
1128     qreal maxDistance = 0;
1129     qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value();
1130     // -ve velocity means list is moving up/left
1131     if (velocity > 0) {
1132         if (data.move.value() < minExtent) {
1133             if (snapMode == QSGGridView::SnapOneRow) {
1134                 if (FxGridItemSG *item = firstVisibleItem())
1135                     maxDistance = qAbs(item->rowPos() + dataValue);
1136             } else {
1137                 maxDistance = qAbs(minExtent - data.move.value());
1138             }
1139         }
1140         if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
1141             data.flickTarget = minExtent;
1142     } else {
1143         if (data.move.value() > maxExtent) {
1144             if (snapMode == QSGGridView::SnapOneRow) {
1145                 qreal pos = snapPosAt(-dataValue) + (isRightToLeftTopToBottom() ? 0 : rowSize());
1146                 maxDistance = qAbs(pos + dataValue);
1147             } else {
1148                 maxDistance = qAbs(maxExtent - data.move.value());
1149             }
1150         }
1151         if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
1152             data.flickTarget = maxExtent;
1153     }
1154     bool overShoot = boundsBehavior == QSGFlickable::DragAndOvershootBounds;
1155     qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
1156     if (maxDistance > 0 || overShoot) {
1157         // This mode requires the grid to stop exactly on a row boundary.
1158         qreal v = velocity;
1159         if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1160             if (v < 0)
1161                 v = -maxVelocity;
1162             else
1163                 v = maxVelocity;
1164         }
1165         qreal accel = deceleration;
1166         qreal v2 = v * v;
1167         qreal overshootDist = 0.0;
1168         if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QSGGridView::SnapOneRow) {
1169             // + rowSize()/4 to encourage moving at least one item in the flick direction
1170             qreal dist = v2 / (accel * 2.0) + rowSize()/4;
1171             dist = qMin(dist, maxDistance);
1172             if (v > 0)
1173                 dist = -dist;
1174             qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
1175             data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
1176             data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
1177             qreal adjDist = -data.flickTarget + data.move.value();
1178             if (qAbs(adjDist) > qAbs(dist)) {
1179                 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1180                 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1181                 if (adjv2 > v2) {
1182                     v2 = adjv2;
1183                     v = qSqrt(v2);
1184                     if (dist > 0)
1185                         v = -v;
1186                 }
1187             }
1188             dist = adjDist;
1189             accel = v2 / (2.0f * qAbs(dist));
1190         } else {
1191             data.flickTarget = velocity > 0 ? minExtent : maxExtent;
1192             overshootDist = overShoot ? overShootDistance(v, vSize) : 0;
1193         }
1194         timeline.reset(data.move);
1195         timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1196         timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1197         if (!flickingHorizontally && q->xflick()) {
1198             flickingHorizontally = true;
1199             emit q->flickingChanged();
1200             emit q->flickingHorizontallyChanged();
1201             emit q->flickStarted();
1202         }
1203         if (!flickingVertically && q->yflick()) {
1204             flickingVertically = true;
1205             emit q->flickingChanged();
1206             emit q->flickingVerticallyChanged();
1207             emit q->flickStarted();
1208         }
1209     } else {
1210         timeline.reset(data.move);
1211         fixup(data, minExtent, maxExtent);
1212     }
1213 }
1214
1215
1216 //----------------------------------------------------------------------------
1217
1218 QSGGridView::QSGGridView(QSGItem *parent)
1219     : QSGFlickable(*(new QSGGridViewPrivate), parent)
1220 {
1221     Q_D(QSGGridView);
1222     d->init();
1223 }
1224
1225 QSGGridView::~QSGGridView()
1226 {
1227     Q_D(QSGGridView);
1228     d->clear();
1229     if (d->ownModel)
1230         delete d->model;
1231     delete d->header;
1232     delete d->footer;
1233 }
1234
1235 // For internal use
1236 int QSGGridView::modelCount() const
1237 {
1238     Q_D(const QSGGridView);
1239     return d->model->count();
1240 }
1241
1242 QVariant QSGGridView::model() const
1243 {
1244     Q_D(const QSGGridView);
1245     return d->modelVariant;
1246 }
1247
1248 void QSGGridView::setModel(const QVariant &model)
1249 {
1250     Q_D(QSGGridView);
1251     if (d->modelVariant == model)
1252         return;
1253     if (d->model) {
1254         disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1255         disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1256         disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1257         disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1258         disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
1259         disconnect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
1260     }
1261     d->clear();
1262     d->modelVariant = model;
1263     QObject *object = qvariant_cast<QObject*>(model);
1264     QSGVisualModel *vim = 0;
1265     if (object && (vim = qobject_cast<QSGVisualModel *>(object))) {
1266         if (d->ownModel) {
1267             delete d->model;
1268             d->ownModel = false;
1269         }
1270         d->model = vim;
1271     } else {
1272         if (!d->ownModel) {
1273             d->model = new QSGVisualDataModel(qmlContext(this), this);
1274             d->ownModel = true;
1275         }
1276         if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
1277             dataModel->setModel(model);
1278     }
1279     if (d->model) {
1280         d->bufferMode = QSGGridViewPrivate::BufferBefore | QSGGridViewPrivate::BufferAfter;
1281         if (isComponentComplete()) {
1282             refill();
1283             if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
1284                 setCurrentIndex(0);
1285             } else {
1286                 d->moveReason = QSGGridViewPrivate::SetIndex;
1287                 d->updateCurrent(d->currentIndex);
1288                 if (d->highlight && d->currentItem) {
1289                     if (d->autoHighlight)
1290                         d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1291                     d->updateTrackedItem();
1292                 }
1293                 d->moveReason = QSGGridViewPrivate::Other;
1294             }
1295         }
1296         connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1297         connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1298         connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1299         connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1300         connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
1301         connect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
1302         emit countChanged();
1303     }
1304     emit modelChanged();
1305 }
1306
1307 QDeclarativeComponent *QSGGridView::delegate() const
1308 {
1309     Q_D(const QSGGridView);
1310     if (d->model) {
1311         if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
1312             return dataModel->delegate();
1313     }
1314
1315     return 0;
1316 }
1317
1318 void QSGGridView::setDelegate(QDeclarativeComponent *delegate)
1319 {
1320     Q_D(QSGGridView);
1321     if (delegate == this->delegate())
1322         return;
1323
1324     if (!d->ownModel) {
1325         d->model = new QSGVisualDataModel(qmlContext(this));
1326         d->ownModel = true;
1327     }
1328     if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model)) {
1329         dataModel->setDelegate(delegate);
1330         if (isComponentComplete()) {
1331             for (int i = 0; i < d->visibleItems.count(); ++i)
1332                 d->releaseItem(d->visibleItems.at(i));
1333             d->visibleItems.clear();
1334             d->releaseItem(d->currentItem);
1335             d->currentItem = 0;
1336             refill();
1337             d->moveReason = QSGGridViewPrivate::SetIndex;
1338             d->updateCurrent(d->currentIndex);
1339             if (d->highlight && d->currentItem) {
1340                 if (d->autoHighlight)
1341                     d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1342                 d->updateTrackedItem();
1343             }
1344             d->moveReason = QSGGridViewPrivate::Other;
1345         }
1346         emit delegateChanged();
1347     }
1348 }
1349
1350 int QSGGridView::currentIndex() const
1351 {
1352     Q_D(const QSGGridView);
1353     return d->currentIndex;
1354 }
1355
1356 void QSGGridView::setCurrentIndex(int index)
1357 {
1358     Q_D(QSGGridView);
1359     if (d->requestedIndex >= 0) // currently creating item
1360         return;
1361     d->currentIndexCleared = (index == -1);
1362     if (index == d->currentIndex)
1363         return;
1364     if (isComponentComplete() && d->isValid()) {
1365         d->moveReason = QSGGridViewPrivate::SetIndex;
1366         d->updateCurrent(index);
1367     } else {
1368         d->currentIndex = index;
1369         emit currentIndexChanged();
1370     }
1371 }
1372
1373 QSGItem *QSGGridView::currentItem()
1374 {
1375     Q_D(QSGGridView);
1376     if (!d->currentItem)
1377         return 0;
1378     return d->currentItem->item;
1379 }
1380
1381 QSGItem *QSGGridView::highlightItem()
1382 {
1383     Q_D(QSGGridView);
1384     if (!d->highlight)
1385         return 0;
1386     return d->highlight->item;
1387 }
1388
1389 int QSGGridView::count() const
1390 {
1391     Q_D(const QSGGridView);
1392     if (d->model)
1393         return d->model->count();
1394     return 0;
1395 }
1396
1397 QDeclarativeComponent *QSGGridView::highlight() const
1398 {
1399     Q_D(const QSGGridView);
1400     return d->highlightComponent;
1401 }
1402
1403 void QSGGridView::setHighlight(QDeclarativeComponent *highlight)
1404 {
1405     Q_D(QSGGridView);
1406     if (highlight != d->highlightComponent) {
1407         d->highlightComponent = highlight;
1408         d->updateCurrent(d->currentIndex);
1409         emit highlightChanged();
1410     }
1411 }
1412
1413 bool QSGGridView::highlightFollowsCurrentItem() const
1414 {
1415     Q_D(const QSGGridView);
1416     return d->autoHighlight;
1417 }
1418
1419 void QSGGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
1420 {
1421     Q_D(QSGGridView);
1422     if (d->autoHighlight != autoHighlight) {
1423         d->autoHighlight = autoHighlight;
1424         if (autoHighlight) {
1425             d->updateHighlight();
1426         } else if (d->highlightXAnimator) {
1427             d->highlightXAnimator->stop();
1428             d->highlightYAnimator->stop();
1429         }
1430     }
1431 }
1432
1433 int QSGGridView::highlightMoveDuration() const
1434 {
1435     Q_D(const QSGGridView);
1436     return d->highlightMoveDuration;
1437 }
1438
1439 void QSGGridView::setHighlightMoveDuration(int duration)
1440 {
1441     Q_D(QSGGridView);
1442     if (d->highlightMoveDuration != duration) {
1443         d->highlightMoveDuration = duration;
1444         if (d->highlightYAnimator) {
1445             d->highlightXAnimator->userDuration = d->highlightMoveDuration;
1446             d->highlightYAnimator->userDuration = d->highlightMoveDuration;
1447         }
1448         emit highlightMoveDurationChanged();
1449     }
1450 }
1451
1452 qreal QSGGridView::preferredHighlightBegin() const
1453 {
1454     Q_D(const QSGGridView);
1455     return d->highlightRangeStart;
1456 }
1457
1458 void QSGGridView::setPreferredHighlightBegin(qreal start)
1459 {
1460     Q_D(QSGGridView);
1461     d->highlightRangeStartValid = true;
1462     if (d->highlightRangeStart == start)
1463         return;
1464     d->highlightRangeStart = start;
1465     d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1466     emit preferredHighlightBeginChanged();
1467 }
1468
1469 void QSGGridView::resetPreferredHighlightBegin()
1470 {
1471     Q_D(QSGGridView);
1472     d->highlightRangeStartValid = false;
1473     if (d->highlightRangeStart == 0)
1474         return;
1475     d->highlightRangeStart = 0;
1476     emit preferredHighlightBeginChanged();
1477 }
1478
1479 qreal QSGGridView::preferredHighlightEnd() const
1480 {
1481     Q_D(const QSGGridView);
1482     return d->highlightRangeEnd;
1483 }
1484
1485 void QSGGridView::setPreferredHighlightEnd(qreal end)
1486 {
1487     Q_D(QSGGridView);
1488     d->highlightRangeEndValid = true;
1489     if (d->highlightRangeEnd == end)
1490         return;
1491     d->highlightRangeEnd = end;
1492     d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1493     emit preferredHighlightEndChanged();
1494 }
1495
1496 void QSGGridView::resetPreferredHighlightEnd()
1497 {
1498     Q_D(QSGGridView);
1499     d->highlightRangeEndValid = false;
1500     if (d->highlightRangeEnd == 0)
1501         return;
1502     d->highlightRangeEnd = 0;
1503     emit preferredHighlightEndChanged();
1504 }
1505
1506 QSGGridView::HighlightRangeMode QSGGridView::highlightRangeMode() const
1507 {
1508     Q_D(const QSGGridView);
1509     return d->highlightRange;
1510 }
1511
1512 void QSGGridView::setHighlightRangeMode(HighlightRangeMode mode)
1513 {
1514     Q_D(QSGGridView);
1515     if (d->highlightRange == mode)
1516         return;
1517     d->highlightRange = mode;
1518     d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1519     emit highlightRangeModeChanged();
1520 }
1521
1522 Qt::LayoutDirection QSGGridView::layoutDirection() const
1523 {
1524     Q_D(const QSGGridView);
1525     return d->layoutDirection;
1526 }
1527
1528 void QSGGridView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1529 {
1530     Q_D(QSGGridView);
1531     if (d->layoutDirection != layoutDirection) {
1532         d->layoutDirection = layoutDirection;
1533         d->regenerate();
1534         emit layoutDirectionChanged();
1535         emit effectiveLayoutDirectionChanged();
1536     }
1537 }
1538
1539 Qt::LayoutDirection QSGGridView::effectiveLayoutDirection() const
1540 {
1541     Q_D(const QSGGridView);
1542     if (d->effectiveLayoutMirror)
1543         return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
1544     else
1545         return d->layoutDirection;
1546 }
1547
1548 QSGGridView::Flow QSGGridView::flow() const
1549 {
1550     Q_D(const QSGGridView);
1551     return d->flow;
1552 }
1553
1554 void QSGGridView::setFlow(Flow flow)
1555 {
1556     Q_D(QSGGridView);
1557     if (d->flow != flow) {
1558         d->flow = flow;
1559         if (d->flow == LeftToRight) {
1560             setContentWidth(-1);
1561             setFlickableDirection(QSGFlickable::VerticalFlick);
1562         } else {
1563             setContentHeight(-1);
1564             setFlickableDirection(QSGFlickable::HorizontalFlick);
1565         }
1566         setContentX(0);
1567         setContentY(0);
1568         d->regenerate();
1569         emit flowChanged();
1570     }
1571 }
1572
1573 bool QSGGridView::isWrapEnabled() const
1574 {
1575     Q_D(const QSGGridView);
1576     return d->wrap;
1577 }
1578
1579 void QSGGridView::setWrapEnabled(bool wrap)
1580 {
1581     Q_D(QSGGridView);
1582     if (d->wrap == wrap)
1583         return;
1584     d->wrap = wrap;
1585     emit keyNavigationWrapsChanged();
1586 }
1587
1588 int QSGGridView::cacheBuffer() const
1589 {
1590     Q_D(const QSGGridView);
1591     return d->buffer;
1592 }
1593
1594 void QSGGridView::setCacheBuffer(int buffer)
1595 {
1596     Q_D(QSGGridView);
1597     if (d->buffer != buffer) {
1598         d->buffer = buffer;
1599         if (isComponentComplete())
1600             refill();
1601         emit cacheBufferChanged();
1602     }
1603 }
1604
1605 int QSGGridView::cellWidth() const
1606 {
1607     Q_D(const QSGGridView);
1608     return d->cellWidth;
1609 }
1610
1611 void QSGGridView::setCellWidth(int cellWidth)
1612 {
1613     Q_D(QSGGridView);
1614     if (cellWidth != d->cellWidth && cellWidth > 0) {
1615         d->cellWidth = qMax(1, cellWidth);
1616         d->updateGrid();
1617         emit cellWidthChanged();
1618         d->layout();
1619     }
1620 }
1621
1622 int QSGGridView::cellHeight() const
1623 {
1624     Q_D(const QSGGridView);
1625     return d->cellHeight;
1626 }
1627
1628 void QSGGridView::setCellHeight(int cellHeight)
1629 {
1630     Q_D(QSGGridView);
1631     if (cellHeight != d->cellHeight && cellHeight > 0) {
1632         d->cellHeight = qMax(1, cellHeight);
1633         d->updateGrid();
1634         emit cellHeightChanged();
1635         d->layout();
1636     }
1637 }
1638
1639 QSGGridView::SnapMode QSGGridView::snapMode() const
1640 {
1641     Q_D(const QSGGridView);
1642     return d->snapMode;
1643 }
1644
1645 void QSGGridView::setSnapMode(SnapMode mode)
1646 {
1647     Q_D(QSGGridView);
1648     if (d->snapMode != mode) {
1649         d->snapMode = mode;
1650         emit snapModeChanged();
1651     }
1652 }
1653
1654 QDeclarativeComponent *QSGGridView::footer() const
1655 {
1656     Q_D(const QSGGridView);
1657     return d->footerComponent;
1658 }
1659
1660 void QSGGridView::setFooter(QDeclarativeComponent *footer)
1661 {
1662     Q_D(QSGGridView);
1663     if (d->footerComponent != footer) {
1664         if (d->footer) {
1665             // XXX todo - the original did scene()->removeItem().  Why?
1666             d->footer->item->setParentItem(0);
1667             d->footer->item->deleteLater();
1668             delete d->footer;
1669             d->footer = 0;
1670         }
1671         d->footerComponent = footer;
1672         if (isComponentComplete()) {
1673             d->updateFooter();
1674             d->updateGrid();
1675             d->fixupPosition();
1676         }
1677         emit footerChanged();
1678     }
1679 }
1680
1681 QDeclarativeComponent *QSGGridView::header() const
1682 {
1683     Q_D(const QSGGridView);
1684     return d->headerComponent;
1685 }
1686
1687 void QSGGridView::setHeader(QDeclarativeComponent *header)
1688 {
1689     Q_D(QSGGridView);
1690     if (d->headerComponent != header) {
1691         if (d->header) {
1692             // XXX todo - the original did scene()->removeItem().  Why?
1693             d->header->item->setParentItem(0);
1694             d->header->item->deleteLater();
1695             delete d->header;
1696             d->header = 0;
1697         }
1698         d->headerComponent = header;
1699         if (isComponentComplete()) {
1700             d->updateHeader();
1701             d->updateFooter();
1702             d->updateGrid();
1703             d->fixupPosition();
1704         }
1705         emit headerChanged();
1706     }
1707 }
1708
1709 void QSGGridView::setContentX(qreal pos)
1710 {
1711     Q_D(QSGGridView);
1712     // Positioning the view manually should override any current movement state
1713     d->moveReason = QSGGridViewPrivate::Other;
1714     QSGFlickable::setContentX(pos);
1715 }
1716
1717 void QSGGridView::setContentY(qreal pos)
1718 {
1719     Q_D(QSGGridView);
1720     // Positioning the view manually should override any current movement state
1721     d->moveReason = QSGGridViewPrivate::Other;
1722     QSGFlickable::setContentY(pos);
1723 }
1724
1725 void QSGGridView::updatePolish() 
1726 {
1727     Q_D(QSGGridView);
1728     QSGFlickable::updatePolish();
1729     d->layout();
1730 }
1731
1732 void QSGGridView::viewportMoved()
1733 {
1734     Q_D(QSGGridView);
1735     QSGFlickable::viewportMoved();
1736     if (!d->itemCount)
1737         return;
1738     d->lazyRelease = true;
1739     if (d->flickingHorizontally || d->flickingVertically) {
1740         if (yflick()) {
1741             if (d->vData.velocity > 0)
1742                 d->bufferMode = QSGGridViewPrivate::BufferBefore;
1743             else if (d->vData.velocity < 0)
1744                 d->bufferMode = QSGGridViewPrivate::BufferAfter;
1745         }
1746
1747         if (xflick()) {
1748             if (d->hData.velocity > 0)
1749                 d->bufferMode = QSGGridViewPrivate::BufferBefore;
1750             else if (d->hData.velocity < 0)
1751                 d->bufferMode = QSGGridViewPrivate::BufferAfter;
1752         }
1753     }
1754     refill();
1755     if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
1756         d->moveReason = QSGGridViewPrivate::Mouse;
1757     if (d->moveReason != QSGGridViewPrivate::SetIndex) {
1758         if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
1759             // reposition highlight
1760             qreal pos = d->highlight->rowPos();
1761             qreal viewPos;
1762             qreal highlightStart;
1763             qreal highlightEnd;
1764             if (d->isRightToLeftTopToBottom()) {
1765                 highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
1766                 highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
1767                 viewPos = -d->position()-d->size();
1768             } else {
1769                 highlightStart = d->highlightRangeStart;
1770                 highlightEnd = d->highlightRangeEnd;
1771                 viewPos = d->position();
1772             }
1773             if (pos > viewPos + highlightEnd - d->rowSize())
1774                 pos = viewPos + highlightEnd - d->rowSize();
1775             if (pos < viewPos + highlightStart)
1776                 pos = viewPos + highlightStart;
1777             d->highlight->setPosition(d->highlight->colPos(), qRound(pos));
1778
1779             // update current index
1780             int idx = d->snapIndex();
1781             if (idx >= 0 && idx != d->currentIndex) {
1782                 d->updateCurrent(idx);
1783                 if (d->currentItem && d->currentItem->colPos() != d->highlight->colPos() && d->autoHighlight) {
1784                     if (d->flow == LeftToRight)
1785                         d->highlightXAnimator->to = d->currentItem->item->x();
1786                     else
1787                         d->highlightYAnimator->to = d->currentItem->item->y();
1788                 }
1789             }
1790         }
1791     }
1792 }
1793
1794 qreal QSGGridView::minYExtent() const
1795 {
1796     Q_D(const QSGGridView);
1797     if (d->flow == QSGGridView::TopToBottom)
1798         return QSGFlickable::minYExtent();
1799     qreal extent = -d->startPosition();
1800     if (d->header && d->visibleItems.count())
1801         extent += d->header->item->height();
1802     if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
1803         extent += d->highlightRangeStart;
1804         extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd));
1805     }
1806     return extent;
1807 }
1808
1809 qreal QSGGridView::maxYExtent() const
1810 {
1811     Q_D(const QSGGridView);
1812     if (d->flow == QSGGridView::TopToBottom)
1813         return QSGFlickable::maxYExtent();
1814     qreal extent;
1815     if (!d->model || !d->model->count()) {
1816         extent = 0;
1817     } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
1818         extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart);
1819         if (d->highlightRangeEnd != d->highlightRangeStart)
1820             extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1));
1821     } else {
1822         extent = -(d->endPosition() - height());
1823     }
1824     if (d->footer)
1825         extent -= d->footer->item->height();
1826     const qreal minY = minYExtent();
1827     if (extent > minY)
1828         extent = minY;
1829     return extent;
1830 }
1831
1832 qreal QSGGridView::minXExtent() const
1833 {
1834     Q_D(const QSGGridView);
1835     if (d->flow == QSGGridView::LeftToRight)
1836         return QSGFlickable::minXExtent();
1837     qreal extent = -d->startPosition();
1838     qreal highlightStart;
1839     qreal highlightEnd;
1840     qreal endPositionFirstItem;
1841     if (d->isRightToLeftTopToBottom()) {
1842         endPositionFirstItem = d->rowPosAt(d->model->count()-1);
1843         highlightStart = d->highlightRangeStartValid
1844                 ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
1845                 : d->size() - (d->lastPosition()-endPositionFirstItem);
1846         highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
1847         if (d->footer && d->visibleItems.count())
1848             extent += d->footer->item->width();
1849     } else {
1850         endPositionFirstItem = d->rowPosAt(0)+d->rowSize();
1851         highlightStart = d->highlightRangeStart;
1852         highlightEnd = d->highlightRangeEnd;
1853         if (d->header && d->visibleItems.count())
1854             extent += d->header->item->width();
1855     }
1856     if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
1857         extent += highlightStart;
1858         extent = qMax(extent, -(endPositionFirstItem - highlightEnd));
1859     }
1860     return extent;
1861 }
1862
1863 qreal QSGGridView::maxXExtent() const
1864 {
1865     Q_D(const QSGGridView);
1866     if (d->flow == QSGGridView::LeftToRight)
1867         return QSGFlickable::maxXExtent();
1868     qreal extent;
1869     qreal highlightStart;
1870     qreal highlightEnd;
1871     qreal lastItemPosition;
1872     if (d->isRightToLeftTopToBottom()){
1873         highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
1874         highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
1875         lastItemPosition = d->endPosition();
1876     } else {
1877         highlightStart = d->highlightRangeStart;
1878         highlightEnd = d->highlightRangeEnd;
1879         if (d->model && d->model->count())
1880             lastItemPosition = d->rowPosAt(d->model->count()-1);
1881     }
1882     if (!d->model || !d->model->count()) {
1883         extent = 0;
1884     } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
1885         extent = -(lastItemPosition - highlightStart);
1886         if (highlightEnd != highlightStart)
1887             extent = d->isRightToLeftTopToBottom()
1888                     ? qMax(extent, -(d->endPosition() - highlightEnd + 1))
1889                     : qMin(extent, -(d->endPosition() - highlightEnd + 1));
1890     } else {
1891         extent = -(d->endPosition() - width());
1892     }
1893     if (d->isRightToLeftTopToBottom()) {
1894         if (d->header)
1895             extent -= d->header->item->width();
1896     } else {
1897         if (d->footer)
1898             extent -= d->footer->item->width();
1899     }
1900
1901     const qreal minX = minXExtent();
1902     if (extent > minX)
1903         extent = minX;
1904     return extent;
1905 }
1906
1907 void QSGGridView::keyPressEvent(QKeyEvent *event)
1908 {
1909     Q_D(QSGGridView);
1910     if (d->model && d->model->count() && d->interactive) {
1911         d->moveReason = QSGGridViewPrivate::SetIndex;
1912         int oldCurrent = currentIndex();
1913         switch (event->key()) {
1914         case Qt::Key_Up:
1915             moveCurrentIndexUp();
1916             break;
1917         case Qt::Key_Down:
1918             moveCurrentIndexDown();
1919             break;
1920         case Qt::Key_Left:
1921             moveCurrentIndexLeft();
1922             break;
1923         case Qt::Key_Right:
1924             moveCurrentIndexRight();
1925             break;
1926         default:
1927             break;
1928         }
1929         if (oldCurrent != currentIndex()) {
1930             event->accept();
1931             return;
1932         }
1933     }
1934     d->moveReason = QSGGridViewPrivate::Other;
1935     event->ignore();
1936     QSGFlickable::keyPressEvent(event);
1937 }
1938
1939 void QSGGridView::moveCurrentIndexUp()
1940 {
1941     Q_D(QSGGridView);
1942     const int count = d->model ? d->model->count() : 0;
1943     if (!count)
1944         return;
1945     if (d->flow == QSGGridView::LeftToRight) {
1946         if (currentIndex() >= d->columns || d->wrap) {
1947             int index = currentIndex() - d->columns;
1948             setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1949         }
1950     } else {
1951         if (currentIndex() > 0 || d->wrap) {
1952             int index = currentIndex() - 1;
1953             setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1954         }
1955     }
1956 }
1957
1958 void QSGGridView::moveCurrentIndexDown()
1959 {
1960     Q_D(QSGGridView);
1961     const int count = d->model ? d->model->count() : 0;
1962     if (!count)
1963         return;
1964     if (d->flow == QSGGridView::LeftToRight) {
1965         if (currentIndex() < count - d->columns || d->wrap) {
1966             int index = currentIndex()+d->columns;
1967             setCurrentIndex((index >= 0 && index < count) ? index : 0);
1968         }
1969     } else {
1970         if (currentIndex() < count - 1 || d->wrap) {
1971             int index = currentIndex() + 1;
1972             setCurrentIndex((index >= 0 && index < count) ? index : 0);
1973         }
1974     }
1975 }
1976
1977 void QSGGridView::moveCurrentIndexLeft()
1978 {
1979     Q_D(QSGGridView);
1980     const int count = d->model ? d->model->count() : 0;
1981     if (!count)
1982         return;
1983     if (effectiveLayoutDirection() == Qt::LeftToRight) {
1984         if (d->flow == QSGGridView::LeftToRight) {
1985             if (currentIndex() > 0 || d->wrap) {
1986                 int index = currentIndex() - 1;
1987                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1988             }
1989         } else {
1990             if (currentIndex() >= d->columns || d->wrap) {
1991                 int index = currentIndex() - d->columns;
1992                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1993             }
1994         }
1995     } else {
1996         if (d->flow == QSGGridView::LeftToRight) {
1997             if (currentIndex() < count - 1 || d->wrap) {
1998                 int index = currentIndex() + 1;
1999                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2000             }
2001         } else {
2002             if (currentIndex() < count - d->columns || d->wrap) {
2003                 int index = currentIndex() + d->columns;
2004                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2005             }
2006         }
2007     }
2008 }
2009
2010 void QSGGridView::moveCurrentIndexRight()
2011 {
2012     Q_D(QSGGridView);
2013     const int count = d->model ? d->model->count() : 0;
2014     if (!count)
2015         return;
2016     if (effectiveLayoutDirection() == Qt::LeftToRight) {
2017         if (d->flow == QSGGridView::LeftToRight) {
2018             if (currentIndex() < count - 1 || d->wrap) {
2019                 int index = currentIndex() + 1;
2020                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2021             }
2022         } else {
2023             if (currentIndex() < count - d->columns || d->wrap) {
2024                 int index = currentIndex()+d->columns;
2025                 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2026             }
2027         }
2028     } else {
2029         if (d->flow == QSGGridView::LeftToRight) {
2030             if (currentIndex() > 0 || d->wrap) {
2031                 int index = currentIndex() - 1;
2032                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2033             }
2034         } else {
2035             if (currentIndex() >= d->columns || d->wrap) {
2036                 int index = currentIndex() - d->columns;
2037                 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2038             }
2039         }
2040     }
2041 }
2042
2043 void QSGGridViewPrivate::positionViewAtIndex(int index, int mode)
2044 {
2045     Q_Q(QSGGridView);
2046     if (!isValid())
2047         return;
2048     if (mode < QSGGridView::Beginning || mode > QSGGridView::Contain)
2049         return;
2050
2051     int idx = qMax(qMin(index, model->count()-1), 0);
2052
2053     if (layoutScheduled)
2054         layout();
2055     qreal pos = isRightToLeftTopToBottom() ? -position() - size() : position();
2056     FxGridItemSG *item = visibleItem(idx);
2057     qreal maxExtent;
2058     if (flow == QSGGridView::LeftToRight)
2059         maxExtent = -q->maxYExtent();
2060     else
2061         maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2062     if (!item) {
2063         int itemPos = rowPosAt(idx);
2064         // save the currently visible items in case any of them end up visible again
2065         QList<FxGridItemSG*> oldVisible = visibleItems;
2066         visibleItems.clear();
2067         visibleIndex = idx - idx % columns;
2068         if (flow == QSGGridView::LeftToRight)
2069             maxExtent = -q->maxYExtent();
2070         else
2071             maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2072         setPosition(qMin(qreal(itemPos), maxExtent));
2073         // now release the reference to all the old visible items.
2074         for (int i = 0; i < oldVisible.count(); ++i)
2075             releaseItem(oldVisible.at(i));
2076         item = visibleItem(idx);
2077     }
2078     if (item) {
2079         qreal itemPos = item->rowPos();
2080         switch (mode) {
2081         case QSGGridView::Beginning:
2082             pos = itemPos;
2083             if (index < 0 && header) {
2084                 pos -= flow == QSGGridView::LeftToRight
2085                             ? header->item->height()
2086                             : header->item->width();
2087             }
2088             break;
2089         case QSGGridView::Center:
2090             pos = itemPos - (size() - rowSize())/2;
2091             break;
2092         case QSGGridView::End:
2093             pos = itemPos - size() + rowSize();
2094             if (index >= model->count() && footer) {
2095                 pos += flow == QSGGridView::LeftToRight
2096                             ? footer->item->height()
2097                             : footer->item->width();
2098             }
2099             break;
2100         case QSGGridView::Visible:
2101             if (itemPos > pos + size())
2102                 pos = itemPos - size() + rowSize();
2103             else if (item->endRowPos() < pos)
2104                 pos = itemPos;
2105             break;
2106         case QSGGridView::Contain:
2107             if (item->endRowPos() > pos + size())
2108                 pos = itemPos - size() + rowSize();
2109             if (itemPos < pos)
2110                 pos = itemPos;
2111         }
2112         pos = qMin(pos, maxExtent);
2113         qreal minExtent;
2114         if (flow == QSGGridView::LeftToRight)
2115             minExtent = -q->minYExtent();
2116         else
2117             minExtent = isRightToLeftTopToBottom() ? q->maxXExtent()-size() : -q->minXExtent();
2118         pos = qMax(pos, minExtent);
2119         moveReason = QSGGridViewPrivate::Other;
2120         q->cancelFlick();
2121         setPosition(pos);
2122     }
2123     fixupPosition();
2124 }
2125
2126 void QSGGridView::positionViewAtIndex(int index, int mode)
2127 {
2128     Q_D(QSGGridView);
2129     if (!d->isValid() || index < 0 || index >= d->model->count())
2130         return;
2131     d->positionViewAtIndex(index, mode);
2132 }
2133
2134 void QSGGridView::positionViewAtBeginning()
2135 {
2136     Q_D(QSGGridView);
2137     if (!d->isValid())
2138         return;
2139     d->positionViewAtIndex(-1, Beginning);
2140 }
2141
2142 void QSGGridView::positionViewAtEnd()
2143 {
2144     Q_D(QSGGridView);
2145     if (!d->isValid())
2146         return;
2147     d->positionViewAtIndex(d->model->count(), End);
2148 }
2149
2150 int QSGGridView::indexAt(qreal x, qreal y) const
2151 {
2152     Q_D(const QSGGridView);
2153     for (int i = 0; i < d->visibleItems.count(); ++i) {
2154         const FxGridItemSG *listItem = d->visibleItems.at(i);
2155         if(listItem->contains(x, y))
2156             return listItem->index;
2157     }
2158
2159     return -1;
2160 }
2161
2162 void QSGGridView::componentComplete()
2163 {
2164     Q_D(QSGGridView);
2165     QSGFlickable::componentComplete();
2166     d->updateHeader();
2167     d->updateFooter();
2168     d->updateGrid();
2169     if (d->isValid()) {
2170         refill();
2171         d->moveReason = QSGGridViewPrivate::SetIndex;
2172         if (d->currentIndex < 0 && !d->currentIndexCleared)
2173             d->updateCurrent(0);
2174         else
2175             d->updateCurrent(d->currentIndex);
2176         if (d->highlight && d->currentItem) {
2177             if (d->autoHighlight)
2178                 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
2179             d->updateTrackedItem();
2180         }
2181         d->moveReason = QSGGridViewPrivate::Other;
2182         d->fixupPosition();
2183     }
2184 }
2185
2186 void QSGGridView::trackedPositionChanged()
2187 {
2188     Q_D(QSGGridView);
2189     if (!d->trackedItem || !d->currentItem)
2190         return;
2191     if (d->moveReason == QSGGridViewPrivate::SetIndex) {
2192         const qreal trackedPos = d->trackedItem->rowPos();
2193         qreal viewPos;
2194         qreal highlightStart;
2195         qreal highlightEnd;
2196         if (d->isRightToLeftTopToBottom()) {
2197             viewPos = -d->position()-d->size();
2198             highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
2199             highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
2200         } else {
2201             viewPos = d->position();
2202             highlightStart = d->highlightRangeStart;
2203             highlightEnd = d->highlightRangeEnd;
2204         }
2205         qreal pos = viewPos;
2206         if (d->haveHighlightRange) {
2207             if (d->highlightRange == StrictlyEnforceRange) {
2208                 if (trackedPos > pos + highlightEnd - d->rowSize())
2209                     pos = trackedPos - highlightEnd + d->rowSize();
2210                 if (trackedPos < pos + highlightStart)
2211                     pos = trackedPos - highlightStart;
2212             } else {
2213                 if (trackedPos < d->startPosition() + highlightStart) {
2214                     pos = d->startPosition();
2215                 } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + highlightEnd) {
2216                     pos = d->endPosition() - d->size() + 1;
2217                     if (pos < d->startPosition())
2218                         pos = d->startPosition();
2219                 } else {
2220                     if (trackedPos < viewPos + highlightStart) {
2221                         pos = trackedPos - highlightStart;
2222                     } else if (trackedPos > viewPos + highlightEnd - d->rowSize()) {
2223                         pos = trackedPos - highlightEnd + d->rowSize();
2224                     }
2225                 }
2226             }
2227         } else {
2228             if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) {
2229                 pos = qMax(trackedPos, d->currentItem->rowPos());
2230             } else if (d->trackedItem->endRowPos() >= viewPos + d->size()
2231                 && d->currentItem->endRowPos() >= viewPos + d->size()) {
2232                 if (d->trackedItem->endRowPos() <= d->currentItem->endRowPos()) {
2233                     pos = d->trackedItem->endRowPos() - d->size() + 1;
2234                     if (d->rowSize() > d->size())
2235                         pos = trackedPos;
2236                 } else {
2237                     pos = d->currentItem->endRowPos() - d->size() + 1;
2238                     if (d->rowSize() > d->size())
2239                         pos = d->currentItem->rowPos();
2240                 }
2241             }
2242         }
2243         if (viewPos != pos) {
2244             cancelFlick();
2245             d->calcVelocity = true;
2246             d->setPosition(pos);
2247             d->calcVelocity = false;
2248         }
2249     }
2250 }
2251
2252 void QSGGridView::itemsInserted(int modelIndex, int count)
2253 {
2254     Q_D(QSGGridView);
2255     if (!isComponentComplete())
2256         return;
2257
2258     int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
2259     if (index < 0) {
2260         int i = d->visibleItems.count() - 1;
2261         while (i > 0 && d->visibleItems.at(i)->index == -1)
2262             --i;
2263         if (d->visibleItems.at(i)->index + 1 == modelIndex) {
2264             // Special case of appending an item to the model.
2265             index = d->visibleIndex + d->visibleItems.count();
2266         } else {
2267             if (modelIndex <= d->visibleIndex) {
2268                 // Insert before visible items
2269                 d->visibleIndex += count;
2270                 for (int i = 0; i < d->visibleItems.count(); ++i) {
2271                     FxGridItemSG *listItem = d->visibleItems.at(i);
2272                     if (listItem->index != -1 && listItem->index >= modelIndex)
2273                         listItem->index += count;
2274                 }
2275             }
2276             if (d->currentIndex >= modelIndex) {
2277                 // adjust current item index
2278                 d->currentIndex += count;
2279                 if (d->currentItem)
2280                     d->currentItem->index = d->currentIndex;
2281                 emit currentIndexChanged();
2282             }
2283             d->scheduleLayout();
2284             d->itemCount += count;
2285             emit countChanged();
2286             return;
2287         }
2288     }
2289
2290     int insertCount = count;
2291     if (index < d->visibleIndex && d->visibleItems.count()) {
2292         insertCount -= d->visibleIndex - index;
2293         index = d->visibleIndex;
2294         modelIndex = d->visibleIndex;
2295     }
2296
2297     qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+width()+1 : d->position();
2298     int to = d->buffer+tempPos+d->size()-1;
2299     int colPos = 0;
2300     int rowPos = 0;
2301     if (d->visibleItems.count()) {
2302         index -= d->visibleIndex;
2303         if (index < d->visibleItems.count()) {
2304             colPos = d->visibleItems.at(index)->colPos();
2305             rowPos = d->visibleItems.at(index)->rowPos();
2306         } else {
2307             // appending items to visible list
2308             colPos = d->visibleItems.at(index-1)->colPos() + d->colSize();
2309             rowPos = d->visibleItems.at(index-1)->rowPos();
2310             if (colPos > d->colSize() * (d->columns-1)) {
2311                 colPos = 0;
2312                 rowPos += d->rowSize();
2313             }
2314         }
2315     } else if (d->itemCount == 0 && d->header) {
2316         rowPos = d->headerSize();
2317     }
2318
2319     // Update the indexes of the following visible items.
2320     for (int i = 0; i < d->visibleItems.count(); ++i) {
2321         FxGridItemSG *listItem = d->visibleItems.at(i);
2322         if (listItem->index != -1 && listItem->index >= modelIndex)
2323             listItem->index += count;
2324     }
2325
2326     bool addedVisible = false;
2327     QList<FxGridItemSG*> added;
2328     int i = 0;
2329     while (i < insertCount && rowPos <= to + d->rowSize()*(d->columns - (colPos/d->colSize()))/qreal(d->columns)) {
2330         if (!addedVisible) {
2331             d->scheduleLayout();
2332             addedVisible = true;
2333         }
2334         FxGridItemSG *item = d->createItem(modelIndex + i);
2335         d->visibleItems.insert(index, item);
2336         item->setPosition(colPos, rowPos);
2337         added.append(item);
2338         colPos += d->colSize();
2339         if (colPos > d->colSize() * (d->columns-1)) {
2340             colPos = 0;
2341             rowPos += d->rowSize();
2342         }
2343         ++index;
2344         ++i;
2345     }
2346     if (i < insertCount) {
2347         // We didn't insert all our new items, which means anything
2348         // beyond the current index is not visible - remove it.
2349         while (d->visibleItems.count() > index) {
2350             d->releaseItem(d->visibleItems.takeLast());
2351         }
2352     }
2353
2354     // update visibleIndex
2355     d->visibleIndex = 0;
2356     for (QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2357         if ((*it)->index != -1) {
2358             d->visibleIndex = (*it)->index;
2359             break;
2360         }
2361     }
2362
2363     if (d->itemCount && d->currentIndex >= modelIndex) {
2364         // adjust current item index
2365         d->currentIndex += count;
2366         if (d->currentItem) {
2367             d->currentItem->index = d->currentIndex;
2368             d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
2369         } else if (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared)) {
2370             d->updateCurrent(0);
2371         }
2372         emit currentIndexChanged();
2373     } else if (d->itemCount == 0 && d->currentIndex == -1) {
2374         setCurrentIndex(0);
2375     }
2376
2377     // everything is in order now - emit add() signal
2378     for (int j = 0; j < added.count(); ++j)
2379         added.at(j)->attached->emitAdd();
2380
2381     d->itemCount += count;
2382     emit countChanged();
2383 }
2384
2385 void QSGGridView::itemsRemoved(int modelIndex, int count)
2386 {
2387     Q_D(QSGGridView);
2388     if (!isComponentComplete())
2389         return;
2390
2391     d->itemCount -= count;
2392     bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count;
2393     bool removedVisible = false;
2394
2395     // Remove the items from the visible list, skipping anything already marked for removal
2396     QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
2397     while (it != d->visibleItems.end()) {
2398         FxGridItemSG *item = *it;
2399         if (item->index == -1 || item->index < modelIndex) {
2400             // already removed, or before removed items
2401             if (item->index < modelIndex && !removedVisible) {
2402                 d->scheduleLayout();
2403                 removedVisible = true;
2404             }
2405             ++it;
2406         } else if (item->index >= modelIndex + count) {
2407             // after removed items
2408             item->index -= count;
2409             ++it;
2410         } else {
2411             // removed item
2412             if (!removedVisible) {
2413                 d->scheduleLayout();
2414                 removedVisible = true;
2415             }
2416             item->attached->emitRemove();
2417             if (item->attached->delayRemove()) {
2418                 item->index = -1;
2419                 connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
2420                 ++it;
2421             } else {
2422                 it = d->visibleItems.erase(it);
2423                 d->releaseItem(item);
2424             }
2425         }
2426     }
2427
2428     // fix current
2429     if (d->currentIndex >= modelIndex + count) {
2430         d->currentIndex -= count;
2431         if (d->currentItem)
2432             d->currentItem->index -= count;
2433         emit currentIndexChanged();
2434     } else if (currentRemoved) {
2435         // current item has been removed.
2436         d->releaseItem(d->currentItem);
2437         d->currentItem = 0;
2438         d->currentIndex = -1;
2439         if (d->itemCount)
2440             d->updateCurrent(qMin(modelIndex, d->itemCount-1));
2441     }
2442
2443     // update visibleIndex
2444     d->visibleIndex = 0;
2445     for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2446         if ((*it)->index != -1) {
2447             d->visibleIndex = (*it)->index;
2448             break;
2449         }
2450     }
2451
2452     if (removedVisible && d->visibleItems.isEmpty()) {
2453         d->timeline.clear();
2454         if (d->itemCount == 0) {
2455             d->setPosition(0);
2456             d->updateHeader();
2457             d->updateFooter();
2458         }
2459     }
2460
2461     emit countChanged();
2462 }
2463
2464 void QSGGridView::destroyRemoved()
2465 {
2466     Q_D(QSGGridView);
2467     for (QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
2468             it != d->visibleItems.end();) {
2469         FxGridItemSG *listItem = *it;
2470         if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
2471             d->releaseItem(listItem);
2472             it = d->visibleItems.erase(it);
2473         } else {
2474             ++it;
2475         }
2476     }
2477
2478     // Correct the positioning of the items
2479     d->layout();
2480 }
2481
2482 void QSGGridView::itemsMoved(int from, int to, int count)
2483 {
2484     Q_D(QSGGridView);
2485     if (!isComponentComplete())
2486         return;
2487     QHash<int,FxGridItemSG*> moved;
2488
2489     FxGridItemSG *firstItem = d->firstVisibleItem();
2490
2491     QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
2492     while (it != d->visibleItems.end()) {
2493         FxGridItemSG *item = *it;
2494         if (item->index >= from && item->index < from + count) {
2495             // take the items that are moving
2496             item->index += (to-from);
2497             moved.insert(item->index, item);
2498             it = d->visibleItems.erase(it);
2499         } else {
2500             if (item->index > from && item->index != -1) {
2501                 // move everything after the moved items.
2502                 item->index -= count;
2503                 if (item->index < d->visibleIndex)
2504                     d->visibleIndex = item->index;
2505             }
2506             ++it;
2507         }
2508     }
2509
2510     int remaining = count;
2511     int endIndex = d->visibleIndex;
2512     it = d->visibleItems.begin();
2513     while (it != d->visibleItems.end()) {
2514         FxGridItemSG *item = *it;
2515         if (remaining && item->index >= to && item->index < to + count) {
2516             // place items in the target position, reusing any existing items
2517             FxGridItemSG *movedItem = moved.take(item->index);
2518             if (!movedItem)
2519                 movedItem = d->createItem(item->index);
2520             it = d->visibleItems.insert(it, movedItem);
2521             if (it == d->visibleItems.begin() && firstItem)
2522                 movedItem->setPosition(firstItem->colPos(), firstItem->rowPos());
2523             ++it;
2524             --remaining;
2525         } else {
2526             if (item->index != -1) {
2527                 if (item->index >= to) {
2528                     // update everything after the moved items.
2529                     item->index += count;
2530                 }
2531                 endIndex = item->index;
2532             }
2533             ++it;
2534         }
2535     }
2536
2537     // If we have moved items to the end of the visible items
2538     // then add any existing moved items that we have
2539     while (FxGridItemSG *item = moved.take(endIndex+1)) {
2540         d->visibleItems.append(item);
2541         ++endIndex;
2542     }
2543
2544     // update visibleIndex
2545     for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2546         if ((*it)->index != -1) {
2547             d->visibleIndex = (*it)->index;
2548             break;
2549         }
2550     }
2551
2552     // Fix current index
2553     if (d->currentIndex >= 0 && d->currentItem) {
2554         int oldCurrent = d->currentIndex;
2555         d->currentIndex = d->model->indexOf(d->currentItem->item, this);
2556         if (oldCurrent != d->currentIndex) {
2557             d->currentItem->index = d->currentIndex;
2558             emit currentIndexChanged();
2559         }
2560     }
2561
2562     // Whatever moved items remain are no longer visible items.
2563     while (moved.count()) {
2564         int idx = moved.begin().key();
2565         FxGridItemSG *item = moved.take(idx);
2566         if (d->currentItem && item->item == d->currentItem->item)
2567             item->setPosition(d->colPosAt(idx), d->rowPosAt(idx));
2568         d->releaseItem(item);
2569     }
2570
2571     d->layout();
2572 }
2573
2574 void QSGGridView::modelReset()
2575 {
2576     Q_D(QSGGridView);
2577     d->clear();
2578     refill();
2579     d->moveReason = QSGGridViewPrivate::SetIndex;
2580     d->updateCurrent(d->currentIndex);
2581     if (d->highlight && d->currentItem) {
2582         if (d->autoHighlight)
2583             d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
2584         d->updateTrackedItem();
2585     }
2586     d->moveReason = QSGGridViewPrivate::Other;
2587
2588     emit countChanged();
2589 }
2590
2591 void QSGGridView::createdItem(int index, QSGItem *item)
2592 {
2593     Q_D(QSGGridView);
2594     if (d->requestedIndex != index) {
2595         item->setParentItem(this);
2596         d->unrequestedItems.insert(item, index);
2597         if (d->flow == QSGGridView::LeftToRight) {
2598             item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index)));
2599         } else {
2600             item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index)));
2601         }
2602     }
2603 }
2604
2605 void QSGGridView::destroyingItem(QSGItem *item)
2606 {
2607     Q_D(QSGGridView);
2608     d->unrequestedItems.remove(item);
2609 }
2610
2611 void QSGGridView::animStopped()
2612 {
2613     Q_D(QSGGridView);
2614     d->bufferMode = QSGGridViewPrivate::NoBuffer;
2615     if (d->haveHighlightRange && d->highlightRange == QSGGridView::StrictlyEnforceRange)
2616         d->updateHighlight();
2617 }
2618
2619 void QSGGridView::refill()
2620 {
2621     Q_D(QSGGridView);
2622     if (d->isRightToLeftTopToBottom())
2623         d->refill(-d->position()-d->size()+1, -d->position());
2624     else
2625         d->refill(d->position(), d->position()+d->size()-1);
2626 }
2627
2628
2629 QSGGridViewAttached *QSGGridView::qmlAttachedProperties(QObject *obj)
2630 {
2631     return new QSGGridViewAttached(obj);
2632 }
2633
2634 QT_END_NAMESPACE