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