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, bool trackGeometry) : FxViewItem(i, own, trackGeometry), view(v) {
240 attached = static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(item));
242 static_cast<QQuickListViewAttached*>(attached)->setView(view);
244 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
245 itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
251 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
252 itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
256 inline QQuickItem *section() const {
257 return attached ? static_cast<QQuickListViewAttached*>(attached)->m_sectionItem : 0;
259 void setSection(QQuickItem *s) {
261 attached = static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(item));
262 static_cast<QQuickListViewAttached*>(attached)->m_sectionItem = s;
265 qreal position() const {
267 if (view->orientation() == QQuickListView::Vertical)
268 return section()->y();
270 return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section()->width()-section()->x() : section()->x());
272 return itemPosition();
275 qreal itemPosition() const {
276 if (view->orientation() == QQuickListView::Vertical)
279 return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX());
283 return (view->orientation() == QQuickListView::Vertical ? item->height()+section()->height() : item->width()+section()->width());
285 return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
287 qreal itemSize() const {
288 return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
290 qreal sectionSize() const {
292 return (view->orientation() == QQuickListView::Vertical ? section()->height() : section()->width());
295 qreal endPosition() const {
296 if (view->orientation() == QQuickListView::Vertical) {
297 return itemY() + item->height();
299 return (view->effectiveLayoutDirection() == Qt::RightToLeft
301 : itemX() + item->width());
304 void setPosition(qreal pos, bool immediate = false) {
305 // position the section immediately even if there is a transition
307 if (view->orientation() == QQuickListView::Vertical) {
308 section()->setY(pos);
310 if (view->effectiveLayoutDirection() == Qt::RightToLeft)
311 section()->setX(-section()->width()-pos);
313 section()->setX(pos);
316 moveTo(pointForPosition(pos), immediate);
318 void setSize(qreal size) {
319 if (view->orientation() == QQuickListView::Vertical)
320 item->setHeight(size);
322 item->setWidth(size);
324 bool contains(qreal x, qreal y) const {
325 return (x >= itemX() && x < itemX() + item->width() &&
326 y >= itemY() && y < itemY() + item->height());
329 QQuickListView *view;
332 QPointF pointForPosition(qreal pos) const {
333 if (view->orientation() == QQuickListView::Vertical) {
335 pos += section()->height();
336 return QPointF(itemX(), pos);
338 if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
340 pos += section()->width();
341 return QPointF(-item->width() - pos, itemY());
344 pos += section()->width();
345 return QPointF(pos, itemY());
351 //----------------------------------------------------------------------------
353 bool QQuickListViewPrivate::isContentFlowReversed() const
355 return isRightToLeft();
358 Qt::Orientation QQuickListViewPrivate::layoutOrientation() const
360 return static_cast<Qt::Orientation>(orient);
363 bool QQuickListViewPrivate::isRightToLeft() const
365 Q_Q(const QQuickListView);
366 return orient == QQuickListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
369 // Returns the item before modelIndex, if created.
370 // May return an item marked for removal.
371 FxViewItem *QQuickListViewPrivate::itemBefore(int modelIndex) const
373 if (modelIndex < visibleIndex)
377 while (idx < visibleItems.count()) {
378 FxViewItem *item = visibleItems.at(idx);
379 if (item->index != -1)
380 lastIndex = item->index;
381 if (item->index == modelIndex)
382 return visibleItems.at(idx-1);
385 if (lastIndex == modelIndex-1)
386 return visibleItems.last();
390 void QQuickListViewPrivate::setPosition(qreal pos)
393 if (orient == QQuickListView::Vertical) {
394 q->QQuickFlickable::setContentY(pos);
397 q->QQuickFlickable::setContentX(-pos-size());
399 q->QQuickFlickable::setContentX(pos);
403 qreal QQuickListViewPrivate::originPosition() const
406 if (!visibleItems.isEmpty()) {
407 pos = (*visibleItems.constBegin())->position();
408 if (visibleIndex > 0)
409 pos -= visibleIndex * (averageSize + spacing);
414 qreal QQuickListViewPrivate::lastPosition() const
417 if (!visibleItems.isEmpty()) {
418 int invisibleCount = visibleItems.count() - visibleIndex;
419 for (int i = visibleItems.count()-1; i >= 0; --i) {
420 if (visibleItems.at(i)->index != -1) {
421 invisibleCount = model->count() - visibleItems.at(i)->index - 1;
425 pos = (*(--visibleItems.constEnd()))->endPosition() + invisibleCount * (averageSize + spacing);
426 } else if (model && model->count()) {
427 pos = (model->count() * averageSize + (model->count()-1) * spacing);
432 qreal QQuickListViewPrivate::positionAt(int modelIndex) const
434 if (FxViewItem *item = visibleItem(modelIndex)) {
435 return item->position();
437 if (!visibleItems.isEmpty()) {
438 if (modelIndex < visibleIndex) {
439 int count = visibleIndex - modelIndex;
441 if (modelIndex == currentIndex && currentItem) {
442 cs = currentItem->size() + spacing;
445 return (*visibleItems.constBegin())->position() - count * (averageSize + spacing) - cs;
447 int count = modelIndex - findLastVisibleIndex(visibleIndex) - 1;
448 return (*(--visibleItems.constEnd()))->endPosition() + spacing + count * (averageSize + spacing);
454 qreal QQuickListViewPrivate::endPositionAt(int modelIndex) const
456 if (FxViewItem *item = visibleItem(modelIndex))
457 return item->endPosition();
458 if (!visibleItems.isEmpty()) {
459 if (modelIndex < visibleIndex) {
460 int count = visibleIndex - modelIndex;
461 return (*visibleItems.constBegin())->position() - (count - 1) * (averageSize + spacing) - spacing;
463 int count = modelIndex - findLastVisibleIndex(visibleIndex) - 1;
464 return (*(--visibleItems.constEnd()))->endPosition() + count * (averageSize + spacing);
470 QString QQuickListViewPrivate::sectionAt(int modelIndex)
472 if (FxViewItem *item = visibleItem(modelIndex))
473 return item->attached->section();
476 if (sectionCriteria) {
477 QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
478 section = sectionCriteria->sectionString(propValue);
484 qreal QQuickListViewPrivate::snapPosAt(qreal pos)
486 if (FxViewItem *snapItem = snapItemAt(pos))
487 return snapItem->position();
488 if (visibleItems.count()) {
489 qreal firstPos = (*visibleItems.constBegin())->position();
490 qreal endPos = (*(--visibleItems.constEnd()))->position();
491 if (pos < firstPos) {
492 return firstPos - qRound((firstPos - pos) / averageSize) * averageSize;
493 } else if (pos > endPos)
494 return endPos + qRound((pos - endPos) / averageSize) * averageSize;
496 return qRound((pos - originPosition()) / averageSize) * averageSize + originPosition();
499 FxViewItem *QQuickListViewPrivate::snapItemAt(qreal pos)
501 FxViewItem *snapItem = 0;
502 qreal prevItemSize = 0;
503 for (int i = 0; i < visibleItems.count(); ++i) {
504 FxViewItem *item = visibleItems.at(i);
505 if (item->index == -1)
507 qreal itemTop = item->position();
508 if (highlight && itemTop >= pos && item->endPosition() <= pos + highlight->size())
510 if (itemTop+item->size()/2 >= pos && itemTop-prevItemSize/2 < pos)
512 prevItemSize = item->size();
517 void QQuickListViewPrivate::changedVisibleIndex(int newIndex)
519 visiblePos = positionAt(newIndex);
520 visibleIndex = newIndex;
523 void QQuickListViewPrivate::init()
525 QQuickItemViewPrivate::init();
526 ::memset(sectionCache, 0, sizeof(QQuickItem*) * sectionCacheSize);
529 void QQuickListViewPrivate::clear()
531 for (int i = 0; i < sectionCacheSize; ++i) {
532 delete sectionCache[i];
536 releaseSectionItem(currentSectionItem);
537 currentSectionItem = 0;
538 releaseSectionItem(nextSectionItem);
540 lastVisibleSection = QString();
541 QQuickItemViewPrivate::clear();
544 FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
548 FxListItemSG *listItem = new FxListItemSG(item, q, false, false);
549 listItem->index = modelIndex;
551 // initialise attached properties
552 if (sectionCriteria) {
553 QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
554 listItem->attached->m_section = sectionCriteria->sectionString(propValue);
555 if (modelIndex > 0) {
556 if (FxViewItem *item = itemBefore(modelIndex))
557 listItem->attached->m_prevSection = item->attached->section();
559 listItem->attached->m_prevSection = sectionAt(modelIndex-1);
561 if (modelIndex < model->count()-1) {
562 if (FxViewItem *item = visibleItem(modelIndex+1))
563 listItem->attached->m_nextSection = static_cast<QQuickListViewAttached*>(item->attached)->section();
565 listItem->attached->m_nextSection = sectionAt(modelIndex+1);
572 void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
574 QQuickItemViewPrivate::initializeViewItem(item);
576 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item->item);
577 itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
579 if (sectionCriteria && sectionCriteria->delegate()) {
580 if (QString::compare(item->attached->m_prevSection, item->attached->m_section, Qt::CaseInsensitive))
581 updateInlineSection(static_cast<FxListItemSG*>(item));
585 bool QQuickListViewPrivate::releaseItem(FxViewItem *item)
590 QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached);
592 bool released = QQuickItemViewPrivate::releaseItem(item);
593 if (released && att && att->m_sectionItem) {
594 // We hold no more references to this item
597 if (!sectionCache[i]) {
598 sectionCache[i] = att->m_sectionItem;
599 sectionCache[i]->setVisible(false);
600 att->m_sectionItem = 0;
604 } while (i < sectionCacheSize);
605 delete att->m_sectionItem;
606 att->m_sectionItem = 0;
612 bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool doBuffer)
614 qreal itemEnd = visiblePos;
615 if (visibleItems.count()) {
616 visiblePos = (*visibleItems.constBegin())->position();
617 itemEnd = (*(--visibleItems.constEnd()))->endPosition() + spacing;
620 int modelIndex = findLastVisibleIndex();
621 bool haveValidItems = modelIndex >= 0;
622 modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
624 if (haveValidItems && (fillFrom > itemEnd+averageSize+spacing
625 || fillTo < visiblePos - averageSize - spacing)) {
626 // We've jumped more than a page. Estimate which items are now
627 // visible and fill from there.
628 int count = (fillFrom - itemEnd) / (averageSize + spacing);
629 int newModelIdx = qBound(0, modelIndex + count, model->count());
630 count = newModelIdx - modelIndex;
632 for (int i = 0; i < visibleItems.count(); ++i)
633 releaseItem(visibleItems.at(i));
634 visibleItems.clear();
635 modelIndex = newModelIdx;
636 visibleIndex = modelIndex;
637 visiblePos = itemEnd + count * (averageSize + spacing);
638 itemEnd = visiblePos;
642 bool changed = false;
643 FxListItemSG *item = 0;
645 while (modelIndex < model->count() && pos <= fillTo) {
646 #ifdef DEBUG_DELEGATE_LIFECYCLE
647 qDebug() << "refill: append item" << modelIndex << "pos" << pos;
649 if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, doBuffer))))
651 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
652 item->setPosition(pos, true);
653 item->item->setVisible(!doBuffer);
654 pos += item->size() + spacing;
655 visibleItems.append(item);
660 if (doBuffer && requestedIndex != -1) // already waiting for an item
663 while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
664 #ifdef DEBUG_DELEGATE_LIFECYCLE
665 qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
667 if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, doBuffer))))
670 visiblePos -= item->size() + spacing;
671 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
672 item->setPosition(visiblePos, true);
673 item->item->setVisible(!doBuffer);
674 visibleItems.prepend(item);
681 bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
683 FxViewItem *item = 0;
684 bool changed = false;
686 // Remove items from the start of the view.
687 // Zero-sized items shouldn't be removed unless a non-zero-sized item is also being
688 // removed, otherwise a zero-sized item is infinitely added and removed over and
691 while (visibleItems.count() > 1 && index < visibleItems.count()
692 && (item = visibleItems.at(index)) && item->endPosition() < bufferFrom) {
693 if (item->attached->delayRemove())
696 if (item->size() > 0) {
697 #ifdef DEBUG_DELEGATE_LIFECYCLE
698 qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
700 // remove this item and all zero-sized items before it
702 if (item->index != -1)
704 visibleItems.removeAt(index);
705 if (item->transitionScheduledOrRunning()) {
706 #ifdef DEBUG_DELEGATE_LIFECYCLE
707 qDebug() << "refill not releasing animating item" << item->index << item->item->objectName();
709 item->releaseAfterTransition = true;
710 releasePendingTransition.append(item);
716 item = visibleItems.at(--index);
724 while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
725 if (item->attached->delayRemove())
727 #ifdef DEBUG_DELEGATE_LIFECYCLE
728 qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
730 visibleItems.removeLast();
731 if (item->transitionScheduledOrRunning()) {
732 #ifdef DEBUG_DELEGATE_LIFECYCLE
733 qDebug() << "refill not releasing animating item" << item->index << item->item->objectName();
735 item->releaseAfterTransition = true;
736 releasePendingTransition.append(item);
746 void QQuickListViewPrivate::visibleItemsChanged()
748 if (visibleItems.count())
749 visiblePos = (*visibleItems.constBegin())->position();
751 if (currentIndex >= 0 && currentItem && !visibleItem(currentIndex)) {
752 static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
756 updateCurrentSection();
757 updateUnrequestedPositions();
760 void QQuickListViewPrivate::layoutVisibleItems(int fromModelIndex)
762 if (!visibleItems.isEmpty()) {
763 const qreal from = isContentFlowReversed() ? -position() - size() : position();
764 const qreal to = isContentFlowReversed() ? -position() : position() + size();
766 FxViewItem *firstItem = *visibleItems.constBegin();
767 bool fixedCurrent = currentItem && firstItem->item == currentItem->item;
768 qreal sum = firstItem->size();
769 qreal pos = firstItem->position() + firstItem->size() + spacing;
770 firstItem->item->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
772 for (int i=1; i < visibleItems.count(); ++i) {
773 FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.at(i));
774 if (item->index >= fromModelIndex) {
775 item->setPosition(pos);
776 item->setVisible(item->endPosition() >= from && item->position() <= to);
778 pos += item->size() + spacing;
780 fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
782 averageSize = qRound(sum / visibleItems.count());
784 // move current item if it is not a visible item.
785 if (currentIndex >= 0 && currentItem && !fixedCurrent)
786 static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
790 void QQuickListViewPrivate::repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer)
792 static_cast<FxListItemSG *>(item)->setPosition(positionAt(index) + sizeBuffer);
795 void QQuickListViewPrivate::repositionPackageItemAt(QQuickItem *item, int index)
798 qreal pos = position();
799 if (orient == QQuickListView::Vertical) {
800 if (item->y() + item->height() > pos && item->y() < pos + q->height())
801 item->setY(positionAt(index));
803 if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
805 item->setX(-positionAt(index)-item->width());
807 item->setX(positionAt(index));
812 void QQuickListViewPrivate::resetFirstItemPosition(qreal pos)
814 FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.first());
815 item->setPosition(pos);
818 void QQuickListViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int)
820 if (!visibleItems.count())
822 qreal diff = forwards - backwards;
823 static_cast<FxListItemSG*>(visibleItems.first())->setPosition(visibleItems.first()->position() + diff);
826 void QQuickListViewPrivate::createHighlight()
829 bool changed = false;
831 if (trackedItem == highlight)
836 delete highlightPosAnimator;
837 delete highlightSizeAnimator;
838 highlightPosAnimator = 0;
839 highlightSizeAnimator = 0;
845 QQuickItem *item = createHighlightItem();
847 FxListItemSG *newHighlight = new FxListItemSG(item, q, true, true);
850 newHighlight->setSize(static_cast<FxListItemSG*>(currentItem)->itemSize());
851 newHighlight->setPosition(static_cast<FxListItemSG*>(currentItem)->itemPosition());
853 const QLatin1String posProp(orient == QQuickListView::Vertical ? "y" : "x");
854 highlightPosAnimator = new QSmoothedAnimation;
855 highlightPosAnimator->target = QQmlProperty(item, posProp);
856 highlightPosAnimator->velocity = highlightMoveSpeed;
857 highlightPosAnimator->userDuration = highlightMoveDuration;
859 const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
860 highlightSizeAnimator = new QSmoothedAnimation;
861 highlightSizeAnimator->velocity = highlightResizeSpeed;
862 highlightSizeAnimator->userDuration = highlightResizeDuration;
863 highlightSizeAnimator->target = QQmlProperty(item, sizeProp);
865 highlight = newHighlight;
870 emit q->highlightItemChanged();
873 void QQuickListViewPrivate::updateHighlight()
875 applyPendingChanges();
877 if ((!currentItem && highlight) || (currentItem && !highlight))
879 bool strictHighlight = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
880 if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
881 // auto-update highlight
882 FxListItemSG *listItem = static_cast<FxListItemSG*>(currentItem);
883 highlightPosAnimator->to = isRightToLeft()
884 ? -listItem->itemPosition()-listItem->itemSize()
885 : listItem->itemPosition();
886 highlightSizeAnimator->to = listItem->itemSize();
887 if (orient == QQuickListView::Vertical) {
888 if (highlight->item->width() == 0)
889 highlight->item->setWidth(currentItem->item->width());
891 if (highlight->item->height() == 0)
892 highlight->item->setHeight(currentItem->item->height());
895 highlightPosAnimator->restart();
896 highlightSizeAnimator->restart();
901 void QQuickListViewPrivate::resetHighlightPosition()
903 if (highlight && currentItem)
904 static_cast<FxListItemSG*>(highlight)->setPosition(static_cast<FxListItemSG*>(currentItem)->itemPosition());
907 QQuickItem * QQuickListViewPrivate::getSectionItem(const QString §ion)
910 QQuickItem *sectionItem = 0;
911 int i = sectionCacheSize-1;
912 while (i >= 0 && !sectionCache[i])
915 sectionItem = sectionCache[i];
917 sectionItem->setVisible(true);
918 QQmlContext *context = QQmlEngine::contextForObject(sectionItem)->parentContext();
919 context->setContextProperty(QLatin1String("section"), section);
921 QQmlContext *creationContext = sectionCriteria->delegate()->creationContext();
922 QQmlContext *context = new QQmlContext(
923 creationContext ? creationContext : qmlContext(q));
924 context->setContextProperty(QLatin1String("section"), section);
925 QObject *nobj = sectionCriteria->delegate()->beginCreate(context);
927 QQml_setParent_noEvent(context, nobj);
928 sectionItem = qobject_cast<QQuickItem *>(nobj);
932 sectionItem->setZ(2);
933 QQml_setParent_noEvent(sectionItem, contentItem);
934 sectionItem->setParentItem(contentItem);
939 sectionCriteria->delegate()->completeCreate();
945 void QQuickListViewPrivate::releaseSectionItem(QQuickItem *item)
951 if (!sectionCache[i]) {
952 sectionCache[i] = item;
953 sectionCache[i]->setVisible(false);
957 } while (i < sectionCacheSize);
961 void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
963 if (!sectionCriteria || !sectionCriteria->delegate())
965 if (QString::compare(listItem->attached->m_prevSection, listItem->attached->m_section, Qt::CaseInsensitive)
966 && (sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels
967 || (listItem->index == 0 && sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart))) {
968 if (!listItem->section()) {
969 qreal pos = listItem->position();
970 listItem->setSection(getSectionItem(listItem->attached->m_section));
971 listItem->setPosition(pos);
973 QQmlContext *context = QQmlEngine::contextForObject(listItem->section())->parentContext();
974 context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
976 } else if (listItem->section()) {
977 qreal pos = listItem->position();
978 releaseSectionItem(listItem->section());
979 listItem->setSection(0);
980 listItem->setPosition(pos);
984 void QQuickListViewPrivate::updateStickySections()
987 || (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem))
990 bool isRtl = isRightToLeft();
991 qreal viewPos = isRightToLeft() ? -position()-size() : position();
992 QQuickItem *sectionItem = 0;
993 QQuickItem *lastSectionItem = 0;
995 while (index < visibleItems.count()) {
996 if (QQuickItem *section = static_cast<FxListItemSG *>(visibleItems.at(index))->section()) {
997 // Find the current section header and last visible section header
998 // and hide them if they will overlap a static section header.
999 qreal sectionPos = orient == QQuickListView::Vertical ? section->y() : section->x();
1000 qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width();
1002 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
1003 visTop = isRtl ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos;
1005 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd)
1006 visBot = isRtl ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size();
1007 section->setVisible(visBot && visTop);
1008 if (visTop && !sectionItem)
1009 sectionItem = section;
1011 if (-sectionPos <= viewPos + size())
1012 lastSectionItem = section;
1014 if (sectionPos + sectionSize < viewPos + size())
1015 lastSectionItem = section;
1021 // Current section header
1022 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart && isValid() && visibleItems.count()) {
1023 if (!currentSectionItem) {
1024 currentSectionItem = getSectionItem(currentSection);
1025 } else if (QString::compare(currentStickySection, currentSection, Qt::CaseInsensitive)) {
1026 QQmlContext *context = QQmlEngine::contextForObject(currentSectionItem)->parentContext();
1027 context->setContextProperty(QLatin1String("section"), currentSection);
1029 currentStickySection = currentSection;
1030 if (!currentSectionItem)
1033 qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1034 bool atBeginning = orient == QQuickListView::Vertical ? vData.atBeginning : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
1035 currentSectionItem->setVisible(!atBeginning && (!header || header->endPosition() < viewPos));
1036 qreal pos = isRtl ? position() + size() - sectionSize : viewPos;
1038 qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x();
1039 pos = isRtl ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
1042 pos = isRtl ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos);
1044 pos = isRtl ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1045 if (orient == QQuickListView::Vertical)
1046 currentSectionItem->setY(pos);
1048 currentSectionItem->setX(pos);
1049 } else if (currentSectionItem) {
1050 releaseSectionItem(currentSectionItem);
1051 currentSectionItem = 0;
1054 // Next section footer
1055 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd && isValid() && visibleItems.count()) {
1056 if (!nextSectionItem) {
1057 nextSectionItem = getSectionItem(nextSection);
1058 } else if (QString::compare(nextStickySection, nextSection, Qt::CaseInsensitive)) {
1059 QQmlContext *context = QQmlEngine::contextForObject(nextSectionItem)->parentContext();
1060 context->setContextProperty(QLatin1String("section"), nextSection);
1062 nextStickySection = nextSection;
1063 if (!nextSectionItem)
1066 qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1067 nextSectionItem->setVisible(!nextSection.isEmpty());
1068 qreal pos = isRtl ? position() : viewPos + size() - sectionSize;
1069 if (lastSectionItem) {
1070 qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x();
1071 pos = isRtl ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
1074 pos = isRtl ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1075 if (orient == QQuickListView::Vertical)
1076 nextSectionItem->setY(pos);
1078 nextSectionItem->setX(pos);
1079 } else if (nextSectionItem) {
1080 releaseSectionItem(nextSectionItem);
1081 nextSectionItem = 0;
1085 void QQuickListViewPrivate::updateSections()
1087 Q_Q(QQuickListView);
1088 if (!q->isComponentComplete())
1091 QQuickItemViewPrivate::updateSections();
1093 if (sectionCriteria && !visibleItems.isEmpty() && isValid()) {
1094 QString prevSection;
1095 if (visibleIndex > 0)
1096 prevSection = sectionAt(visibleIndex-1);
1097 QQuickListViewAttached *prevAtt = 0;
1099 for (int i = 0; i < visibleItems.count(); ++i) {
1100 QQuickListViewAttached *attached = static_cast<QQuickListViewAttached*>(visibleItems.at(i)->attached);
1101 attached->setPrevSection(prevSection);
1102 if (visibleItems.at(i)->index != -1) {
1103 QString propValue = model->stringValue(visibleItems.at(i)->index, sectionCriteria->property());
1104 attached->setSection(sectionCriteria->sectionString(propValue));
1105 idx = visibleItems.at(i)->index;
1107 updateInlineSection(static_cast<FxListItemSG*>(visibleItems.at(i)));
1109 prevAtt->setNextSection(attached->section());
1110 prevSection = attached->section();
1114 if (idx > 0 && idx < model->count()-1)
1115 prevAtt->setNextSection(sectionAt(idx+1));
1117 prevAtt->setNextSection(QString());
1121 lastVisibleSection = QString();
1122 updateCurrentSection();
1123 updateStickySections();
1126 void QQuickListViewPrivate::updateCurrentSection()
1128 Q_Q(QQuickListView);
1129 if (!sectionCriteria || visibleItems.isEmpty()) {
1130 if (!currentSection.isEmpty()) {
1131 currentSection.clear();
1132 emit q->currentSectionChanged();
1136 bool inlineSections = sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels;
1137 qreal sectionThreshold = position();
1138 if (currentSectionItem && !inlineSections)
1139 sectionThreshold += orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1141 int modelIndex = visibleIndex;
1142 while (index < visibleItems.count() && visibleItems.at(index)->endPosition() <= sectionThreshold) {
1143 if (visibleItems.at(index)->index != -1)
1144 modelIndex = visibleItems.at(index)->index;
1148 QString newSection = currentSection;
1149 if (index < visibleItems.count())
1150 newSection = visibleItems.at(index)->attached->section();
1152 newSection = (*visibleItems.constBegin())->attached->section();
1153 if (newSection != currentSection) {
1154 currentSection = newSection;
1155 updateStickySections();
1156 emit q->currentSectionChanged();
1159 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
1160 // Don't want to scan for next section on every movement, so remember
1161 // the last section in the visible area and only scan for the next
1162 // section when that changes. Clearing lastVisibleSection will also
1164 QString lastSection = currentSection;
1165 qreal endPos = isRightToLeft() ? -position() : position() + size();
1166 if (nextSectionItem && !inlineSections)
1167 endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1168 while (index < visibleItems.count() && static_cast<FxListItemSG*>(visibleItems.at(index))->itemPosition() < endPos) {
1169 if (visibleItems.at(index)->index != -1)
1170 modelIndex = visibleItems.at(index)->index;
1171 lastSection = visibleItems.at(index)->attached->section();
1175 if (lastVisibleSection != lastSection) {
1176 nextSection = QString();
1177 lastVisibleSection = lastSection;
1178 for (int i = modelIndex; i < itemCount; ++i) {
1179 QString section = sectionAt(i);
1180 if (section != lastSection) {
1181 nextSection = section;
1182 updateStickySections();
1190 void QQuickListViewPrivate::initializeCurrentItem()
1192 QQuickItemViewPrivate::initializeCurrentItem();
1195 FxListItemSG *listItem = static_cast<FxListItemSG *>(currentItem);
1197 // don't reposition the item if it is already in the visibleItems list
1198 FxViewItem *actualItem = visibleItem(currentIndex);
1200 if (currentIndex == visibleIndex - 1 && visibleItems.count()) {
1201 // We can calculate exact postion in this case
1202 listItem->setPosition(visibleItems.first()->position() - currentItem->size() - spacing);
1204 // Create current item now and position as best we can.
1205 // Its position will be corrected when it becomes visible.
1206 listItem->setPosition(positionAt(currentIndex));
1210 if (visibleItems.isEmpty())
1211 averageSize = listItem->size();
1215 void QQuickListViewPrivate::updateAverage()
1217 if (!visibleItems.count())
1220 for (int i = 0; i < visibleItems.count(); ++i)
1221 sum += visibleItems.at(i)->size();
1222 averageSize = qRound(sum / visibleItems.count());
1225 qreal QQuickListViewPrivate::headerSize() const
1227 return header ? header->size() : 0.0;
1230 qreal QQuickListViewPrivate::footerSize() const
1232 return footer ? footer->size() : 0.0;
1235 bool QQuickListViewPrivate::showHeaderForIndex(int index) const
1240 bool QQuickListViewPrivate::showFooterForIndex(int index) const
1242 return index == model->count()-1;
1245 void QQuickListViewPrivate::updateFooter()
1247 Q_Q(QQuickListView);
1248 bool created = false;
1250 QQuickItem *item = createComponentItem(footerComponent);
1254 footer = new FxListItemSG(item, q, true, true);
1258 FxListItemSG *listItem = static_cast<FxListItemSG*>(footer);
1259 if (visibleItems.count()) {
1260 qreal endPos = lastPosition();
1261 if (findLastVisibleIndex() == model->count()-1) {
1262 listItem->setPosition(endPos);
1264 qreal visiblePos = position() + q->height();
1265 if (endPos <= visiblePos || listItem->position() < endPos)
1266 listItem->setPosition(endPos);
1269 listItem->setPosition(visiblePos);
1273 emit q->footerItemChanged();
1276 void QQuickListViewPrivate::updateHeader()
1278 Q_Q(QQuickListView);
1279 bool created = false;
1281 QQuickItem *item = createComponentItem(headerComponent);
1285 header = new FxListItemSG(item, q, true, true);
1289 FxListItemSG *listItem = static_cast<FxListItemSG*>(header);
1291 if (visibleItems.count()) {
1292 qreal startPos = originPosition();
1293 if (visibleIndex == 0) {
1294 listItem->setPosition(startPos - headerSize());
1296 if (position() <= startPos || listItem->position() > startPos - headerSize())
1297 listItem->setPosition(startPos - headerSize());
1300 listItem->setPosition(-headerSize());
1305 emit q->headerItemChanged();
1308 void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
1310 Q_Q(QQuickListView);
1311 QQuickItemViewPrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
1312 if (!q->isComponentComplete())
1314 if (item != contentItem && (!highlight || item != highlight->item)) {
1315 if ((orient == QQuickListView::Vertical && newGeometry.height() != oldGeometry.height())
1316 || (orient == QQuickListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
1323 void QQuickListViewPrivate::fixupPosition()
1325 if ((haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange)
1326 || snapMode != QQuickListView::NoSnap)
1328 if (orient == QQuickListView::Vertical)
1334 void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
1336 if ((orient == QQuickListView::Horizontal && &data == &vData)
1337 || (orient == QQuickListView::Vertical && &data == &hData))
1340 correctFlick = false;
1341 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1342 bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
1344 qreal viewPos = isRightToLeft() ? -position()-size() : position();
1346 if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) {
1347 qreal tempPosition = isRightToLeft() ? -position()-size() : position();
1348 if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) {
1349 // if we've been dragged < averageSize/2 then bias towards the next item
1350 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1352 if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < averageSize/2)
1353 bias = averageSize/2;
1354 else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -averageSize/2)
1355 bias = -averageSize/2;
1356 if (isRightToLeft())
1358 tempPosition -= bias;
1360 FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
1361 if (!topItem && strictHighlightRange && currentItem) {
1362 // StrictlyEnforceRange always keeps an item in range
1364 topItem = currentItem;
1366 FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
1367 if (!bottomItem && strictHighlightRange && currentItem) {
1368 // StrictlyEnforceRange always keeps an item in range
1370 bottomItem = currentItem;
1373 bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1374 if (topItem && (isInBounds || strictHighlightRange)) {
1375 if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
1376 pos = isRightToLeft() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart;
1378 if (isRightToLeft())
1379 pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
1381 pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
1383 } else if (bottomItem && isInBounds) {
1384 if (isRightToLeft())
1385 pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
1387 pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
1389 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1393 qreal dist = qAbs(data.move + pos);
1395 timeline.reset(data.move);
1396 if (fixupMode != Immediate) {
1397 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1398 data.fixingUp = true;
1400 timeline.set(data.move, -pos);
1402 vTime = timeline.time();
1404 } else if (currentItem && strictHighlightRange && moveReason != QQuickListViewPrivate::SetIndex) {
1406 qreal pos = static_cast<FxListItemSG*>(currentItem)->itemPosition();
1407 if (viewPos < pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd)
1408 viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd;
1409 if (viewPos > pos - highlightRangeStart)
1410 viewPos = pos - highlightRangeStart;
1411 if (isRightToLeft())
1412 viewPos = -viewPos-size();
1414 timeline.reset(data.move);
1415 if (viewPos != position()) {
1416 if (fixupMode != Immediate) {
1417 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1418 data.fixingUp = true;
1420 timeline.set(data.move, -viewPos);
1423 vTime = timeline.time();
1425 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1427 data.inOvershoot = false;
1431 void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1432 QQuickTimeLineCallback::Callback fixupCallback, qreal velocity)
1434 Q_Q(QQuickListView);
1436 data.fixingUp = false;
1438 if ((!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange) && snapMode == QQuickListView::NoSnap) {
1439 correctFlick = true;
1440 QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1443 qreal maxDistance = 0;
1444 qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value();
1446 // -ve velocity means list is moving up/left
1448 if (data.move.value() < minExtent) {
1449 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1450 // if we've been dragged < averageSize/2 then bias towards the next item
1451 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1452 qreal bias = dist < averageSize/2 ? averageSize/2 : 0;
1453 if (isRightToLeft())
1455 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart;
1456 maxDistance = qAbs(data.flickTarget - data.move.value());
1457 velocity = maxVelocity;
1459 maxDistance = qAbs(minExtent - data.move.value());
1462 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1463 data.flickTarget = minExtent;
1465 if (data.move.value() > maxExtent) {
1466 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1467 // if we've been dragged < averageSize/2 then bias towards the next item
1468 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1469 qreal bias = -dist < averageSize/2 ? averageSize/2 : 0;
1470 if (isRightToLeft())
1472 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart;
1473 maxDistance = qAbs(data.flickTarget - data.move.value());
1474 velocity = -maxVelocity;
1476 maxDistance = qAbs(maxExtent - data.move.value());
1479 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1480 data.flickTarget = maxExtent;
1482 bool overShoot = boundsBehavior == QQuickFlickable::DragAndOvershootBounds;
1483 if (maxDistance > 0 || overShoot) {
1484 // These modes require the list to stop exactly on an item boundary.
1485 // The initial flick will estimate the boundary to stop on.
1486 // Since list items can have variable sizes, the boundary will be
1487 // reevaluated and adjusted as we approach the boundary.
1489 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1495 if (!hData.flicking && !vData.flicking) {
1496 // the initial flick - estimate boundary
1497 qreal accel = deceleration;
1499 overshootDist = 0.0;
1500 // + averageSize/4 to encourage moving at least one item in the flick direction
1501 qreal dist = v2 / (accel * 2.0) + averageSize/4;
1502 if (maxDistance > 0)
1503 dist = qMin(dist, maxDistance);
1506 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) {
1507 if (snapMode != QQuickListView::SnapOneItem) {
1508 qreal distTemp = isRightToLeft() ? -dist : dist;
1509 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart;
1511 data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
1513 if (data.flickTarget >= minExtent) {
1514 overshootDist = overShootDistance(vSize);
1515 data.flickTarget += overshootDist;
1516 } else if (data.flickTarget <= maxExtent) {
1517 overshootDist = overShootDistance(vSize);
1518 data.flickTarget -= overshootDist;
1521 qreal adjDist = -data.flickTarget + data.move.value();
1522 if (qAbs(adjDist) > qAbs(dist)) {
1523 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1524 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1533 accel = v2 / (2.0f * qAbs(dist));
1534 } else if (overShoot) {
1535 data.flickTarget = data.move.value() - dist;
1536 if (data.flickTarget >= minExtent) {
1537 overshootDist = overShootDistance(vSize);
1538 data.flickTarget += overshootDist;
1539 } else if (data.flickTarget <= maxExtent) {
1540 overshootDist = overShootDistance(vSize);
1541 data.flickTarget -= overshootDist;
1544 timeline.reset(data.move);
1545 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1546 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
1547 if (!hData.flicking && q->xflick()) {
1548 hData.flicking = true;
1549 emit q->flickingChanged();
1550 emit q->flickingHorizontallyChanged();
1551 emit q->flickStarted();
1553 if (!vData.flicking && q->yflick()) {
1554 vData.flicking = true;
1555 emit q->flickingChanged();
1556 emit q->flickingVerticallyChanged();
1557 emit q->flickStarted();
1559 correctFlick = true;
1561 // reevaluate the target boundary.
1562 qreal newtarget = data.flickTarget;
1563 if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) {
1564 qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
1565 newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart;
1566 newtarget = isRightToLeft() ? -newtarget+size() : newtarget;
1568 if (velocity < 0 && newtarget <= maxExtent)
1569 newtarget = maxExtent - overshootDist;
1570 else if (velocity > 0 && newtarget >= minExtent)
1571 newtarget = minExtent + overshootDist;
1572 if (newtarget == data.flickTarget) { // boundary unchanged - nothing to do
1573 if (qAbs(velocity) < MinimumFlickVelocity)
1574 correctFlick = false;
1577 data.flickTarget = newtarget;
1578 qreal dist = -newtarget + data.move.value();
1579 if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
1580 correctFlick = false;
1581 timeline.reset(data.move);
1582 fixup(data, minExtent, maxExtent);
1585 timeline.reset(data.move);
1586 timeline.accelDistance(data.move, v, -dist);
1587 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
1590 correctFlick = false;
1591 timeline.reset(data.move);
1592 fixup(data, minExtent, maxExtent);
1596 //----------------------------------------------------------------------------
1599 \qmlclass ListView QQuickListView
1600 \inqmlmodule QtQuick 2
1601 \ingroup qml-view-elements
1603 \brief The ListView item provides a list view of items provided by a model.
1605 A ListView displays data from models created from built-in QML elements like ListModel
1606 and XmlListModel, or custom model classes defined in C++ that inherit from
1609 A ListView has a \l model, which defines the data to be displayed, and
1610 a \l delegate, which defines how the data should be displayed. Items in a
1611 ListView are laid out horizontally or vertically. List views are inherently
1612 flickable because ListView inherits from \l Flickable.
1614 \section1 Example Usage
1616 The following example shows the definition of a simple list model defined
1617 in a file called \c ContactModel.qml:
1619 \snippet doc/src/snippets/qml/listview/ContactModel.qml 0
1621 Another component can display this model data in a ListView, like this:
1623 \snippet doc/src/snippets/qml/listview/listview.qml import
1625 \snippet doc/src/snippets/qml/listview/listview.qml classdocs simple
1627 \image listview-simple.png
1629 Here, the ListView creates a \c ContactModel component for its model, and a \l Text element
1630 for its delegate. The view will create a new \l Text component for each item in the model. Notice
1631 the delegate is able to access the model's \c name and \c number data directly.
1633 An improved list view is shown below. The delegate is visually improved and is moved
1634 into a separate \c contactDelegate component.
1636 \snippet doc/src/snippets/qml/listview/listview.qml classdocs advanced
1637 \image listview-highlight.png
1639 The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
1640 and \c focus is set to \c true to enable keyboard navigation for the list view.
1641 The list view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
1643 Delegates are instantiated as needed and may be destroyed at any time.
1644 State should \e never be stored in a delegate.
1646 ListView attaches a number of properties to the root item of the delegate, for example
1647 \c {ListView.isCurrentItem}. In the following example, the root delegate item can access
1648 this attached property directly as \c ListView.isCurrentItem, while the child
1649 \c contactInfo object must refer to this property as \c wrapper.ListView.isCurrentItem.
1651 \snippet doc/src/snippets/qml/listview/listview.qml isCurrentItem
1653 \note Views do not enable \e clip automatically. If the view
1654 is not clipped by another item or the screen, it will be necessary
1655 to set \e {clip: true} in order to have the out of view items clipped
1658 \sa {QML Data Models}, GridView, {declarative/modelviews/listview}{ListView examples}
1660 QQuickListView::QQuickListView(QQuickItem *parent)
1661 : QQuickItemView(*(new QQuickListViewPrivate), parent)
1665 QQuickListView::~QQuickListView()
1670 \qmlattachedproperty bool QtQuick2::ListView::isCurrentItem
1671 This attached property is true if this delegate is the current item; otherwise false.
1673 It is attached to each instance of the delegate.
1675 This property may be used to adjust the appearance of the current item, for example:
1677 \snippet doc/src/snippets/qml/listview/listview.qml isCurrentItem
1681 \qmlattachedproperty ListView QtQuick2::ListView::view
1682 This attached property holds the view that manages this delegate instance.
1684 It is attached to each instance of the delegate.
1688 \qmlattachedproperty string QtQuick2::ListView::previousSection
1689 This attached property holds the section of the previous 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::nextSection
1698 This attached property holds the section of the next 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 string QtQuick2::ListView::section
1707 This attached property holds the section of this element.
1709 It is attached to each instance of the delegate.
1711 The section is evaluated using the \l {ListView::section.property}{section} properties.
1715 \qmlattachedproperty bool QtQuick2::ListView::delayRemove
1717 This attached property holds whether the delegate may be destroyed. It
1718 is attached to each instance of the delegate. The default value is false.
1720 It is sometimes necessary to delay the destruction of an item
1721 until an animation completes. The example delegate below ensures that the
1722 animation completes before the item is removed from the list.
1724 \snippet doc/src/snippets/qml/listview/listview.qml delayRemove
1726 If a \l remove transition has been specified, it will not be applied until
1727 delayRemove is returned to \c false.
1731 \qmlattachedsignal QtQuick2::ListView::onAdd()
1732 This attached signal handler is called immediately after an item is added to the view.
1734 If an \l add transition is specified, it is applied immediately after
1735 this signal handler is called.
1739 \qmlattachedsignal QtQuick2::ListView::onRemove()
1740 This attached handler is called immediately before an item is removed from the view.
1742 If a \l remove transition has been specified, it is applied after
1743 this signal handler is called, providing that delayRemove is false.
1747 \qmlproperty model QtQuick2::ListView::model
1748 This property holds the model providing data for the list.
1750 The model provides the set of data that is used to create the items
1751 in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
1752 or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
1753 used, it must be a subclass of \l QAbstractItemModel or a simple list.
1755 \sa {qmlmodels}{Data Models}
1759 \qmlproperty Component QtQuick2::ListView::delegate
1761 The delegate provides a template defining each item instantiated by the view.
1762 The index is exposed as an accessible \c index property. Properties of the
1763 model are also available depending upon the type of \l {qmlmodels}{Data Model}.
1765 The number of elements in the delegate has a direct effect on the
1766 flicking performance of the view. If at all possible, place functionality
1767 that is not needed for the normal display of the delegate in a \l Loader which
1768 can load additional elements when needed.
1770 The ListView will lay out the items based on the size of the root item
1773 It is recommended that the delegate's size be a whole number to avoid sub-pixel
1776 \note Delegates are instantiated as needed and may be destroyed at any time.
1777 State should \e never be stored in a delegate.
1780 \qmlproperty int QtQuick2::ListView::currentIndex
1781 \qmlproperty Item QtQuick2::ListView::currentItem
1783 The \c currentIndex property holds the index of the current item, and
1784 \c currentItem holds the current item. Setting the currentIndex to -1
1785 will clear the highlight and set currentItem to null.
1787 If highlightFollowsCurrentItem is \c true, setting either of these
1788 properties will smoothly scroll the ListView so that the current
1789 item becomes visible.
1791 Note that the position of the current item
1792 may only be approximate until it becomes visible in the view.
1796 \qmlproperty Item QtQuick2::ListView::highlightItem
1798 This holds the highlight item created from the \l highlight component.
1800 The \c highlightItem is managed by the view unless
1801 \l highlightFollowsCurrentItem is set to false.
1803 \sa highlight, highlightFollowsCurrentItem
1807 \qmlproperty int QtQuick2::ListView::count
1808 This property holds the number of items in the view.
1812 \qmlproperty Component QtQuick2::ListView::highlight
1813 This property holds the component to use as the highlight.
1815 An instance of the highlight component is created for each list.
1816 The geometry of the resulting component instance is managed by the list
1817 so as to stay with the current item, unless the highlightFollowsCurrentItem
1820 \sa highlightItem, highlightFollowsCurrentItem, {declarative/modelviews/listview}{ListView examples}
1824 \qmlproperty bool QtQuick2::ListView::highlightFollowsCurrentItem
1825 This property holds whether the highlight is managed by the view.
1827 If this property is true (the default value), the highlight is moved smoothly
1828 to follow the current item. Otherwise, the
1829 highlight is not moved by the view, and any movement must be implemented
1832 Here is a highlight with its motion defined by a \l {SpringAnimation} item:
1834 \snippet doc/src/snippets/qml/listview/listview.qml highlightFollowsCurrentItem
1836 Note that the highlight animation also affects the way that the view
1837 is scrolled. This is because the view moves to maintain the
1838 highlight within the preferred highlight range (or visible viewport).
1840 \sa highlight, highlightMoveSpeed
1842 //###Possibly rename these properties, since they are very useful even without a highlight?
1844 \qmlproperty real QtQuick2::ListView::preferredHighlightBegin
1845 \qmlproperty real QtQuick2::ListView::preferredHighlightEnd
1846 \qmlproperty enumeration QtQuick2::ListView::highlightRangeMode
1848 These properties define the preferred range of the highlight (for the current item)
1849 within the view. The \c preferredHighlightBegin value must be less than the
1850 \c preferredHighlightEnd value.
1852 These properties affect the position of the current item when the list is scrolled.
1853 For example, if the currently selected item should stay in the middle of the
1854 list when the view is scrolled, set the \c preferredHighlightBegin and
1855 \c preferredHighlightEnd values to the top and bottom coordinates of where the middle
1856 item would be. If the \c currentItem is changed programmatically, the list will
1857 automatically scroll so that the current item is in the middle of the view.
1858 Furthermore, the behavior of the current item index will occur whether or not a
1861 Valid values for \c highlightRangeMode are:
1864 \li ListView.ApplyRange - the view attempts to maintain the highlight within the range.
1865 However, the highlight can move outside of the range at the ends of the list or due
1866 to mouse interaction.
1867 \li ListView.StrictlyEnforceRange - the highlight never moves outside of the range.
1868 The current item changes if a keyboard or mouse action would cause the highlight to move
1869 outside of the range.
1870 \li ListView.NoHighlightRange - this is the default value.
1873 void QQuickListView::setHighlightFollowsCurrentItem(bool autoHighlight)
1875 Q_D(QQuickListView);
1876 if (d->autoHighlight != autoHighlight) {
1877 if (!autoHighlight) {
1878 if (d->highlightPosAnimator)
1879 d->highlightPosAnimator->stop();
1880 if (d->highlightSizeAnimator)
1881 d->highlightSizeAnimator->stop();
1883 QQuickItemView::setHighlightFollowsCurrentItem(autoHighlight);
1888 \qmlproperty real QtQuick2::ListView::spacing
1890 This property holds the spacing between items.
1892 The default value is 0.
1894 qreal QQuickListView::spacing() const
1896 Q_D(const QQuickListView);
1900 void QQuickListView::setSpacing(qreal spacing)
1902 Q_D(QQuickListView);
1903 if (spacing != d->spacing) {
1904 d->spacing = spacing;
1905 d->forceLayout = true;
1907 emit spacingChanged();
1912 \qmlproperty enumeration QtQuick2::ListView::orientation
1913 This property holds the orientation of the list.
1918 \li ListView.Horizontal - Items are laid out horizontally
1919 \li ListView.Vertical (default) - Items are laid out vertically
1924 \li Horizontal orientation:
1925 \image ListViewHorizontal.png
1928 \li Vertical orientation:
1929 \image listview-highlight.png
1932 QQuickListView::Orientation QQuickListView::orientation() const
1934 Q_D(const QQuickListView);
1938 void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
1940 Q_D(QQuickListView);
1941 if (d->orient != orientation) {
1942 d->orient = orientation;
1943 if (d->orient == Vertical) {
1944 setContentWidth(-1);
1945 setFlickableDirection(VerticalFlick);
1948 setContentHeight(-1);
1949 setFlickableDirection(HorizontalFlick);
1953 emit orientationChanged();
1958 \qmlproperty enumeration QtQuick2::ListView::layoutDirection
1959 This property holds the layout direction of the horizontal list.
1964 \li Qt.LeftToRight (default) - Items will be laid out from left to right.
1965 \li Qt.RightToLeft - Items will be laid out from right to let.
1968 \sa ListView::effectiveLayoutDirection
1973 \qmlproperty enumeration QtQuick2::ListView::effectiveLayoutDirection
1974 This property holds the effective layout direction of the horizontal list.
1976 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1977 the visual layout direction of the horizontal list will be mirrored. However, the
1978 property \l {ListView::layoutDirection}{layoutDirection} will remain unchanged.
1980 \sa ListView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1984 \qmlproperty bool QtQuick2::ListView::keyNavigationWraps
1985 This property holds whether the list wraps key navigation.
1987 If this is true, key navigation that would move the current item selection
1988 past the end of the list instead wraps around and moves the selection to
1989 the start of the list, and vice-versa.
1991 By default, key navigation is not wrapped.
1996 \qmlproperty int QtQuick2::ListView::cacheBuffer
1997 This property determines whether delegates are retained outside the
1998 visible area of the view.
2000 If this value is non-zero, the view may keep as many delegates
2001 instantiated as it can fit within the buffer specified. For example,
2002 if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
2003 set to 40, then up to 2 delegates above and 2 delegates below the visible
2004 area may be created/retained. The buffered delegates are created asynchronously,
2005 allowing creation to occur across multiple frames and reducing the
2006 likelihood of skipping frames. In order to improve painting performance
2007 delegates outside the visible area have their \l visible property set to
2008 false until they are moved into the visible area.
2010 Note that cacheBuffer is not a pixel buffer - it only maintains additional
2011 instantiated delegates.
2013 Setting this value can improve the smoothness of scrolling behavior at the expense
2014 of additional memory usage. It is not a substitute for creating efficient
2015 delegates; the fewer elements in a delegate, the faster a view can be
2021 \qmlproperty string QtQuick2::ListView::section.property
2022 \qmlproperty enumeration QtQuick2::ListView::section.criteria
2023 \qmlproperty Component QtQuick2::ListView::section.delegate
2024 \qmlproperty enumeration QtQuick2::ListView::section.labelPositioning
2026 These properties determine the expression to be evaluated and appearance
2027 of the section labels.
2029 \c section.property holds the name of the property that is the basis
2032 \c section.criteria holds the criteria for forming each section based on
2033 \c section.property. This value can be one of:
2036 \li ViewSection.FullString (default) - sections are created based on the
2037 \c section.property value.
2038 \li ViewSection.FirstCharacter - sections are created based on the first
2039 character of the \c section.property value (for example, 'A', 'B', 'C'
2040 sections, etc. for an address book)
2043 A case insensitive comparison is used when determining section
2046 \c section.delegate holds the delegate component for each section.
2048 \c section.labelPositioning determines whether the current and/or
2049 next section labels stick to the start/end of the view, and whether
2050 the labels are shown inline. This value can be a combination of:
2053 \li ViewSection.InlineLabels - section labels are shown inline between
2054 the item delegates separating sections (default).
2055 \li ViewSection.CurrentLabelAtStart - the current section label sticks to the
2056 start of the view as it is moved.
2057 \li ViewSection.NextLabelAtEnd - the next section label (beyond all visible
2058 sections) sticks to the end of the view as it is moved. \note Enabling
2059 \c ViewSection.NextLabelAtEnd requires the view to scan ahead for the next
2060 section, which has performance implications, especially for slower models.
2063 Each item in the list has attached properties named \c ListView.section,
2064 \c ListView.previousSection and \c ListView.nextSection.
2066 For example, here is a ListView that displays a list of animals, separated
2067 into sections. Each item in the ListView is placed in a different section
2068 depending on the "size" property of the model item. The \c sectionHeading
2069 delegate component provides the light blue bar that marks the beginning of
2073 \snippet examples/declarative/modelviews/listview/sections.qml 0
2075 \image qml-listview-sections-example.png
2077 \note Adding sections to a ListView does not automatically re-order the
2078 list items by the section criteria.
2079 If the model is not ordered by section, then it is possible that
2080 the sections created will not be unique; each boundary between
2081 differing sections will result in a section header being created
2082 even if that section exists elsewhere.
2084 \sa {declarative/modelviews/listview}{ListView examples}
2086 QQuickViewSection *QQuickListView::sectionCriteria()
2088 Q_D(QQuickListView);
2089 if (!d->sectionCriteria) {
2090 d->sectionCriteria = new QQuickViewSection(this);
2091 connect(d->sectionCriteria, SIGNAL(propertyChanged()), this, SLOT(updateSections()));
2093 return d->sectionCriteria;
2097 \qmlproperty string QtQuick2::ListView::currentSection
2098 This property holds the section that is currently at the beginning of the view.
2100 QString QQuickListView::currentSection() const
2102 Q_D(const QQuickListView);
2103 return d->currentSection;
2107 \qmlproperty real QtQuick2::ListView::highlightMoveSpeed
2108 \qmlproperty int QtQuick2::ListView::highlightMoveDuration
2109 \qmlproperty real QtQuick2::ListView::highlightResizeSpeed
2110 \qmlproperty int QtQuick2::ListView::highlightResizeDuration
2112 These properties hold the move and resize animation speed of the highlight delegate.
2114 \l highlightFollowsCurrentItem must be true for these properties
2117 The default value for the speed properties is 400 pixels/second.
2118 The default value for the duration properties is -1, i.e. the
2119 highlight will take as much time as necessary to move at the set speed.
2121 These properties have the same characteristics as a SmoothedAnimation.
2123 \sa highlightFollowsCurrentItem
2125 qreal QQuickListView::highlightMoveSpeed() const
2127 Q_D(const QQuickListView);
2128 return d->highlightMoveSpeed;
2131 void QQuickListView::setHighlightMoveSpeed(qreal speed)
2133 Q_D(QQuickListView);
2134 if (d->highlightMoveSpeed != speed) {
2135 d->highlightMoveSpeed = speed;
2136 if (d->highlightPosAnimator)
2137 d->highlightPosAnimator->velocity = d->highlightMoveSpeed;
2138 emit highlightMoveSpeedChanged();
2142 void QQuickListView::setHighlightMoveDuration(int duration)
2144 Q_D(QQuickListView);
2145 if (d->highlightMoveDuration != duration) {
2146 if (d->highlightPosAnimator)
2147 d->highlightPosAnimator->userDuration = duration;
2148 QQuickItemView::setHighlightMoveDuration(duration);
2152 qreal QQuickListView::highlightResizeSpeed() const
2154 Q_D(const QQuickListView);
2155 return d->highlightResizeSpeed;
2158 void QQuickListView::setHighlightResizeSpeed(qreal speed)
2160 Q_D(QQuickListView);
2161 if (d->highlightResizeSpeed != speed) {
2162 d->highlightResizeSpeed = speed;
2163 if (d->highlightSizeAnimator)
2164 d->highlightSizeAnimator->velocity = d->highlightResizeSpeed;
2165 emit highlightResizeSpeedChanged();
2169 int QQuickListView::highlightResizeDuration() const
2171 Q_D(const QQuickListView);
2172 return d->highlightResizeDuration;
2175 void QQuickListView::setHighlightResizeDuration(int duration)
2177 Q_D(QQuickListView);
2178 if (d->highlightResizeDuration != duration) {
2179 d->highlightResizeDuration = duration;
2180 if (d->highlightSizeAnimator)
2181 d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
2182 emit highlightResizeDurationChanged();
2187 \qmlproperty enumeration QtQuick2::ListView::snapMode
2189 This property determines how the view scrolling will settle following a drag or flick.
2190 The possible values are:
2193 \li ListView.NoSnap (default) - the view stops anywhere within the visible area.
2194 \li ListView.SnapToItem - the view settles with an item aligned with the start of
2196 \li ListView.SnapOneItem - the view settles no more than one item away from the first
2197 visible item at the time the mouse button is released. This mode is particularly
2198 useful for moving one page at a time.
2201 \c snapMode does not affect the \l currentIndex. To update the
2202 \l currentIndex as the list is moved, set \l highlightRangeMode
2203 to \c ListView.StrictlyEnforceRange.
2205 \sa highlightRangeMode
2207 QQuickListView::SnapMode QQuickListView::snapMode() const
2209 Q_D(const QQuickListView);
2213 void QQuickListView::setSnapMode(SnapMode mode)
2215 Q_D(QQuickListView);
2216 if (d->snapMode != mode) {
2218 emit snapModeChanged();
2224 \qmlproperty Component QtQuick2::ListView::footer
2225 This property holds the component to use as the footer.
2227 An instance of the footer component is created for each view. The
2228 footer is positioned at the end of the view, after any items.
2230 \sa header, footerItem
2235 \qmlproperty Component QtQuick2::ListView::header
2236 This property holds the component to use as the header.
2238 An instance of the header component is created for each view. The
2239 header is positioned at the beginning of the view, before any items.
2241 \sa footer, headertem
2245 \qmlproperty Item QtQuick2::ListView::headerItem
2246 This holds the header item created from the \l header component.
2248 An instance of the header component is created for each view. The
2249 header is positioned at the beginning of the view, before any items.
2251 \sa header, footerItem
2255 \qmlproperty Item QtQuick2::ListView::footerItem
2256 This holds the footer item created from the \l footer component.
2258 An instance of the footer component is created for each view. The
2259 footer is positioned at the end of the view, after any items.
2261 \sa footer, headerItem
2265 \qmlproperty Transition QtQuick2::ListView::populate
2267 This property holds the transition to apply to the items that are initially created
2270 It is applied to all items that are created when:
2273 \li The view is first created
2274 \li The view's \l model changes
2275 \li The view's \l model is \l {QAbstractItemModel::reset}{reset}, if the model is a QAbstractItemModel subclass
2278 For example, here is a view that specifies such a transition:
2283 populate: Transition {
2284 NumberAnimation { properties: "x,y"; duration: 1000 }
2289 When the view is initialized, the view will create all the necessary items for the view,
2290 then animate them to their correct positions within the view over one second.
2292 For more details and examples on how to use view transitions, see the ViewTransition
2295 \sa add, ViewTransition
2299 \qmlproperty Transition QtQuick2::ListView::add
2301 This property holds the transition to apply to items that are added to the view.
2303 For example, here is a view that specifies such a transition:
2309 NumberAnimation { properties: "x,y"; from: 100; duration: 1000 }
2314 Whenever an item is added to the above view, the item will be animated from the position (100,100)
2315 to its final x,y position within the view, over one second. The transition only applies to
2316 the new items that are added to the view; it does not apply to the items below that are
2317 displaced by the addition of the new items. To animate the displaced items, set the \l displaced
2318 or \l addDisplaced properties.
2320 For more details and examples on how to use view transitions, see the ViewTransition
2323 \note This transition is not applied to the items that are created when the view is initially
2324 populated, or when the view's \l model changes. In those cases, the \l populate transition is
2327 \sa addDisplaced, populate, ViewTransition
2331 \qmlproperty Transition QtQuick2::ListView::addDisplaced
2333 This property holds the transition to apply to items within the view that are displaced by
2334 the addition of other items to the view.
2336 For example, here is a view that specifies such a transition:
2341 addDisplaced: Transition {
2342 NumberAnimation { properties: "x,y"; duration: 1000 }
2347 Whenever an item is added to the above view, all items beneath the new item are displaced, causing
2348 them to move down (or sideways, if horizontally orientated) within the view. As this
2349 displacement occurs, the items' movement to their new x,y positions within the view will be
2350 animated by a NumberAnimation over one second, as specified. This transition is not applied to
2351 the new item that has been added to the view; to animate the added items, set the \l add
2354 If an item is displaced by multiple types of operations at the same time, it is not defined as to
2355 whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2356 if it is not necessary to specify different transitions depending on whether an item is displaced
2357 by an add, move or remove operation, consider setting the \l displaced property instead.
2359 For more details and examples on how to use view transitions, see the ViewTransition
2362 \note This transition is not applied to the items that are created when the view is initially
2363 populated, or when the view's \l model changes. In those cases, the \l populate transition is
2366 \sa displaced, add, populate, ViewTransition
2370 \qmlproperty Transition QtQuick2::ListView::move
2372 This property holds the transition to apply to items in the view that are being moved due
2373 to a move operation in the view's \l model.
2375 For example, here is a view that specifies such a transition:
2381 NumberAnimation { properties: "x,y"; duration: 1000 }
2386 Whenever the \l model performs a move operation to move a particular set of indexes, the
2387 respective items in the view will be animated to their new positions in the view over one
2388 second. The transition only applies to the items that are the subject of the move operation
2389 in the model; it does not apply to items below them that are displaced by the move operation.
2390 To animate the displaced items, set the \l displaced or \l moveDisplaced properties.
2392 For more details and examples on how to use view transitions, see the ViewTransition
2395 \sa moveDisplaced, ViewTransition
2399 \qmlproperty Transition QtQuick2::ListView::moveDisplaced
2401 This property holds the transition to apply to items that are displaced by a move operation in
2402 the view's \l model.
2404 For example, here is a view that specifies such a transition:
2409 moveDisplaced: Transition {
2410 NumberAnimation { properties: "x,y"; duration: 1000 }
2415 Whenever the \l model performs a move operation to move a particular set of indexes, the items
2416 between the source and destination indexes of the move operation are displaced, causing them
2417 to move upwards or downwards (or sideways, if horizontally orientated) within the view. As this
2418 displacement occurs, the items' movement to their new x,y positions within the view will be
2419 animated by a NumberAnimation over one second, as specified. This transition is not applied to
2420 the items that are the actual subjects of the move operation; to animate the moved items, set
2421 the \l move property.
2423 If an item is displaced by multiple types of operations at the same time, it is not defined as to
2424 whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2425 if it is not necessary to specify different transitions depending on whether an item is displaced
2426 by an add, move or remove operation, consider setting the \l displaced property instead.
2428 For more details and examples on how to use view transitions, see the ViewTransition
2431 \sa displaced, move, ViewTransition
2435 \qmlproperty Transition QtQuick2::ListView::remove
2437 This property holds the transition to apply to items that are removed from the view.
2439 For example, here is a view that specifies such a transition:
2444 remove: Transition {
2446 NumberAnimation { property: "opacity"; to: 0; duration: 1000 }
2447 NumberAnimation { properties: "x,y"; to: 100; duration: 1000 }
2453 Whenever an item is removed from the above view, the item will be animated to the position (100,100)
2454 over one second, and in parallel will also change its opacity to 0. The transition
2455 only applies to the items that are removed from the view; it does not apply to the items below
2456 them that are displaced by the removal of the items. To animate the displaced items, set the
2457 \l displaced or \l removeDisplaced properties.
2459 Note that by the time the transition is applied, the item has already been removed from the
2460 model; any references to the model data for the removed index will not be valid.
2462 Additionally, if the \l delayRemove attached property has been set for a delegate item, the
2463 remove transition will not be applied until \l delayRemove becomes false again.
2465 For more details and examples on how to use view transitions, see the ViewTransition
2468 \sa removeDisplaced, ViewTransition
2472 \qmlproperty Transition QtQuick2::ListView::removeDisplaced
2474 This property holds the transition to apply to items in the view that are displaced by the
2475 removal of other items in the view.
2477 For example, here is a view that specifies such a transition:
2482 removeDisplaced: Transition {
2483 NumberAnimation { properties: "x,y"; duration: 1000 }
2488 Whenever an item is removed from the above view, all items beneath it are displaced, causing
2489 them to move upwards (or sideways, if horizontally orientated) within the view. As this
2490 displacement occurs, the items' movement to their new x,y positions within the view will be
2491 animated by a NumberAnimation over one second, as specified. This transition is not applied to
2492 the item that has actually been removed from the view; to animate the removed items, set the
2495 If an item is displaced by multiple types of operations at the same time, it is not defined as to
2496 whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2497 if it is not necessary to specify different transitions depending on whether an item is displaced
2498 by an add, move or remove operation, consider setting the \l displaced property instead.
2500 For more details and examples on how to use view transitions, see the ViewTransition
2503 \sa displaced, remove, ViewTransition
2507 \qmlproperty Transition QtQuick2::ListView::displaced
2508 This property holds the generic transition to apply to items that have been displaced by
2509 any model operation that affects the view.
2511 This is a convenience for specifying the generic transition to be applied to any items
2512 that are displaced by an add, move or remove operation, without having to specify the
2513 individual addDisplaced, moveDisplaced and removeDisplaced properties. For example, here
2514 is a view that specifies a displaced transition:
2519 displaced: Transition {
2520 NumberAnimation { properties: "x,y"; duration: 1000 }
2525 When any item is added, moved or removed within the above view, the items below it are
2526 displaced, causing them to move down (or sideways, if horizontally orientated) within the
2527 view. As this displacement occurs, the items' movement to their new x,y positions within
2528 the view will be animated by a NumberAnimation over one second, as specified.
2530 If a view specifies this generic displaced transition as well as a specific addDisplaced,
2531 moveDisplaced or removeDisplaced transition, the more specific transition will be used
2532 instead of the generic displaced transition when the relevant operation occurs, providing that
2533 the more specific transition has not been disabled (by setting \l {Transition::enabled}{enabled}
2534 to false). If it has indeed been disabled, the generic displaced transition is applied instead.
2536 For more details and examples on how to use view transitions, see the ViewTransition
2539 \sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition
2542 void QQuickListView::viewportMoved()
2544 Q_D(QQuickListView);
2545 QQuickItemView::viewportMoved();
2548 // Recursion can occur due to refill changing the content size.
2549 if (d->inViewportMoved)
2551 d->inViewportMoved = true;
2554 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
2555 else if (d->isRightToLeft())
2556 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
2558 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
2562 // Set visibility of items to eliminate cost of items outside the visible area.
2563 qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
2564 qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
2565 for (int i = 0; i < d->visibleItems.count(); ++i) {
2566 FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i));
2567 item->item->setVisible(item->endPosition() >= from && item->position() <= to);
2570 d->currentItem->item->setVisible(d->currentItem->endPosition() >= from && d->currentItem->position() <= to);
2572 if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2573 d->moveReason = QQuickListViewPrivate::Mouse;
2574 if (d->moveReason != QQuickListViewPrivate::SetIndex) {
2575 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2576 // reposition highlight
2577 qreal pos = d->highlight->position();
2578 qreal viewPos = d->isRightToLeft() ? -d->position()-d->size() : d->position();
2579 if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
2580 pos = viewPos + d->highlightRangeEnd - d->highlight->size();
2581 if (pos < viewPos + d->highlightRangeStart)
2582 pos = viewPos + d->highlightRangeStart;
2583 if (pos != d->highlight->position()) {
2584 d->highlightPosAnimator->stop();
2585 static_cast<FxListItemSG*>(d->highlight)->setPosition(pos);
2587 d->updateHighlight();
2590 // update current index
2591 if (FxViewItem *snapItem = d->snapItemAt(d->highlight->position())) {
2592 if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
2593 d->updateCurrent(snapItem->index);
2598 if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
2599 d->inFlickCorrection = true;
2600 // Near an end and it seems that the extent has changed?
2601 // Recalculate the flick so that we don't end up in an odd position.
2602 if (yflick() && !d->vData.inOvershoot) {
2603 if (d->vData.velocity > 0) {
2604 const qreal minY = minYExtent();
2605 if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
2606 && minY != d->vData.flickTarget)
2607 d->flickY(-d->vData.smoothVelocity.value());
2608 } else if (d->vData.velocity < 0) {
2609 const qreal maxY = maxYExtent();
2610 if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
2611 && maxY != d->vData.flickTarget)
2612 d->flickY(-d->vData.smoothVelocity.value());
2616 if (xflick() && !d->hData.inOvershoot) {
2617 if (d->hData.velocity > 0) {
2618 const qreal minX = minXExtent();
2619 if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
2620 && minX != d->hData.flickTarget)
2621 d->flickX(-d->hData.smoothVelocity.value());
2622 } else if (d->hData.velocity < 0) {
2623 const qreal maxX = maxXExtent();
2624 if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
2625 && maxX != d->hData.flickTarget)
2626 d->flickX(-d->hData.smoothVelocity.value());
2629 d->inFlickCorrection = false;
2631 if (d->sectionCriteria) {
2632 d->updateCurrentSection();
2633 d->updateStickySections();
2635 d->inViewportMoved = false;
2638 void QQuickListView::keyPressEvent(QKeyEvent *event)
2640 Q_D(QQuickListView);
2641 if (d->model && d->model->count() && d->interactive) {
2642 if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left)
2643 || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right)
2644 || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Up)) {
2645 if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) {
2646 decrementCurrentIndex();
2649 } else if (d->wrap) {
2653 } else if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right)
2654 || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left)
2655 || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Down)) {
2656 if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) {
2657 incrementCurrentIndex();
2660 } else if (d->wrap) {
2667 QQuickItemView::keyPressEvent(event);
2670 void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
2672 Q_D(QQuickListView);
2673 if (d->isRightToLeft() && d->orient == QQuickListView::Horizontal) {
2674 // maintain position relative to the right edge
2675 int dx = newGeometry.width() - oldGeometry.width();
2676 setContentX(contentX() - dx);
2678 QQuickItemView::geometryChanged(newGeometry, oldGeometry);
2683 \qmlmethod QtQuick2::ListView::incrementCurrentIndex()
2685 Increments the current index. The current index will wrap
2686 if keyNavigationWraps is true and it is currently at the end.
2687 This method has no effect if the \l count is zero.
2689 \b Note: methods should only be called after the Component has completed.
2691 void QQuickListView::incrementCurrentIndex()
2693 Q_D(QQuickListView);
2694 int count = d->model ? d->model->count() : 0;
2695 if (count && (currentIndex() < count - 1 || d->wrap)) {
2696 d->moveReason = QQuickListViewPrivate::SetIndex;
2697 int index = currentIndex()+1;
2698 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2703 \qmlmethod QtQuick2::ListView::decrementCurrentIndex()
2705 Decrements the current index. The current index will wrap
2706 if keyNavigationWraps is true and it is currently at the beginning.
2707 This method has no effect if the \l count is zero.
2709 \b Note: methods should only be called after the Component has completed.
2711 void QQuickListView::decrementCurrentIndex()
2713 Q_D(QQuickListView);
2714 int count = d->model ? d->model->count() : 0;
2715 if (count && (currentIndex() > 0 || d->wrap)) {
2716 d->moveReason = QQuickListViewPrivate::SetIndex;
2717 int index = currentIndex()-1;
2718 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2722 void QQuickListView::updateSections()
2724 Q_D(QQuickListView);
2725 if (isComponentComplete() && d->model) {
2726 QList<QByteArray> roles;
2727 if (d->sectionCriteria && !d->sectionCriteria->property().isEmpty())
2728 roles << d->sectionCriteria->property().toUtf8();
2729 d->model->setWatchedRoles(roles);
2730 d->updateSections();
2732 d->forceLayout = true;
2738 bool QQuickListViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
2740 int modelIndex = change.index;
2741 int count = change.count;
2743 qreal tempPos = isRightToLeft() ? -position()-size() : position();
2744 int index = visibleItems.count() ? mapFromModel(modelIndex) : 0;
2747 int i = visibleItems.count() - 1;
2748 while (i > 0 && visibleItems.at(i)->index == -1)
2750 if (i == 0 && visibleItems.first()->index == -1) {
2751 // there are no visible items except items marked for removal
2752 index = visibleItems.count();
2753 } else if (visibleItems.at(i)->index + 1 == modelIndex
2754 && visibleItems.at(i)->endPosition() <= buffer+tempPos+size()) {
2755 // Special case of appending an item to the model.
2756 index = visibleItems.count();
2758 if (modelIndex < visibleIndex) {
2759 // Insert before visible items
2760 visibleIndex += count;
2761 for (int i = 0; i < visibleItems.count(); ++i) {
2762 FxViewItem *item = visibleItems.at(i);
2763 if (item->index != -1 && item->index >= modelIndex)
2764 item->index += count;
2771 // index can be the next item past the end of the visible items list (i.e. appended)
2773 if (visibleItems.count()) {
2774 pos = index < visibleItems.count() ? visibleItems.at(index)->position()
2775 : visibleItems.last()->endPosition()+spacing;
2778 int prevVisibleCount = visibleItems.count();
2779 if (insertResult->visiblePos.isValid() && pos < insertResult->visiblePos) {
2780 // Insert items before the visible item.
2781 int insertionIdx = index;
2783 int from = tempPos - buffer;
2785 for (i = count-1; i >= 0; --i) {
2786 if (pos > from && insertionIdx < visibleIndex) {
2787 // item won't be visible, just note the size for repositioning
2788 insertResult->sizeChangesBeforeVisiblePos += averageSize + spacing;
2789 pos -= averageSize + spacing;
2791 // item is before first visible e.g. in cache buffer
2792 FxViewItem *item = 0;
2793 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2794 item->index = modelIndex + i;
2796 item = createItem(modelIndex + i);
2800 visibleItems.insert(insertionIdx, item);
2801 if (insertionIdx == 0)
2802 insertResult->changedFirstItem = true;
2803 if (!change.isMove()) {
2804 addedItems->append(item);
2805 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2807 insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing;
2808 pos -= item->size() + spacing;
2814 int to = buffer+tempPos+size();
2815 for (i = 0; i < count && pos <= to; ++i) {
2816 FxViewItem *item = 0;
2817 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2818 item->index = modelIndex + i;
2819 bool newItem = !item;
2821 item = createItem(modelIndex + i);
2825 visibleItems.insert(index, item);
2827 insertResult->changedFirstItem = true;
2828 if (change.isMove()) {
2829 // we know this is a move target, since move displaced items that are
2830 // shuffled into view due to a move would be added in refill()
2831 if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true))
2832 movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
2834 addedItems->append(item);
2835 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2837 insertResult->sizeChangesAfterVisiblePos += item->size() + spacing;
2838 pos += item->size() + spacing;
2843 for (; index < visibleItems.count(); ++index) {
2844 FxViewItem *item = visibleItems.at(index);
2845 if (item->index != -1) {
2846 item->index += count;
2847 if (change.isMove())
2848 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false);
2850 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, false);
2854 updateVisibleIndex();
2856 return visibleItems.count() > prevVisibleCount;
2859 void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult)
2861 Q_UNUSED(insertionResult);
2866 int markerItemIndex = -1;
2867 for (int i=0; i<visibleItems.count(); i++) {
2868 if (visibleItems[i]->index == afterModelIndex) {
2869 markerItemIndex = i;
2873 if (markerItemIndex < 0)
2876 const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
2877 qreal sizeRemoved = -removalResult.sizeChangesAfterVisiblePos
2878 - (removalResult.countChangeAfterVisibleItems * (averageSize + spacing));
2880 for (int i=markerItemIndex+1; i<visibleItems.count() && visibleItems.at(i)->position() < viewEndPos; i++) {
2881 FxListItemSG *listItem = static_cast<FxListItemSG *>(visibleItems[i]);
2882 if (!listItem->transitionScheduledOrRunning()) {
2883 qreal pos = listItem->position();
2884 listItem->setPosition(pos - sizeRemoved);
2885 listItem->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
2886 listItem->setPosition(pos);
2892 \qmlmethod QtQuick2::ListView::positionViewAtIndex(int index, PositionMode mode)
2894 Positions the view such that the \a index is at the position specified by
2898 \li ListView.Beginning - position item at the top (or left for horizontal orientation) of the view.
2899 \li ListView.Center - position item in the center of the view.
2900 \li ListView.End - position item at bottom (or right for horizontal orientation) of the view.
2901 \li ListView.Visible - if any part of the item is visible then take no action, otherwise
2902 bring the item into view.
2903 \li ListView.Contain - ensure the entire item is visible. If the item is larger than
2904 the view the item is positioned at the top (or left for horizontal orientation) of the view.
2907 If positioning the view at \a index would cause empty space to be displayed at
2908 the beginning or end of the view, the view will be positioned at the boundary.
2910 It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2911 at a particular index. This is unreliable since removing items from the start
2912 of the list does not cause all other items to be repositioned, and because
2913 the actual start of the view can vary based on the size of the delegates.
2914 The correct way to bring an item into view is with \c positionViewAtIndex.
2916 \b Note: methods should only be called after the Component has completed. To position
2917 the view at startup, this method should be called by Component.onCompleted. For
2918 example, to position the view at the end:
2921 Component.onCompleted: positionViewAtIndex(count - 1, ListView.Beginning)
2926 \qmlmethod QtQuick2::ListView::positionViewAtBeginning()
2927 \qmlmethod QtQuick2::ListView::positionViewAtEnd()
2929 Positions the view at the beginning or end, taking into account any header or footer.
2931 It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2932 at a particular index. This is unreliable since removing items from the start
2933 of the list does not cause all other items to be repositioned, and because
2934 the actual start of the view can vary based on the size of the delegates.
2936 \b Note: methods should only be called after the Component has completed. To position
2937 the view at startup, this method should be called by Component.onCompleted. For
2938 example, to position the view at the end on startup:
2941 Component.onCompleted: positionViewAtEnd()
2946 \qmlmethod int QtQuick2::ListView::indexAt(int x, int y)
2948 Returns the index of the visible item containing the point \a x, \a y in content
2949 coordinates. If there is no item at the point specified, or the item is
2950 not visible -1 is returned.
2952 If the item is outside the visible area, -1 is returned, regardless of
2953 whether an item will exist at that point when scrolled into view.
2955 \b Note: methods should only be called after the Component has completed.
2959 \qmlmethod Item QtQuick2::ListView::itemAt(int x, int y)
2961 Returns the visible item containing the point \a x, \a y in content
2962 coordinates. If there is no item at the point specified, or the item is
2963 not visible null is returned.
2965 If the item is outside the visible area, null is returned, regardless of
2966 whether an item will exist at that point when scrolled into view.
2968 \b Note: methods should only be called after the Component has completed.
2971 QQuickListViewAttached *QQuickListView::qmlAttachedProperties(QObject *obj)
2973 return new QQuickListViewAttached(obj);