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