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