1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qquicklistview_p.h"
43 #include "qquickitemview_p_p.h"
44 #include "qquickvisualitemmodel_p.h"
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>
53 #include <private/qquicksmoothedanimation_p_p.h>
54 #include <private/qlistmodelinterface_p.h>
55 #include "qplatformdefs.h"
59 #ifndef QML_FLICK_SNAPONETHRESHOLD
60 #define QML_FLICK_SNAPONETHRESHOLD 30
63 //#define DEBUG_DELEGATE_LIFECYCLE
67 class QQuickListViewPrivate : public QQuickItemViewPrivate
69 Q_DECLARE_PUBLIC(QQuickListView)
71 static QQuickListViewPrivate* get(QQuickListView *item) { return item->d_func(); }
73 virtual Qt::Orientation layoutOrientation() const;
74 virtual bool isContentFlowReversed() const;
75 bool isRightToLeft() const;
77 virtual qreal positionAt(int index) const;
78 virtual qreal endPositionAt(int index) const;
79 virtual qreal originPosition() const;
80 virtual qreal lastPosition() const;
82 FxViewItem *itemBefore(int modelIndex) const;
83 QString sectionAt(int modelIndex);
84 qreal snapPosAt(qreal pos);
85 FxViewItem *snapItemAt(qreal pos);
90 virtual bool addVisibleItems(qreal fillFrom, qreal fillTo, bool doBuffer);
91 virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
92 virtual void visibleItemsChanged();
94 virtual FxViewItem *newViewItem(int index, QQuickItem *item);
95 virtual void initializeViewItem(FxViewItem *item);
96 virtual bool releaseItem(FxViewItem *item);
97 virtual void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer);
98 virtual void repositionPackageItemAt(QQuickItem *item, int index);
99 virtual void resetFirstItemPosition(qreal pos = 0.0);
100 virtual void adjustFirstItem(qreal forwards, qreal backwards, int);
102 virtual void createHighlight();
103 virtual void updateHighlight();
104 virtual void resetHighlightPosition();
106 virtual void setPosition(qreal pos);
107 virtual void layoutVisibleItems(int fromModelIndex = 0);
109 virtual bool applyInsertionChange(const QQuickChangeSet::Insert &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView);
110 virtual void translateAndTransitionItemsAfter(int afterIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult);
112 virtual void updateSections();
113 QQuickItem *getSectionItem(const QString §ion);
114 void releaseSectionItem(QQuickItem *item);
115 void updateInlineSection(FxListItemSG *);
116 void updateCurrentSection();
117 void updateStickySections();
119 virtual qreal headerSize() const;
120 virtual qreal footerSize() const;
121 virtual bool showHeaderForIndex(int index) const;
122 virtual bool showFooterForIndex(int index) const;
123 virtual void updateHeader();
124 virtual void updateFooter();
126 virtual void changedVisibleIndex(int newIndex);
127 virtual void initializeCurrentItem();
129 void updateAverage();
131 void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
132 virtual void fixupPosition();
133 virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
134 virtual void flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
135 QQuickTimeLineCallback::Callback fixupCallback, qreal velocity);
137 QQuickListView::Orientation orient;
141 QQuickListView::SnapMode snapMode;
143 QSmoothedAnimation *highlightPosAnimator;
144 QSmoothedAnimation *highlightSizeAnimator;
145 qreal highlightMoveSpeed;
146 qreal highlightResizeSpeed;
147 int highlightResizeDuration;
149 QQuickViewSection *sectionCriteria;
150 QString currentSection;
151 static const int sectionCacheSize = 5;
152 QQuickItem *sectionCache[sectionCacheSize];
153 QQuickItem *currentSectionItem;
154 QString currentStickySection;
155 QQuickItem *nextSectionItem;
156 QString nextStickySection;
157 QString lastVisibleSection;
161 bool correctFlick : 1;
162 bool inFlickCorrection : 1;
164 QQuickListViewPrivate()
165 : orient(QQuickListView::Vertical)
167 , averageSize(100.0), spacing(0.0)
168 , snapMode(QQuickListView::NoSnap)
169 , highlightPosAnimator(0), highlightSizeAnimator(0)
170 , highlightMoveSpeed(400), highlightResizeSpeed(400), highlightResizeDuration(-1)
171 , sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
172 , overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
174 ~QQuickListViewPrivate() {
175 delete highlightPosAnimator;
176 delete highlightSizeAnimator;
179 friend class QQuickViewSection;
182 //----------------------------------------------------------------------------
184 QQuickViewSection::QQuickViewSection(QQuickListView *parent)
185 : QObject(parent), m_criteria(FullString), m_delegate(0), m_labelPositioning(InlineLabels)
186 , m_view(parent ? QQuickListViewPrivate::get(parent) : 0)
190 void QQuickViewSection::setProperty(const QString &property)
192 if (property != m_property) {
193 m_property = property;
194 emit propertyChanged();
195 m_view->updateSections();
199 void QQuickViewSection::setCriteria(QQuickViewSection::SectionCriteria criteria)
201 if (criteria != m_criteria) {
202 m_criteria = criteria;
203 emit criteriaChanged();
204 m_view->updateSections();
208 void QQuickViewSection::setDelegate(QQmlComponent *delegate)
210 if (delegate != m_delegate) {
211 m_delegate = delegate;
212 emit delegateChanged();
213 m_view->updateSections();
217 QString QQuickViewSection::sectionString(const QString &value)
219 if (m_criteria == FirstCharacter)
220 return value.isEmpty() ? QString() : value.at(0);
225 void QQuickViewSection::setLabelPositioning(int l)
227 if (m_labelPositioning != l) {
228 m_labelPositioning = l;
229 emit labelPositioningChanged();
230 m_view->updateSections();
234 //----------------------------------------------------------------------------
236 class FxListItemSG : public FxViewItem
239 FxListItemSG(QQuickItem *i, QQuickListView *v, bool own) : FxViewItem(i, own), view(v) {
240 attached = static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(item));
242 static_cast<QQuickListViewAttached*>(attached)->setView(view);
247 inline QQuickItem *section() const {
248 return attached ? static_cast<QQuickListViewAttached*>(attached)->m_sectionItem : 0;
250 void setSection(QQuickItem *s) {
252 attached = static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(item));
253 static_cast<QQuickListViewAttached*>(attached)->m_sectionItem = s;
256 qreal position() const {
258 if (view->orientation() == QQuickListView::Vertical)
259 return section()->y();
261 return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section()->width()-section()->x() : section()->x());
263 return itemPosition();
266 qreal itemPosition() const {
267 if (view->orientation() == QQuickListView::Vertical)
270 return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX());
274 return (view->orientation() == QQuickListView::Vertical ? item->height()+section()->height() : item->width()+section()->width());
276 return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
278 qreal itemSize() const {
279 return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
281 qreal sectionSize() const {
283 return (view->orientation() == QQuickListView::Vertical ? section()->height() : section()->width());
286 qreal endPosition() const {
287 if (view->orientation() == QQuickListView::Vertical) {
288 return itemY() + item->height();
290 return (view->effectiveLayoutDirection() == Qt::RightToLeft
292 : itemX() + item->width());
295 void setPosition(qreal pos, bool immediate = false) {
296 // position the section immediately even if there is a transition
298 if (view->orientation() == QQuickListView::Vertical) {
299 section()->setY(pos);
301 if (view->effectiveLayoutDirection() == Qt::RightToLeft)
302 section()->setX(-section()->width()-pos);
304 section()->setX(pos);
307 moveTo(pointForPosition(pos), immediate);
309 void setSize(qreal size) {
310 if (view->orientation() == QQuickListView::Vertical)
311 item->setHeight(size);
313 item->setWidth(size);
315 bool contains(qreal x, qreal y) const {
316 return (x >= itemX() && x < itemX() + item->width() &&
317 y >= itemY() && y < itemY() + item->height());
320 QQuickListView *view;
323 QPointF pointForPosition(qreal pos) const {
324 if (view->orientation() == QQuickListView::Vertical) {
326 pos += section()->height();
327 return QPointF(itemX(), pos);
329 if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
331 pos += section()->width();
332 return QPointF(-item->width() - pos, itemY());
335 pos += section()->width();
336 return QPointF(pos, itemY());
342 //----------------------------------------------------------------------------
344 bool QQuickListViewPrivate::isContentFlowReversed() const
346 return isRightToLeft();
349 Qt::Orientation QQuickListViewPrivate::layoutOrientation() const
351 return static_cast<Qt::Orientation>(orient);
354 bool QQuickListViewPrivate::isRightToLeft() const
356 Q_Q(const QQuickListView);
357 return orient == QQuickListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
360 // Returns the item before modelIndex, if created.
361 // May return an item marked for removal.
362 FxViewItem *QQuickListViewPrivate::itemBefore(int modelIndex) const
364 if (modelIndex < visibleIndex)
368 while (idx < visibleItems.count()) {
369 FxViewItem *item = visibleItems.at(idx);
370 if (item->index != -1)
371 lastIndex = item->index;
372 if (item->index == modelIndex)
373 return visibleItems.at(idx-1);
376 if (lastIndex == modelIndex-1)
377 return visibleItems.last();
381 void QQuickListViewPrivate::setPosition(qreal pos)
384 if (orient == QQuickListView::Vertical) {
385 q->QQuickFlickable::setContentY(pos);
388 q->QQuickFlickable::setContentX(-pos-size());
390 q->QQuickFlickable::setContentX(pos);
394 qreal QQuickListViewPrivate::originPosition() const
397 if (!visibleItems.isEmpty()) {
398 pos = (*visibleItems.constBegin())->position();
399 if (visibleIndex > 0)
400 pos -= visibleIndex * (averageSize + spacing);
405 qreal QQuickListViewPrivate::lastPosition() const
408 if (!visibleItems.isEmpty()) {
409 int invisibleCount = visibleItems.count() - visibleIndex;
410 for (int i = visibleItems.count()-1; i >= 0; --i) {
411 if (visibleItems.at(i)->index != -1) {
412 invisibleCount = model->count() - visibleItems.at(i)->index - 1;
416 pos = (*(--visibleItems.constEnd()))->endPosition() + invisibleCount * (averageSize + spacing);
417 } else if (model && model->count()) {
418 pos = (model->count() * averageSize + (model->count()-1) * spacing);
423 qreal QQuickListViewPrivate::positionAt(int modelIndex) const
425 if (FxViewItem *item = visibleItem(modelIndex)) {
426 return item->position();
428 if (!visibleItems.isEmpty()) {
429 if (modelIndex < visibleIndex) {
430 int count = visibleIndex - modelIndex;
432 if (modelIndex == currentIndex && currentItem) {
433 cs = currentItem->size() + spacing;
436 return (*visibleItems.constBegin())->position() - count * (averageSize + spacing) - cs;
438 int count = modelIndex - findLastVisibleIndex(visibleIndex) - 1;
439 return (*(--visibleItems.constEnd()))->endPosition() + spacing + count * (averageSize + spacing);
445 qreal QQuickListViewPrivate::endPositionAt(int modelIndex) const
447 if (FxViewItem *item = visibleItem(modelIndex))
448 return item->endPosition();
449 if (!visibleItems.isEmpty()) {
450 if (modelIndex < visibleIndex) {
451 int count = visibleIndex - modelIndex;
452 return (*visibleItems.constBegin())->position() - (count - 1) * (averageSize + spacing) - spacing;
454 int count = modelIndex - findLastVisibleIndex(visibleIndex) - 1;
455 return (*(--visibleItems.constEnd()))->endPosition() + count * (averageSize + spacing);
461 QString QQuickListViewPrivate::sectionAt(int modelIndex)
463 if (FxViewItem *item = visibleItem(modelIndex))
464 return item->attached->section();
467 if (sectionCriteria) {
468 QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
469 section = sectionCriteria->sectionString(propValue);
475 qreal QQuickListViewPrivate::snapPosAt(qreal pos)
477 if (FxViewItem *snapItem = snapItemAt(pos))
478 return snapItem->position();
479 if (visibleItems.count()) {
480 qreal firstPos = (*visibleItems.constBegin())->position();
481 qreal endPos = (*(--visibleItems.constEnd()))->position();
482 if (pos < firstPos) {
483 return firstPos - qRound((firstPos - pos) / averageSize) * averageSize;
484 } else if (pos > endPos)
485 return endPos + qRound((pos - endPos) / averageSize) * averageSize;
487 return qRound((pos - originPosition()) / averageSize) * averageSize + originPosition();
490 FxViewItem *QQuickListViewPrivate::snapItemAt(qreal pos)
492 FxViewItem *snapItem = 0;
493 qreal prevItemSize = 0;
494 for (int i = 0; i < visibleItems.count(); ++i) {
495 FxViewItem *item = visibleItems.at(i);
496 if (item->index == -1)
498 qreal itemTop = item->position();
499 if (highlight && itemTop >= pos && item->endPosition() <= pos + highlight->size())
501 if (itemTop+item->size()/2 >= pos && itemTop-prevItemSize/2 < pos)
503 prevItemSize = item->size();
508 void QQuickListViewPrivate::changedVisibleIndex(int newIndex)
510 visiblePos = positionAt(newIndex);
511 visibleIndex = newIndex;
514 void QQuickListViewPrivate::init()
516 QQuickItemViewPrivate::init();
517 ::memset(sectionCache, 0, sizeof(QQuickItem*) * sectionCacheSize);
520 void QQuickListViewPrivate::clear()
522 for (int i = 0; i < sectionCacheSize; ++i) {
523 delete sectionCache[i];
527 releaseSectionItem(currentSectionItem);
528 currentSectionItem = 0;
529 releaseSectionItem(nextSectionItem);
531 lastVisibleSection = QString();
532 QQuickItemViewPrivate::clear();
535 FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
539 FxListItemSG *listItem = new FxListItemSG(item, q, false);
540 listItem->index = modelIndex;
542 // initialise attached properties
543 if (sectionCriteria) {
544 QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
545 listItem->attached->m_section = sectionCriteria->sectionString(propValue);
546 if (modelIndex > 0) {
547 if (FxViewItem *item = itemBefore(modelIndex))
548 listItem->attached->m_prevSection = item->attached->section();
550 listItem->attached->m_prevSection = sectionAt(modelIndex-1);
552 if (modelIndex < model->count()-1) {
553 if (FxViewItem *item = visibleItem(modelIndex+1))
554 listItem->attached->m_nextSection = static_cast<QQuickListViewAttached*>(item->attached)->section();
556 listItem->attached->m_nextSection = sectionAt(modelIndex+1);
563 void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
565 QQuickItemViewPrivate::initializeViewItem(item);
567 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item->item);
568 itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
570 if (sectionCriteria && sectionCriteria->delegate()) {
571 if (item->attached->m_prevSection != item->attached->m_section)
572 updateInlineSection(static_cast<FxListItemSG*>(item));
576 bool QQuickListViewPrivate::releaseItem(FxViewItem *item)
581 QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached);
583 bool released = QQuickItemViewPrivate::releaseItem(item);
584 if (released && att && att->m_sectionItem) {
585 // We hold no more references to this item
588 if (!sectionCache[i]) {
589 sectionCache[i] = att->m_sectionItem;
590 sectionCache[i]->setVisible(false);
591 att->m_sectionItem = 0;
595 } while (i < sectionCacheSize);
596 delete att->m_sectionItem;
597 att->m_sectionItem = 0;
603 bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool doBuffer)
605 qreal itemEnd = visiblePos;
606 if (visibleItems.count()) {
607 visiblePos = (*visibleItems.constBegin())->position();
608 itemEnd = (*(--visibleItems.constEnd()))->endPosition() + spacing;
611 int modelIndex = findLastVisibleIndex();
612 bool haveValidItems = modelIndex >= 0;
613 modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
615 if (haveValidItems && (fillFrom > itemEnd+averageSize+spacing
616 || fillTo < visiblePos - averageSize - spacing)) {
617 // We've jumped more than a page. Estimate which items are now
618 // visible and fill from there.
619 int count = (fillFrom - itemEnd) / (averageSize + spacing);
620 int newModelIdx = qBound(0, modelIndex + count, model->count());
621 count = newModelIdx - modelIndex;
623 for (int i = 0; i < visibleItems.count(); ++i)
624 releaseItem(visibleItems.at(i));
625 visibleItems.clear();
626 modelIndex = newModelIdx;
627 visibleIndex = modelIndex;
628 visiblePos = itemEnd + count * (averageSize + spacing);
629 itemEnd = visiblePos;
633 bool changed = false;
634 FxListItemSG *item = 0;
636 while (modelIndex < model->count() && pos <= fillTo) {
637 #ifdef DEBUG_DELEGATE_LIFECYCLE
638 qDebug() << "refill: append item" << modelIndex << "pos" << pos;
640 if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, doBuffer))))
642 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
643 item->setPosition(pos, true);
644 item->item->setVisible(!doBuffer);
645 pos += item->size() + spacing;
646 visibleItems.append(item);
651 if (doBuffer && requestedIndex != -1) // already waiting for an item
654 while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
655 #ifdef DEBUG_DELEGATE_LIFECYCLE
656 qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
658 if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, doBuffer))))
661 visiblePos -= item->size() + spacing;
662 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
663 item->setPosition(visiblePos, true);
664 item->item->setVisible(!doBuffer);
665 visibleItems.prepend(item);
672 bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
674 FxViewItem *item = 0;
675 bool changed = false;
677 // Remove items from the start of the view.
678 // Zero-sized items shouldn't be removed unless a non-zero-sized item is also being
679 // removed, otherwise a zero-sized item is infinitely added and removed over and
682 while (visibleItems.count() > 1 && index < visibleItems.count()
683 && (item = visibleItems.at(index)) && item->endPosition() < bufferFrom) {
684 if (item->attached->delayRemove())
687 if (item->size() > 0) {
688 #ifdef DEBUG_DELEGATE_LIFECYCLE
689 qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
691 // remove this item and all zero-sized items before it
693 if (item->index != -1)
695 visibleItems.removeAt(index);
696 if (item->transitionScheduledOrRunning()) {
697 #ifdef DEBUG_DELEGATE_LIFECYCLE
698 qDebug() << "refill not releasing animating item" << item->index << item->item->objectName();
700 item->releaseAfterTransition = true;
701 releasePendingTransition.append(item);
707 item = visibleItems.at(--index);
715 while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
716 if (item->attached->delayRemove())
718 #ifdef DEBUG_DELEGATE_LIFECYCLE
719 qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
721 visibleItems.removeLast();
722 if (item->transitionScheduledOrRunning()) {
723 #ifdef DEBUG_DELEGATE_LIFECYCLE
724 qDebug() << "refill not releasing animating item" << item->index << item->item->objectName();
726 item->releaseAfterTransition = true;
727 releasePendingTransition.append(item);
737 void QQuickListViewPrivate::visibleItemsChanged()
739 if (visibleItems.count())
740 visiblePos = (*visibleItems.constBegin())->position();
742 if (currentIndex >= 0 && currentItem && !visibleItem(currentIndex)) {
743 static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
747 updateCurrentSection();
748 updateUnrequestedPositions();
751 void QQuickListViewPrivate::layoutVisibleItems(int fromModelIndex)
753 if (!visibleItems.isEmpty()) {
754 const qreal from = isContentFlowReversed() ? -position() - size() : position();
755 const qreal to = isContentFlowReversed() ? -position() : position() + size();
757 FxViewItem *firstItem = *visibleItems.constBegin();
758 bool fixedCurrent = currentItem && firstItem->item == currentItem->item;
759 qreal sum = firstItem->size();
760 qreal pos = firstItem->position() + firstItem->size() + spacing;
761 firstItem->item->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
763 for (int i=1; i < visibleItems.count(); ++i) {
764 FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.at(i));
765 if (item->index >= fromModelIndex) {
766 item->setPosition(pos);
767 item->setVisible(item->endPosition() >= from && item->position() <= to);
769 pos += item->size() + spacing;
771 fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
773 averageSize = qRound(sum / visibleItems.count());
775 // move current item if it is not a visible item.
776 if (currentIndex >= 0 && currentItem && !fixedCurrent)
777 static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
781 void QQuickListViewPrivate::repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer)
783 static_cast<FxListItemSG *>(item)->setPosition(positionAt(index) + sizeBuffer);
786 void QQuickListViewPrivate::repositionPackageItemAt(QQuickItem *item, int index)
789 qreal pos = position();
790 if (orient == QQuickListView::Vertical) {
791 if (item->y() + item->height() > pos && item->y() < pos + q->height())
792 item->setY(positionAt(index));
794 if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
796 item->setX(-positionAt(index)-item->width());
798 item->setX(positionAt(index));
803 void QQuickListViewPrivate::resetFirstItemPosition(qreal pos)
805 FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.first());
806 item->setPosition(pos);
809 void QQuickListViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int)
811 if (!visibleItems.count())
813 qreal diff = forwards - backwards;
814 static_cast<FxListItemSG*>(visibleItems.first())->setPosition(visibleItems.first()->position() + diff);
817 void QQuickListViewPrivate::createHighlight()
820 bool changed = false;
822 if (trackedItem == highlight)
827 delete highlightPosAnimator;
828 delete highlightSizeAnimator;
829 highlightPosAnimator = 0;
830 highlightSizeAnimator = 0;
836 QQuickItem *item = createHighlightItem();
838 FxListItemSG *newHighlight = new FxListItemSG(item, q, true);
841 newHighlight->setSize(static_cast<FxListItemSG*>(currentItem)->itemSize());
842 newHighlight->setPosition(static_cast<FxListItemSG*>(currentItem)->itemPosition());
844 const QLatin1String posProp(orient == QQuickListView::Vertical ? "y" : "x");
845 highlightPosAnimator = new QSmoothedAnimation;
846 highlightPosAnimator->target = QQmlProperty(item, posProp);
847 highlightPosAnimator->velocity = highlightMoveSpeed;
848 highlightPosAnimator->userDuration = highlightMoveDuration;
850 const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
851 highlightSizeAnimator = new QSmoothedAnimation;
852 highlightSizeAnimator->velocity = highlightResizeSpeed;
853 highlightSizeAnimator->userDuration = highlightResizeDuration;
854 highlightSizeAnimator->target = QQmlProperty(item, sizeProp);
856 highlight = newHighlight;
861 emit q->highlightItemChanged();
864 void QQuickListViewPrivate::updateHighlight()
866 applyPendingChanges();
868 if ((!currentItem && highlight) || (currentItem && !highlight))
870 bool strictHighlight = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
871 if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
872 // auto-update highlight
873 FxListItemSG *listItem = static_cast<FxListItemSG*>(currentItem);
874 highlightPosAnimator->to = isRightToLeft()
875 ? -listItem->itemPosition()-listItem->itemSize()
876 : listItem->itemPosition();
877 highlightSizeAnimator->to = listItem->itemSize();
878 if (orient == QQuickListView::Vertical) {
879 if (highlight->item->width() == 0)
880 highlight->item->setWidth(currentItem->item->width());
882 if (highlight->item->height() == 0)
883 highlight->item->setHeight(currentItem->item->height());
886 highlightPosAnimator->restart();
887 highlightSizeAnimator->restart();
892 void QQuickListViewPrivate::resetHighlightPosition()
894 if (highlight && currentItem)
895 static_cast<FxListItemSG*>(highlight)->setPosition(static_cast<FxListItemSG*>(currentItem)->itemPosition());
898 QQuickItem * QQuickListViewPrivate::getSectionItem(const QString §ion)
901 QQuickItem *sectionItem = 0;
902 int i = sectionCacheSize-1;
903 while (i >= 0 && !sectionCache[i])
906 sectionItem = sectionCache[i];
908 sectionItem->setVisible(true);
909 QQmlContext *context = QQmlEngine::contextForObject(sectionItem)->parentContext();
910 context->setContextProperty(QLatin1String("section"), section);
912 QQmlContext *creationContext = sectionCriteria->delegate()->creationContext();
913 QQmlContext *context = new QQmlContext(
914 creationContext ? creationContext : qmlContext(q));
915 context->setContextProperty(QLatin1String("section"), section);
916 QObject *nobj = sectionCriteria->delegate()->beginCreate(context);
918 QQml_setParent_noEvent(context, nobj);
919 sectionItem = qobject_cast<QQuickItem *>(nobj);
923 sectionItem->setZ(2);
924 QQml_setParent_noEvent(sectionItem, contentItem);
925 sectionItem->setParentItem(contentItem);
930 sectionCriteria->delegate()->completeCreate();
936 void QQuickListViewPrivate::releaseSectionItem(QQuickItem *item)
942 if (!sectionCache[i]) {
943 sectionCache[i] = item;
944 sectionCache[i]->setVisible(false);
948 } while (i < sectionCacheSize);
952 void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
954 if (!sectionCriteria || !sectionCriteria->delegate())
956 if (listItem->attached->m_prevSection != listItem->attached->m_section
957 && (sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels
958 || (listItem->index == 0 && sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart))) {
959 if (!listItem->section()) {
960 qreal pos = listItem->position();
961 listItem->setSection(getSectionItem(listItem->attached->m_section));
962 listItem->setPosition(pos);
964 QQmlContext *context = QQmlEngine::contextForObject(listItem->section())->parentContext();
965 context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
967 } else if (listItem->section()) {
968 qreal pos = listItem->position();
969 releaseSectionItem(listItem->section());
970 listItem->setSection(0);
971 listItem->setPosition(pos);
975 void QQuickListViewPrivate::updateStickySections()
978 || (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem))
981 bool isRtl = isRightToLeft();
982 qreal viewPos = isRightToLeft() ? -position()-size() : position();
983 QQuickItem *sectionItem = 0;
984 QQuickItem *lastSectionItem = 0;
986 while (index < visibleItems.count()) {
987 if (QQuickItem *section = static_cast<FxListItemSG *>(visibleItems.at(index))->section()) {
988 // Find the current section header and last visible section header
989 // and hide them if they will overlap a static section header.
990 qreal sectionPos = orient == QQuickListView::Vertical ? section->y() : section->x();
991 qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width();
993 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
994 visTop = isRtl ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos;
996 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd)
997 visBot = isRtl ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size();
998 section->setVisible(visBot && visTop);
999 if (visTop && !sectionItem)
1000 sectionItem = section;
1002 if (-sectionPos <= viewPos + size())
1003 lastSectionItem = section;
1005 if (sectionPos + sectionSize < viewPos + size())
1006 lastSectionItem = section;
1012 // Current section header
1013 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart && isValid() && visibleItems.count()) {
1014 if (!currentSectionItem) {
1015 currentSectionItem = getSectionItem(currentSection);
1016 } else if (currentStickySection != currentSection) {
1017 QQmlContext *context = QQmlEngine::contextForObject(currentSectionItem)->parentContext();
1018 context->setContextProperty(QLatin1String("section"), currentSection);
1020 currentStickySection = currentSection;
1021 if (!currentSectionItem)
1024 qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1025 bool atBeginning = orient == QQuickListView::Vertical ? vData.atBeginning : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
1026 currentSectionItem->setVisible(!atBeginning && (!header || header->endPosition() < viewPos));
1027 qreal pos = isRtl ? position() + size() - sectionSize : viewPos;
1029 qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x();
1030 pos = isRtl ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
1033 pos = isRtl ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos);
1035 pos = isRtl ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1036 if (orient == QQuickListView::Vertical)
1037 currentSectionItem->setY(pos);
1039 currentSectionItem->setX(pos);
1040 } else if (currentSectionItem) {
1041 releaseSectionItem(currentSectionItem);
1042 currentSectionItem = 0;
1045 // Next section footer
1046 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd && isValid() && visibleItems.count()) {
1047 if (!nextSectionItem) {
1048 nextSectionItem = getSectionItem(nextSection);
1049 } else if (nextStickySection != nextSection) {
1050 QQmlContext *context = QQmlEngine::contextForObject(nextSectionItem)->parentContext();
1051 context->setContextProperty(QLatin1String("section"), nextSection);
1053 nextStickySection = nextSection;
1054 if (!nextSectionItem)
1057 qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1058 nextSectionItem->setVisible(!nextSection.isEmpty());
1059 qreal pos = isRtl ? position() : viewPos + size() - sectionSize;
1060 if (lastSectionItem) {
1061 qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x();
1062 pos = isRtl ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
1065 pos = isRtl ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1066 if (orient == QQuickListView::Vertical)
1067 nextSectionItem->setY(pos);
1069 nextSectionItem->setX(pos);
1070 } else if (nextSectionItem) {
1071 releaseSectionItem(nextSectionItem);
1072 nextSectionItem = 0;
1076 void QQuickListViewPrivate::updateSections()
1078 Q_Q(QQuickListView);
1079 if (!q->isComponentComplete())
1082 QQuickItemViewPrivate::updateSections();
1084 if (sectionCriteria && !visibleItems.isEmpty() && isValid()) {
1085 QString prevSection;
1086 if (visibleIndex > 0)
1087 prevSection = sectionAt(visibleIndex-1);
1088 QQuickListViewAttached *prevAtt = 0;
1090 for (int i = 0; i < visibleItems.count(); ++i) {
1091 QQuickListViewAttached *attached = static_cast<QQuickListViewAttached*>(visibleItems.at(i)->attached);
1092 attached->setPrevSection(prevSection);
1093 if (visibleItems.at(i)->index != -1) {
1094 QString propValue = model->stringValue(visibleItems.at(i)->index, sectionCriteria->property());
1095 attached->setSection(sectionCriteria->sectionString(propValue));
1096 idx = visibleItems.at(i)->index;
1098 updateInlineSection(static_cast<FxListItemSG*>(visibleItems.at(i)));
1100 prevAtt->setNextSection(attached->section());
1101 prevSection = attached->section();
1105 if (idx > 0 && idx < model->count()-1)
1106 prevAtt->setNextSection(sectionAt(idx+1));
1108 prevAtt->setNextSection(QString());
1112 lastVisibleSection = QString();
1113 updateCurrentSection();
1114 updateStickySections();
1117 void QQuickListViewPrivate::updateCurrentSection()
1119 Q_Q(QQuickListView);
1120 if (!sectionCriteria || visibleItems.isEmpty()) {
1121 if (!currentSection.isEmpty()) {
1122 currentSection.clear();
1123 emit q->currentSectionChanged();
1127 bool inlineSections = sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels;
1128 qreal sectionThreshold = position();
1129 if (currentSectionItem && !inlineSections)
1130 sectionThreshold += orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1132 int modelIndex = visibleIndex;
1133 while (index < visibleItems.count() && visibleItems.at(index)->endPosition() <= sectionThreshold) {
1134 if (visibleItems.at(index)->index != -1)
1135 modelIndex = visibleItems.at(index)->index;
1139 QString newSection = currentSection;
1140 if (index < visibleItems.count())
1141 newSection = visibleItems.at(index)->attached->section();
1143 newSection = (*visibleItems.constBegin())->attached->section();
1144 if (newSection != currentSection) {
1145 currentSection = newSection;
1146 updateStickySections();
1147 emit q->currentSectionChanged();
1150 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
1151 // Don't want to scan for next section on every movement, so remember
1152 // the last section in the visible area and only scan for the next
1153 // section when that changes. Clearing lastVisibleSection will also
1155 QString lastSection = currentSection;
1156 qreal endPos = isRightToLeft() ? -position() : position() + size();
1157 if (nextSectionItem && !inlineSections)
1158 endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1159 while (index < visibleItems.count() && static_cast<FxListItemSG*>(visibleItems.at(index))->itemPosition() < endPos) {
1160 if (visibleItems.at(index)->index != -1)
1161 modelIndex = visibleItems.at(index)->index;
1162 lastSection = visibleItems.at(index)->attached->section();
1166 if (lastVisibleSection != lastSection) {
1167 nextSection = QString();
1168 lastVisibleSection = lastSection;
1169 for (int i = modelIndex; i < itemCount; ++i) {
1170 QString section = sectionAt(i);
1171 if (section != lastSection) {
1172 nextSection = section;
1173 updateStickySections();
1181 void QQuickListViewPrivate::initializeCurrentItem()
1183 QQuickItemViewPrivate::initializeCurrentItem();
1186 FxListItemSG *listItem = static_cast<FxListItemSG *>(currentItem);
1188 // don't reposition the item if it is already in the visibleItems list
1189 FxViewItem *actualItem = visibleItem(currentIndex);
1191 if (currentIndex == visibleIndex - 1 && visibleItems.count()) {
1192 // We can calculate exact postion in this case
1193 listItem->setPosition(visibleItems.first()->position() - currentItem->size() - spacing);
1195 // Create current item now and position as best we can.
1196 // Its position will be corrected when it becomes visible.
1197 listItem->setPosition(positionAt(currentIndex));
1201 if (visibleItems.isEmpty())
1202 averageSize = listItem->size();
1206 void QQuickListViewPrivate::updateAverage()
1208 if (!visibleItems.count())
1211 for (int i = 0; i < visibleItems.count(); ++i)
1212 sum += visibleItems.at(i)->size();
1213 averageSize = qRound(sum / visibleItems.count());
1216 qreal QQuickListViewPrivate::headerSize() const
1218 return header ? header->size() : 0.0;
1221 qreal QQuickListViewPrivate::footerSize() const
1223 return footer ? footer->size() : 0.0;
1226 bool QQuickListViewPrivate::showHeaderForIndex(int index) const
1231 bool QQuickListViewPrivate::showFooterForIndex(int index) const
1233 return index == model->count()-1;
1236 void QQuickListViewPrivate::updateFooter()
1238 Q_Q(QQuickListView);
1239 bool created = false;
1241 QQuickItem *item = createComponentItem(footerComponent, true);
1245 footer = new FxListItemSG(item, q, true);
1249 FxListItemSG *listItem = static_cast<FxListItemSG*>(footer);
1250 if (visibleItems.count()) {
1251 qreal endPos = lastPosition();
1252 if (findLastVisibleIndex() == model->count()-1) {
1253 listItem->setPosition(endPos);
1255 qreal visiblePos = position() + q->height();
1256 if (endPos <= visiblePos || listItem->position() < endPos)
1257 listItem->setPosition(endPos);
1260 listItem->setPosition(visiblePos);
1264 emit q->footerItemChanged();
1267 void QQuickListViewPrivate::updateHeader()
1269 Q_Q(QQuickListView);
1270 bool created = false;
1272 QQuickItem *item = createComponentItem(headerComponent, true);
1276 header = new FxListItemSG(item, q, true);
1280 FxListItemSG *listItem = static_cast<FxListItemSG*>(header);
1282 if (visibleItems.count()) {
1283 qreal startPos = originPosition();
1284 if (visibleIndex == 0) {
1285 listItem->setPosition(startPos - headerSize());
1287 if (position() <= startPos || listItem->position() > startPos - headerSize())
1288 listItem->setPosition(startPos - headerSize());
1291 listItem->setPosition(-headerSize());
1296 emit q->headerItemChanged();
1299 void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
1301 Q_Q(QQuickListView);
1302 QQuickItemViewPrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
1303 if (!q->isComponentComplete())
1305 if (item != contentItem && (!highlight || item != highlight->item)) {
1306 if ((orient == QQuickListView::Vertical && newGeometry.height() != oldGeometry.height())
1307 || (orient == QQuickListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
1314 void QQuickListViewPrivate::fixupPosition()
1316 if ((haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange)
1317 || snapMode != QQuickListView::NoSnap)
1319 if (orient == QQuickListView::Vertical)
1325 void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
1327 if ((orient == QQuickListView::Horizontal && &data == &vData)
1328 || (orient == QQuickListView::Vertical && &data == &hData))
1331 correctFlick = false;
1332 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1333 bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
1335 qreal viewPos = isRightToLeft() ? -position()-size() : position();
1337 if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) {
1338 qreal tempPosition = isRightToLeft() ? -position()-size() : position();
1339 if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) {
1340 // if we've been dragged < averageSize/2 then bias towards the next item
1341 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1343 if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < averageSize/2)
1344 bias = averageSize/2;
1345 else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -averageSize/2)
1346 bias = -averageSize/2;
1347 if (isRightToLeft())
1349 tempPosition -= bias;
1351 FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
1352 if (!topItem && strictHighlightRange && currentItem) {
1353 // StrictlyEnforceRange always keeps an item in range
1355 topItem = currentItem;
1357 FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
1358 if (!bottomItem && strictHighlightRange && currentItem) {
1359 // StrictlyEnforceRange always keeps an item in range
1361 bottomItem = currentItem;
1364 bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1365 if (topItem && (isInBounds || strictHighlightRange)) {
1366 if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
1367 pos = isRightToLeft() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart;
1369 if (isRightToLeft())
1370 pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
1372 pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
1374 } else if (bottomItem && isInBounds) {
1375 if (isRightToLeft())
1376 pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
1378 pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
1380 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1384 qreal dist = qAbs(data.move + pos);
1386 timeline.reset(data.move);
1387 if (fixupMode != Immediate) {
1388 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1389 data.fixingUp = true;
1391 timeline.set(data.move, -pos);
1393 vTime = timeline.time();
1395 } else if (currentItem && strictHighlightRange && moveReason != QQuickListViewPrivate::SetIndex) {
1397 qreal pos = static_cast<FxListItemSG*>(currentItem)->itemPosition();
1398 if (viewPos < pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd)
1399 viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd;
1400 if (viewPos > pos - highlightRangeStart)
1401 viewPos = pos - highlightRangeStart;
1402 if (isRightToLeft())
1403 viewPos = -viewPos-size();
1405 timeline.reset(data.move);
1406 if (viewPos != position()) {
1407 if (fixupMode != Immediate) {
1408 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1409 data.fixingUp = true;
1411 timeline.set(data.move, -viewPos);
1414 vTime = timeline.time();
1416 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1418 data.inOvershoot = false;
1422 void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1423 QQuickTimeLineCallback::Callback fixupCallback, qreal velocity)
1425 Q_Q(QQuickListView);
1427 data.fixingUp = false;
1429 if ((!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange) && snapMode == QQuickListView::NoSnap) {
1430 correctFlick = true;
1431 QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1434 qreal maxDistance = 0;
1435 qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value();
1437 // -ve velocity means list is moving up/left
1439 if (data.move.value() < minExtent) {
1440 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1441 // if we've been dragged < averageSize/2 then bias towards the next item
1442 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1443 qreal bias = dist < averageSize/2 ? averageSize/2 : 0;
1444 if (isRightToLeft())
1446 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart;
1447 maxDistance = qAbs(data.flickTarget - data.move.value());
1448 velocity = maxVelocity;
1450 maxDistance = qAbs(minExtent - data.move.value());
1453 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1454 data.flickTarget = minExtent;
1456 if (data.move.value() > maxExtent) {
1457 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1458 // if we've been dragged < averageSize/2 then bias towards the next item
1459 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1460 qreal bias = -dist < averageSize/2 ? averageSize/2 : 0;
1461 if (isRightToLeft())
1463 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart;
1464 maxDistance = qAbs(data.flickTarget - data.move.value());
1465 velocity = -maxVelocity;
1467 maxDistance = qAbs(maxExtent - data.move.value());
1470 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1471 data.flickTarget = maxExtent;
1473 bool overShoot = boundsBehavior == QQuickFlickable::DragAndOvershootBounds;
1474 if (maxDistance > 0 || overShoot) {
1475 // These modes require the list to stop exactly on an item boundary.
1476 // The initial flick will estimate the boundary to stop on.
1477 // Since list items can have variable sizes, the boundary will be
1478 // reevaluated and adjusted as we approach the boundary.
1480 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1486 if (!hData.flicking && !vData.flicking) {
1487 // the initial flick - estimate boundary
1488 qreal accel = deceleration;
1490 overshootDist = 0.0;
1491 // + averageSize/4 to encourage moving at least one item in the flick direction
1492 qreal dist = v2 / (accel * 2.0) + averageSize/4;
1493 if (maxDistance > 0)
1494 dist = qMin(dist, maxDistance);
1497 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) {
1498 if (snapMode != QQuickListView::SnapOneItem) {
1499 qreal distTemp = isRightToLeft() ? -dist : dist;
1500 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart;
1502 data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
1504 if (data.flickTarget >= minExtent) {
1505 overshootDist = overShootDistance(vSize);
1506 data.flickTarget += overshootDist;
1507 } else if (data.flickTarget <= maxExtent) {
1508 overshootDist = overShootDistance(vSize);
1509 data.flickTarget -= overshootDist;
1512 qreal adjDist = -data.flickTarget + data.move.value();
1513 if (qAbs(adjDist) > qAbs(dist)) {
1514 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1515 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1524 accel = v2 / (2.0f * qAbs(dist));
1525 } else if (overShoot) {
1526 data.flickTarget = data.move.value() - dist;
1527 if (data.flickTarget >= minExtent) {
1528 overshootDist = overShootDistance(vSize);
1529 data.flickTarget += overshootDist;
1530 } else if (data.flickTarget <= maxExtent) {
1531 overshootDist = overShootDistance(vSize);
1532 data.flickTarget -= overshootDist;
1535 timeline.reset(data.move);
1536 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1537 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
1538 if (!hData.flicking && q->xflick()) {
1539 hData.flicking = true;
1540 emit q->flickingChanged();
1541 emit q->flickingHorizontallyChanged();
1542 emit q->flickStarted();
1544 if (!vData.flicking && q->yflick()) {
1545 vData.flicking = true;
1546 emit q->flickingChanged();
1547 emit q->flickingVerticallyChanged();
1548 emit q->flickStarted();
1550 correctFlick = true;
1552 // reevaluate the target boundary.
1553 qreal newtarget = data.flickTarget;
1554 if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) {
1555 qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
1556 newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart;
1557 newtarget = isRightToLeft() ? -newtarget+size() : newtarget;
1559 if (velocity < 0 && newtarget <= maxExtent)
1560 newtarget = maxExtent - overshootDist;
1561 else if (velocity > 0 && newtarget >= minExtent)
1562 newtarget = minExtent + overshootDist;
1563 if (newtarget == data.flickTarget) { // boundary unchanged - nothing to do
1564 if (qAbs(velocity) < MinimumFlickVelocity)
1565 correctFlick = false;
1568 data.flickTarget = newtarget;
1569 qreal dist = -newtarget + data.move.value();
1570 if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
1571 correctFlick = false;
1572 timeline.reset(data.move);
1573 fixup(data, minExtent, maxExtent);
1576 timeline.reset(data.move);
1577 timeline.accelDistance(data.move, v, -dist);
1578 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
1581 correctFlick = false;
1582 timeline.reset(data.move);
1583 fixup(data, minExtent, maxExtent);
1587 //----------------------------------------------------------------------------
1590 \qmlclass ListView QQuickListView
1591 \inqmlmodule QtQuick 2
1592 \ingroup qml-view-elements
1594 \brief The ListView item provides a list view of items provided by a model.
1596 A ListView displays data from models created from built-in QML elements like ListModel
1597 and XmlListModel, or custom model classes defined in C++ that inherit from
1600 A ListView has a \l model, which defines the data to be displayed, and
1601 a \l delegate, which defines how the data should be displayed. Items in a
1602 ListView are laid out horizontally or vertically. List views are inherently
1603 flickable because ListView inherits from \l Flickable.
1605 \section1 Example Usage
1607 The following example shows the definition of a simple list model defined
1608 in a file called \c ContactModel.qml:
1610 \snippet doc/src/snippets/qml/listview/ContactModel.qml 0
1612 Another component can display this model data in a ListView, like this:
1614 \snippet doc/src/snippets/qml/listview/listview.qml import
1616 \snippet doc/src/snippets/qml/listview/listview.qml classdocs simple
1618 \image listview-simple.png
1620 Here, the ListView creates a \c ContactModel component for its model, and a \l Text element
1621 for its delegate. The view will create a new \l Text component for each item in the model. Notice
1622 the delegate is able to access the model's \c name and \c number data directly.
1624 An improved list view is shown below. The delegate is visually improved and is moved
1625 into a separate \c contactDelegate component.
1627 \snippet doc/src/snippets/qml/listview/listview.qml classdocs advanced
1628 \image listview-highlight.png
1630 The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
1631 and \c focus is set to \c true to enable keyboard navigation for the list view.
1632 The list view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
1634 Delegates are instantiated as needed and may be destroyed at any time.
1635 State should \e never be stored in a delegate.
1637 ListView attaches a number of properties to the root item of the delegate, for example
1638 \c {ListView.isCurrentItem}. In the following example, the root delegate item can access
1639 this attached property directly as \c ListView.isCurrentItem, while the child
1640 \c contactInfo object must refer to this property as \c wrapper.ListView.isCurrentItem.
1642 \snippet doc/src/snippets/qml/listview/listview.qml isCurrentItem
1644 \note Views do not enable \e clip automatically. If the view
1645 is not clipped by another item or the screen, it will be necessary
1646 to set \e {clip: true} in order to have the out of view items clipped
1649 \sa {QML Data Models}, GridView, {declarative/modelviews/listview}{ListView examples}
1651 QQuickListView::QQuickListView(QQuickItem *parent)
1652 : QQuickItemView(*(new QQuickListViewPrivate), parent)
1656 QQuickListView::~QQuickListView()
1661 \qmlattachedproperty bool QtQuick2::ListView::isCurrentItem
1662 This attached property is true if this delegate is the current item; otherwise false.
1664 It is attached to each instance of the delegate.
1666 This property may be used to adjust the appearance of the current item, for example:
1668 \snippet doc/src/snippets/qml/listview/listview.qml isCurrentItem
1672 \qmlattachedproperty ListView QtQuick2::ListView::view
1673 This attached property holds the view that manages this delegate instance.
1675 It is attached to each instance of the delegate.
1679 \qmlattachedproperty string QtQuick2::ListView::previousSection
1680 This attached property holds the section of the previous element.
1682 It is attached to each instance of the delegate.
1684 The section is evaluated using the \l {ListView::section.property}{section} properties.
1688 \qmlattachedproperty string QtQuick2::ListView::nextSection
1689 This attached property holds the section of the next element.
1691 It is attached to each instance of the delegate.
1693 The section is evaluated using the \l {ListView::section.property}{section} properties.
1697 \qmlattachedproperty string QtQuick2::ListView::section
1698 This attached property holds the section of this element.
1700 It is attached to each instance of the delegate.
1702 The section is evaluated using the \l {ListView::section.property}{section} properties.
1706 \qmlattachedproperty bool QtQuick2::ListView::delayRemove
1708 This attached property holds whether the delegate may be destroyed. It
1709 is attached to each instance of the delegate. The default value is false.
1711 It is sometimes necessary to delay the destruction of an item
1712 until an animation completes. The example delegate below ensures that the
1713 animation completes before the item is removed from the list.
1715 \snippet doc/src/snippets/qml/listview/listview.qml delayRemove
1717 If a \l remove transition has been specified, it will not be applied until
1718 delayRemove is returned to \c false.
1722 \qmlattachedsignal QtQuick2::ListView::onAdd()
1723 This attached signal handler is called immediately after an item is added to the view.
1725 If an \l add transition is specified, it is applied immediately after
1726 this signal handler is called.
1730 \qmlattachedsignal QtQuick2::ListView::onRemove()
1731 This attached handler is called immediately before an item is removed from the view.
1733 If a \l remove transition has been specified, it is applied after
1734 this signal handler is called, providing that delayRemove is false.
1738 \qmlproperty model QtQuick2::ListView::model
1739 This property holds the model providing data for the list.
1741 The model provides the set of data that is used to create the items
1742 in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
1743 or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
1744 used, it must be a subclass of \l QAbstractItemModel or a simple list.
1746 \sa {qmlmodels}{Data Models}
1750 \qmlproperty Component QtQuick2::ListView::delegate
1752 The delegate provides a template defining each item instantiated by the view.
1753 The index is exposed as an accessible \c index property. Properties of the
1754 model are also available depending upon the type of \l {qmlmodels}{Data Model}.
1756 The number of elements in the delegate has a direct effect on the
1757 flicking performance of the view. If at all possible, place functionality
1758 that is not needed for the normal display of the delegate in a \l Loader which
1759 can load additional elements when needed.
1761 The ListView will lay out the items based on the size of the root item
1764 It is recommended that the delegate's size be a whole number to avoid sub-pixel
1767 \note Delegates are instantiated as needed and may be destroyed at any time.
1768 State should \e never be stored in a delegate.
1771 \qmlproperty int QtQuick2::ListView::currentIndex
1772 \qmlproperty Item QtQuick2::ListView::currentItem
1774 The \c currentIndex property holds the index of the current item, and
1775 \c currentItem holds the current item. Setting the currentIndex to -1
1776 will clear the highlight and set currentItem to null.
1778 If highlightFollowsCurrentItem is \c true, setting either of these
1779 properties will smoothly scroll the ListView so that the current
1780 item becomes visible.
1782 Note that the position of the current item
1783 may only be approximate until it becomes visible in the view.
1787 \qmlproperty Item QtQuick2::ListView::highlightItem
1789 This holds the highlight item created from the \l highlight component.
1791 The \c highlightItem is managed by the view unless
1792 \l highlightFollowsCurrentItem is set to false.
1794 \sa highlight, highlightFollowsCurrentItem
1798 \qmlproperty int QtQuick2::ListView::count
1799 This property holds the number of items in the view.
1803 \qmlproperty Component QtQuick2::ListView::highlight
1804 This property holds the component to use as the highlight.
1806 An instance of the highlight component is created for each list.
1807 The geometry of the resulting component instance is managed by the list
1808 so as to stay with the current item, unless the highlightFollowsCurrentItem
1811 \sa highlightItem, highlightFollowsCurrentItem, {declarative/modelviews/listview}{ListView examples}
1815 \qmlproperty bool QtQuick2::ListView::highlightFollowsCurrentItem
1816 This property holds whether the highlight is managed by the view.
1818 If this property is true (the default value), the highlight is moved smoothly
1819 to follow the current item. Otherwise, the
1820 highlight is not moved by the view, and any movement must be implemented
1823 Here is a highlight with its motion defined by a \l {SpringAnimation} item:
1825 \snippet doc/src/snippets/qml/listview/listview.qml highlightFollowsCurrentItem
1827 Note that the highlight animation also affects the way that the view
1828 is scrolled. This is because the view moves to maintain the
1829 highlight within the preferred highlight range (or visible viewport).
1831 \sa highlight, highlightMoveSpeed
1833 //###Possibly rename these properties, since they are very useful even without a highlight?
1835 \qmlproperty real QtQuick2::ListView::preferredHighlightBegin
1836 \qmlproperty real QtQuick2::ListView::preferredHighlightEnd
1837 \qmlproperty enumeration QtQuick2::ListView::highlightRangeMode
1839 These properties define the preferred range of the highlight (for the current item)
1840 within the view. The \c preferredHighlightBegin value must be less than the
1841 \c preferredHighlightEnd value.
1843 These properties affect the position of the current item when the list is scrolled.
1844 For example, if the currently selected item should stay in the middle of the
1845 list when the view is scrolled, set the \c preferredHighlightBegin and
1846 \c preferredHighlightEnd values to the top and bottom coordinates of where the middle
1847 item would be. If the \c currentItem is changed programmatically, the list will
1848 automatically scroll so that the current item is in the middle of the view.
1849 Furthermore, the behavior of the current item index will occur whether or not a
1852 Valid values for \c highlightRangeMode are:
1855 \li ListView.ApplyRange - the view attempts to maintain the highlight within the range.
1856 However, the highlight can move outside of the range at the ends of the list or due
1857 to mouse interaction.
1858 \li ListView.StrictlyEnforceRange - the highlight never moves outside of the range.
1859 The current item changes if a keyboard or mouse action would cause the highlight to move
1860 outside of the range.
1861 \li ListView.NoHighlightRange - this is the default value.
1864 void QQuickListView::setHighlightFollowsCurrentItem(bool autoHighlight)
1866 Q_D(QQuickListView);
1867 if (d->autoHighlight != autoHighlight) {
1868 if (!autoHighlight) {
1869 if (d->highlightPosAnimator)
1870 d->highlightPosAnimator->stop();
1871 if (d->highlightSizeAnimator)
1872 d->highlightSizeAnimator->stop();
1874 QQuickItemView::setHighlightFollowsCurrentItem(autoHighlight);
1879 \qmlproperty real QtQuick2::ListView::spacing
1881 This property holds the spacing between items.
1883 The default value is 0.
1885 qreal QQuickListView::spacing() const
1887 Q_D(const QQuickListView);
1891 void QQuickListView::setSpacing(qreal spacing)
1893 Q_D(QQuickListView);
1894 if (spacing != d->spacing) {
1895 d->spacing = spacing;
1896 d->forceLayout = true;
1898 emit spacingChanged();
1903 \qmlproperty enumeration QtQuick2::ListView::orientation
1904 This property holds the orientation of the list.
1909 \li ListView.Horizontal - Items are laid out horizontally
1910 \li ListView.Vertical (default) - Items are laid out vertically
1915 \li Horizontal orientation:
1916 \image ListViewHorizontal.png
1919 \li Vertical orientation:
1920 \image listview-highlight.png
1923 QQuickListView::Orientation QQuickListView::orientation() const
1925 Q_D(const QQuickListView);
1929 void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
1931 Q_D(QQuickListView);
1932 if (d->orient != orientation) {
1933 d->orient = orientation;
1934 if (d->orient == Vertical) {
1935 setContentWidth(-1);
1936 setFlickableDirection(VerticalFlick);
1939 setContentHeight(-1);
1940 setFlickableDirection(HorizontalFlick);
1944 emit orientationChanged();
1949 \qmlproperty enumeration QtQuick2::ListView::layoutDirection
1950 This property holds the layout direction of the horizontal list.
1955 \li Qt.LeftToRight (default) - Items will be laid out from left to right.
1956 \li Qt.RightToLeft - Items will be laid out from right to let.
1959 \sa ListView::effectiveLayoutDirection
1964 \qmlproperty enumeration QtQuick2::ListView::effectiveLayoutDirection
1965 This property holds the effective layout direction of the horizontal list.
1967 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1968 the visual layout direction of the horizontal list will be mirrored. However, the
1969 property \l {ListView::layoutDirection}{layoutDirection} will remain unchanged.
1971 \sa ListView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1975 \qmlproperty bool QtQuick2::ListView::keyNavigationWraps
1976 This property holds whether the list wraps key navigation.
1978 If this is true, key navigation that would move the current item selection
1979 past the end of the list instead wraps around and moves the selection to
1980 the start of the list, and vice-versa.
1982 By default, key navigation is not wrapped.
1987 \qmlproperty int QtQuick2::ListView::cacheBuffer
1988 This property determines whether delegates are retained outside the
1989 visible area of the view.
1991 If this value is non-zero, the view may keep as many delegates
1992 instantiated as it can fit within the buffer specified. For example,
1993 if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
1994 set to 40, then up to 2 delegates above and 2 delegates below the visible
1995 area may be created/retained. The buffered delegates are created asynchronously,
1996 allowing creation to occur across multiple frames and reducing the
1997 likelihood of skipping frames. In order to improve painting performance
1998 delegates outside the visible area have their \l visible property set to
1999 false until they are moved into the visible area.
2001 Note that cacheBuffer is not a pixel buffer - it only maintains additional
2002 instantiated delegates.
2004 Setting this value can improve the smoothness of scrolling behavior at the expense
2005 of additional memory usage. It is not a substitute for creating efficient
2006 delegates; the fewer elements in a delegate, the faster a view can be
2012 \qmlproperty string QtQuick2::ListView::section.property
2013 \qmlproperty enumeration QtQuick2::ListView::section.criteria
2014 \qmlproperty Component QtQuick2::ListView::section.delegate
2015 \qmlproperty enumeration QtQuick2::ListView::section.labelPositioning
2017 These properties determine the expression to be evaluated and appearance
2018 of the section labels.
2020 \c section.property holds the name of the property that is the basis
2023 \c section.criteria holds the criteria for forming each section based on
2024 \c section.property. This value can be one of:
2027 \li ViewSection.FullString (default) - sections are created based on the
2028 \c section.property value.
2029 \li ViewSection.FirstCharacter - sections are created based on the first
2030 character of the \c section.property value (for example, 'A', 'B', 'C'
2031 sections, etc. for an address book)
2034 \c section.delegate holds the delegate component for each section.
2036 \c section.labelPositioning determines whether the current and/or
2037 next section labels stick to the start/end of the view, and whether
2038 the labels are shown inline. This value can be a combination of:
2041 \li ViewSection.InlineLabels - section labels are shown inline between
2042 the item delegates separating sections (default).
2043 \li ViewSection.CurrentLabelAtStart - the current section label sticks to the
2044 start of the view as it is moved.
2045 \li ViewSection.NextLabelAtEnd - the next section label (beyond all visible
2046 sections) sticks to the end of the view as it is moved. \note Enabling
2047 \c ViewSection.NextLabelAtEnd requires the view to scan ahead for the next
2048 section, which has performance implications, especially for slower models.
2051 Each item in the list has attached properties named \c ListView.section,
2052 \c ListView.previousSection and \c ListView.nextSection.
2054 For example, here is a ListView that displays a list of animals, separated
2055 into sections. Each item in the ListView is placed in a different section
2056 depending on the "size" property of the model item. The \c sectionHeading
2057 delegate component provides the light blue bar that marks the beginning of
2061 \snippet examples/declarative/modelviews/listview/sections.qml 0
2063 \image qml-listview-sections-example.png
2065 \note Adding sections to a ListView does not automatically re-order the
2066 list items by the section criteria.
2067 If the model is not ordered by section, then it is possible that
2068 the sections created will not be unique; each boundary between
2069 differing sections will result in a section header being created
2070 even if that section exists elsewhere.
2072 \sa {declarative/modelviews/listview}{ListView examples}
2074 QQuickViewSection *QQuickListView::sectionCriteria()
2076 Q_D(QQuickListView);
2077 if (!d->sectionCriteria) {
2078 d->sectionCriteria = new QQuickViewSection(this);
2079 connect(d->sectionCriteria, SIGNAL(propertyChanged()), this, SLOT(updateSections()));
2081 return d->sectionCriteria;
2085 \qmlproperty string QtQuick2::ListView::currentSection
2086 This property holds the section that is currently at the beginning of the view.
2088 QString QQuickListView::currentSection() const
2090 Q_D(const QQuickListView);
2091 return d->currentSection;
2095 \qmlproperty real QtQuick2::ListView::highlightMoveSpeed
2096 \qmlproperty int QtQuick2::ListView::highlightMoveDuration
2097 \qmlproperty real QtQuick2::ListView::highlightResizeSpeed
2098 \qmlproperty int QtQuick2::ListView::highlightResizeDuration
2100 These properties hold the move and resize animation speed of the highlight delegate.
2102 \l highlightFollowsCurrentItem must be true for these properties
2105 The default value for the speed properties is 400 pixels/second.
2106 The default value for the duration properties is -1, i.e. the
2107 highlight will take as much time as necessary to move at the set speed.
2109 These properties have the same characteristics as a SmoothedAnimation.
2111 \sa highlightFollowsCurrentItem
2113 qreal QQuickListView::highlightMoveSpeed() const
2115 Q_D(const QQuickListView);
2116 return d->highlightMoveSpeed;
2119 void QQuickListView::setHighlightMoveSpeed(qreal speed)
2121 Q_D(QQuickListView);
2122 if (d->highlightMoveSpeed != speed) {
2123 d->highlightMoveSpeed = speed;
2124 if (d->highlightPosAnimator)
2125 d->highlightPosAnimator->velocity = d->highlightMoveSpeed;
2126 emit highlightMoveSpeedChanged();
2130 void QQuickListView::setHighlightMoveDuration(int duration)
2132 Q_D(QQuickListView);
2133 if (d->highlightMoveDuration != duration) {
2134 if (d->highlightPosAnimator)
2135 d->highlightPosAnimator->userDuration = duration;
2136 QQuickItemView::setHighlightMoveDuration(duration);
2140 qreal QQuickListView::highlightResizeSpeed() const
2142 Q_D(const QQuickListView);
2143 return d->highlightResizeSpeed;
2146 void QQuickListView::setHighlightResizeSpeed(qreal speed)
2148 Q_D(QQuickListView);
2149 if (d->highlightResizeSpeed != speed) {
2150 d->highlightResizeSpeed = speed;
2151 if (d->highlightSizeAnimator)
2152 d->highlightSizeAnimator->velocity = d->highlightResizeSpeed;
2153 emit highlightResizeSpeedChanged();
2157 int QQuickListView::highlightResizeDuration() const
2159 Q_D(const QQuickListView);
2160 return d->highlightResizeDuration;
2163 void QQuickListView::setHighlightResizeDuration(int duration)
2165 Q_D(QQuickListView);
2166 if (d->highlightResizeDuration != duration) {
2167 d->highlightResizeDuration = duration;
2168 if (d->highlightSizeAnimator)
2169 d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
2170 emit highlightResizeDurationChanged();
2175 \qmlproperty enumeration QtQuick2::ListView::snapMode
2177 This property determines how the view scrolling will settle following a drag or flick.
2178 The possible values are:
2181 \li ListView.NoSnap (default) - the view stops anywhere within the visible area.
2182 \li ListView.SnapToItem - the view settles with an item aligned with the start of
2184 \li ListView.SnapOneItem - the view settles no more than one item away from the first
2185 visible item at the time the mouse button is released. This mode is particularly
2186 useful for moving one page at a time.
2189 \c snapMode does not affect the \l currentIndex. To update the
2190 \l currentIndex as the list is moved, set \l highlightRangeMode
2191 to \c ListView.StrictlyEnforceRange.
2193 \sa highlightRangeMode
2195 QQuickListView::SnapMode QQuickListView::snapMode() const
2197 Q_D(const QQuickListView);
2201 void QQuickListView::setSnapMode(SnapMode mode)
2203 Q_D(QQuickListView);
2204 if (d->snapMode != mode) {
2206 emit snapModeChanged();
2212 \qmlproperty Component QtQuick2::ListView::footer
2213 This property holds the component to use as the footer.
2215 An instance of the footer component is created for each view. The
2216 footer is positioned at the end of the view, after any items.
2218 \sa header, footerItem
2223 \qmlproperty Component QtQuick2::ListView::header
2224 This property holds the component to use as the header.
2226 An instance of the header component is created for each view. The
2227 header is positioned at the beginning of the view, before any items.
2229 \sa footer, headertem
2233 \qmlproperty Item QtQuick2::ListView::headerItem
2234 This holds the header item created from the \l header component.
2236 An instance of the header component is created for each view. The
2237 header is positioned at the beginning of the view, before any items.
2239 \sa header, footerItem
2243 \qmlproperty Item QtQuick2::ListView::footerItem
2244 This holds the footer item created from the \l footer component.
2246 An instance of the footer component is created for each view. The
2247 footer is positioned at the end of the view, after any items.
2249 \sa footer, headerItem
2253 \qmlproperty Transition QtQuick2::ListView::populate
2255 This property holds the transition to apply to the items that are initially created
2258 It is applied to all items that are created when:
2261 \li The view is first created
2262 \li The view's \l model changes
2263 \li The view's \l model is \l {QAbstractItemModel::reset}{reset}, if the model is a QAbstractItemModel subclass
2266 For example, here is a view that specifies such a transition:
2271 populate: Transition {
2272 NumberAnimation { properties: "x,y"; duration: 1000 }
2277 When the view is initialized, the view will create all the necessary items for the view,
2278 then animate them to their correct positions within the view over one second.
2280 For more details and examples on how to use view transitions, see the ViewTransition
2283 \sa add, ViewTransition
2287 \qmlproperty Transition QtQuick2::ListView::add
2289 This property holds the transition to apply to items that are added to the view.
2291 For example, here is a view that specifies such a transition:
2297 NumberAnimation { properties: "x,y"; from: 100; duration: 1000 }
2302 Whenever an item is added to the above view, the item will be animated from the position (100,100)
2303 to its final x,y position within the view, over one second. The transition only applies to
2304 the new items that are added to the view; it does not apply to the items below that are
2305 displaced by the addition of the new items. To animate the displaced items, set the \l displaced
2306 or \l addDisplaced properties.
2308 For more details and examples on how to use view transitions, see the ViewTransition
2311 \note This transition is not applied to the items that are created when the view is initially
2312 populated, or when the view's \l model changes. In those cases, the \l populate transition is
2315 \sa addDisplaced, populate, ViewTransition
2319 \qmlproperty Transition QtQuick2::ListView::addDisplaced
2321 This property holds the transition to apply to items within the view that are displaced by
2322 the addition of other items to the view.
2324 For example, here is a view that specifies such a transition:
2329 addDisplaced: Transition {
2330 NumberAnimation { properties: "x,y"; duration: 1000 }
2335 Whenever an item is added to the above view, all items beneath the new item are displaced, causing
2336 them to move down (or sideways, if horizontally orientated) within the view. As this
2337 displacement occurs, the items' movement to their new x,y positions within the view will be
2338 animated by a NumberAnimation over one second, as specified. This transition is not applied to
2339 the new item that has been added to the view; to animate the added items, set the \l add
2342 If an item is displaced by multiple types of operations at the same time, it is not defined as to
2343 whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2344 if it is not necessary to specify different transitions depending on whether an item is displaced
2345 by an add, move or remove operation, consider setting the \l displaced property instead.
2347 For more details and examples on how to use view transitions, see the ViewTransition
2350 \note This transition is not applied to the items that are created when the view is initially
2351 populated, or when the view's \l model changes. In those cases, the \l populate transition is
2354 \sa displaced, add, populate, ViewTransition
2358 \qmlproperty Transition QtQuick2::ListView::move
2360 This property holds the transition to apply to items in the view that are being moved due
2361 to a move operation in the view's \l model.
2363 For example, here is a view that specifies such a transition:
2369 NumberAnimation { properties: "x,y"; duration: 1000 }
2374 Whenever the \l model performs a move operation to move a particular set of indexes, the
2375 respective items in the view will be animated to their new positions in the view over one
2376 second. The transition only applies to the items that are the subject of the move operation
2377 in the model; it does not apply to items below them that are displaced by the move operation.
2378 To animate the displaced items, set the \l displaced or \l moveDisplaced properties.
2380 For more details and examples on how to use view transitions, see the ViewTransition
2383 \sa moveDisplaced, ViewTransition
2387 \qmlproperty Transition QtQuick2::ListView::moveDisplaced
2389 This property holds the transition to apply to items that are displaced by a move operation in
2390 the view's \l model.
2392 For example, here is a view that specifies such a transition:
2397 moveDisplaced: Transition {
2398 NumberAnimation { properties: "x,y"; duration: 1000 }
2403 Whenever the \l model performs a move operation to move a particular set of indexes, the items
2404 between the source and destination indexes of the move operation are displaced, causing them
2405 to move upwards or downwards (or sideways, if horizontally orientated) within the view. As this
2406 displacement occurs, the items' movement to their new x,y positions within the view will be
2407 animated by a NumberAnimation over one second, as specified. This transition is not applied to
2408 the items that are the actual subjects of the move operation; to animate the moved items, set
2409 the \l move property.
2411 If an item is displaced by multiple types of operations at the same time, it is not defined as to
2412 whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2413 if it is not necessary to specify different transitions depending on whether an item is displaced
2414 by an add, move or remove operation, consider setting the \l displaced property instead.
2416 For more details and examples on how to use view transitions, see the ViewTransition
2419 \sa displaced, move, ViewTransition
2423 \qmlproperty Transition QtQuick2::ListView::remove
2425 This property holds the transition to apply to items that are removed from the view.
2427 For example, here is a view that specifies such a transition:
2432 remove: Transition {
2434 NumberAnimation { property: "opacity"; to: 0; duration: 1000 }
2435 NumberAnimation { properties: "x,y"; to: 100; duration: 1000 }
2441 Whenever an item is removed from the above view, the item will be animated to the position (100,100)
2442 over one second, and in parallel will also change its opacity to 0. The transition
2443 only applies to the items that are removed from the view; it does not apply to the items below
2444 them that are displaced by the removal of the items. To animate the displaced items, set the
2445 \l displaced or \l removeDisplaced properties.
2447 Note that by the time the transition is applied, the item has already been removed from the
2448 model; any references to the model data for the removed index will not be valid.
2450 Additionally, if the \l delayRemove attached property has been set for a delegate item, the
2451 remove transition will not be applied until \l delayRemove becomes false again.
2453 For more details and examples on how to use view transitions, see the ViewTransition
2456 \sa removeDisplaced, ViewTransition
2460 \qmlproperty Transition QtQuick2::ListView::removeDisplaced
2462 This property holds the transition to apply to items in the view that are displaced by the
2463 removal of other items in the view.
2465 For example, here is a view that specifies such a transition:
2470 removeDisplaced: Transition {
2471 NumberAnimation { properties: "x,y"; duration: 1000 }
2476 Whenever an item is removed from the above view, all items beneath it are displaced, causing
2477 them to move upwards (or sideways, if horizontally orientated) within the view. As this
2478 displacement occurs, the items' movement to their new x,y positions within the view will be
2479 animated by a NumberAnimation over one second, as specified. This transition is not applied to
2480 the item that has actually been removed from the view; to animate the removed items, set the
2483 If an item is displaced by multiple types of operations at the same time, it is not defined as to
2484 whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2485 if it is not necessary to specify different transitions depending on whether an item is displaced
2486 by an add, move or remove operation, consider setting the \l displaced property instead.
2488 For more details and examples on how to use view transitions, see the ViewTransition
2491 \sa displaced, remove, ViewTransition
2495 \qmlproperty Transition QtQuick2::ListView::displaced
2496 This property holds the generic transition to apply to items that have been displaced by
2497 any model operation that affects the view.
2499 This is a convenience for specifying the generic transition to be applied to any items
2500 that are displaced by an add, move or remove operation, without having to specify the
2501 individual addDisplaced, moveDisplaced and removeDisplaced properties. For example, here
2502 is a view that specifies a displaced transition:
2507 displaced: Transition {
2508 NumberAnimation { properties: "x,y"; duration: 1000 }
2513 When any item is added, moved or removed within the above view, the items below it are
2514 displaced, causing them to move down (or sideways, if horizontally orientated) within the
2515 view. As this displacement occurs, the items' movement to their new x,y positions within
2516 the view will be animated by a NumberAnimation over one second, as specified.
2518 If a view specifies this generic displaced transition as well as a specific addDisplaced,
2519 moveDisplaced or removeDisplaced transition, the more specific transition will be used
2520 instead of the generic displaced transition when the relevant operation occurs, providing that
2521 the more specific transition has not been disabled (by setting \l {Transition::enabled}{enabled}
2522 to false). If it has indeed been disabled, the generic displaced transition is applied instead.
2524 For more details and examples on how to use view transitions, see the ViewTransition
2527 \sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition
2530 void QQuickListView::viewportMoved()
2532 Q_D(QQuickListView);
2533 QQuickItemView::viewportMoved();
2536 // Recursion can occur due to refill changing the content size.
2537 if (d->inViewportMoved)
2539 d->inViewportMoved = true;
2542 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
2543 else if (d->isRightToLeft())
2544 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
2546 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
2550 // Set visibility of items to eliminate cost of items outside the visible area.
2551 qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
2552 qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
2553 for (int i = 0; i < d->visibleItems.count(); ++i) {
2554 FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i));
2555 item->item->setVisible(item->endPosition() >= from && item->position() <= to);
2558 d->currentItem->item->setVisible(d->currentItem->endPosition() >= from && d->currentItem->position() <= to);
2560 if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2561 d->moveReason = QQuickListViewPrivate::Mouse;
2562 if (d->moveReason != QQuickListViewPrivate::SetIndex) {
2563 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2564 // reposition highlight
2565 qreal pos = d->highlight->position();
2566 qreal viewPos = d->isRightToLeft() ? -d->position()-d->size() : d->position();
2567 if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
2568 pos = viewPos + d->highlightRangeEnd - d->highlight->size();
2569 if (pos < viewPos + d->highlightRangeStart)
2570 pos = viewPos + d->highlightRangeStart;
2571 if (pos != d->highlight->position()) {
2572 d->highlightPosAnimator->stop();
2573 static_cast<FxListItemSG*>(d->highlight)->setPosition(pos);
2575 d->updateHighlight();
2578 // update current index
2579 if (FxViewItem *snapItem = d->snapItemAt(d->highlight->position())) {
2580 if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
2581 d->updateCurrent(snapItem->index);
2586 if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
2587 d->inFlickCorrection = true;
2588 // Near an end and it seems that the extent has changed?
2589 // Recalculate the flick so that we don't end up in an odd position.
2590 if (yflick() && !d->vData.inOvershoot) {
2591 if (d->vData.velocity > 0) {
2592 const qreal minY = minYExtent();
2593 if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
2594 && minY != d->vData.flickTarget)
2595 d->flickY(-d->vData.smoothVelocity.value());
2596 } else if (d->vData.velocity < 0) {
2597 const qreal maxY = maxYExtent();
2598 if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
2599 && maxY != d->vData.flickTarget)
2600 d->flickY(-d->vData.smoothVelocity.value());
2604 if (xflick() && !d->hData.inOvershoot) {
2605 if (d->hData.velocity > 0) {
2606 const qreal minX = minXExtent();
2607 if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
2608 && minX != d->hData.flickTarget)
2609 d->flickX(-d->hData.smoothVelocity.value());
2610 } else if (d->hData.velocity < 0) {
2611 const qreal maxX = maxXExtent();
2612 if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
2613 && maxX != d->hData.flickTarget)
2614 d->flickX(-d->hData.smoothVelocity.value());
2617 d->inFlickCorrection = false;
2619 if (d->sectionCriteria) {
2620 d->updateCurrentSection();
2621 d->updateStickySections();
2623 d->inViewportMoved = false;
2626 void QQuickListView::keyPressEvent(QKeyEvent *event)
2628 Q_D(QQuickListView);
2629 if (d->model && d->model->count() && d->interactive) {
2630 if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left)
2631 || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right)
2632 || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Up)) {
2633 if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) {
2634 decrementCurrentIndex();
2637 } else if (d->wrap) {
2641 } else if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right)
2642 || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left)
2643 || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Down)) {
2644 if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) {
2645 incrementCurrentIndex();
2648 } else if (d->wrap) {
2655 QQuickItemView::keyPressEvent(event);
2658 void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
2660 Q_D(QQuickListView);
2661 if (d->isRightToLeft() && d->orient == QQuickListView::Horizontal) {
2662 // maintain position relative to the right edge
2663 int dx = newGeometry.width() - oldGeometry.width();
2664 setContentX(contentX() - dx);
2666 QQuickItemView::geometryChanged(newGeometry, oldGeometry);
2671 \qmlmethod QtQuick2::ListView::incrementCurrentIndex()
2673 Increments the current index. The current index will wrap
2674 if keyNavigationWraps is true and it is currently at the end.
2675 This method has no effect if the \l count is zero.
2677 \b Note: methods should only be called after the Component has completed.
2679 void QQuickListView::incrementCurrentIndex()
2681 Q_D(QQuickListView);
2682 int count = d->model ? d->model->count() : 0;
2683 if (count && (currentIndex() < count - 1 || d->wrap)) {
2684 d->moveReason = QQuickListViewPrivate::SetIndex;
2685 int index = currentIndex()+1;
2686 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2691 \qmlmethod QtQuick2::ListView::decrementCurrentIndex()
2693 Decrements the current index. The current index will wrap
2694 if keyNavigationWraps is true and it is currently at the beginning.
2695 This method has no effect if the \l count is zero.
2697 \b Note: methods should only be called after the Component has completed.
2699 void QQuickListView::decrementCurrentIndex()
2701 Q_D(QQuickListView);
2702 int count = d->model ? d->model->count() : 0;
2703 if (count && (currentIndex() > 0 || d->wrap)) {
2704 d->moveReason = QQuickListViewPrivate::SetIndex;
2705 int index = currentIndex()-1;
2706 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2710 void QQuickListView::updateSections()
2712 Q_D(QQuickListView);
2713 if (isComponentComplete() && d->model) {
2714 QList<QByteArray> roles;
2715 if (d->sectionCriteria && !d->sectionCriteria->property().isEmpty())
2716 roles << d->sectionCriteria->property().toUtf8();
2717 d->model->setWatchedRoles(roles);
2718 d->updateSections();
2720 d->forceLayout = true;
2726 bool QQuickListViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
2728 int modelIndex = change.index;
2729 int count = change.count;
2731 qreal tempPos = isRightToLeft() ? -position()-size() : position();
2732 int index = visibleItems.count() ? mapFromModel(modelIndex) : 0;
2735 int i = visibleItems.count() - 1;
2736 while (i > 0 && visibleItems.at(i)->index == -1)
2738 if (i == 0 && visibleItems.first()->index == -1) {
2739 // there are no visible items except items marked for removal
2740 index = visibleItems.count();
2741 } else if (visibleItems.at(i)->index + 1 == modelIndex
2742 && visibleItems.at(i)->endPosition() <= buffer+tempPos+size()) {
2743 // Special case of appending an item to the model.
2744 index = visibleItems.count();
2746 if (modelIndex < visibleIndex) {
2747 // Insert before visible items
2748 visibleIndex += count;
2749 for (int i = 0; i < visibleItems.count(); ++i) {
2750 FxViewItem *item = visibleItems.at(i);
2751 if (item->index != -1 && item->index >= modelIndex)
2752 item->index += count;
2759 // index can be the next item past the end of the visible items list (i.e. appended)
2761 if (visibleItems.count()) {
2762 pos = index < visibleItems.count() ? visibleItems.at(index)->position()
2763 : visibleItems.last()->endPosition()+spacing;
2766 int prevVisibleCount = visibleItems.count();
2767 if (insertResult->visiblePos.isValid() && pos < insertResult->visiblePos) {
2768 // Insert items before the visible item.
2769 int insertionIdx = index;
2771 int from = tempPos - buffer;
2773 for (i = count-1; i >= 0; --i) {
2774 if (pos > from && insertionIdx < visibleIndex) {
2775 // item won't be visible, just note the size for repositioning
2776 insertResult->sizeChangesBeforeVisiblePos += averageSize + spacing;
2777 pos -= averageSize + spacing;
2779 // item is before first visible e.g. in cache buffer
2780 FxViewItem *item = 0;
2781 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2782 item->index = modelIndex + i;
2784 item = createItem(modelIndex + i);
2788 visibleItems.insert(insertionIdx, item);
2789 if (insertionIdx == 0)
2790 insertResult->changedFirstItem = true;
2791 if (!change.isMove()) {
2792 addedItems->append(item);
2793 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2795 insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing;
2796 pos -= item->size() + spacing;
2802 int to = buffer+tempPos+size();
2803 for (i = 0; i < count && pos <= to; ++i) {
2804 FxViewItem *item = 0;
2805 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2806 item->index = modelIndex + i;
2807 bool newItem = !item;
2809 item = createItem(modelIndex + i);
2813 visibleItems.insert(index, item);
2815 insertResult->changedFirstItem = true;
2816 if (change.isMove()) {
2817 // we know this is a move target, since move displaced items that are
2818 // shuffled into view due to a move would be added in refill()
2819 if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true))
2820 movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
2822 addedItems->append(item);
2823 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2825 insertResult->sizeChangesAfterVisiblePos += item->size() + spacing;
2826 pos += item->size() + spacing;
2831 for (; index < visibleItems.count(); ++index) {
2832 FxViewItem *item = visibleItems.at(index);
2833 if (item->index != -1) {
2834 item->index += count;
2835 if (change.isMove())
2836 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false);
2838 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, false);
2842 updateVisibleIndex();
2844 return visibleItems.count() > prevVisibleCount;
2847 void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult)
2849 Q_UNUSED(insertionResult);
2854 int markerItemIndex = -1;
2855 for (int i=0; i<visibleItems.count(); i++) {
2856 if (visibleItems[i]->index == afterModelIndex) {
2857 markerItemIndex = i;
2861 if (markerItemIndex < 0)
2864 const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
2865 qreal sizeRemoved = -removalResult.sizeChangesAfterVisiblePos
2866 - (removalResult.countChangeAfterVisibleItems * (averageSize + spacing));
2868 for (int i=markerItemIndex+1; i<visibleItems.count() && visibleItems.at(i)->position() < viewEndPos; i++) {
2869 FxListItemSG *listItem = static_cast<FxListItemSG *>(visibleItems[i]);
2870 if (!listItem->transitionScheduledOrRunning()) {
2871 qreal pos = listItem->position();
2872 listItem->setPosition(pos - sizeRemoved);
2873 listItem->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
2874 listItem->setPosition(pos);
2880 \qmlmethod QtQuick2::ListView::positionViewAtIndex(int index, PositionMode mode)
2882 Positions the view such that the \a index is at the position specified by
2886 \li ListView.Beginning - position item at the top (or left for horizontal orientation) of the view.
2887 \li ListView.Center - position item in the center of the view.
2888 \li ListView.End - position item at bottom (or right for horizontal orientation) of the view.
2889 \li ListView.Visible - if any part of the item is visible then take no action, otherwise
2890 bring the item into view.
2891 \li ListView.Contain - ensure the entire item is visible. If the item is larger than
2892 the view the item is positioned at the top (or left for horizontal orientation) of the view.
2895 If positioning the view at \a index would cause empty space to be displayed at
2896 the beginning or end of the view, the view will be positioned at the boundary.
2898 It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2899 at a particular index. This is unreliable since removing items from the start
2900 of the list does not cause all other items to be repositioned, and because
2901 the actual start of the view can vary based on the size of the delegates.
2902 The correct way to bring an item into view is with \c positionViewAtIndex.
2904 \b Note: methods should only be called after the Component has completed. To position
2905 the view at startup, this method should be called by Component.onCompleted. For
2906 example, to position the view at the end:
2909 Component.onCompleted: positionViewAtIndex(count - 1, ListView.Beginning)
2914 \qmlmethod QtQuick2::ListView::positionViewAtBeginning()
2915 \qmlmethod QtQuick2::ListView::positionViewAtEnd()
2917 Positions the view at the beginning or end, taking into account any header or footer.
2919 It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2920 at a particular index. This is unreliable since removing items from the start
2921 of the list does not cause all other items to be repositioned, and because
2922 the actual start of the view can vary based on the size of the delegates.
2924 \b Note: methods should only be called after the Component has completed. To position
2925 the view at startup, this method should be called by Component.onCompleted. For
2926 example, to position the view at the end on startup:
2929 Component.onCompleted: positionViewAtEnd()
2934 \qmlmethod int QtQuick2::ListView::indexAt(int x, int y)
2936 Returns the index of the visible item containing the point \a x, \a y in content
2937 coordinates. If there is no item at the point specified, or the item is
2938 not visible -1 is returned.
2940 If the item is outside the visible area, -1 is returned, regardless of
2941 whether an item will exist at that point when scrolled into view.
2943 \b Note: methods should only be called after the Component has completed.
2947 \qmlmethod Item QtQuick2::ListView::itemAt(int x, int y)
2949 Returns the visible item containing the point \a x, \a y in content
2950 coordinates. If there is no item at the point specified, or the item is
2951 not visible null is returned.
2953 If the item is outside the visible area, null is returned, regardless of
2954 whether an item will exist at that point when scrolled into view.
2956 \b Note: methods should only be called after the Component has completed.
2959 QQuickListViewAttached *QQuickListView::qmlAttachedProperties(QObject *obj)
2961 return new QQuickListViewAttached(obj);