80681f7dd7da64c9863e2461eb32c36d0d032990
[profile/ivi/qtdeclarative.git] / src / quick / items / qquicklistview.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquicklistview_p.h"
43 #include "qquickitemview_p_p.h"
44 #include "qquickvisualitemmodel_p.h"
45
46 #include <QtDeclarative/qdeclarativeexpression.h>
47 #include <QtDeclarative/qdeclarativeengine.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QtCore/qmath.h>
51 #include <QtCore/qcoreapplication.h>
52
53 #include <private/qdeclarativesmoothedanimation_p_p.h>
54 #include <private/qlistmodelinterface_p.h>
55 #include "qplatformdefs.h"
56
57 QT_BEGIN_NAMESPACE
58
59 #ifndef QML_FLICK_SNAPONETHRESHOLD
60 #define QML_FLICK_SNAPONETHRESHOLD 30
61 #endif
62
63 //#define DEBUG_DELEGATE_LIFECYCLE
64
65 class FxListItemSG;
66
67 class QQuickListViewPrivate : public QQuickItemViewPrivate
68 {
69     Q_DECLARE_PUBLIC(QQuickListView)
70 public:
71     static QQuickListViewPrivate* get(QQuickListView *item) { return item->d_func(); }
72
73     virtual Qt::Orientation layoutOrientation() const;
74     virtual bool isContentFlowReversed() const;
75     bool isRightToLeft() const;
76
77     virtual qreal positionAt(int index) const;
78     virtual qreal endPositionAt(int index) const;
79     virtual qreal originPosition() const;
80     virtual qreal lastPosition() const;
81
82     FxViewItem *itemBefore(int modelIndex) const;
83     QString sectionAt(int modelIndex);
84     qreal snapPosAt(qreal pos);
85     FxViewItem *snapItemAt(qreal pos);
86
87     virtual void init();
88     virtual void clear();
89
90     virtual bool addVisibleItems(qreal fillFrom, qreal fillTo, bool doBuffer);
91     virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
92     virtual void visibleItemsChanged();
93
94     virtual FxViewItem *newViewItem(int index, QQuickItem *item);
95     virtual void initializeViewItem(FxViewItem *item);
96     virtual void releaseItem(FxViewItem *item);
97     virtual void repositionPackageItemAt(QQuickItem *item, int index);
98     virtual void resetFirstItemPosition(qreal pos = 0.0);
99     virtual void adjustFirstItem(qreal forwards, qreal backwards, int);
100
101     virtual void createHighlight();
102     virtual void updateHighlight();
103     virtual void resetHighlightPosition();
104
105     virtual void setPosition(qreal pos);
106     virtual void layoutVisibleItems(int fromModelIndex = 0);
107     virtual bool applyInsertionChange(const QDeclarativeChangeSet::Insert &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems);
108
109     virtual void updateSections();
110     QQuickItem *getSectionItem(const QString &section);
111     void releaseSectionItem(QQuickItem *item);
112     void updateInlineSection(FxListItemSG *);
113     void updateCurrentSection();
114     void updateStickySections();
115
116     virtual qreal headerSize() const;
117     virtual qreal footerSize() const;
118     virtual bool showHeaderForIndex(int index) const;
119     virtual bool showFooterForIndex(int index) const;
120     virtual void updateHeader();
121     virtual void updateFooter();
122
123     virtual void changedVisibleIndex(int newIndex);
124     virtual void initializeCurrentItem();
125
126     void updateAverage();
127
128     void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
129     virtual void fixupPosition();
130     virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
131     virtual void flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
132                         QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
133
134     QQuickListView::Orientation orient;
135     qreal visiblePos;
136     qreal averageSize;
137     qreal spacing;
138     QQuickListView::SnapMode snapMode;
139
140     QSmoothedAnimation *highlightPosAnimator;
141     QSmoothedAnimation *highlightSizeAnimator;
142     qreal highlightMoveSpeed;
143     qreal highlightResizeSpeed;
144     int highlightResizeDuration;
145
146     QQuickViewSection *sectionCriteria;
147     QString currentSection;
148     static const int sectionCacheSize = 5;
149     QQuickItem *sectionCache[sectionCacheSize];
150     QQuickItem *currentSectionItem;
151     QString currentStickySection;
152     QQuickItem *nextSectionItem;
153     QString nextStickySection;
154     QString lastVisibleSection;
155     QString nextSection;
156
157     qreal overshootDist;
158     bool correctFlick : 1;
159     bool inFlickCorrection : 1;
160
161     QQuickListViewPrivate()
162         : orient(QQuickListView::Vertical)
163         , visiblePos(0)
164         , averageSize(100.0), spacing(0.0)
165         , snapMode(QQuickListView::NoSnap)
166         , highlightPosAnimator(0), highlightSizeAnimator(0)
167         , highlightMoveSpeed(400), highlightResizeSpeed(400), highlightResizeDuration(-1)
168         , sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
169         , overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
170     {}
171
172     friend class QQuickViewSection;
173 };
174
175 //----------------------------------------------------------------------------
176
177 QQuickViewSection::QQuickViewSection(QQuickListView *parent)
178     : QObject(parent), m_criteria(FullString), m_delegate(0), m_labelPositioning(InlineLabels)
179     , m_view(parent ? QQuickListViewPrivate::get(parent) : 0)
180 {
181 }
182
183 void QQuickViewSection::setProperty(const QString &property)
184 {
185     if (property != m_property) {
186         m_property = property;
187         emit propertyChanged();
188         m_view->updateSections();
189     }
190 }
191
192 void QQuickViewSection::setCriteria(QQuickViewSection::SectionCriteria criteria)
193 {
194     if (criteria != m_criteria) {
195         m_criteria = criteria;
196         emit criteriaChanged();
197         m_view->updateSections();
198     }
199 }
200
201 void QQuickViewSection::setDelegate(QDeclarativeComponent *delegate)
202 {
203     if (delegate != m_delegate) {
204         m_delegate = delegate;
205         emit delegateChanged();
206         m_view->updateSections();
207     }
208 }
209
210 QString QQuickViewSection::sectionString(const QString &value)
211 {
212     if (m_criteria == FirstCharacter)
213         return value.isEmpty() ? QString() : value.at(0);
214     else
215         return value;
216 }
217
218 void QQuickViewSection::setLabelPositioning(int l)
219 {
220     if (m_labelPositioning != l) {
221         m_labelPositioning = l;
222         emit labelPositioningChanged();
223         m_view->updateSections();
224     }
225 }
226
227 //----------------------------------------------------------------------------
228
229 class FxListItemSG : public FxViewItem
230 {
231 public:
232     FxListItemSG(QQuickItem *i, QQuickListView *v, bool own) : FxViewItem(i, own), section(0), view(v) {
233         attached = static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(item));
234         if (attached)
235             static_cast<QQuickListViewAttached*>(attached)->setView(view);
236     }
237
238     ~FxListItemSG() {}
239
240     qreal position() const {
241         if (section) {
242             if (view->orientation() == QQuickListView::Vertical)
243                 return section->y();
244             else
245                 return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section->width()-section->x() : section->x());
246         } else {
247             return itemPosition();
248         }
249     }
250     qreal itemPosition() const {
251         if (view->orientation() == QQuickListView::Vertical)
252             return item->y();
253         else
254             return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-item->x() : item->x());
255     }
256     qreal size() const {
257         if (section)
258             return (view->orientation() == QQuickListView::Vertical ? item->height()+section->height() : item->width()+section->width());
259         else
260             return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
261     }
262     qreal itemSize() const {
263         return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
264     }
265     qreal sectionSize() const {
266         if (section)
267             return (view->orientation() == QQuickListView::Vertical ? section->height() : section->width());
268         return 0.0;
269     }
270     qreal endPosition() const {
271         if (view->orientation() == QQuickListView::Vertical) {
272             return item->y() + item->height();
273         } else {
274             return (view->effectiveLayoutDirection() == Qt::RightToLeft
275                     ? -item->x()
276                     : item->x() + item->width());
277         }
278     }
279     void setPosition(qreal pos) {
280         if (view->orientation() == QQuickListView::Vertical) {
281             if (section) {
282                 section->setY(pos);
283                 pos += section->height();
284             }
285             item->setY(pos);
286         } else {
287             if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
288                 if (section) {
289                     section->setX(-section->width()-pos);
290                     pos += section->width();
291                 }
292                 item->setX(-item->width()-pos);
293             } else {
294                 if (section) {
295                     section->setX(pos);
296                     pos += section->width();
297                 }
298                 item->setX(pos);
299             }
300         }
301     }
302     void setSize(qreal size) {
303         if (view->orientation() == QQuickListView::Vertical)
304             item->setHeight(size);
305         else
306             item->setWidth(size);
307     }
308     bool contains(qreal x, qreal y) const {
309         return (x >= item->x() && x < item->x() + item->width() &&
310                 y >= item->y() && y < item->y() + item->height());
311     }
312
313     QQuickItem *section;
314     QQuickListView *view;
315 };
316
317 //----------------------------------------------------------------------------
318
319 bool QQuickListViewPrivate::isContentFlowReversed() const
320 {
321     return isRightToLeft();
322 }
323
324 Qt::Orientation QQuickListViewPrivate::layoutOrientation() const
325 {
326     return static_cast<Qt::Orientation>(orient);
327 }
328
329 bool QQuickListViewPrivate::isRightToLeft() const
330 {
331     Q_Q(const QQuickListView);
332     return orient == QQuickListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
333 }
334
335 // Returns the item before modelIndex, if created.
336 // May return an item marked for removal.
337 FxViewItem *QQuickListViewPrivate::itemBefore(int modelIndex) const
338 {
339     if (modelIndex < visibleIndex)
340         return 0;
341     int idx = 1;
342     int lastIndex = -1;
343     while (idx < visibleItems.count()) {
344         FxViewItem *item = visibleItems.at(idx);
345         if (item->index != -1)
346             lastIndex = item->index;
347         if (item->index == modelIndex)
348             return visibleItems.at(idx-1);
349         ++idx;
350     }
351     if (lastIndex == modelIndex-1)
352         return visibleItems.last();
353     return 0;
354 }
355
356 void QQuickListViewPrivate::setPosition(qreal pos)
357 {
358     Q_Q(QQuickListView);
359     if (orient == QQuickListView::Vertical) {
360         q->QQuickFlickable::setContentY(pos);
361     } else {
362         if (isRightToLeft())
363             q->QQuickFlickable::setContentX(-pos-size());
364         else
365             q->QQuickFlickable::setContentX(pos);
366     }
367 }
368
369 qreal QQuickListViewPrivate::originPosition() const
370 {
371     qreal pos = 0;
372     if (!visibleItems.isEmpty()) {
373         pos = (*visibleItems.constBegin())->position();
374         if (visibleIndex > 0)
375             pos -= visibleIndex * (averageSize + spacing);
376     }
377     return pos;
378 }
379
380 qreal QQuickListViewPrivate::lastPosition() const
381 {
382     qreal pos = 0;
383     if (!visibleItems.isEmpty()) {
384         int invisibleCount = visibleItems.count() - visibleIndex;
385         for (int i = visibleItems.count()-1; i >= 0; --i) {
386             if (visibleItems.at(i)->index != -1) {
387                 invisibleCount = model->count() - visibleItems.at(i)->index - 1;
388                 break;
389             }
390         }
391         pos = (*(--visibleItems.constEnd()))->endPosition() + invisibleCount * (averageSize + spacing);
392     } else if (model && model->count()) {
393         pos = (model->count() * averageSize + (model->count()-1) * spacing);
394     }
395     return pos;
396 }
397
398 qreal QQuickListViewPrivate::positionAt(int modelIndex) const
399 {
400     if (FxViewItem *item = visibleItem(modelIndex))
401         return item->position();
402     if (!visibleItems.isEmpty()) {
403         if (modelIndex < visibleIndex) {
404             int count = visibleIndex - modelIndex;
405             qreal cs = 0;
406             if (modelIndex == currentIndex && currentItem) {
407                 cs = currentItem->size() + spacing;
408                 --count;
409             }
410             return (*visibleItems.constBegin())->position() - count * (averageSize + spacing) - cs;
411         } else {
412             int count = modelIndex - findLastVisibleIndex(visibleIndex) - 1;
413             return (*(--visibleItems.constEnd()))->endPosition() + spacing + count * (averageSize + spacing);
414         }
415     }
416     return 0;
417 }
418
419 qreal QQuickListViewPrivate::endPositionAt(int modelIndex) const
420 {
421     if (FxViewItem *item = visibleItem(modelIndex))
422         return item->endPosition();
423     if (!visibleItems.isEmpty()) {
424         if (modelIndex < visibleIndex) {
425             int count = visibleIndex - modelIndex;
426             return (*visibleItems.constBegin())->position() - (count - 1) * (averageSize + spacing) - spacing;
427         } else {
428             int count = modelIndex - findLastVisibleIndex(visibleIndex) - 1;
429             return (*(--visibleItems.constEnd()))->endPosition() + count * (averageSize + spacing);
430         }
431     }
432     return 0;
433 }
434
435 QString QQuickListViewPrivate::sectionAt(int modelIndex)
436 {
437     if (FxViewItem *item = visibleItem(modelIndex))
438         return item->attached->section();
439
440     QString section;
441     if (sectionCriteria) {
442         QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
443         section = sectionCriteria->sectionString(propValue);
444     }
445
446     return section;
447 }
448
449 qreal QQuickListViewPrivate::snapPosAt(qreal pos)
450 {
451     if (FxViewItem *snapItem = snapItemAt(pos))
452         return snapItem->position();
453     if (visibleItems.count()) {
454         qreal firstPos = (*visibleItems.constBegin())->position();
455         qreal endPos = (*(--visibleItems.constEnd()))->position();
456         if (pos < firstPos) {
457             return firstPos - qRound((firstPos - pos) / averageSize) * averageSize;
458         } else if (pos > endPos)
459             return endPos + qRound((pos - endPos) / averageSize) * averageSize;
460     }
461     return qRound((pos - originPosition()) / averageSize) * averageSize + originPosition();
462 }
463
464 FxViewItem *QQuickListViewPrivate::snapItemAt(qreal pos)
465 {
466     FxViewItem *snapItem = 0;
467     qreal prevItemSize = 0;
468     for (int i = 0; i < visibleItems.count(); ++i) {
469         FxViewItem *item = visibleItems.at(i);
470         if (item->index == -1)
471             continue;
472         qreal itemTop = item->position();
473         if (highlight && itemTop >= pos && item->endPosition() <= pos + highlight->size())
474             return item;
475         if (itemTop+item->size()/2 >= pos && itemTop-prevItemSize/2 < pos)
476             snapItem = item;
477         prevItemSize = item->size();
478     }
479     return snapItem;
480 }
481
482 void QQuickListViewPrivate::changedVisibleIndex(int newIndex)
483 {
484     visiblePos = positionAt(newIndex);
485     visibleIndex = newIndex;
486 }
487
488 void QQuickListViewPrivate::init()
489 {
490     QQuickItemViewPrivate::init();
491     ::memset(sectionCache, 0, sizeof(QQuickItem*) * sectionCacheSize);
492 }
493
494 void QQuickListViewPrivate::clear()
495 {
496     for (int i = 0; i < sectionCacheSize; ++i) {
497         delete sectionCache[i];
498         sectionCache[i] = 0;
499     }
500     visiblePos = 0;
501     currentSectionItem = 0;
502     nextSectionItem = 0;
503     lastVisibleSection = QString();
504     QQuickItemViewPrivate::clear();
505 }
506
507 FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
508 {
509     Q_Q(QQuickListView);
510
511     FxListItemSG *listItem = new FxListItemSG(item, q, false);
512     listItem->index = modelIndex;
513
514     // initialise attached properties
515     if (sectionCriteria) {
516         QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
517         listItem->attached->m_section = sectionCriteria->sectionString(propValue);
518         if (modelIndex > 0) {
519             if (FxViewItem *item = itemBefore(modelIndex))
520                 listItem->attached->m_prevSection = item->attached->section();
521             else
522                 listItem->attached->m_prevSection = sectionAt(modelIndex-1);
523         }
524         if (modelIndex < model->count()-1) {
525             if (FxViewItem *item = visibleItem(modelIndex+1))
526                 listItem->attached->m_nextSection = static_cast<QQuickListViewAttached*>(item->attached)->section();
527             else
528                 listItem->attached->m_nextSection = sectionAt(modelIndex+1);
529         }
530     }
531
532     return listItem;
533 }
534
535 void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
536 {
537     QQuickItemViewPrivate::initializeViewItem(item);
538
539     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item->item);
540     itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
541
542     if (sectionCriteria && sectionCriteria->delegate()) {
543         if (item->attached->m_prevSection != item->attached->m_section)
544             updateInlineSection(static_cast<FxListItemSG*>(item));
545     }
546 }
547
548 void QQuickListViewPrivate::releaseItem(FxViewItem *item)
549 {
550     if (item) {
551         FxListItemSG* listItem = static_cast<FxListItemSG*>(item);
552         if (listItem->section) {
553             int i = 0;
554             do {
555                 if (!sectionCache[i]) {
556                     sectionCache[i] = listItem->section;
557                     sectionCache[i]->setVisible(false);
558                     listItem->section = 0;
559                     break;
560                 }
561                 ++i;
562             } while (i < sectionCacheSize);
563             delete listItem->section;
564         }
565     }
566     QQuickItemViewPrivate::releaseItem(item);
567 }
568
569 bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool doBuffer)
570 {
571     qreal itemEnd = visiblePos;
572     if (visibleItems.count()) {
573         visiblePos = (*visibleItems.constBegin())->position();
574         itemEnd = (*(--visibleItems.constEnd()))->endPosition() + spacing;
575     }
576
577     int modelIndex = findLastVisibleIndex();
578     bool haveValidItems = modelIndex >= 0;
579     modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
580
581     if (haveValidItems && (fillFrom > itemEnd+averageSize+spacing
582         || fillTo < visiblePos - averageSize - spacing)) {
583         // We've jumped more than a page.  Estimate which items are now
584         // visible and fill from there.
585         int count = (fillFrom - itemEnd) / (averageSize + spacing);
586         for (int i = 0; i < visibleItems.count(); ++i)
587             releaseItem(visibleItems.at(i));
588         visibleItems.clear();
589         modelIndex += count;
590         if (modelIndex >= model->count()) {
591             count -= modelIndex - model->count() + 1;
592             modelIndex = model->count() - 1;
593         } else if (modelIndex < 0) {
594             count -= modelIndex;
595             modelIndex = 0;
596         }
597         visibleIndex = modelIndex;
598         visiblePos = itemEnd + count * (averageSize + spacing);
599         itemEnd = visiblePos;
600     }
601
602     bool changed = false;
603     FxListItemSG *item = 0;
604     qreal pos = itemEnd;
605     while (modelIndex < model->count() && pos <= fillTo) {
606 #ifdef DEBUG_DELEGATE_LIFECYCLE
607         qDebug() << "refill: append item" << modelIndex << "pos" << pos;
608 #endif
609         if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, doBuffer))))
610             break;
611         item->setPosition(pos);
612         item->item->setVisible(!doBuffer);
613         pos += item->size() + spacing;
614         visibleItems.append(item);
615         ++modelIndex;
616         changed = true;
617     }
618
619     if (doBuffer && requestedIndex != -1) // already waiting for an item
620         return changed;
621
622     while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
623 #ifdef DEBUG_DELEGATE_LIFECYCLE
624         qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
625 #endif
626         if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, doBuffer))))
627             break;
628         --visibleIndex;
629         visiblePos -= item->size() + spacing;
630         item->setPosition(visiblePos);
631         item->item->setVisible(!doBuffer);
632         visibleItems.prepend(item);
633         changed = true;
634     }
635
636     return changed;
637 }
638
639 bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
640 {
641     FxViewItem *item = 0;
642     bool changed = false;
643
644     // Remove items from the start of the view.
645     // Zero-sized items shouldn't be removed unless a non-zero-sized item is also being
646     // removed, otherwise a zero-sized item is infinitely added and removed over and
647     // over by refill().
648     int index = 0;
649     while (visibleItems.count() > 1 && index < visibleItems.count()
650            && (item = visibleItems.at(index)) && item->endPosition() < bufferFrom) {
651         if (item->attached->delayRemove())
652             break;
653         if (item->size() > 0) {
654 #ifdef DEBUG_DELEGATE_LIFECYCLE
655             qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
656 #endif
657             // remove this item and all zero-sized items before it
658             while (item) {
659                 if (item->index != -1)
660                     visibleIndex++;
661                 visibleItems.removeAt(index);
662                 releaseItem(item);
663                 if (index == 0)
664                     break;
665                 item = visibleItems.at(--index);
666             }
667             changed = true;
668         } else {
669             index++;
670         }
671     }
672
673     while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
674         if (item->attached->delayRemove())
675             break;
676 #ifdef DEBUG_DELEGATE_LIFECYCLE
677         qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
678 #endif
679         visibleItems.removeLast();
680         releaseItem(item);
681         changed = true;
682     }
683
684     return changed;
685 }
686
687 void QQuickListViewPrivate::visibleItemsChanged()
688 {
689     if (visibleItems.count())
690         visiblePos = (*visibleItems.constBegin())->position();
691     updateAverage();
692     if (currentIndex >= 0 && currentItem && !visibleItem(currentIndex)) {
693         static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
694         updateHighlight();
695     }
696     if (sectionCriteria)
697         updateCurrentSection();
698     updateHeader();
699     updateFooter();
700     updateViewport();
701     updateUnrequestedPositions();
702 }
703
704 void QQuickListViewPrivate::layoutVisibleItems(int fromModelIndex)
705 {
706     if (!visibleItems.isEmpty()) {
707         const qreal from = isContentFlowReversed() ? -position() - size() : position();
708         const qreal to = isContentFlowReversed() ? -position() : position() + size();
709
710         FxViewItem *firstItem = *visibleItems.constBegin();
711         bool fixedCurrent = currentItem && firstItem->item == currentItem->item;
712         qreal sum = firstItem->size();
713         qreal pos = firstItem->position() + firstItem->size() + spacing;
714         firstItem->item->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
715         for (int i=1; i < visibleItems.count(); ++i) {
716             FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.at(i));
717             if (item->index >= fromModelIndex) {
718                 item->setPosition(pos);
719                 item->item->setVisible(item->endPosition() >= from && item->position() <= to);
720             }
721             pos += item->size() + spacing;
722             sum += item->size();
723             fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
724         }
725         averageSize = qRound(sum / visibleItems.count());
726
727         // move current item if it is not a visible item.
728         if (currentIndex >= 0 && currentItem && !fixedCurrent) {
729             static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
730         }
731     }
732 }
733
734 void QQuickListViewPrivate::repositionPackageItemAt(QQuickItem *item, int index)
735 {
736     Q_Q(QQuickListView);
737     qreal pos = position();
738     if (orient == QQuickListView::Vertical) {
739         if (item->y() + item->height() > pos && item->y() < pos + q->height())
740             item->setY(positionAt(index));
741     } else {
742         if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
743             if (isRightToLeft())
744                 item->setX(-positionAt(index)-item->width());
745             else
746                 item->setX(positionAt(index));
747         }
748     }
749 }
750
751 void QQuickListViewPrivate::resetFirstItemPosition(qreal pos)
752 {
753     FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.first());
754     item->setPosition(pos);
755 }
756
757 void QQuickListViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int)
758 {
759     if (!visibleItems.count())
760         return;
761     qreal diff = forwards - backwards;
762     static_cast<FxListItemSG*>(visibleItems.first())->setPosition(visibleItems.first()->position() + diff);
763 }
764
765 void QQuickListViewPrivate::createHighlight()
766 {
767     Q_Q(QQuickListView);
768     bool changed = false;
769     if (highlight) {
770         if (trackedItem == highlight)
771             trackedItem = 0;
772         delete highlight;
773         highlight = 0;
774
775         delete highlightPosAnimator;
776         delete highlightSizeAnimator;
777         highlightPosAnimator = 0;
778         highlightSizeAnimator = 0;
779
780         changed = true;
781     }
782
783     if (currentItem) {
784         QQuickItem *item = createHighlightItem();
785         if (item) {
786             FxListItemSG *newHighlight = new FxListItemSG(item, q, true);
787
788             if (autoHighlight) {
789                 newHighlight->setSize(static_cast<FxListItemSG*>(currentItem)->itemSize());
790                 newHighlight->setPosition(static_cast<FxListItemSG*>(currentItem)->itemPosition());
791             }
792             const QLatin1String posProp(orient == QQuickListView::Vertical ? "y" : "x");
793             highlightPosAnimator = new QSmoothedAnimation(q);
794             highlightPosAnimator->target = QDeclarativeProperty(item, posProp);
795             highlightPosAnimator->velocity = highlightMoveSpeed;
796             highlightPosAnimator->userDuration = highlightMoveDuration;
797
798             const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
799             highlightSizeAnimator = new QSmoothedAnimation(q);
800             highlightSizeAnimator->velocity = highlightResizeSpeed;
801             highlightSizeAnimator->userDuration = highlightResizeDuration;
802             highlightSizeAnimator->target = QDeclarativeProperty(item, sizeProp);
803
804             highlight = newHighlight;
805             changed = true;
806         }
807     }
808     if (changed)
809         emit q->highlightItemChanged();
810 }
811
812 void QQuickListViewPrivate::updateHighlight()
813 {
814     applyPendingChanges();
815
816     if ((!currentItem && highlight) || (currentItem && !highlight))
817         createHighlight();
818     bool strictHighlight = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
819     if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
820         // auto-update highlight
821         FxListItemSG *listItem = static_cast<FxListItemSG*>(currentItem);
822         highlightPosAnimator->to = isRightToLeft()
823                 ? -listItem->itemPosition()-listItem->itemSize()
824                 : listItem->itemPosition();
825         highlightSizeAnimator->to = listItem->itemSize();
826         if (orient == QQuickListView::Vertical) {
827             if (highlight->item->width() == 0)
828                 highlight->item->setWidth(currentItem->item->width());
829         } else {
830             if (highlight->item->height() == 0)
831                 highlight->item->setHeight(currentItem->item->height());
832         }
833
834         highlightPosAnimator->restart();
835         highlightSizeAnimator->restart();
836     }
837     updateTrackedItem();
838 }
839
840 void QQuickListViewPrivate::resetHighlightPosition()
841 {
842     if (highlight && currentItem)
843         static_cast<FxListItemSG*>(highlight)->setPosition(static_cast<FxListItemSG*>(currentItem)->itemPosition());
844 }
845
846 QQuickItem * QQuickListViewPrivate::getSectionItem(const QString &section)
847 {
848     Q_Q(QQuickListView);
849     QQuickItem *sectionItem = 0;
850     int i = sectionCacheSize-1;
851     while (i >= 0 && !sectionCache[i])
852         --i;
853     if (i >= 0) {
854         sectionItem = sectionCache[i];
855         sectionCache[i] = 0;
856         sectionItem->setVisible(true);
857         QDeclarativeContext *context = QDeclarativeEngine::contextForObject(sectionItem)->parentContext();
858         context->setContextProperty(QLatin1String("section"), section);
859     } else {
860         QDeclarativeContext *creationContext = sectionCriteria->delegate()->creationContext();
861         QDeclarativeContext *context = new QDeclarativeContext(
862                 creationContext ? creationContext : qmlContext(q));
863         context->setContextProperty(QLatin1String("section"), section);
864         QObject *nobj = sectionCriteria->delegate()->beginCreate(context);
865         if (nobj) {
866             QDeclarative_setParent_noEvent(context, nobj);
867             sectionItem = qobject_cast<QQuickItem *>(nobj);
868             if (!sectionItem) {
869                 delete nobj;
870             } else {
871                 sectionItem->setZ(2);
872                 QDeclarative_setParent_noEvent(sectionItem, contentItem);
873                 sectionItem->setParentItem(contentItem);
874             }
875         } else {
876             delete context;
877         }
878         sectionCriteria->delegate()->completeCreate();
879     }
880
881     return sectionItem;
882 }
883
884 void QQuickListViewPrivate::releaseSectionItem(QQuickItem *item)
885 {
886     int i = 0;
887     do {
888         if (!sectionCache[i]) {
889             sectionCache[i] = item;
890             sectionCache[i]->setVisible(false);
891             return;
892         }
893         ++i;
894     } while (i < sectionCacheSize);
895     delete item;
896 }
897
898 void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
899 {
900     if (!sectionCriteria || !sectionCriteria->delegate())
901         return;
902     if (listItem->attached->m_prevSection != listItem->attached->m_section
903             && (sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels
904                 || (listItem->index == 0 && sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart))) {
905         if (!listItem->section) {
906             qreal pos = listItem->position();
907             listItem->section = getSectionItem(listItem->attached->m_section);
908             listItem->setPosition(pos);
909         } else {
910             QDeclarativeContext *context = QDeclarativeEngine::contextForObject(listItem->section)->parentContext();
911             context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
912         }
913     } else if (listItem->section) {
914         qreal pos = listItem->position();
915         releaseSectionItem(listItem->section);
916         listItem->section = 0;
917         listItem->setPosition(pos);
918     }
919 }
920
921 void QQuickListViewPrivate::updateStickySections()
922 {
923     if (!sectionCriteria || visibleItems.isEmpty()
924             || (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem))
925         return;
926
927     bool isRtl = isRightToLeft();
928     qreal viewPos = isRightToLeft() ? -position()-size() : position();
929     QQuickItem *sectionItem = 0;
930     QQuickItem *lastSectionItem = 0;
931     int index = 0;
932     while (index < visibleItems.count()) {
933         if (QQuickItem *section = static_cast<FxListItemSG *>(visibleItems.at(index))->section) {
934             // Find the current section header and last visible section header
935             // and hide them if they will overlap a static section header.
936             qreal sectionPos = orient == QQuickListView::Vertical ? section->y() : section->x();
937             qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width();
938             bool visTop = true;
939             if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
940                 visTop = isRtl ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos;
941             bool visBot = true;
942             if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd)
943                 visBot = isRtl ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size();
944             section->setVisible(visBot && visTop);
945             if (visTop && !sectionItem)
946                 sectionItem = section;
947             if (isRtl) {
948                if (-sectionPos <= viewPos + size())
949                     lastSectionItem = section;
950             } else {
951                 if (sectionPos + sectionSize < viewPos + size())
952                     lastSectionItem = section;
953             }
954         }
955         ++index;
956     }
957
958     // Current section header
959     if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart) {
960         if (!currentSectionItem) {
961             currentSectionItem = getSectionItem(currentSection);
962         } else if (currentStickySection != currentSection) {
963             QDeclarativeContext *context = QDeclarativeEngine::contextForObject(currentSectionItem)->parentContext();
964             context->setContextProperty(QLatin1String("section"), currentSection);
965         }
966         currentStickySection = currentSection;
967         if (!currentSectionItem)
968             return;
969
970         qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
971         bool atBeginning = orient == QQuickListView::Vertical ? vData.atBeginning : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
972         currentSectionItem->setVisible(!atBeginning && (!header || header->endPosition() < viewPos));
973         qreal pos = isRtl ? position() + size() - sectionSize : viewPos;
974         if (sectionItem) {
975             qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x();
976             pos = isRtl ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
977         }
978         if (header)
979             pos = isRtl ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos);
980         if (footer)
981             pos = isRtl ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
982         if (orient == QQuickListView::Vertical)
983             currentSectionItem->setY(pos);
984         else
985             currentSectionItem->setX(pos);
986     } else if (currentSectionItem) {
987         releaseSectionItem(currentSectionItem);
988         currentSectionItem = 0;
989     }
990
991     // Next section footer
992     if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
993         if (!nextSectionItem) {
994             nextSectionItem = getSectionItem(nextSection);
995         } else if (nextStickySection != nextSection) {
996             QDeclarativeContext *context = QDeclarativeEngine::contextForObject(nextSectionItem)->parentContext();
997             context->setContextProperty(QLatin1String("section"), nextSection);
998         }
999         nextStickySection = nextSection;
1000         if (!nextSectionItem)
1001             return;
1002
1003         qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1004         nextSectionItem->setVisible(!nextSection.isEmpty());
1005         qreal pos = isRtl ? position() : viewPos + size() - sectionSize;
1006         if (lastSectionItem) {
1007             qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x();
1008             pos = isRtl ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
1009         }
1010         if (header)
1011             pos = isRtl ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1012         if (orient == QQuickListView::Vertical)
1013             nextSectionItem->setY(pos);
1014         else
1015             nextSectionItem->setX(pos);
1016     } else if (nextSectionItem) {
1017         releaseSectionItem(nextSectionItem);
1018         nextSectionItem = 0;
1019     }
1020 }
1021
1022 void QQuickListViewPrivate::updateSections()
1023 {
1024     Q_Q(QQuickListView);
1025     if (!q->isComponentComplete())
1026         return;
1027
1028     QQuickItemViewPrivate::updateSections();
1029
1030     if (sectionCriteria && !visibleItems.isEmpty()) {
1031         QString prevSection;
1032         if (visibleIndex > 0)
1033             prevSection = sectionAt(visibleIndex-1);
1034         QQuickListViewAttached *prevAtt = 0;
1035         int idx = -1;
1036         for (int i = 0; i < visibleItems.count(); ++i) {
1037             QQuickListViewAttached *attached = static_cast<QQuickListViewAttached*>(visibleItems.at(i)->attached);
1038             attached->setPrevSection(prevSection);
1039             if (visibleItems.at(i)->index != -1) {
1040                 QString propValue = model->stringValue(visibleItems.at(i)->index, sectionCriteria->property());
1041                 attached->setSection(sectionCriteria->sectionString(propValue));
1042                 idx = visibleItems.at(i)->index;
1043             }
1044             updateInlineSection(static_cast<FxListItemSG*>(visibleItems.at(i)));
1045             if (prevAtt)
1046                 prevAtt->setNextSection(attached->section());
1047             prevSection = attached->section();
1048             prevAtt = attached;
1049         }
1050         if (prevAtt) {
1051             if (idx > 0 && idx < model->count()-1)
1052                 prevAtt->setNextSection(sectionAt(idx+1));
1053             else
1054                 prevAtt->setNextSection(QString());
1055         }
1056     }
1057
1058     lastVisibleSection = QString();
1059     updateCurrentSection();
1060     updateStickySections();
1061 }
1062
1063 void QQuickListViewPrivate::updateCurrentSection()
1064 {
1065     Q_Q(QQuickListView);
1066     if (!sectionCriteria || visibleItems.isEmpty()) {
1067         if (!currentSection.isEmpty()) {
1068             currentSection.clear();
1069             emit q->currentSectionChanged();
1070         }
1071         return;
1072     }
1073     bool inlineSections = sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels;
1074     qreal sectionThreshold = position();
1075     if (currentSectionItem && !inlineSections)
1076         sectionThreshold += orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1077     int index = 0;
1078     int modelIndex = visibleIndex;
1079     while (index < visibleItems.count() && visibleItems.at(index)->endPosition() <= sectionThreshold) {
1080         if (visibleItems.at(index)->index != -1)
1081             modelIndex = visibleItems.at(index)->index;
1082         ++index;
1083     }
1084
1085     QString newSection = currentSection;
1086     if (index < visibleItems.count())
1087         newSection = visibleItems.at(index)->attached->section();
1088     else
1089         newSection = (*visibleItems.constBegin())->attached->section();
1090     if (newSection != currentSection) {
1091         currentSection = newSection;
1092         updateStickySections();
1093         emit q->currentSectionChanged();
1094     }
1095
1096     if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
1097         // Don't want to scan for next section on every movement, so remember
1098         // the last section in the visible area and only scan for the next
1099         // section when that changes.  Clearing lastVisibleSection will also
1100         // force searching.
1101         QString lastSection = currentSection;
1102         qreal endPos = isRightToLeft() ? -position() : position() + size();
1103         if (nextSectionItem && !inlineSections)
1104             endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1105         while (index < visibleItems.count() && static_cast<FxListItemSG*>(visibleItems.at(index))->itemPosition() < endPos) {
1106             if (visibleItems.at(index)->index != -1)
1107                 modelIndex = visibleItems.at(index)->index;
1108             lastSection = visibleItems.at(index)->attached->section();
1109             ++index;
1110         }
1111
1112         if (lastVisibleSection != lastSection) {
1113             nextSection = QString();
1114             lastVisibleSection = lastSection;
1115             for (int i = modelIndex; i < itemCount; ++i) {
1116                 QString section = sectionAt(i);
1117                 if (section != lastSection) {
1118                     nextSection = section;
1119                     updateStickySections();
1120                     break;
1121                 }
1122             }
1123         }
1124     }
1125 }
1126
1127 void QQuickListViewPrivate::initializeCurrentItem()
1128 {
1129     QQuickItemViewPrivate::initializeCurrentItem();
1130
1131     if (currentItem) {
1132         FxListItemSG *listItem = static_cast<FxListItemSG *>(currentItem);
1133
1134         if (currentIndex == visibleIndex - 1 && visibleItems.count()) {
1135             // We can calculate exact postion in this case
1136             listItem->setPosition(visibleItems.first()->position() - currentItem->size() - spacing);
1137         } else {
1138             // Create current item now and position as best we can.
1139             // Its position will be corrected when it becomes visible.
1140             listItem->setPosition(positionAt(currentIndex));
1141         }
1142
1143         // Avoid showing section delegate twice.  We still need the section heading so that
1144         // currentItem positioning works correctly.
1145         // This is slightly sub-optimal, but section heading caching minimizes the impact.
1146         if (listItem->section)
1147             listItem->section->setVisible(false);
1148
1149         if (visibleItems.isEmpty())
1150             averageSize = listItem->size();
1151     }
1152 }
1153
1154 void QQuickListViewPrivate::updateAverage()
1155 {
1156     if (!visibleItems.count())
1157         return;
1158     qreal sum = 0.0;
1159     for (int i = 0; i < visibleItems.count(); ++i)
1160         sum += visibleItems.at(i)->size();
1161     averageSize = qRound(sum / visibleItems.count());
1162 }
1163
1164 qreal QQuickListViewPrivate::headerSize() const
1165 {
1166     return header ? header->size() : 0.0;
1167 }
1168
1169 qreal QQuickListViewPrivate::footerSize() const
1170 {
1171     return footer ? footer->size() : 0.0;
1172 }
1173
1174 bool QQuickListViewPrivate::showHeaderForIndex(int index) const
1175 {
1176     return index == 0;
1177 }
1178
1179 bool QQuickListViewPrivate::showFooterForIndex(int index) const
1180 {
1181     return index == model->count()-1;
1182 }
1183
1184 void QQuickListViewPrivate::updateFooter()
1185 {
1186     Q_Q(QQuickListView);
1187     bool created = false;
1188     if (!footer) {
1189         QQuickItem *item = createComponentItem(footerComponent, true);
1190         if (!item)
1191             return;
1192         item->setZ(1);
1193         footer = new FxListItemSG(item, q, true);
1194         created = true;
1195     }
1196
1197     FxListItemSG *listItem = static_cast<FxListItemSG*>(footer);
1198     if (visibleItems.count()) {
1199         qreal endPos = lastPosition();
1200         if (findLastVisibleIndex() == model->count()-1) {
1201             listItem->setPosition(endPos);
1202         } else {
1203             qreal visiblePos = position() + q->height();
1204             if (endPos <= visiblePos || listItem->position() < endPos)
1205                 listItem->setPosition(endPos);
1206         }
1207     } else {
1208         listItem->setPosition(visiblePos);
1209     }
1210
1211     if (created)
1212         emit q->footerItemChanged();
1213 }
1214
1215 void QQuickListViewPrivate::updateHeader()
1216 {
1217     Q_Q(QQuickListView);
1218     bool created = false;
1219     if (!header) {
1220         QQuickItem *item = createComponentItem(headerComponent, true);
1221         if (!item)
1222             return;
1223         item->setZ(1);
1224         header = new FxListItemSG(item, q, true);
1225         created = true;
1226     }
1227
1228     FxListItemSG *listItem = static_cast<FxListItemSG*>(header);
1229     if (listItem) {
1230         if (visibleItems.count()) {
1231             qreal startPos = originPosition();
1232             if (visibleIndex == 0) {
1233                 listItem->setPosition(startPos - headerSize());
1234             } else {
1235                 if (position() <= startPos || listItem->position() > startPos - headerSize())
1236                     listItem->setPosition(startPos - headerSize());
1237             }
1238         } else {
1239             listItem->setPosition(-headerSize());
1240         }
1241     }
1242
1243     if (created)
1244         emit q->headerItemChanged();
1245 }
1246
1247 void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
1248 {
1249     Q_Q(QQuickListView);
1250     QQuickItemViewPrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
1251     if (!q->isComponentComplete())
1252         return;
1253     if (item != contentItem && (!highlight || item != highlight->item)) {
1254         if ((orient == QQuickListView::Vertical && newGeometry.height() != oldGeometry.height())
1255             || (orient == QQuickListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
1256             forceLayout = true;
1257             q->polish();
1258         }
1259     }
1260 }
1261
1262 void QQuickListViewPrivate::fixupPosition()
1263 {
1264     if ((haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange)
1265         || snapMode != QQuickListView::NoSnap)
1266         moveReason = Other;
1267     if (orient == QQuickListView::Vertical)
1268         fixupY();
1269     else
1270         fixupX();
1271 }
1272
1273 void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
1274 {
1275     if ((orient == QQuickListView::Horizontal && &data == &vData)
1276         || (orient == QQuickListView::Vertical && &data == &hData))
1277         return;
1278
1279     correctFlick = false;
1280     fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1281     bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
1282
1283     qreal viewPos = isRightToLeft() ? -position()-size() : position();
1284
1285     if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) {
1286         qreal tempPosition = isRightToLeft() ? -position()-size() : position();
1287         if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) {
1288             // if we've been dragged < averageSize/2 then bias towards the next item
1289             qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1290             qreal bias = 0;
1291             if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < averageSize/2)
1292                 bias = averageSize/2;
1293             else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -averageSize/2)
1294                 bias = -averageSize/2;
1295             if (isRightToLeft())
1296                 bias = -bias;
1297             tempPosition -= bias;
1298         }
1299         FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
1300         if (!topItem && strictHighlightRange && currentItem) {
1301             // StrictlyEnforceRange always keeps an item in range
1302             updateHighlight();
1303             topItem = currentItem;
1304         }
1305         FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
1306         if (!bottomItem && strictHighlightRange && currentItem) {
1307             // StrictlyEnforceRange always keeps an item in range
1308             updateHighlight();
1309             bottomItem = currentItem;
1310         }
1311         qreal pos;
1312         bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1313         if (topItem && (isInBounds || strictHighlightRange)) {
1314             if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
1315                 pos = isRightToLeft() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart;
1316             } else {
1317                 if (isRightToLeft())
1318                     pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
1319                 else
1320                     pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
1321             }
1322         } else if (bottomItem && isInBounds) {
1323             if (isRightToLeft())
1324                 pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
1325             else
1326                 pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
1327         } else {
1328             QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1329             return;
1330         }
1331
1332         qreal dist = qAbs(data.move + pos);
1333         if (dist > 0) {
1334             timeline.reset(data.move);
1335             if (fixupMode != Immediate) {
1336                 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1337                 data.fixingUp = true;
1338             } else {
1339                 timeline.set(data.move, -pos);
1340             }
1341             vTime = timeline.time();
1342         }
1343     } else if (currentItem && strictHighlightRange && moveReason != QQuickListViewPrivate::SetIndex) {
1344         updateHighlight();
1345         qreal pos = static_cast<FxListItemSG*>(currentItem)->itemPosition();
1346         if (viewPos < pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd)
1347             viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd;
1348         if (viewPos > pos - highlightRangeStart)
1349             viewPos = pos - highlightRangeStart;
1350         if (isRightToLeft())
1351             viewPos = -viewPos-size();
1352
1353         timeline.reset(data.move);
1354         if (viewPos != position()) {
1355             if (fixupMode != Immediate) {
1356                 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1357                 data.fixingUp = true;
1358             } else {
1359                 timeline.set(data.move, -viewPos);
1360             }
1361         }
1362         vTime = timeline.time();
1363     } else {
1364         QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1365     }
1366     data.inOvershoot = false;
1367     fixupMode = Normal;
1368 }
1369
1370 void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1371                                         QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
1372 {
1373     Q_Q(QQuickListView);
1374
1375     data.fixingUp = false;
1376     moveReason = Mouse;
1377     if ((!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange) && snapMode == QQuickListView::NoSnap) {
1378         correctFlick = true;
1379         QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1380         return;
1381     }
1382     qreal maxDistance = 0;
1383     qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value();
1384
1385     // -ve velocity means list is moving up/left
1386     if (velocity > 0) {
1387         if (data.move.value() < minExtent) {
1388             if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1389                 // if we've been dragged < averageSize/2 then bias towards the next item
1390                 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1391                 qreal bias = dist < averageSize/2 ? averageSize/2 : 0;
1392                 if (isRightToLeft())
1393                     bias = -bias;
1394                 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart;
1395                 maxDistance = qAbs(data.flickTarget - data.move.value());
1396                 velocity = maxVelocity;
1397             } else {
1398                 maxDistance = qAbs(minExtent - data.move.value());
1399             }
1400         }
1401         if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1402             data.flickTarget = minExtent;
1403     } else {
1404         if (data.move.value() > maxExtent) {
1405             if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1406                 // if we've been dragged < averageSize/2 then bias towards the next item
1407                 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1408                 qreal bias = -dist < averageSize/2 ? averageSize/2 : 0;
1409                 if (isRightToLeft())
1410                     bias = -bias;
1411                 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart;
1412                 maxDistance = qAbs(data.flickTarget - data.move.value());
1413                 velocity = -maxVelocity;
1414             } else {
1415                 maxDistance = qAbs(maxExtent - data.move.value());
1416             }
1417         }
1418         if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1419             data.flickTarget = maxExtent;
1420     }
1421     bool overShoot = boundsBehavior == QQuickFlickable::DragAndOvershootBounds;
1422     if (maxDistance > 0 || overShoot) {
1423         // These modes require the list to stop exactly on an item boundary.
1424         // The initial flick will estimate the boundary to stop on.
1425         // Since list items can have variable sizes, the boundary will be
1426         // reevaluated and adjusted as we approach the boundary.
1427         qreal v = velocity;
1428         if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1429             if (v < 0)
1430                 v = -maxVelocity;
1431             else
1432                 v = maxVelocity;
1433         }
1434         if (!hData.flicking && !vData.flicking) {
1435             // the initial flick - estimate boundary
1436             qreal accel = deceleration;
1437             qreal v2 = v * v;
1438             overshootDist = 0.0;
1439             // + averageSize/4 to encourage moving at least one item in the flick direction
1440             qreal dist = v2 / (accel * 2.0) + averageSize/4;
1441             if (maxDistance > 0)
1442                 dist = qMin(dist, maxDistance);
1443             if (v > 0)
1444                 dist = -dist;
1445             if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) {
1446                 if (snapMode != QQuickListView::SnapOneItem) {
1447                     qreal distTemp = isRightToLeft() ? -dist : dist;
1448                     data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart;
1449                 }
1450                 data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
1451                 if (overShoot) {
1452                     if (data.flickTarget >= minExtent) {
1453                         overshootDist = overShootDistance(vSize);
1454                         data.flickTarget += overshootDist;
1455                     } else if (data.flickTarget <= maxExtent) {
1456                         overshootDist = overShootDistance(vSize);
1457                         data.flickTarget -= overshootDist;
1458                     }
1459                 }
1460                 qreal adjDist = -data.flickTarget + data.move.value();
1461                 if (qAbs(adjDist) > qAbs(dist)) {
1462                     // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1463                     qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1464                     if (adjv2 > v2) {
1465                         v2 = adjv2;
1466                         v = qSqrt(v2);
1467                         if (dist > 0)
1468                             v = -v;
1469                     }
1470                 }
1471                 dist = adjDist;
1472                 accel = v2 / (2.0f * qAbs(dist));
1473             } else if (overShoot) {
1474                 data.flickTarget = data.move.value() - dist;
1475                 if (data.flickTarget >= minExtent) {
1476                     overshootDist = overShootDistance(vSize);
1477                     data.flickTarget += overshootDist;
1478                 } else if (data.flickTarget <= maxExtent) {
1479                     overshootDist = overShootDistance(vSize);
1480                     data.flickTarget -= overshootDist;
1481                 }
1482             }
1483             timeline.reset(data.move);
1484             timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1485             timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1486             if (!hData.flicking && q->xflick()) {
1487                 hData.flicking = true;
1488                 emit q->flickingChanged();
1489                 emit q->flickingHorizontallyChanged();
1490                 emit q->flickStarted();
1491             }
1492             if (!vData.flicking && q->yflick()) {
1493                 vData.flicking = true;
1494                 emit q->flickingChanged();
1495                 emit q->flickingVerticallyChanged();
1496                 emit q->flickStarted();
1497             }
1498             correctFlick = true;
1499         } else {
1500             // reevaluate the target boundary.
1501             qreal newtarget = data.flickTarget;
1502             if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) {
1503                 qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
1504                 newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart;
1505                 newtarget = isRightToLeft() ? -newtarget+size() : newtarget;
1506             }
1507             if (velocity < 0 && newtarget <= maxExtent)
1508                 newtarget = maxExtent - overshootDist;
1509             else if (velocity > 0 && newtarget >= minExtent)
1510                 newtarget = minExtent + overshootDist;
1511             if (newtarget == data.flickTarget) { // boundary unchanged - nothing to do
1512                 if (qAbs(velocity) < MinimumFlickVelocity)
1513                     correctFlick = false;
1514                 return;
1515             }
1516             data.flickTarget = newtarget;
1517             qreal dist = -newtarget + data.move.value();
1518             if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
1519                 correctFlick = false;
1520                 timeline.reset(data.move);
1521                 fixup(data, minExtent, maxExtent);
1522                 return;
1523             }
1524             timeline.reset(data.move);
1525             timeline.accelDistance(data.move, v, -dist);
1526             timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1527         }
1528     } else {
1529         correctFlick = false;
1530         timeline.reset(data.move);
1531         fixup(data, minExtent, maxExtent);
1532     }
1533 }
1534
1535 //----------------------------------------------------------------------------
1536
1537 /*!
1538     \qmlclass ListView QQuickListView
1539     \inqmlmodule QtQuick 2
1540     \ingroup qml-view-elements
1541     \inherits Flickable
1542     \brief The ListView item provides a list view of items provided by a model.
1543
1544     A ListView displays data from models created from built-in QML elements like ListModel
1545     and XmlListModel, or custom model classes defined in C++ that inherit from
1546     QAbstractListModel.
1547
1548     A ListView has a \l model, which defines the data to be displayed, and
1549     a \l delegate, which defines how the data should be displayed. Items in a
1550     ListView are laid out horizontally or vertically. List views are inherently
1551     flickable because ListView inherits from \l Flickable.
1552
1553     \section1 Example Usage
1554
1555     The following example shows the definition of a simple list model defined
1556     in a file called \c ContactModel.qml:
1557
1558     \snippet doc/src/snippets/declarative/listview/ContactModel.qml 0
1559
1560     Another component can display this model data in a ListView, like this:
1561
1562     \snippet doc/src/snippets/declarative/listview/listview.qml import
1563     \codeline
1564     \snippet doc/src/snippets/declarative/listview/listview.qml classdocs simple
1565
1566     \image listview-simple.png
1567
1568     Here, the ListView creates a \c ContactModel component for its model, and a \l Text element
1569     for its delegate. The view will create a new \l Text component for each item in the model. Notice
1570     the delegate is able to access the model's \c name and \c number data directly.
1571
1572     An improved list view is shown below. The delegate is visually improved and is moved
1573     into a separate \c contactDelegate component.
1574
1575     \snippet doc/src/snippets/declarative/listview/listview.qml classdocs advanced
1576     \image listview-highlight.png
1577
1578     The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
1579     and \c focus is set to \c true to enable keyboard navigation for the list view.
1580     The list view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
1581
1582     Delegates are instantiated as needed and may be destroyed at any time.
1583     State should \e never be stored in a delegate.
1584
1585     ListView attaches a number of properties to the root item of the delegate, for example
1586     \c {ListView.isCurrentItem}.  In the following example, the root delegate item can access
1587     this attached property directly as \c ListView.isCurrentItem, while the child
1588     \c contactInfo object must refer to this property as \c wrapper.ListView.isCurrentItem.
1589
1590     \snippet doc/src/snippets/declarative/listview/listview.qml isCurrentItem
1591
1592     \note Views do not enable \e clip automatically.  If the view
1593     is not clipped by another item or the screen, it will be necessary
1594     to set \e {clip: true} in order to have the out of view items clipped
1595     nicely.
1596
1597     \sa {QML Data Models}, GridView, {declarative/modelviews/listview}{ListView examples}
1598 */
1599 QQuickListView::QQuickListView(QQuickItem *parent)
1600     : QQuickItemView(*(new QQuickListViewPrivate), parent)
1601 {
1602 }
1603
1604 QQuickListView::~QQuickListView()
1605 {
1606 }
1607
1608 /*!
1609     \qmlattachedproperty bool QtQuick2::ListView::isCurrentItem
1610     This attached property is true if this delegate is the current item; otherwise false.
1611
1612     It is attached to each instance of the delegate.
1613
1614     This property may be used to adjust the appearance of the current item, for example:
1615
1616     \snippet doc/src/snippets/declarative/listview/listview.qml isCurrentItem
1617 */
1618
1619 /*!
1620     \qmlattachedproperty ListView QtQuick2::ListView::view
1621     This attached property holds the view that manages this delegate instance.
1622
1623     It is attached to each instance of the delegate.
1624 */
1625
1626 /*!
1627     \qmlattachedproperty string QtQuick2::ListView::previousSection
1628     This attached property holds the section of the previous element.
1629
1630     It is attached to each instance of the delegate.
1631
1632     The section is evaluated using the \l {ListView::section.property}{section} properties.
1633 */
1634
1635 /*!
1636     \qmlattachedproperty string QtQuick2::ListView::nextSection
1637     This attached property holds the section of the next element.
1638
1639     It is attached to each instance of the delegate.
1640
1641     The section is evaluated using the \l {ListView::section.property}{section} properties.
1642 */
1643
1644 /*!
1645     \qmlattachedproperty string QtQuick2::ListView::section
1646     This attached property holds the section of this element.
1647
1648     It is attached to each instance of the delegate.
1649
1650     The section is evaluated using the \l {ListView::section.property}{section} properties.
1651 */
1652
1653 /*!
1654     \qmlattachedproperty bool QtQuick2::ListView::delayRemove
1655     This attached property holds whether the delegate may be destroyed.
1656
1657     It is attached to each instance of the delegate.
1658
1659     It is sometimes necessary to delay the destruction of an item
1660     until an animation completes.
1661
1662     The example delegate below ensures that the animation completes before
1663     the item is removed from the list.
1664
1665     \snippet doc/src/snippets/declarative/listview/listview.qml delayRemove
1666 */
1667
1668 /*!
1669     \qmlattachedsignal QtQuick2::ListView::onAdd()
1670     This attached handler is called immediately after an item is added to the view.
1671 */
1672
1673 /*!
1674     \qmlattachedsignal QtQuick2::ListView::onRemove()
1675     This attached handler is called immediately before an item is removed from the view.
1676 */
1677
1678 /*!
1679     \qmlproperty model QtQuick2::ListView::model
1680     This property holds the model providing data for the list.
1681
1682     The model provides the set of data that is used to create the items
1683     in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
1684     or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
1685     used, it must be a subclass of \l QAbstractItemModel or a simple list.
1686
1687     \sa {qmlmodels}{Data Models}
1688 */
1689
1690 /*!
1691     \qmlproperty Component QtQuick2::ListView::delegate
1692
1693     The delegate provides a template defining each item instantiated by the view.
1694     The index is exposed as an accessible \c index property.  Properties of the
1695     model are also available depending upon the type of \l {qmlmodels}{Data Model}.
1696
1697     The number of elements in the delegate has a direct effect on the
1698     flicking performance of the view.  If at all possible, place functionality
1699     that is not needed for the normal display of the delegate in a \l Loader which
1700     can load additional elements when needed.
1701
1702     The ListView will lay out the items based on the size of the root item
1703     in the delegate.
1704
1705     It is recommended that the delegate's size be a whole number to avoid sub-pixel
1706     alignment of items.
1707
1708     \note Delegates are instantiated as needed and may be destroyed at any time.
1709     State should \e never be stored in a delegate.
1710 */
1711 /*!
1712     \qmlproperty int QtQuick2::ListView::currentIndex
1713     \qmlproperty Item QtQuick2::ListView::currentItem
1714
1715     The \c currentIndex property holds the index of the current item, and
1716     \c currentItem holds the current item.   Setting the currentIndex to -1
1717     will clear the highlight and set currentItem to null.
1718
1719     If highlightFollowsCurrentItem is \c true, setting either of these
1720     properties will smoothly scroll the ListView so that the current
1721     item becomes visible.
1722
1723     Note that the position of the current item
1724     may only be approximate until it becomes visible in the view.
1725 */
1726
1727 /*!
1728   \qmlproperty Item QtQuick2::ListView::highlightItem
1729
1730     This holds the highlight item created from the \l highlight component.
1731
1732   The \c highlightItem is managed by the view unless
1733   \l highlightFollowsCurrentItem is set to false.
1734
1735   \sa highlight, highlightFollowsCurrentItem
1736 */
1737
1738 /*!
1739   \qmlproperty int QtQuick2::ListView::count
1740   This property holds the number of items in the view.
1741 */
1742
1743 /*!
1744     \qmlproperty Component QtQuick2::ListView::highlight
1745     This property holds the component to use as the highlight.
1746
1747     An instance of the highlight component is created for each list.
1748     The geometry of the resulting component instance is managed by the list
1749     so as to stay with the current item, unless the highlightFollowsCurrentItem
1750     property is false.
1751
1752     \sa highlightItem, highlightFollowsCurrentItem, {declarative/modelviews/listview}{ListView examples}
1753 */
1754
1755 /*!
1756     \qmlproperty bool QtQuick2::ListView::highlightFollowsCurrentItem
1757     This property holds whether the highlight is managed by the view.
1758
1759     If this property is true (the default value), the highlight is moved smoothly
1760     to follow the current item.  Otherwise, the
1761     highlight is not moved by the view, and any movement must be implemented
1762     by the highlight.
1763
1764     Here is a highlight with its motion defined by a \l {SpringAnimation} item:
1765
1766     \snippet doc/src/snippets/declarative/listview/listview.qml highlightFollowsCurrentItem
1767
1768     Note that the highlight animation also affects the way that the view
1769     is scrolled.  This is because the view moves to maintain the
1770     highlight within the preferred highlight range (or visible viewport).
1771
1772     \sa highlight, highlightMoveSpeed
1773 */
1774 //###Possibly rename these properties, since they are very useful even without a highlight?
1775 /*!
1776     \qmlproperty real QtQuick2::ListView::preferredHighlightBegin
1777     \qmlproperty real QtQuick2::ListView::preferredHighlightEnd
1778     \qmlproperty enumeration QtQuick2::ListView::highlightRangeMode
1779
1780     These properties define the preferred range of the highlight (for the current item)
1781     within the view. The \c preferredHighlightBegin value must be less than the
1782     \c preferredHighlightEnd value.
1783
1784     These properties affect the position of the current item when the list is scrolled.
1785     For example, if the currently selected item should stay in the middle of the
1786     list when the view is scrolled, set the \c preferredHighlightBegin and
1787     \c preferredHighlightEnd values to the top and bottom coordinates of where the middle
1788     item would be. If the \c currentItem is changed programmatically, the list will
1789     automatically scroll so that the current item is in the middle of the view.
1790     Furthermore, the behavior of the current item index will occur whether or not a
1791     highlight exists.
1792
1793     Valid values for \c highlightRangeMode are:
1794
1795     \list
1796     \o ListView.ApplyRange - the view attempts to maintain the highlight within the range.
1797        However, the highlight can move outside of the range at the ends of the list or due
1798        to mouse interaction.
1799     \o ListView.StrictlyEnforceRange - the highlight never moves outside of the range.
1800        The current item changes if a keyboard or mouse action would cause the highlight to move
1801        outside of the range.
1802     \o ListView.NoHighlightRange - this is the default value.
1803     \endlist
1804 */
1805 void QQuickListView::setHighlightFollowsCurrentItem(bool autoHighlight)
1806 {
1807     Q_D(QQuickListView);
1808     if (d->autoHighlight != autoHighlight) {
1809         if (!autoHighlight) {
1810             if (d->highlightPosAnimator)
1811                 d->highlightPosAnimator->stop();
1812             if (d->highlightSizeAnimator)
1813                 d->highlightSizeAnimator->stop();
1814         }
1815         QQuickItemView::setHighlightFollowsCurrentItem(autoHighlight);
1816     }
1817 }
1818
1819 /*!
1820     \qmlproperty real QtQuick2::ListView::spacing
1821
1822     This property holds the spacing between items.
1823
1824     The default value is 0.
1825 */
1826 qreal QQuickListView::spacing() const
1827 {
1828     Q_D(const QQuickListView);
1829     return d->spacing;
1830 }
1831
1832 void QQuickListView::setSpacing(qreal spacing)
1833 {
1834     Q_D(QQuickListView);
1835     if (spacing != d->spacing) {
1836         d->spacing = spacing;
1837         d->forceLayout = true;
1838         polish();
1839         emit spacingChanged();
1840     }
1841 }
1842
1843 /*!
1844     \qmlproperty enumeration QtQuick2::ListView::orientation
1845     This property holds the orientation of the list.
1846
1847     Possible values:
1848
1849     \list
1850     \o ListView.Horizontal - Items are laid out horizontally
1851     \o ListView.Vertical (default) - Items are laid out vertically
1852     \endlist
1853
1854     \table
1855     \row
1856     \o Horizontal orientation:
1857     \image ListViewHorizontal.png
1858
1859     \row
1860     \o Vertical orientation:
1861     \image listview-highlight.png
1862     \endtable
1863 */
1864 QQuickListView::Orientation QQuickListView::orientation() const
1865 {
1866     Q_D(const QQuickListView);
1867     return d->orient;
1868 }
1869
1870 void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
1871 {
1872     Q_D(QQuickListView);
1873     if (d->orient != orientation) {
1874         d->orient = orientation;
1875         if (d->orient == Vertical) {
1876             setContentWidth(-1);
1877             setFlickableDirection(VerticalFlick);
1878             setContentX(0);
1879         } else {
1880             setContentHeight(-1);
1881             setFlickableDirection(HorizontalFlick);
1882             setContentY(0);
1883         }
1884         d->regenerate();
1885         emit orientationChanged();
1886     }
1887 }
1888
1889 /*!
1890   \qmlproperty enumeration QtQuick2::ListView::layoutDirection
1891   This property holds the layout direction of the horizontal list.
1892
1893   Possible values:
1894
1895   \list
1896   \o Qt.LeftToRight (default) - Items will be laid out from left to right.
1897   \o Qt.RightToLeft - Items will be laid out from right to let.
1898   \endlist
1899
1900   \sa ListView::effectiveLayoutDirection
1901 */
1902
1903
1904 /*!
1905     \qmlproperty enumeration QtQuick2::ListView::effectiveLayoutDirection
1906     This property holds the effective layout direction of the horizontal list.
1907
1908     When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1909     the visual layout direction of the horizontal list will be mirrored. However, the
1910     property \l {ListView::layoutDirection}{layoutDirection} will remain unchanged.
1911
1912     \sa ListView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1913 */
1914
1915 /*!
1916     \qmlproperty bool QtQuick2::ListView::keyNavigationWraps
1917     This property holds whether the list wraps key navigation.
1918
1919     If this is true, key navigation that would move the current item selection
1920     past the end of the list instead wraps around and moves the selection to
1921     the start of the list, and vice-versa.
1922
1923     By default, key navigation is not wrapped.
1924 */
1925
1926
1927 /*!
1928     \qmlproperty int QtQuick2::ListView::cacheBuffer
1929     This property determines whether delegates are retained outside the
1930     visible area of the view.
1931
1932     If this value is non-zero, the view may keep as many delegates
1933     instantiated as it can fit within the buffer specified.  For example,
1934     if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
1935     set to 40, then up to 2 delegates above and 2 delegates below the visible
1936     area may be created/retained.  The buffered delegates are created asynchronously,
1937     allowing creation to occur across multiple frames and reducing the
1938     likelihood of skipping frames.  In order to improve painting performance
1939     delegates outside the visible area have their \l visible property set to
1940     false until they are moved into the visible area.
1941
1942     Note that cacheBuffer is not a pixel buffer - it only maintains additional
1943     instantiated delegates.
1944
1945     Setting this value can improve the smoothness of scrolling behavior at the expense
1946     of additional memory usage.  It is not a substitute for creating efficient
1947     delegates; the fewer elements in a delegate, the faster a view can be
1948     scrolled.
1949 */
1950
1951
1952 /*!
1953     \qmlproperty string QtQuick2::ListView::section.property
1954     \qmlproperty enumeration QtQuick2::ListView::section.criteria
1955     \qmlproperty Component QtQuick2::ListView::section.delegate
1956     \qmlproperty enumeration QtQuick2::ListView::section.labelPositioning
1957
1958     These properties determine the expression to be evaluated and appearance
1959     of the section labels.
1960
1961     \c section.property holds the name of the property that is the basis
1962     of each section.
1963
1964     \c section.criteria holds the criteria for forming each section based on
1965     \c section.property. This value can be one of:
1966
1967     \list
1968     \o ViewSection.FullString (default) - sections are created based on the
1969     \c section.property value.
1970     \o ViewSection.FirstCharacter - sections are created based on the first
1971     character of the \c section.property value (for example, 'A', 'B', 'C'
1972     sections, etc. for an address book)
1973     \endlist
1974
1975     \c section.delegate holds the delegate component for each section.
1976
1977     \c section.labelPositioning determines whether the current and/or
1978     next section labels stick to the start/end of the view, and whether
1979     the labels are shown inline.  This value can be a combination of:
1980
1981     \list
1982     \o ViewSection.InlineLabels - section labels are shown inline between
1983     the item delegates separating sections (default).
1984     \o ViewSection.CurrentLabelAtStart - the current section label sticks to the
1985     start of the view as it is moved.
1986     \o ViewSection.NextLabelAtEnd - the next section label (beyond all visible
1987     sections) sticks to the end of the view as it is moved. \note Enabling
1988     \c ViewSection.NextLabelAtEnd requires the view to scan ahead for the next
1989     section, which has performance implications, especially for slower models.
1990     \endlist
1991
1992     Each item in the list has attached properties named \c ListView.section,
1993     \c ListView.previousSection and \c ListView.nextSection.
1994
1995     For example, here is a ListView that displays a list of animals, separated
1996     into sections. Each item in the ListView is placed in a different section
1997     depending on the "size" property of the model item. The \c sectionHeading
1998     delegate component provides the light blue bar that marks the beginning of
1999     each section.
2000
2001
2002     \snippet examples/declarative/modelviews/listview/sections.qml 0
2003
2004     \image qml-listview-sections-example.png
2005
2006     \note Adding sections to a ListView does not automatically re-order the
2007     list items by the section criteria.
2008     If the model is not ordered by section, then it is possible that
2009     the sections created will not be unique; each boundary between
2010     differing sections will result in a section header being created
2011     even if that section exists elsewhere.
2012
2013     \sa {declarative/modelviews/listview}{ListView examples}
2014 */
2015 QQuickViewSection *QQuickListView::sectionCriteria()
2016 {
2017     Q_D(QQuickListView);
2018     if (!d->sectionCriteria) {
2019         d->sectionCriteria = new QQuickViewSection(this);
2020         connect(d->sectionCriteria, SIGNAL(propertyChanged()), this, SLOT(updateSections()));
2021     }
2022     return d->sectionCriteria;
2023 }
2024
2025 /*!
2026     \qmlproperty string QtQuick2::ListView::currentSection
2027     This property holds the section that is currently at the beginning of the view.
2028 */
2029 QString QQuickListView::currentSection() const
2030 {
2031     Q_D(const QQuickListView);
2032     return d->currentSection;
2033 }
2034
2035 /*!
2036     \qmlproperty real QtQuick2::ListView::highlightMoveSpeed
2037     \qmlproperty int QtQuick2::ListView::highlightMoveDuration
2038     \qmlproperty real QtQuick2::ListView::highlightResizeSpeed
2039     \qmlproperty int QtQuick2::ListView::highlightResizeDuration
2040
2041     These properties hold the move and resize animation speed of the highlight delegate.
2042
2043     \l highlightFollowsCurrentItem must be true for these properties
2044     to have effect.
2045
2046     The default value for the speed properties is 400 pixels/second.
2047     The default value for the duration properties is -1, i.e. the
2048     highlight will take as much time as necessary to move at the set speed.
2049
2050     These properties have the same characteristics as a SmoothedAnimation.
2051
2052     \sa highlightFollowsCurrentItem
2053 */
2054 qreal QQuickListView::highlightMoveSpeed() const
2055 {
2056     Q_D(const QQuickListView);
2057     return d->highlightMoveSpeed;
2058 }
2059
2060 void QQuickListView::setHighlightMoveSpeed(qreal speed)
2061 {
2062     Q_D(QQuickListView);
2063     if (d->highlightMoveSpeed != speed) {
2064         d->highlightMoveSpeed = speed;
2065         if (d->highlightPosAnimator)
2066             d->highlightPosAnimator->velocity = d->highlightMoveSpeed;
2067         emit highlightMoveSpeedChanged();
2068     }
2069 }
2070
2071 void QQuickListView::setHighlightMoveDuration(int duration)
2072 {
2073     Q_D(QQuickListView);
2074     if (d->highlightMoveDuration != duration) {
2075         if (d->highlightPosAnimator)
2076             d->highlightPosAnimator->userDuration = duration;
2077         QQuickItemView::setHighlightMoveDuration(duration);
2078     }
2079 }
2080
2081 qreal QQuickListView::highlightResizeSpeed() const
2082 {
2083     Q_D(const QQuickListView);
2084     return d->highlightResizeSpeed;
2085 }
2086
2087 void QQuickListView::setHighlightResizeSpeed(qreal speed)
2088 {
2089     Q_D(QQuickListView);
2090     if (d->highlightResizeSpeed != speed) {
2091         d->highlightResizeSpeed = speed;
2092         if (d->highlightSizeAnimator)
2093             d->highlightSizeAnimator->velocity = d->highlightResizeSpeed;
2094         emit highlightResizeSpeedChanged();
2095     }
2096 }
2097
2098 int QQuickListView::highlightResizeDuration() const
2099 {
2100     Q_D(const QQuickListView);
2101     return d->highlightResizeDuration;
2102 }
2103
2104 void QQuickListView::setHighlightResizeDuration(int duration)
2105 {
2106     Q_D(QQuickListView);
2107     if (d->highlightResizeDuration != duration) {
2108         d->highlightResizeDuration = duration;
2109         if (d->highlightSizeAnimator)
2110             d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
2111         emit highlightResizeDurationChanged();
2112     }
2113 }
2114
2115 /*!
2116     \qmlproperty enumeration QtQuick2::ListView::snapMode
2117
2118     This property determines how the view scrolling will settle following a drag or flick.
2119     The possible values are:
2120
2121     \list
2122     \o ListView.NoSnap (default) - the view stops anywhere within the visible area.
2123     \o ListView.SnapToItem - the view settles with an item aligned with the start of
2124     the view.
2125     \o ListView.SnapOneItem - the view settles no more than one item away from the first
2126     visible item at the time the mouse button is released.  This mode is particularly
2127     useful for moving one page at a time.
2128     \endlist
2129
2130     \c snapMode does not affect the \l currentIndex.  To update the
2131     \l currentIndex as the list is moved, set \l highlightRangeMode
2132     to \c ListView.StrictlyEnforceRange.
2133
2134     \sa highlightRangeMode
2135 */
2136 QQuickListView::SnapMode QQuickListView::snapMode() const
2137 {
2138     Q_D(const QQuickListView);
2139     return d->snapMode;
2140 }
2141
2142 void QQuickListView::setSnapMode(SnapMode mode)
2143 {
2144     Q_D(QQuickListView);
2145     if (d->snapMode != mode) {
2146         d->snapMode = mode;
2147         emit snapModeChanged();
2148     }
2149 }
2150
2151
2152 /*!
2153     \qmlproperty Component QtQuick2::ListView::footer
2154     This property holds the component to use as the footer.
2155
2156     An instance of the footer component is created for each view.  The
2157     footer is positioned at the end of the view, after any items.
2158
2159     \sa header, footerItem
2160 */
2161
2162
2163 /*!
2164     \qmlproperty Component QtQuick2::ListView::header
2165     This property holds the component to use as the header.
2166
2167     An instance of the header component is created for each view.  The
2168     header is positioned at the beginning of the view, before any items.
2169
2170     \sa footer, headertem
2171 */
2172
2173 /*!
2174     \qmlproperty Item QtQuick2::ListView::headerItem
2175     This holds the header item created from the \l header component.
2176
2177     An instance of the header component is created for each view.  The
2178     header is positioned at the beginning of the view, before any items.
2179
2180     \sa header, footerItem
2181 */
2182
2183 /*!
2184     \qmlproperty Item QtQuick2::ListView::footerItem
2185     This holds the footer item created from the \l footer component.
2186
2187     An instance of the footer component is created for each view.  The
2188     footer is positioned at the end of the view, after any items.
2189
2190     \sa footer, headerItem
2191 */
2192
2193 void QQuickListView::viewportMoved()
2194 {
2195     Q_D(QQuickListView);
2196     QQuickItemView::viewportMoved();
2197     if (!d->itemCount)
2198         return;
2199     // Recursion can occur due to refill changing the content size.
2200     if (d->inViewportMoved)
2201         return;
2202     d->inViewportMoved = true;
2203
2204     if (yflick())
2205         d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
2206     else if (d->isRightToLeft())
2207         d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
2208     else
2209         d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
2210
2211     d->refill();
2212
2213     // Set visibility of items to eliminate cost of items outside the visible area.
2214     qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
2215     qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
2216     for (int i = 0; i < d->visibleItems.count(); ++i) {
2217         FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i));
2218         item->item->setVisible(item->endPosition() >= from && item->position() <= to);
2219     }
2220
2221     if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2222         d->moveReason = QQuickListViewPrivate::Mouse;
2223     if (d->moveReason != QQuickListViewPrivate::SetIndex) {
2224         if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2225             // reposition highlight
2226             qreal pos = d->highlight->position();
2227             qreal viewPos = d->isRightToLeft() ? -d->position()-d->size() : d->position();
2228             if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
2229                 pos = viewPos + d->highlightRangeEnd - d->highlight->size();
2230             if (pos < viewPos + d->highlightRangeStart)
2231                 pos = viewPos + d->highlightRangeStart;
2232             if (pos != d->highlight->position()) {
2233                 d->highlightPosAnimator->stop();
2234                 static_cast<FxListItemSG*>(d->highlight)->setPosition(pos);
2235             } else {
2236                 d->updateHighlight();
2237             }
2238
2239             // update current index
2240             if (FxViewItem *snapItem = d->snapItemAt(d->highlight->position())) {
2241                 if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
2242                     d->updateCurrent(snapItem->index);
2243             }
2244         }
2245     }
2246
2247     if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
2248         d->inFlickCorrection = true;
2249         // Near an end and it seems that the extent has changed?
2250         // Recalculate the flick so that we don't end up in an odd position.
2251         if (yflick() && !d->vData.inOvershoot) {
2252             if (d->vData.velocity > 0) {
2253                 const qreal minY = minYExtent();
2254                 if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
2255                     && minY != d->vData.flickTarget)
2256                     d->flickY(-d->vData.smoothVelocity.value());
2257             } else if (d->vData.velocity < 0) {
2258                 const qreal maxY = maxYExtent();
2259                 if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
2260                     && maxY != d->vData.flickTarget)
2261                     d->flickY(-d->vData.smoothVelocity.value());
2262             }
2263         }
2264
2265         if (xflick() && !d->hData.inOvershoot) {
2266             if (d->hData.velocity > 0) {
2267                 const qreal minX = minXExtent();
2268                 if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
2269                     && minX != d->hData.flickTarget)
2270                     d->flickX(-d->hData.smoothVelocity.value());
2271             } else if (d->hData.velocity < 0) {
2272                 const qreal maxX = maxXExtent();
2273                 if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
2274                     && maxX != d->hData.flickTarget)
2275                     d->flickX(-d->hData.smoothVelocity.value());
2276             }
2277         }
2278         d->inFlickCorrection = false;
2279     }
2280     if (d->sectionCriteria) {
2281         d->updateCurrentSection();
2282         d->updateStickySections();
2283     }
2284     d->inViewportMoved = false;
2285 }
2286
2287 void QQuickListView::keyPressEvent(QKeyEvent *event)
2288 {
2289     Q_D(QQuickListView);
2290     if (d->model && d->model->count() && d->interactive) {
2291         if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left)
2292                     || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right)
2293                     || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Up)) {
2294             if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) {
2295                 decrementCurrentIndex();
2296                 event->accept();
2297                 return;
2298             } else if (d->wrap) {
2299                 event->accept();
2300                 return;
2301             }
2302         } else if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right)
2303                     || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left)
2304                     || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Down)) {
2305             if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) {
2306                 incrementCurrentIndex();
2307                 event->accept();
2308                 return;
2309             } else if (d->wrap) {
2310                 event->accept();
2311                 return;
2312             }
2313         }
2314     }
2315     event->ignore();
2316     QQuickItemView::keyPressEvent(event);
2317 }
2318
2319 void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
2320 {
2321     Q_D(QQuickListView);
2322     if (d->isRightToLeft() && d->orient == QQuickListView::Horizontal) {
2323         // maintain position relative to the right edge
2324         int dx = newGeometry.width() - oldGeometry.width();
2325         setContentX(contentX() - dx);
2326     }
2327     QQuickItemView::geometryChanged(newGeometry, oldGeometry);
2328 }
2329
2330
2331 /*!
2332     \qmlmethod QtQuick2::ListView::incrementCurrentIndex()
2333
2334     Increments the current index.  The current index will wrap
2335     if keyNavigationWraps is true and it is currently at the end.
2336     This method has no effect if the \l count is zero.
2337
2338     \bold Note: methods should only be called after the Component has completed.
2339 */
2340 void QQuickListView::incrementCurrentIndex()
2341 {
2342     Q_D(QQuickListView);
2343     int count = d->model ? d->model->count() : 0;
2344     if (count && (currentIndex() < count - 1 || d->wrap)) {
2345         d->moveReason = QQuickListViewPrivate::SetIndex;
2346         int index = currentIndex()+1;
2347         setCurrentIndex((index >= 0 && index < count) ? index : 0);
2348     }
2349 }
2350
2351 /*!
2352     \qmlmethod QtQuick2::ListView::decrementCurrentIndex()
2353
2354     Decrements the current index.  The current index will wrap
2355     if keyNavigationWraps is true and it is currently at the beginning.
2356     This method has no effect if the \l count is zero.
2357
2358     \bold Note: methods should only be called after the Component has completed.
2359 */
2360 void QQuickListView::decrementCurrentIndex()
2361 {
2362     Q_D(QQuickListView);
2363     int count = d->model ? d->model->count() : 0;
2364     if (count && (currentIndex() > 0 || d->wrap)) {
2365         d->moveReason = QQuickListViewPrivate::SetIndex;
2366         int index = currentIndex()-1;
2367         setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2368     }
2369 }
2370
2371 void QQuickListView::updateSections()
2372 {
2373     Q_D(QQuickListView);
2374     if (isComponentComplete() && d->model) {
2375         QList<QByteArray> roles;
2376         if (d->sectionCriteria && !d->sectionCriteria->property().isEmpty())
2377             roles << d->sectionCriteria->property().toUtf8();
2378         d->model->setWatchedRoles(roles);
2379         d->updateSections();
2380         if (d->itemCount) {
2381             d->forceLayout = true;
2382             polish();
2383         }
2384     }
2385 }
2386
2387 bool QQuickListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Insert &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems)
2388 {
2389     int modelIndex = change.index;
2390     int count = change.count;
2391
2392     qreal tempPos = isRightToLeft() ? -position()-size() : position();
2393     int index = visibleItems.count() ? mapFromModel(modelIndex) : 0;
2394
2395     if (index < 0) {
2396         int i = visibleItems.count() - 1;
2397         while (i > 0 && visibleItems.at(i)->index == -1)
2398             --i;
2399         if (i == 0 && visibleItems.first()->index == -1) {
2400             // there are no visible items except items marked for removal
2401             index = visibleItems.count();
2402         } else if (visibleItems.at(i)->index + 1 == modelIndex
2403             && visibleItems.at(i)->endPosition() <= buffer+tempPos+size()) {
2404             // Special case of appending an item to the model.
2405             index = visibleItems.count();
2406         } else {
2407             if (modelIndex < visibleIndex) {
2408                 // Insert before visible items
2409                 visibleIndex += count;
2410                 for (int i = 0; i < visibleItems.count(); ++i) {
2411                     FxViewItem *item = visibleItems.at(i);
2412                     if (item->index != -1 && item->index >= modelIndex)
2413                         item->index += count;
2414                 }
2415             }
2416             return true;
2417         }
2418     }
2419
2420     // index can be the next item past the end of the visible items list (i.e. appended)
2421     int pos = 0;
2422     if (visibleItems.count()) {
2423         pos = index < visibleItems.count() ? visibleItems.at(index)->position()
2424                                                 : visibleItems.last()->endPosition()+spacing;
2425     }
2426
2427     int prevVisibleCount = visibleItems.count();
2428     if (insertResult->visiblePos.isValid() && pos < insertResult->visiblePos) {
2429         // Insert items before the visible item.
2430         int insertionIdx = index;
2431         int i = 0;
2432         int from = tempPos - buffer;
2433
2434         for (i = count-1; i >= 0; --i) {
2435             if (pos > from && insertionIdx < visibleIndex) {
2436                 // item won't be visible, just note the size for repositioning
2437                 insertResult->sizeChangesBeforeVisiblePos += averageSize + spacing;
2438                 pos -= averageSize + spacing;
2439             } else {
2440                 // item is before first visible e.g. in cache buffer
2441                 FxViewItem *item = 0;
2442                 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2443                     item->index = modelIndex + i;
2444                 if (!item)
2445                     item = createItem(modelIndex + i);
2446                 if (!item)
2447                     return false;
2448
2449                 visibleItems.insert(insertionIdx, item);
2450                 if (insertionIdx == 0)
2451                     insertResult->changedFirstItem = true;
2452                 if (!change.isMove())
2453                     addedItems->append(item);
2454                 insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing;
2455                 pos -= item->size() + spacing;
2456             }
2457             index++;
2458         }
2459     } else {
2460         int i = 0;
2461         int to = buffer+tempPos+size();
2462         for (i = 0; i < count && pos <= to; ++i) {
2463             FxViewItem *item = 0;
2464             if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2465                 item->index = modelIndex + i;
2466             if (!item)
2467                 item = createItem(modelIndex + i);
2468             if (!item)
2469                 return false;
2470
2471             visibleItems.insert(index, item);
2472             if (index == 0)
2473                 insertResult->changedFirstItem = true;
2474             if (!change.isMove())
2475                 addedItems->append(item);
2476             insertResult->sizeChangesAfterVisiblePos += item->size() + spacing;
2477             pos += item->size() + spacing;
2478             ++index;
2479         }
2480     }
2481
2482     for (; index < visibleItems.count(); ++index) {
2483         FxViewItem *item = visibleItems.at(index);
2484         if (item->index != -1)
2485             item->index += count;
2486     }
2487
2488     updateVisibleIndex();
2489
2490     return visibleItems.count() > prevVisibleCount;
2491 }
2492
2493
2494 /*!
2495     \qmlmethod QtQuick2::ListView::positionViewAtIndex(int index, PositionMode mode)
2496
2497     Positions the view such that the \a index is at the position specified by
2498     \a mode:
2499
2500     \list
2501     \o ListView.Beginning - position item at the top (or left for horizontal orientation) of the view.
2502     \o ListView.Center - position item in the center of the view.
2503     \o ListView.End - position item at bottom (or right for horizontal orientation) of the view.
2504     \o ListView.Visible - if any part of the item is visible then take no action, otherwise
2505     bring the item into view.
2506     \o ListView.Contain - ensure the entire item is visible.  If the item is larger than
2507     the view the item is positioned at the top (or left for horizontal orientation) of the view.
2508     \endlist
2509
2510     If positioning the view at \a index would cause empty space to be displayed at
2511     the beginning or end of the view, the view will be positioned at the boundary.
2512
2513     It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2514     at a particular index.  This is unreliable since removing items from the start
2515     of the list does not cause all other items to be repositioned, and because
2516     the actual start of the view can vary based on the size of the delegates.
2517     The correct way to bring an item into view is with \c positionViewAtIndex.
2518
2519     \bold Note: methods should only be called after the Component has completed.  To position
2520     the view at startup, this method should be called by Component.onCompleted.  For
2521     example, to position the view at the end:
2522
2523     \code
2524     Component.onCompleted: positionViewAtIndex(count - 1, ListView.Beginning)
2525     \endcode
2526 */
2527
2528 /*!
2529     \qmlmethod QtQuick2::ListView::positionViewAtBeginning()
2530     \qmlmethod QtQuick2::ListView::positionViewAtEnd()
2531
2532     Positions the view at the beginning or end, taking into account any header or footer.
2533
2534     It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2535     at a particular index.  This is unreliable since removing items from the start
2536     of the list does not cause all other items to be repositioned, and because
2537     the actual start of the view can vary based on the size of the delegates.
2538
2539     \bold Note: methods should only be called after the Component has completed.  To position
2540     the view at startup, this method should be called by Component.onCompleted.  For
2541     example, to position the view at the end on startup:
2542
2543     \code
2544     Component.onCompleted: positionViewAtEnd()
2545     \endcode
2546 */
2547
2548 /*!
2549     \qmlmethod int QtQuick2::ListView::indexAt(int x, int y)
2550
2551     Returns the index of the visible item containing the point \a x, \a y in content
2552     coordinates.  If there is no item at the point specified, or the item is
2553     not visible -1 is returned.
2554
2555     If the item is outside the visible area, -1 is returned, regardless of
2556     whether an item will exist at that point when scrolled into view.
2557
2558     \bold Note: methods should only be called after the Component has completed.
2559 */
2560
2561 /*!
2562     \qmlmethod Item QtQuick2::ListView::itemAt(int x, int y)
2563
2564     Returns the visible item containing the point \a x, \a y in content
2565     coordinates.  If there is no item at the point specified, or the item is
2566     not visible null is returned.
2567
2568     If the item is outside the visible area, null is returned, regardless of
2569     whether an item will exist at that point when scrolled into view.
2570
2571     \bold Note: methods should only be called after the Component has completed.
2572 */
2573
2574 QQuickListViewAttached *QQuickListView::qmlAttachedProperties(QObject *obj)
2575 {
2576     return new QQuickListViewAttached(obj);
2577 }
2578
2579 QT_END_NAMESPACE