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 QtDeclarative 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 <QtDeclarative/qdeclarativeexpression.h>
47 #include <QtDeclarative/qdeclarativeengine.h>
48 #include <QtDeclarative/qdeclarativeinfo.h>
49 #include <QtGui/qevent.h>
50 #include <QtCore/qmath.h>
51 #include <QtCore/qcoreapplication.h>
53 #include <private/qdeclarativesmoothedanimation_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 QDeclarativeChangeSet::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 QDeclarativeTimeLineCallback::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(QDeclarativeComponent *delegate)
210 if (delegate != m_delegate) {
211 m_delegate = delegate;
212 emit delegateChanged();
213 m_view->updateSections();
217 QString QQuickViewSection::sectionString(const QString &value)
219 if (m_criteria == FirstCharacter)
220 return value.isEmpty() ? QString() : value.at(0);
225 void QQuickViewSection::setLabelPositioning(int l)
227 if (m_labelPositioning != l) {
228 m_labelPositioning = l;
229 emit labelPositioningChanged();
230 m_view->updateSections();
234 //----------------------------------------------------------------------------
236 class FxListItemSG : public FxViewItem
239 FxListItemSG(QQuickItem *i, QQuickListView *v, bool own) : FxViewItem(i, own), view(v) {
240 attached = static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(item));
242 static_cast<QQuickListViewAttached*>(attached)->setView(view);
247 inline QQuickItem *section() const {
248 return attached ? static_cast<QQuickListViewAttached*>(attached)->m_sectionItem : 0;
250 void setSection(QQuickItem *s) {
252 attached = static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(item));
253 static_cast<QQuickListViewAttached*>(attached)->m_sectionItem = s;
256 qreal position() const {
258 if (view->orientation() == QQuickListView::Vertical)
259 return section()->y();
261 return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section()->width()-section()->x() : section()->x());
263 return itemPosition();
266 qreal itemPosition() const {
267 if (view->orientation() == QQuickListView::Vertical)
270 return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX());
274 return (view->orientation() == QQuickListView::Vertical ? item->height()+section()->height() : item->width()+section()->width());
276 return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
278 qreal itemSize() const {
279 return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
281 qreal sectionSize() const {
283 return (view->orientation() == QQuickListView::Vertical ? section()->height() : section()->width());
286 qreal endPosition() const {
287 if (view->orientation() == QQuickListView::Vertical) {
288 return itemY() + item->height();
290 return (view->effectiveLayoutDirection() == Qt::RightToLeft
292 : itemX() + item->width());
295 void setPosition(qreal pos) {
296 // position the section immediately even if there is a transition
298 if (view->orientation() == QQuickListView::Vertical) {
299 section()->setY(pos);
301 if (view->effectiveLayoutDirection() == Qt::RightToLeft)
302 section()->setX(-section()->width()-pos);
304 section()->setX(pos);
307 moveTo(pointForPosition(pos));
309 void setSize(qreal size) {
310 if (view->orientation() == QQuickListView::Vertical)
311 item->setHeight(size);
313 item->setWidth(size);
315 bool contains(qreal x, qreal y) const {
316 return (x >= itemX() && x < itemX() + item->width() &&
317 y >= itemY() && y < itemY() + item->height());
320 QQuickListView *view;
323 QPointF pointForPosition(qreal pos) const {
324 if (view->orientation() == QQuickListView::Vertical) {
326 pos += section()->height();
327 return QPointF(itemX(), pos);
329 if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
331 pos += section()->width();
332 return QPointF(-item->width() - pos, itemY());
335 pos += section()->width();
336 return QPointF(pos, itemY());
342 //----------------------------------------------------------------------------
344 bool QQuickListViewPrivate::isContentFlowReversed() const
346 return isRightToLeft();
349 Qt::Orientation QQuickListViewPrivate::layoutOrientation() const
351 return static_cast<Qt::Orientation>(orient);
354 bool QQuickListViewPrivate::isRightToLeft() const
356 Q_Q(const QQuickListView);
357 return orient == QQuickListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
360 // Returns the item before modelIndex, if created.
361 // May return an item marked for removal.
362 FxViewItem *QQuickListViewPrivate::itemBefore(int modelIndex) const
364 if (modelIndex < visibleIndex)
368 while (idx < visibleItems.count()) {
369 FxViewItem *item = visibleItems.at(idx);
370 if (item->index != -1)
371 lastIndex = item->index;
372 if (item->index == modelIndex)
373 return visibleItems.at(idx-1);
376 if (lastIndex == modelIndex-1)
377 return visibleItems.last();
381 void QQuickListViewPrivate::setPosition(qreal pos)
384 if (orient == QQuickListView::Vertical) {
385 q->QQuickFlickable::setContentY(pos);
388 q->QQuickFlickable::setContentX(-pos-size());
390 q->QQuickFlickable::setContentX(pos);
394 qreal QQuickListViewPrivate::originPosition() const
397 if (!visibleItems.isEmpty()) {
398 pos = (*visibleItems.constBegin())->position();
399 if (visibleIndex > 0)
400 pos -= visibleIndex * (averageSize + spacing);
405 qreal QQuickListViewPrivate::lastPosition() const
408 if (!visibleItems.isEmpty()) {
409 int invisibleCount = visibleItems.count() - visibleIndex;
410 for (int i = visibleItems.count()-1; i >= 0; --i) {
411 if (visibleItems.at(i)->index != -1) {
412 invisibleCount = model->count() - visibleItems.at(i)->index - 1;
416 pos = (*(--visibleItems.constEnd()))->endPosition() + invisibleCount * (averageSize + spacing);
417 } else if (model && model->count()) {
418 pos = (model->count() * averageSize + (model->count()-1) * spacing);
423 qreal QQuickListViewPrivate::positionAt(int modelIndex) const
425 if (FxViewItem *item = visibleItem(modelIndex)) {
426 return item->position();
428 if (!visibleItems.isEmpty()) {
429 if (modelIndex < visibleIndex) {
430 int count = visibleIndex - modelIndex;
432 if (modelIndex == currentIndex && currentItem) {
433 cs = currentItem->size() + spacing;
436 return (*visibleItems.constBegin())->position() - count * (averageSize + spacing) - cs;
438 int count = modelIndex - findLastVisibleIndex(visibleIndex) - 1;
439 return (*(--visibleItems.constEnd()))->endPosition() + spacing + count * (averageSize + spacing);
445 qreal QQuickListViewPrivate::endPositionAt(int modelIndex) const
447 if (FxViewItem *item = visibleItem(modelIndex))
448 return item->endPosition();
449 if (!visibleItems.isEmpty()) {
450 if (modelIndex < visibleIndex) {
451 int count = visibleIndex - modelIndex;
452 return (*visibleItems.constBegin())->position() - (count - 1) * (averageSize + spacing) - spacing;
454 int count = modelIndex - findLastVisibleIndex(visibleIndex) - 1;
455 return (*(--visibleItems.constEnd()))->endPosition() + count * (averageSize + spacing);
461 QString QQuickListViewPrivate::sectionAt(int modelIndex)
463 if (FxViewItem *item = visibleItem(modelIndex))
464 return item->attached->section();
467 if (sectionCriteria) {
468 QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
469 section = sectionCriteria->sectionString(propValue);
475 qreal QQuickListViewPrivate::snapPosAt(qreal pos)
477 if (FxViewItem *snapItem = snapItemAt(pos))
478 return snapItem->position();
479 if (visibleItems.count()) {
480 qreal firstPos = (*visibleItems.constBegin())->position();
481 qreal endPos = (*(--visibleItems.constEnd()))->position();
482 if (pos < firstPos) {
483 return firstPos - qRound((firstPos - pos) / averageSize) * averageSize;
484 } else if (pos > endPos)
485 return endPos + qRound((pos - endPos) / averageSize) * averageSize;
487 return qRound((pos - originPosition()) / averageSize) * averageSize + originPosition();
490 FxViewItem *QQuickListViewPrivate::snapItemAt(qreal pos)
492 FxViewItem *snapItem = 0;
493 qreal prevItemSize = 0;
494 for (int i = 0; i < visibleItems.count(); ++i) {
495 FxViewItem *item = visibleItems.at(i);
496 if (item->index == -1)
498 qreal itemTop = item->position();
499 if (highlight && itemTop >= pos && item->endPosition() <= pos + highlight->size())
501 if (itemTop+item->size()/2 >= pos && itemTop-prevItemSize/2 < pos)
503 prevItemSize = item->size();
508 void QQuickListViewPrivate::changedVisibleIndex(int newIndex)
510 visiblePos = positionAt(newIndex);
511 visibleIndex = newIndex;
514 void QQuickListViewPrivate::init()
516 QQuickItemViewPrivate::init();
517 ::memset(sectionCache, 0, sizeof(QQuickItem*) * sectionCacheSize);
520 void QQuickListViewPrivate::clear()
522 for (int i = 0; i < sectionCacheSize; ++i) {
523 delete sectionCache[i];
527 currentSectionItem = 0;
529 lastVisibleSection = QString();
530 QQuickItemViewPrivate::clear();
533 FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
537 FxListItemSG *listItem = new FxListItemSG(item, q, false);
538 listItem->index = modelIndex;
540 // initialise attached properties
541 if (sectionCriteria) {
542 QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
543 listItem->attached->m_section = sectionCriteria->sectionString(propValue);
544 if (modelIndex > 0) {
545 if (FxViewItem *item = itemBefore(modelIndex))
546 listItem->attached->m_prevSection = item->attached->section();
548 listItem->attached->m_prevSection = sectionAt(modelIndex-1);
550 if (modelIndex < model->count()-1) {
551 if (FxViewItem *item = visibleItem(modelIndex+1))
552 listItem->attached->m_nextSection = static_cast<QQuickListViewAttached*>(item->attached)->section();
554 listItem->attached->m_nextSection = sectionAt(modelIndex+1);
561 void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
563 QQuickItemViewPrivate::initializeViewItem(item);
565 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item->item);
566 itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
568 if (sectionCriteria && sectionCriteria->delegate()) {
569 if (item->attached->m_prevSection != item->attached->m_section)
570 updateInlineSection(static_cast<FxListItemSG*>(item));
574 bool QQuickListViewPrivate::releaseItem(FxViewItem *item)
579 QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached);
581 bool released = QQuickItemViewPrivate::releaseItem(item);
582 if (released && att && att->m_sectionItem) {
583 // We hold no more references to this item
586 if (!sectionCache[i]) {
587 sectionCache[i] = att->m_sectionItem;
588 sectionCache[i]->setVisible(false);
589 att->m_sectionItem = 0;
593 } while (i < sectionCacheSize);
594 delete att->m_sectionItem;
595 att->m_sectionItem = 0;
601 bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool doBuffer)
603 qreal itemEnd = visiblePos;
604 if (visibleItems.count()) {
605 visiblePos = (*visibleItems.constBegin())->position();
606 itemEnd = (*(--visibleItems.constEnd()))->endPosition() + spacing;
609 int modelIndex = findLastVisibleIndex();
610 bool haveValidItems = modelIndex >= 0;
611 modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
613 if (haveValidItems && (fillFrom > itemEnd+averageSize+spacing
614 || fillTo < visiblePos - averageSize - spacing)) {
615 // We've jumped more than a page. Estimate which items are now
616 // visible and fill from there.
617 int count = (fillFrom - itemEnd) / (averageSize + spacing);
618 for (int i = 0; i < visibleItems.count(); ++i)
619 releaseItem(visibleItems.at(i));
620 visibleItems.clear();
622 if (modelIndex >= model->count()) {
623 count -= modelIndex - model->count() + 1;
624 modelIndex = model->count() - 1;
625 } else if (modelIndex < 0) {
629 visibleIndex = modelIndex;
630 visiblePos = itemEnd + count * (averageSize + spacing);
631 itemEnd = visiblePos;
634 bool changed = false;
635 FxListItemSG *item = 0;
637 while (modelIndex < model->count() && pos <= fillTo) {
638 #ifdef DEBUG_DELEGATE_LIFECYCLE
639 qDebug() << "refill: append item" << modelIndex << "pos" << pos;
641 if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, doBuffer))))
643 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
644 item->setPosition(pos);
645 item->item->setVisible(!doBuffer);
646 pos += item->size() + spacing;
647 visibleItems.append(item);
652 if (doBuffer && requestedIndex != -1) // already waiting for an item
655 while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
656 #ifdef DEBUG_DELEGATE_LIFECYCLE
657 qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
659 if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, doBuffer))))
662 visiblePos -= item->size() + spacing;
663 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
664 item->setPosition(visiblePos);
665 item->item->setVisible(!doBuffer);
666 visibleItems.prepend(item);
673 bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
675 FxViewItem *item = 0;
676 bool changed = false;
678 // Remove items from the start of the view.
679 // Zero-sized items shouldn't be removed unless a non-zero-sized item is also being
680 // removed, otherwise a zero-sized item is infinitely added and removed over and
683 while (visibleItems.count() > 1 && index < visibleItems.count()
684 && (item = visibleItems.at(index)) && item->endPosition() < bufferFrom) {
685 if (item->attached->delayRemove())
688 if (item->size() > 0) {
689 #ifdef DEBUG_DELEGATE_LIFECYCLE
690 qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
692 // remove this item and all zero-sized items before it
694 if (item->index != -1)
696 visibleItems.removeAt(index);
697 if (item->transitionScheduledOrRunning()) {
698 #ifdef DEBUG_DELEGATE_LIFECYCLE
699 qDebug() << "refill not releasing animating item" << item->index << item->item->objectName();
701 item->releaseAfterTransition = true;
702 releasePendingTransition.append(item);
708 item = visibleItems.at(--index);
716 while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
717 if (item->attached->delayRemove())
719 #ifdef DEBUG_DELEGATE_LIFECYCLE
720 qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
722 visibleItems.removeLast();
723 if (item->transitionScheduledOrRunning()) {
724 #ifdef DEBUG_DELEGATE_LIFECYCLE
725 qDebug() << "refill not releasing animating item" << item->index << item->item->objectName();
727 item->releaseAfterTransition = true;
728 releasePendingTransition.append(item);
738 void QQuickListViewPrivate::visibleItemsChanged()
740 if (visibleItems.count())
741 visiblePos = (*visibleItems.constBegin())->position();
743 if (currentIndex >= 0 && currentItem && !visibleItem(currentIndex)) {
744 static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
748 updateCurrentSection();
749 updateUnrequestedPositions();
752 void QQuickListViewPrivate::layoutVisibleItems(int fromModelIndex)
754 if (!visibleItems.isEmpty()) {
755 const qreal from = isContentFlowReversed() ? -position() - size() : position();
756 const qreal to = isContentFlowReversed() ? -position() : position() + size();
758 FxViewItem *firstItem = *visibleItems.constBegin();
759 bool fixedCurrent = currentItem && firstItem->item == currentItem->item;
760 qreal sum = firstItem->size();
761 qreal pos = firstItem->position() + firstItem->size() + spacing;
762 firstItem->item->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
764 for (int i=1; i < visibleItems.count(); ++i) {
765 FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.at(i));
766 if (item->index >= fromModelIndex) {
767 item->setPosition(pos);
768 item->setVisible(item->endPosition() >= from && item->position() <= to);
770 pos += item->size() + spacing;
772 fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
774 averageSize = qRound(sum / visibleItems.count());
776 // move current item if it is not a visible item.
777 if (currentIndex >= 0 && currentItem && !fixedCurrent)
778 static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
782 void QQuickListViewPrivate::repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer)
784 static_cast<FxListItemSG *>(item)->setPosition(positionAt(index) + sizeBuffer);
787 void QQuickListViewPrivate::repositionPackageItemAt(QQuickItem *item, int index)
790 qreal pos = position();
791 if (orient == QQuickListView::Vertical) {
792 if (item->y() + item->height() > pos && item->y() < pos + q->height())
793 item->setY(positionAt(index));
795 if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
797 item->setX(-positionAt(index)-item->width());
799 item->setX(positionAt(index));
804 void QQuickListViewPrivate::resetFirstItemPosition(qreal pos)
806 FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.first());
807 item->setPosition(pos);
810 void QQuickListViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int)
812 if (!visibleItems.count())
814 qreal diff = forwards - backwards;
815 static_cast<FxListItemSG*>(visibleItems.first())->setPosition(visibleItems.first()->position() + diff);
818 void QQuickListViewPrivate::createHighlight()
821 bool changed = false;
823 if (trackedItem == highlight)
828 delete highlightPosAnimator;
829 delete highlightSizeAnimator;
830 highlightPosAnimator = 0;
831 highlightSizeAnimator = 0;
837 QQuickItem *item = createHighlightItem();
839 FxListItemSG *newHighlight = new FxListItemSG(item, q, true);
842 newHighlight->setSize(static_cast<FxListItemSG*>(currentItem)->itemSize());
843 newHighlight->setPosition(static_cast<FxListItemSG*>(currentItem)->itemPosition());
845 const QLatin1String posProp(orient == QQuickListView::Vertical ? "y" : "x");
846 highlightPosAnimator = new QSmoothedAnimation;
847 highlightPosAnimator->target = QDeclarativeProperty(item, posProp);
848 highlightPosAnimator->velocity = highlightMoveSpeed;
849 highlightPosAnimator->userDuration = highlightMoveDuration;
851 const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
852 highlightSizeAnimator = new QSmoothedAnimation;
853 highlightSizeAnimator->velocity = highlightResizeSpeed;
854 highlightSizeAnimator->userDuration = highlightResizeDuration;
855 highlightSizeAnimator->target = QDeclarativeProperty(item, sizeProp);
857 highlight = newHighlight;
862 emit q->highlightItemChanged();
865 void QQuickListViewPrivate::updateHighlight()
867 applyPendingChanges();
869 if ((!currentItem && highlight) || (currentItem && !highlight))
871 bool strictHighlight = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
872 if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
873 // auto-update highlight
874 FxListItemSG *listItem = static_cast<FxListItemSG*>(currentItem);
875 highlightPosAnimator->to = isRightToLeft()
876 ? -listItem->itemPosition()-listItem->itemSize()
877 : listItem->itemPosition();
878 highlightSizeAnimator->to = listItem->itemSize();
879 if (orient == QQuickListView::Vertical) {
880 if (highlight->item->width() == 0)
881 highlight->item->setWidth(currentItem->item->width());
883 if (highlight->item->height() == 0)
884 highlight->item->setHeight(currentItem->item->height());
887 highlightPosAnimator->restart();
888 highlightSizeAnimator->restart();
893 void QQuickListViewPrivate::resetHighlightPosition()
895 if (highlight && currentItem)
896 static_cast<FxListItemSG*>(highlight)->setPosition(static_cast<FxListItemSG*>(currentItem)->itemPosition());
899 QQuickItem * QQuickListViewPrivate::getSectionItem(const QString §ion)
902 QQuickItem *sectionItem = 0;
903 int i = sectionCacheSize-1;
904 while (i >= 0 && !sectionCache[i])
907 sectionItem = sectionCache[i];
909 sectionItem->setVisible(true);
910 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(sectionItem)->parentContext();
911 context->setContextProperty(QLatin1String("section"), section);
913 QDeclarativeContext *creationContext = sectionCriteria->delegate()->creationContext();
914 QDeclarativeContext *context = new QDeclarativeContext(
915 creationContext ? creationContext : qmlContext(q));
916 context->setContextProperty(QLatin1String("section"), section);
917 QObject *nobj = sectionCriteria->delegate()->beginCreate(context);
919 QDeclarative_setParent_noEvent(context, nobj);
920 sectionItem = qobject_cast<QQuickItem *>(nobj);
924 sectionItem->setZ(2);
925 QDeclarative_setParent_noEvent(sectionItem, contentItem);
926 sectionItem->setParentItem(contentItem);
931 sectionCriteria->delegate()->completeCreate();
937 void QQuickListViewPrivate::releaseSectionItem(QQuickItem *item)
941 if (!sectionCache[i]) {
942 sectionCache[i] = item;
943 sectionCache[i]->setVisible(false);
947 } while (i < sectionCacheSize);
951 void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
953 if (!sectionCriteria || !sectionCriteria->delegate())
955 if (listItem->attached->m_prevSection != listItem->attached->m_section
956 && (sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels
957 || (listItem->index == 0 && sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart))) {
958 if (!listItem->section()) {
959 qreal pos = listItem->position();
960 listItem->setSection(getSectionItem(listItem->attached->m_section));
961 listItem->setPosition(pos);
963 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(listItem->section())->parentContext();
964 context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
966 } else if (listItem->section()) {
967 qreal pos = listItem->position();
968 releaseSectionItem(listItem->section());
969 listItem->setSection(0);
970 listItem->setPosition(pos);
974 void QQuickListViewPrivate::updateStickySections()
976 if (!sectionCriteria || visibleItems.isEmpty()
977 || (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem))
980 bool isRtl = isRightToLeft();
981 qreal viewPos = isRightToLeft() ? -position()-size() : position();
982 QQuickItem *sectionItem = 0;
983 QQuickItem *lastSectionItem = 0;
985 while (index < visibleItems.count()) {
986 if (QQuickItem *section = static_cast<FxListItemSG *>(visibleItems.at(index))->section()) {
987 // Find the current section header and last visible section header
988 // and hide them if they will overlap a static section header.
989 qreal sectionPos = orient == QQuickListView::Vertical ? section->y() : section->x();
990 qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width();
992 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
993 visTop = isRtl ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos;
995 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd)
996 visBot = isRtl ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size();
997 section->setVisible(visBot && visTop);
998 if (visTop && !sectionItem)
999 sectionItem = section;
1001 if (-sectionPos <= viewPos + size())
1002 lastSectionItem = section;
1004 if (sectionPos + sectionSize < viewPos + size())
1005 lastSectionItem = section;
1011 // Current section header
1012 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart) {
1013 if (!currentSectionItem) {
1014 currentSectionItem = getSectionItem(currentSection);
1015 } else if (currentStickySection != currentSection) {
1016 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(currentSectionItem)->parentContext();
1017 context->setContextProperty(QLatin1String("section"), currentSection);
1019 currentStickySection = currentSection;
1020 if (!currentSectionItem)
1023 qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1024 bool atBeginning = orient == QQuickListView::Vertical ? vData.atBeginning : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
1025 currentSectionItem->setVisible(!atBeginning && (!header || header->endPosition() < viewPos));
1026 qreal pos = isRtl ? position() + size() - sectionSize : viewPos;
1028 qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x();
1029 pos = isRtl ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
1032 pos = isRtl ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos);
1034 pos = isRtl ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1035 if (orient == QQuickListView::Vertical)
1036 currentSectionItem->setY(pos);
1038 currentSectionItem->setX(pos);
1039 } else if (currentSectionItem) {
1040 releaseSectionItem(currentSectionItem);
1041 currentSectionItem = 0;
1044 // Next section footer
1045 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
1046 if (!nextSectionItem) {
1047 nextSectionItem = getSectionItem(nextSection);
1048 } else if (nextStickySection != nextSection) {
1049 QDeclarativeContext *context = QDeclarativeEngine::contextForObject(nextSectionItem)->parentContext();
1050 context->setContextProperty(QLatin1String("section"), nextSection);
1052 nextStickySection = nextSection;
1053 if (!nextSectionItem)
1056 qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1057 nextSectionItem->setVisible(!nextSection.isEmpty());
1058 qreal pos = isRtl ? position() : viewPos + size() - sectionSize;
1059 if (lastSectionItem) {
1060 qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x();
1061 pos = isRtl ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
1064 pos = isRtl ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1065 if (orient == QQuickListView::Vertical)
1066 nextSectionItem->setY(pos);
1068 nextSectionItem->setX(pos);
1069 } else if (nextSectionItem) {
1070 releaseSectionItem(nextSectionItem);
1071 nextSectionItem = 0;
1075 void QQuickListViewPrivate::updateSections()
1077 Q_Q(QQuickListView);
1078 if (!q->isComponentComplete())
1081 QQuickItemViewPrivate::updateSections();
1083 if (sectionCriteria && !visibleItems.isEmpty()) {
1084 QString prevSection;
1085 if (visibleIndex > 0)
1086 prevSection = sectionAt(visibleIndex-1);
1087 QQuickListViewAttached *prevAtt = 0;
1089 for (int i = 0; i < visibleItems.count(); ++i) {
1090 QQuickListViewAttached *attached = static_cast<QQuickListViewAttached*>(visibleItems.at(i)->attached);
1091 attached->setPrevSection(prevSection);
1092 if (visibleItems.at(i)->index != -1) {
1093 QString propValue = model->stringValue(visibleItems.at(i)->index, sectionCriteria->property());
1094 attached->setSection(sectionCriteria->sectionString(propValue));
1095 idx = visibleItems.at(i)->index;
1097 updateInlineSection(static_cast<FxListItemSG*>(visibleItems.at(i)));
1099 prevAtt->setNextSection(attached->section());
1100 prevSection = attached->section();
1104 if (idx > 0 && idx < model->count()-1)
1105 prevAtt->setNextSection(sectionAt(idx+1));
1107 prevAtt->setNextSection(QString());
1111 lastVisibleSection = QString();
1112 updateCurrentSection();
1113 updateStickySections();
1116 void QQuickListViewPrivate::updateCurrentSection()
1118 Q_Q(QQuickListView);
1119 if (!sectionCriteria || visibleItems.isEmpty()) {
1120 if (!currentSection.isEmpty()) {
1121 currentSection.clear();
1122 emit q->currentSectionChanged();
1126 bool inlineSections = sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels;
1127 qreal sectionThreshold = position();
1128 if (currentSectionItem && !inlineSections)
1129 sectionThreshold += orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1131 int modelIndex = visibleIndex;
1132 while (index < visibleItems.count() && visibleItems.at(index)->endPosition() <= sectionThreshold) {
1133 if (visibleItems.at(index)->index != -1)
1134 modelIndex = visibleItems.at(index)->index;
1138 QString newSection = currentSection;
1139 if (index < visibleItems.count())
1140 newSection = visibleItems.at(index)->attached->section();
1142 newSection = (*visibleItems.constBegin())->attached->section();
1143 if (newSection != currentSection) {
1144 currentSection = newSection;
1145 updateStickySections();
1146 emit q->currentSectionChanged();
1149 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
1150 // Don't want to scan for next section on every movement, so remember
1151 // the last section in the visible area and only scan for the next
1152 // section when that changes. Clearing lastVisibleSection will also
1154 QString lastSection = currentSection;
1155 qreal endPos = isRightToLeft() ? -position() : position() + size();
1156 if (nextSectionItem && !inlineSections)
1157 endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1158 while (index < visibleItems.count() && static_cast<FxListItemSG*>(visibleItems.at(index))->itemPosition() < endPos) {
1159 if (visibleItems.at(index)->index != -1)
1160 modelIndex = visibleItems.at(index)->index;
1161 lastSection = visibleItems.at(index)->attached->section();
1165 if (lastVisibleSection != lastSection) {
1166 nextSection = QString();
1167 lastVisibleSection = lastSection;
1168 for (int i = modelIndex; i < itemCount; ++i) {
1169 QString section = sectionAt(i);
1170 if (section != lastSection) {
1171 nextSection = section;
1172 updateStickySections();
1180 void QQuickListViewPrivate::initializeCurrentItem()
1182 QQuickItemViewPrivate::initializeCurrentItem();
1185 FxListItemSG *listItem = static_cast<FxListItemSG *>(currentItem);
1187 // don't reposition the item if it is already in the visibleItems list
1188 FxViewItem *actualItem = visibleItem(currentIndex);
1190 if (currentIndex == visibleIndex - 1 && visibleItems.count()) {
1191 // We can calculate exact postion in this case
1192 listItem->setPosition(visibleItems.first()->position() - currentItem->size() - spacing);
1194 // Create current item now and position as best we can.
1195 // Its position will be corrected when it becomes visible.
1196 listItem->setPosition(positionAt(currentIndex));
1200 if (visibleItems.isEmpty())
1201 averageSize = listItem->size();
1205 void QQuickListViewPrivate::updateAverage()
1207 if (!visibleItems.count())
1210 for (int i = 0; i < visibleItems.count(); ++i)
1211 sum += visibleItems.at(i)->size();
1212 averageSize = qRound(sum / visibleItems.count());
1215 qreal QQuickListViewPrivate::headerSize() const
1217 return header ? header->size() : 0.0;
1220 qreal QQuickListViewPrivate::footerSize() const
1222 return footer ? footer->size() : 0.0;
1225 bool QQuickListViewPrivate::showHeaderForIndex(int index) const
1230 bool QQuickListViewPrivate::showFooterForIndex(int index) const
1232 return index == model->count()-1;
1235 void QQuickListViewPrivate::updateFooter()
1237 Q_Q(QQuickListView);
1238 bool created = false;
1240 QQuickItem *item = createComponentItem(footerComponent, true);
1244 footer = new FxListItemSG(item, q, true);
1248 FxListItemSG *listItem = static_cast<FxListItemSG*>(footer);
1249 if (visibleItems.count()) {
1250 qreal endPos = lastPosition();
1251 if (findLastVisibleIndex() == model->count()-1) {
1252 listItem->setPosition(endPos);
1254 qreal visiblePos = position() + q->height();
1255 if (endPos <= visiblePos || listItem->position() < endPos)
1256 listItem->setPosition(endPos);
1259 listItem->setPosition(visiblePos);
1263 emit q->footerItemChanged();
1266 void QQuickListViewPrivate::updateHeader()
1268 Q_Q(QQuickListView);
1269 bool created = false;
1271 QQuickItem *item = createComponentItem(headerComponent, true);
1275 header = new FxListItemSG(item, q, true);
1279 FxListItemSG *listItem = static_cast<FxListItemSG*>(header);
1281 if (visibleItems.count()) {
1282 qreal startPos = originPosition();
1283 if (visibleIndex == 0) {
1284 listItem->setPosition(startPos - headerSize());
1286 if (position() <= startPos || listItem->position() > startPos - headerSize())
1287 listItem->setPosition(startPos - headerSize());
1290 listItem->setPosition(-headerSize());
1295 emit q->headerItemChanged();
1298 void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
1300 Q_Q(QQuickListView);
1301 QQuickItemViewPrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
1302 if (!q->isComponentComplete())
1304 if (item != contentItem && (!highlight || item != highlight->item)) {
1305 if ((orient == QQuickListView::Vertical && newGeometry.height() != oldGeometry.height())
1306 || (orient == QQuickListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
1313 void QQuickListViewPrivate::fixupPosition()
1315 if ((haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange)
1316 || snapMode != QQuickListView::NoSnap)
1318 if (orient == QQuickListView::Vertical)
1324 void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
1326 if ((orient == QQuickListView::Horizontal && &data == &vData)
1327 || (orient == QQuickListView::Vertical && &data == &hData))
1330 correctFlick = false;
1331 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1332 bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
1334 qreal viewPos = isRightToLeft() ? -position()-size() : position();
1336 if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) {
1337 qreal tempPosition = isRightToLeft() ? -position()-size() : position();
1338 if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) {
1339 // if we've been dragged < averageSize/2 then bias towards the next item
1340 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1342 if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < averageSize/2)
1343 bias = averageSize/2;
1344 else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -averageSize/2)
1345 bias = -averageSize/2;
1346 if (isRightToLeft())
1348 tempPosition -= bias;
1350 FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
1351 if (!topItem && strictHighlightRange && currentItem) {
1352 // StrictlyEnforceRange always keeps an item in range
1354 topItem = currentItem;
1356 FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
1357 if (!bottomItem && strictHighlightRange && currentItem) {
1358 // StrictlyEnforceRange always keeps an item in range
1360 bottomItem = currentItem;
1363 bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1364 if (topItem && (isInBounds || strictHighlightRange)) {
1365 if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
1366 pos = isRightToLeft() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart;
1368 if (isRightToLeft())
1369 pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
1371 pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
1373 } else if (bottomItem && isInBounds) {
1374 if (isRightToLeft())
1375 pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
1377 pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
1379 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1383 qreal dist = qAbs(data.move + pos);
1385 timeline.reset(data.move);
1386 if (fixupMode != Immediate) {
1387 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1388 data.fixingUp = true;
1390 timeline.set(data.move, -pos);
1392 vTime = timeline.time();
1394 } else if (currentItem && strictHighlightRange && moveReason != QQuickListViewPrivate::SetIndex) {
1396 qreal pos = static_cast<FxListItemSG*>(currentItem)->itemPosition();
1397 if (viewPos < pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd)
1398 viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd;
1399 if (viewPos > pos - highlightRangeStart)
1400 viewPos = pos - highlightRangeStart;
1401 if (isRightToLeft())
1402 viewPos = -viewPos-size();
1404 timeline.reset(data.move);
1405 if (viewPos != position()) {
1406 if (fixupMode != Immediate) {
1407 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1408 data.fixingUp = true;
1410 timeline.set(data.move, -viewPos);
1413 vTime = timeline.time();
1415 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1417 data.inOvershoot = false;
1421 void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1422 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
1424 Q_Q(QQuickListView);
1426 data.fixingUp = false;
1428 if ((!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange) && snapMode == QQuickListView::NoSnap) {
1429 correctFlick = true;
1430 QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1433 qreal maxDistance = 0;
1434 qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value();
1436 // -ve velocity means list is moving up/left
1438 if (data.move.value() < minExtent) {
1439 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1440 // if we've been dragged < averageSize/2 then bias towards the next item
1441 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1442 qreal bias = dist < averageSize/2 ? averageSize/2 : 0;
1443 if (isRightToLeft())
1445 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart;
1446 maxDistance = qAbs(data.flickTarget - data.move.value());
1447 velocity = maxVelocity;
1449 maxDistance = qAbs(minExtent - data.move.value());
1452 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1453 data.flickTarget = minExtent;
1455 if (data.move.value() > maxExtent) {
1456 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1457 // if we've been dragged < averageSize/2 then bias towards the next item
1458 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1459 qreal bias = -dist < averageSize/2 ? averageSize/2 : 0;
1460 if (isRightToLeft())
1462 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart;
1463 maxDistance = qAbs(data.flickTarget - data.move.value());
1464 velocity = -maxVelocity;
1466 maxDistance = qAbs(maxExtent - data.move.value());
1469 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1470 data.flickTarget = maxExtent;
1472 bool overShoot = boundsBehavior == QQuickFlickable::DragAndOvershootBounds;
1473 if (maxDistance > 0 || overShoot) {
1474 // These modes require the list to stop exactly on an item boundary.
1475 // The initial flick will estimate the boundary to stop on.
1476 // Since list items can have variable sizes, the boundary will be
1477 // reevaluated and adjusted as we approach the boundary.
1479 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1485 if (!hData.flicking && !vData.flicking) {
1486 // the initial flick - estimate boundary
1487 qreal accel = deceleration;
1489 overshootDist = 0.0;
1490 // + averageSize/4 to encourage moving at least one item in the flick direction
1491 qreal dist = v2 / (accel * 2.0) + averageSize/4;
1492 if (maxDistance > 0)
1493 dist = qMin(dist, maxDistance);
1496 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) {
1497 if (snapMode != QQuickListView::SnapOneItem) {
1498 qreal distTemp = isRightToLeft() ? -dist : dist;
1499 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart;
1501 data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
1503 if (data.flickTarget >= minExtent) {
1504 overshootDist = overShootDistance(vSize);
1505 data.flickTarget += overshootDist;
1506 } else if (data.flickTarget <= maxExtent) {
1507 overshootDist = overShootDistance(vSize);
1508 data.flickTarget -= overshootDist;
1511 qreal adjDist = -data.flickTarget + data.move.value();
1512 if (qAbs(adjDist) > qAbs(dist)) {
1513 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1514 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1523 accel = v2 / (2.0f * qAbs(dist));
1524 } else if (overShoot) {
1525 data.flickTarget = data.move.value() - dist;
1526 if (data.flickTarget >= minExtent) {
1527 overshootDist = overShootDistance(vSize);
1528 data.flickTarget += overshootDist;
1529 } else if (data.flickTarget <= maxExtent) {
1530 overshootDist = overShootDistance(vSize);
1531 data.flickTarget -= overshootDist;
1534 timeline.reset(data.move);
1535 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1536 timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1537 if (!hData.flicking && q->xflick()) {
1538 hData.flicking = true;
1539 emit q->flickingChanged();
1540 emit q->flickingHorizontallyChanged();
1541 emit q->flickStarted();
1543 if (!vData.flicking && q->yflick()) {
1544 vData.flicking = true;
1545 emit q->flickingChanged();
1546 emit q->flickingVerticallyChanged();
1547 emit q->flickStarted();
1549 correctFlick = true;
1551 // reevaluate the target boundary.
1552 qreal newtarget = data.flickTarget;
1553 if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) {
1554 qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
1555 newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart;
1556 newtarget = isRightToLeft() ? -newtarget+size() : newtarget;
1558 if (velocity < 0 && newtarget <= maxExtent)
1559 newtarget = maxExtent - overshootDist;
1560 else if (velocity > 0 && newtarget >= minExtent)
1561 newtarget = minExtent + overshootDist;
1562 if (newtarget == data.flickTarget) { // boundary unchanged - nothing to do
1563 if (qAbs(velocity) < MinimumFlickVelocity)
1564 correctFlick = false;
1567 data.flickTarget = newtarget;
1568 qreal dist = -newtarget + data.move.value();
1569 if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
1570 correctFlick = false;
1571 timeline.reset(data.move);
1572 fixup(data, minExtent, maxExtent);
1575 timeline.reset(data.move);
1576 timeline.accelDistance(data.move, v, -dist);
1577 timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1580 correctFlick = false;
1581 timeline.reset(data.move);
1582 fixup(data, minExtent, maxExtent);
1586 //----------------------------------------------------------------------------
1589 \qmlclass ListView QQuickListView
1590 \inqmlmodule QtQuick 2
1591 \ingroup qml-view-elements
1593 \brief The ListView item provides a list view of items provided by a model.
1595 A ListView displays data from models created from built-in QML elements like ListModel
1596 and XmlListModel, or custom model classes defined in C++ that inherit from
1599 A ListView has a \l model, which defines the data to be displayed, and
1600 a \l delegate, which defines how the data should be displayed. Items in a
1601 ListView are laid out horizontally or vertically. List views are inherently
1602 flickable because ListView inherits from \l Flickable.
1604 \section1 Example Usage
1606 The following example shows the definition of a simple list model defined
1607 in a file called \c ContactModel.qml:
1609 \snippet doc/src/snippets/declarative/listview/ContactModel.qml 0
1611 Another component can display this model data in a ListView, like this:
1613 \snippet doc/src/snippets/declarative/listview/listview.qml import
1615 \snippet doc/src/snippets/declarative/listview/listview.qml classdocs simple
1617 \image listview-simple.png
1619 Here, the ListView creates a \c ContactModel component for its model, and a \l Text element
1620 for its delegate. The view will create a new \l Text component for each item in the model. Notice
1621 the delegate is able to access the model's \c name and \c number data directly.
1623 An improved list view is shown below. The delegate is visually improved and is moved
1624 into a separate \c contactDelegate component.
1626 \snippet doc/src/snippets/declarative/listview/listview.qml classdocs advanced
1627 \image listview-highlight.png
1629 The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
1630 and \c focus is set to \c true to enable keyboard navigation for the list view.
1631 The list view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
1633 Delegates are instantiated as needed and may be destroyed at any time.
1634 State should \e never be stored in a delegate.
1636 ListView attaches a number of properties to the root item of the delegate, for example
1637 \c {ListView.isCurrentItem}. In the following example, the root delegate item can access
1638 this attached property directly as \c ListView.isCurrentItem, while the child
1639 \c contactInfo object must refer to this property as \c wrapper.ListView.isCurrentItem.
1641 \snippet doc/src/snippets/declarative/listview/listview.qml isCurrentItem
1643 \note Views do not enable \e clip automatically. If the view
1644 is not clipped by another item or the screen, it will be necessary
1645 to set \e {clip: true} in order to have the out of view items clipped
1648 \sa {QML Data Models}, GridView, {declarative/modelviews/listview}{ListView examples}
1650 QQuickListView::QQuickListView(QQuickItem *parent)
1651 : QQuickItemView(*(new QQuickListViewPrivate), parent)
1655 QQuickListView::~QQuickListView()
1660 \qmlattachedproperty bool QtQuick2::ListView::isCurrentItem
1661 This attached property is true if this delegate is the current item; otherwise false.
1663 It is attached to each instance of the delegate.
1665 This property may be used to adjust the appearance of the current item, for example:
1667 \snippet doc/src/snippets/declarative/listview/listview.qml isCurrentItem
1671 \qmlattachedproperty ListView QtQuick2::ListView::view
1672 This attached property holds the view that manages this delegate instance.
1674 It is attached to each instance of the delegate.
1678 \qmlattachedproperty string QtQuick2::ListView::previousSection
1679 This attached property holds the section of the previous element.
1681 It is attached to each instance of the delegate.
1683 The section is evaluated using the \l {ListView::section.property}{section} properties.
1687 \qmlattachedproperty string QtQuick2::ListView::nextSection
1688 This attached property holds the section of the next element.
1690 It is attached to each instance of the delegate.
1692 The section is evaluated using the \l {ListView::section.property}{section} properties.
1696 \qmlattachedproperty string QtQuick2::ListView::section
1697 This attached property holds the section of this element.
1699 It is attached to each instance of the delegate.
1701 The section is evaluated using the \l {ListView::section.property}{section} properties.
1705 \qmlattachedproperty bool QtQuick2::ListView::delayRemove
1707 This attached property holds whether the delegate may be destroyed. It
1708 is attached to each instance of the delegate. The default value is false.
1710 It is sometimes necessary to delay the destruction of an item
1711 until an animation completes. The example delegate below ensures that the
1712 animation completes before the item is removed from the list.
1714 \snippet doc/src/snippets/declarative/listview/listview.qml delayRemove
1716 If a \l remove transition has been specified, it will not be applied until
1717 delayRemove is returned to \c false.
1721 \qmlattachedsignal QtQuick2::ListView::onAdd()
1722 This attached signal handler is called immediately after an item is added to the view.
1724 If an \l add transition is specified, it is applied immediately after
1725 this signal handler is called.
1729 \qmlattachedsignal QtQuick2::ListView::onRemove()
1730 This attached handler is called immediately before an item is removed from the view.
1732 If a \l remove transition has been specified, it is applied after
1733 this signal handler is called, providing that delayRemove is false.
1737 \qmlproperty model QtQuick2::ListView::model
1738 This property holds the model providing data for the list.
1740 The model provides the set of data that is used to create the items
1741 in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
1742 or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
1743 used, it must be a subclass of \l QAbstractItemModel or a simple list.
1745 \sa {qmlmodels}{Data Models}
1749 \qmlproperty Component QtQuick2::ListView::delegate
1751 The delegate provides a template defining each item instantiated by the view.
1752 The index is exposed as an accessible \c index property. Properties of the
1753 model are also available depending upon the type of \l {qmlmodels}{Data Model}.
1755 The number of elements in the delegate has a direct effect on the
1756 flicking performance of the view. If at all possible, place functionality
1757 that is not needed for the normal display of the delegate in a \l Loader which
1758 can load additional elements when needed.
1760 The ListView will lay out the items based on the size of the root item
1763 It is recommended that the delegate's size be a whole number to avoid sub-pixel
1766 \note Delegates are instantiated as needed and may be destroyed at any time.
1767 State should \e never be stored in a delegate.
1770 \qmlproperty int QtQuick2::ListView::currentIndex
1771 \qmlproperty Item QtQuick2::ListView::currentItem
1773 The \c currentIndex property holds the index of the current item, and
1774 \c currentItem holds the current item. Setting the currentIndex to -1
1775 will clear the highlight and set currentItem to null.
1777 If highlightFollowsCurrentItem is \c true, setting either of these
1778 properties will smoothly scroll the ListView so that the current
1779 item becomes visible.
1781 Note that the position of the current item
1782 may only be approximate until it becomes visible in the view.
1786 \qmlproperty Item QtQuick2::ListView::highlightItem
1788 This holds the highlight item created from the \l highlight component.
1790 The \c highlightItem is managed by the view unless
1791 \l highlightFollowsCurrentItem is set to false.
1793 \sa highlight, highlightFollowsCurrentItem
1797 \qmlproperty int QtQuick2::ListView::count
1798 This property holds the number of items in the view.
1802 \qmlproperty Component QtQuick2::ListView::highlight
1803 This property holds the component to use as the highlight.
1805 An instance of the highlight component is created for each list.
1806 The geometry of the resulting component instance is managed by the list
1807 so as to stay with the current item, unless the highlightFollowsCurrentItem
1810 \sa highlightItem, highlightFollowsCurrentItem, {declarative/modelviews/listview}{ListView examples}
1814 \qmlproperty bool QtQuick2::ListView::highlightFollowsCurrentItem
1815 This property holds whether the highlight is managed by the view.
1817 If this property is true (the default value), the highlight is moved smoothly
1818 to follow the current item. Otherwise, the
1819 highlight is not moved by the view, and any movement must be implemented
1822 Here is a highlight with its motion defined by a \l {SpringAnimation} item:
1824 \snippet doc/src/snippets/declarative/listview/listview.qml highlightFollowsCurrentItem
1826 Note that the highlight animation also affects the way that the view
1827 is scrolled. This is because the view moves to maintain the
1828 highlight within the preferred highlight range (or visible viewport).
1830 \sa highlight, highlightMoveSpeed
1832 //###Possibly rename these properties, since they are very useful even without a highlight?
1834 \qmlproperty real QtQuick2::ListView::preferredHighlightBegin
1835 \qmlproperty real QtQuick2::ListView::preferredHighlightEnd
1836 \qmlproperty enumeration QtQuick2::ListView::highlightRangeMode
1838 These properties define the preferred range of the highlight (for the current item)
1839 within the view. The \c preferredHighlightBegin value must be less than the
1840 \c preferredHighlightEnd value.
1842 These properties affect the position of the current item when the list is scrolled.
1843 For example, if the currently selected item should stay in the middle of the
1844 list when the view is scrolled, set the \c preferredHighlightBegin and
1845 \c preferredHighlightEnd values to the top and bottom coordinates of where the middle
1846 item would be. If the \c currentItem is changed programmatically, the list will
1847 automatically scroll so that the current item is in the middle of the view.
1848 Furthermore, the behavior of the current item index will occur whether or not a
1851 Valid values for \c highlightRangeMode are:
1854 \o ListView.ApplyRange - the view attempts to maintain the highlight within the range.
1855 However, the highlight can move outside of the range at the ends of the list or due
1856 to mouse interaction.
1857 \o ListView.StrictlyEnforceRange - the highlight never moves outside of the range.
1858 The current item changes if a keyboard or mouse action would cause the highlight to move
1859 outside of the range.
1860 \o ListView.NoHighlightRange - this is the default value.
1863 void QQuickListView::setHighlightFollowsCurrentItem(bool autoHighlight)
1865 Q_D(QQuickListView);
1866 if (d->autoHighlight != autoHighlight) {
1867 if (!autoHighlight) {
1868 if (d->highlightPosAnimator)
1869 d->highlightPosAnimator->stop();
1870 if (d->highlightSizeAnimator)
1871 d->highlightSizeAnimator->stop();
1873 QQuickItemView::setHighlightFollowsCurrentItem(autoHighlight);
1878 \qmlproperty real QtQuick2::ListView::spacing
1880 This property holds the spacing between items.
1882 The default value is 0.
1884 qreal QQuickListView::spacing() const
1886 Q_D(const QQuickListView);
1890 void QQuickListView::setSpacing(qreal spacing)
1892 Q_D(QQuickListView);
1893 if (spacing != d->spacing) {
1894 d->spacing = spacing;
1895 d->forceLayout = true;
1897 emit spacingChanged();
1902 \qmlproperty enumeration QtQuick2::ListView::orientation
1903 This property holds the orientation of the list.
1908 \o ListView.Horizontal - Items are laid out horizontally
1909 \o ListView.Vertical (default) - Items are laid out vertically
1914 \o Horizontal orientation:
1915 \image ListViewHorizontal.png
1918 \o Vertical orientation:
1919 \image listview-highlight.png
1922 QQuickListView::Orientation QQuickListView::orientation() const
1924 Q_D(const QQuickListView);
1928 void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
1930 Q_D(QQuickListView);
1931 if (d->orient != orientation) {
1932 d->orient = orientation;
1933 if (d->orient == Vertical) {
1934 setContentWidth(-1);
1935 setFlickableDirection(VerticalFlick);
1938 setContentHeight(-1);
1939 setFlickableDirection(HorizontalFlick);
1943 emit orientationChanged();
1948 \qmlproperty enumeration QtQuick2::ListView::layoutDirection
1949 This property holds the layout direction of the horizontal list.
1954 \o Qt.LeftToRight (default) - Items will be laid out from left to right.
1955 \o Qt.RightToLeft - Items will be laid out from right to let.
1958 \sa ListView::effectiveLayoutDirection
1963 \qmlproperty enumeration QtQuick2::ListView::effectiveLayoutDirection
1964 This property holds the effective layout direction of the horizontal list.
1966 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1967 the visual layout direction of the horizontal list will be mirrored. However, the
1968 property \l {ListView::layoutDirection}{layoutDirection} will remain unchanged.
1970 \sa ListView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1974 \qmlproperty bool QtQuick2::ListView::keyNavigationWraps
1975 This property holds whether the list wraps key navigation.
1977 If this is true, key navigation that would move the current item selection
1978 past the end of the list instead wraps around and moves the selection to
1979 the start of the list, and vice-versa.
1981 By default, key navigation is not wrapped.
1986 \qmlproperty int QtQuick2::ListView::cacheBuffer
1987 This property determines whether delegates are retained outside the
1988 visible area of the view.
1990 If this value is non-zero, the view may keep as many delegates
1991 instantiated as it can fit within the buffer specified. For example,
1992 if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
1993 set to 40, then up to 2 delegates above and 2 delegates below the visible
1994 area may be created/retained. The buffered delegates are created asynchronously,
1995 allowing creation to occur across multiple frames and reducing the
1996 likelihood of skipping frames. In order to improve painting performance
1997 delegates outside the visible area have their \l visible property set to
1998 false until they are moved into the visible area.
2000 Note that cacheBuffer is not a pixel buffer - it only maintains additional
2001 instantiated delegates.
2003 Setting this value can improve the smoothness of scrolling behavior at the expense
2004 of additional memory usage. It is not a substitute for creating efficient
2005 delegates; the fewer elements in a delegate, the faster a view can be
2011 \qmlproperty string QtQuick2::ListView::section.property
2012 \qmlproperty enumeration QtQuick2::ListView::section.criteria
2013 \qmlproperty Component QtQuick2::ListView::section.delegate
2014 \qmlproperty enumeration QtQuick2::ListView::section.labelPositioning
2016 These properties determine the expression to be evaluated and appearance
2017 of the section labels.
2019 \c section.property holds the name of the property that is the basis
2022 \c section.criteria holds the criteria for forming each section based on
2023 \c section.property. This value can be one of:
2026 \o ViewSection.FullString (default) - sections are created based on the
2027 \c section.property value.
2028 \o ViewSection.FirstCharacter - sections are created based on the first
2029 character of the \c section.property value (for example, 'A', 'B', 'C'
2030 sections, etc. for an address book)
2033 \c section.delegate holds the delegate component for each section.
2035 \c section.labelPositioning determines whether the current and/or
2036 next section labels stick to the start/end of the view, and whether
2037 the labels are shown inline. This value can be a combination of:
2040 \o ViewSection.InlineLabels - section labels are shown inline between
2041 the item delegates separating sections (default).
2042 \o ViewSection.CurrentLabelAtStart - the current section label sticks to the
2043 start of the view as it is moved.
2044 \o ViewSection.NextLabelAtEnd - the next section label (beyond all visible
2045 sections) sticks to the end of the view as it is moved. \note Enabling
2046 \c ViewSection.NextLabelAtEnd requires the view to scan ahead for the next
2047 section, which has performance implications, especially for slower models.
2050 Each item in the list has attached properties named \c ListView.section,
2051 \c ListView.previousSection and \c ListView.nextSection.
2053 For example, here is a ListView that displays a list of animals, separated
2054 into sections. Each item in the ListView is placed in a different section
2055 depending on the "size" property of the model item. The \c sectionHeading
2056 delegate component provides the light blue bar that marks the beginning of
2060 \snippet examples/declarative/modelviews/listview/sections.qml 0
2062 \image qml-listview-sections-example.png
2064 \note Adding sections to a ListView does not automatically re-order the
2065 list items by the section criteria.
2066 If the model is not ordered by section, then it is possible that
2067 the sections created will not be unique; each boundary between
2068 differing sections will result in a section header being created
2069 even if that section exists elsewhere.
2071 \sa {declarative/modelviews/listview}{ListView examples}
2073 QQuickViewSection *QQuickListView::sectionCriteria()
2075 Q_D(QQuickListView);
2076 if (!d->sectionCriteria) {
2077 d->sectionCriteria = new QQuickViewSection(this);
2078 connect(d->sectionCriteria, SIGNAL(propertyChanged()), this, SLOT(updateSections()));
2080 return d->sectionCriteria;
2084 \qmlproperty string QtQuick2::ListView::currentSection
2085 This property holds the section that is currently at the beginning of the view.
2087 QString QQuickListView::currentSection() const
2089 Q_D(const QQuickListView);
2090 return d->currentSection;
2094 \qmlproperty real QtQuick2::ListView::highlightMoveSpeed
2095 \qmlproperty int QtQuick2::ListView::highlightMoveDuration
2096 \qmlproperty real QtQuick2::ListView::highlightResizeSpeed
2097 \qmlproperty int QtQuick2::ListView::highlightResizeDuration
2099 These properties hold the move and resize animation speed of the highlight delegate.
2101 \l highlightFollowsCurrentItem must be true for these properties
2104 The default value for the speed properties is 400 pixels/second.
2105 The default value for the duration properties is -1, i.e. the
2106 highlight will take as much time as necessary to move at the set speed.
2108 These properties have the same characteristics as a SmoothedAnimation.
2110 \sa highlightFollowsCurrentItem
2112 qreal QQuickListView::highlightMoveSpeed() const
2114 Q_D(const QQuickListView);
2115 return d->highlightMoveSpeed;
2118 void QQuickListView::setHighlightMoveSpeed(qreal speed)
2120 Q_D(QQuickListView);
2121 if (d->highlightMoveSpeed != speed) {
2122 d->highlightMoveSpeed = speed;
2123 if (d->highlightPosAnimator)
2124 d->highlightPosAnimator->velocity = d->highlightMoveSpeed;
2125 emit highlightMoveSpeedChanged();
2129 void QQuickListView::setHighlightMoveDuration(int duration)
2131 Q_D(QQuickListView);
2132 if (d->highlightMoveDuration != duration) {
2133 if (d->highlightPosAnimator)
2134 d->highlightPosAnimator->userDuration = duration;
2135 QQuickItemView::setHighlightMoveDuration(duration);
2139 qreal QQuickListView::highlightResizeSpeed() const
2141 Q_D(const QQuickListView);
2142 return d->highlightResizeSpeed;
2145 void QQuickListView::setHighlightResizeSpeed(qreal speed)
2147 Q_D(QQuickListView);
2148 if (d->highlightResizeSpeed != speed) {
2149 d->highlightResizeSpeed = speed;
2150 if (d->highlightSizeAnimator)
2151 d->highlightSizeAnimator->velocity = d->highlightResizeSpeed;
2152 emit highlightResizeSpeedChanged();
2156 int QQuickListView::highlightResizeDuration() const
2158 Q_D(const QQuickListView);
2159 return d->highlightResizeDuration;
2162 void QQuickListView::setHighlightResizeDuration(int duration)
2164 Q_D(QQuickListView);
2165 if (d->highlightResizeDuration != duration) {
2166 d->highlightResizeDuration = duration;
2167 if (d->highlightSizeAnimator)
2168 d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
2169 emit highlightResizeDurationChanged();
2174 \qmlproperty enumeration QtQuick2::ListView::snapMode
2176 This property determines how the view scrolling will settle following a drag or flick.
2177 The possible values are:
2180 \o ListView.NoSnap (default) - the view stops anywhere within the visible area.
2181 \o ListView.SnapToItem - the view settles with an item aligned with the start of
2183 \o ListView.SnapOneItem - the view settles no more than one item away from the first
2184 visible item at the time the mouse button is released. This mode is particularly
2185 useful for moving one page at a time.
2188 \c snapMode does not affect the \l currentIndex. To update the
2189 \l currentIndex as the list is moved, set \l highlightRangeMode
2190 to \c ListView.StrictlyEnforceRange.
2192 \sa highlightRangeMode
2194 QQuickListView::SnapMode QQuickListView::snapMode() const
2196 Q_D(const QQuickListView);
2200 void QQuickListView::setSnapMode(SnapMode mode)
2202 Q_D(QQuickListView);
2203 if (d->snapMode != mode) {
2205 emit snapModeChanged();
2211 \qmlproperty Component QtQuick2::ListView::footer
2212 This property holds the component to use as the footer.
2214 An instance of the footer component is created for each view. The
2215 footer is positioned at the end of the view, after any items.
2217 \sa header, footerItem
2222 \qmlproperty Component QtQuick2::ListView::header
2223 This property holds the component to use as the header.
2225 An instance of the header component is created for each view. The
2226 header is positioned at the beginning of the view, before any items.
2228 \sa footer, headertem
2232 \qmlproperty Item QtQuick2::ListView::headerItem
2233 This holds the header item created from the \l header component.
2235 An instance of the header component is created for each view. The
2236 header is positioned at the beginning of the view, before any items.
2238 \sa header, footerItem
2242 \qmlproperty Item QtQuick2::ListView::footerItem
2243 This holds the footer item created from the \l footer component.
2245 An instance of the footer component is created for each view. The
2246 footer is positioned at the end of the view, after any items.
2248 \sa footer, headerItem
2252 \qmlproperty Transition QtQuick2::ListView::populate
2254 This property holds the transition to apply to the items that are initially created
2257 It is applied to all items that are created when:
2260 \o The view is first created
2261 \o The view's \l model changes
2262 \o The view's \l model is \l {QAbstractItemModel::reset}{reset}, if the model is a QAbstractItemModel subclass
2265 For example, here is a view that specifies such a transition:
2270 populate: Transition {
2271 NumberAnimation { properties: "x,y"; duration: 1000 }
2276 When the view is initialized, the view will create all the necessary items for the view,
2277 then animate them to their correct positions within the view over one second.
2279 For more details and examples on how to use view transitions, see the ViewTransition
2282 \sa add, ViewTransition
2286 \qmlproperty Transition QtQuick2::ListView::add
2288 This property holds the transition to apply to items that are added to the view.
2290 For example, here is a view that specifies such a transition:
2296 NumberAnimation { properties: "x,y"; from: 100; duration: 1000 }
2301 Whenever an item is added to the above view, the item will be animated from the position (100,100)
2302 to its final x,y position within the view, over one second. The transition only applies to
2303 the new items that are added to the view; it does not apply to the items below that are
2304 displaced by the addition of the new items. To animate the displaced items, set the \l displaced
2305 or \l addDisplaced properties.
2307 For more details and examples on how to use view transitions, see the ViewTransition
2310 \note This transition is not applied to the items that are created when the view is initially
2311 populated, or when the view's \l model changes. In those cases, the \l populate transition is
2314 \sa addDisplaced, populate, ViewTransition
2318 \qmlproperty Transition QtQuick2::ListView::addDisplaced
2320 This property holds the transition to apply to items within the view that are displaced by
2321 the addition of other items to the view.
2323 For example, here is a view that specifies such a transition:
2328 addDisplaced: Transition {
2329 NumberAnimation { properties: "x,y"; duration: 1000 }
2334 Whenever an item is added to the above view, all items beneath the new item are displaced, causing
2335 them to move down (or sideways, if horizontally orientated) within the view. As this
2336 displacement occurs, the items' movement to their new x,y positions within the view will be
2337 animated by a NumberAnimation over one second, as specified. This transition is not applied to
2338 the new item that has been added to the view; to animate the added items, set the \l add
2341 If an item is displaced by multiple types of operations at the same time, it is not defined as to
2342 whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2343 if it is not necessary to specify different transitions depending on whether an item is displaced
2344 by an add, move or remove operation, consider setting the \l displaced property instead.
2346 For more details and examples on how to use view transitions, see the ViewTransition
2349 \note This transition is not applied to the items that are created when the view is initially
2350 populated, or when the view's \l model changes. In those cases, the \l populate transition is
2353 \sa displaced, add, populate, ViewTransition
2357 \qmlproperty Transition QtQuick2::ListView::move
2359 This property holds the transition to apply to items in the view that are being moved due
2360 to a move operation in the view's \l model.
2362 For example, here is a view that specifies such a transition:
2368 NumberAnimation { properties: "x,y"; duration: 1000 }
2373 Whenever the \l model performs a move operation to move a particular set of indexes, the
2374 respective items in the view will be animated to their new positions in the view over one
2375 second. The transition only applies to the items that are the subject of the move operation
2376 in the model; it does not apply to items below them that are displaced by the move operation.
2377 To animate the displaced items, set the \l displaced or \l moveDisplaced properties.
2379 For more details and examples on how to use view transitions, see the ViewTransition
2382 \sa moveDisplaced, ViewTransition
2386 \qmlproperty Transition QtQuick2::ListView::moveDisplaced
2388 This property holds the transition to apply to items that are displaced by a move operation in
2389 the view's \l model.
2391 For example, here is a view that specifies such a transition:
2396 moveDisplaced: Transition {
2397 NumberAnimation { properties: "x,y"; duration: 1000 }
2402 Whenever the \l model performs a move operation to move a particular set of indexes, the items
2403 between the source and destination indexes of the move operation are displaced, causing them
2404 to move upwards or downwards (or sideways, if horizontally orientated) within the view. As this
2405 displacement occurs, the items' movement to their new x,y positions within the view will be
2406 animated by a NumberAnimation over one second, as specified. This transition is not applied to
2407 the items that are the actual subjects of the move operation; to animate the moved items, set
2408 the \l move property.
2410 If an item is displaced by multiple types of operations at the same time, it is not defined as to
2411 whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2412 if it is not necessary to specify different transitions depending on whether an item is displaced
2413 by an add, move or remove operation, consider setting the \l displaced property instead.
2415 For more details and examples on how to use view transitions, see the ViewTransition
2418 \sa displaced, move, ViewTransition
2422 \qmlproperty Transition QtQuick2::ListView::remove
2424 This property holds the transition to apply to items that are removed from the view.
2426 For example, here is a view that specifies such a transition:
2431 remove: Transition {
2433 NumberAnimation { property: "opacity"; to: 0; duration: 1000 }
2434 NumberAnimation { properties: "x,y"; to: 100; duration: 1000 }
2440 Whenever an item is removed from the above view, the item will be animated to the position (100,100)
2441 over one second, and in parallel will also change its opacity to 0. The transition
2442 only applies to the items that are removed from the view; it does not apply to the items below
2443 them that are displaced by the removal of the items. To animate the displaced items, set the
2444 \l displaced or \l removeDisplaced properties.
2446 Note that by the time the transition is applied, the item has already been removed from the
2447 model; any references to the model data for the removed index will not be valid.
2449 Additionally, if the \l delayRemove attached property has been set for a delegate item, the
2450 remove transition will not be applied until \l delayRemove becomes false again.
2452 For more details and examples on how to use view transitions, see the ViewTransition
2455 \sa removeDisplaced, ViewTransition
2459 \qmlproperty Transition QtQuick2::ListView::removeDisplaced
2461 This property holds the transition to apply to items in the view that are displaced by the
2462 removal of other items in the view.
2464 For example, here is a view that specifies such a transition:
2469 removeDisplaced: Transition {
2470 NumberAnimation { properties: "x,y"; duration: 1000 }
2475 Whenever an item is removed from the above view, all items beneath it are displaced, causing
2476 them to move upwards (or sideways, if horizontally orientated) within the view. As this
2477 displacement occurs, the items' movement to their new x,y positions within the view will be
2478 animated by a NumberAnimation over one second, as specified. This transition is not applied to
2479 the item that has actually been removed from the view; to animate the removed items, set the
2482 If an item is displaced by multiple types of operations at the same time, it is not defined as to
2483 whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2484 if it is not necessary to specify different transitions depending on whether an item is displaced
2485 by an add, move or remove operation, consider setting the \l displaced property instead.
2487 For more details and examples on how to use view transitions, see the ViewTransition
2490 \sa displaced, remove, ViewTransition
2494 \qmlproperty Transition QtQuick2::ListView::displaced
2495 This property holds the generic transition to apply to items that have been displaced by
2496 any model operation that affects the view.
2498 This is a convenience for specifying the generic transition to be applied to any items
2499 that are displaced by an add, move or remove operation, without having to specify the
2500 individual addDisplaced, moveDisplaced and removeDisplaced properties. For example, here
2501 is a view that specifies a displaced transition:
2506 displaced: Transition {
2507 NumberAnimation { properties: "x,y"; duration: 1000 }
2512 When any item is added, moved or removed within the above view, the items below it are
2513 displaced, causing them to move down (or sideways, if horizontally orientated) within the
2514 view. As this displacement occurs, the items' movement to their new x,y positions within
2515 the view will be animated by a NumberAnimation over one second, as specified.
2517 If a view specifies this generic displaced transition as well as a specific addDisplaced,
2518 moveDisplaced or removeDisplaced transition, the more specific transition will be used
2519 instead of the generic displaced transition when the relevant operation occurs, providing that
2520 the more specific transition has not been disabled (by setting \l {Transition::enabled}{enabled}
2521 to false). If it has indeed been disabled, the generic displaced transition is applied instead.
2523 For more details and examples on how to use view transitions, see the ViewTransition
2526 \sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition
2529 void QQuickListView::viewportMoved()
2531 Q_D(QQuickListView);
2532 QQuickItemView::viewportMoved();
2535 // Recursion can occur due to refill changing the content size.
2536 if (d->inViewportMoved)
2538 d->inViewportMoved = true;
2541 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
2542 else if (d->isRightToLeft())
2543 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
2545 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
2549 // Set visibility of items to eliminate cost of items outside the visible area.
2550 qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
2551 qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
2552 for (int i = 0; i < d->visibleItems.count(); ++i) {
2553 FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i));
2554 item->item->setVisible(item->endPosition() >= from && item->position() <= to);
2557 if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2558 d->moveReason = QQuickListViewPrivate::Mouse;
2559 if (d->moveReason != QQuickListViewPrivate::SetIndex) {
2560 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2561 // reposition highlight
2562 qreal pos = d->highlight->position();
2563 qreal viewPos = d->isRightToLeft() ? -d->position()-d->size() : d->position();
2564 if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
2565 pos = viewPos + d->highlightRangeEnd - d->highlight->size();
2566 if (pos < viewPos + d->highlightRangeStart)
2567 pos = viewPos + d->highlightRangeStart;
2568 if (pos != d->highlight->position()) {
2569 d->highlightPosAnimator->stop();
2570 static_cast<FxListItemSG*>(d->highlight)->setPosition(pos);
2572 d->updateHighlight();
2575 // update current index
2576 if (FxViewItem *snapItem = d->snapItemAt(d->highlight->position())) {
2577 if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
2578 d->updateCurrent(snapItem->index);
2583 if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
2584 d->inFlickCorrection = true;
2585 // Near an end and it seems that the extent has changed?
2586 // Recalculate the flick so that we don't end up in an odd position.
2587 if (yflick() && !d->vData.inOvershoot) {
2588 if (d->vData.velocity > 0) {
2589 const qreal minY = minYExtent();
2590 if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
2591 && minY != d->vData.flickTarget)
2592 d->flickY(-d->vData.smoothVelocity.value());
2593 } else if (d->vData.velocity < 0) {
2594 const qreal maxY = maxYExtent();
2595 if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
2596 && maxY != d->vData.flickTarget)
2597 d->flickY(-d->vData.smoothVelocity.value());
2601 if (xflick() && !d->hData.inOvershoot) {
2602 if (d->hData.velocity > 0) {
2603 const qreal minX = minXExtent();
2604 if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
2605 && minX != d->hData.flickTarget)
2606 d->flickX(-d->hData.smoothVelocity.value());
2607 } else if (d->hData.velocity < 0) {
2608 const qreal maxX = maxXExtent();
2609 if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
2610 && maxX != d->hData.flickTarget)
2611 d->flickX(-d->hData.smoothVelocity.value());
2614 d->inFlickCorrection = false;
2616 if (d->sectionCriteria) {
2617 d->updateCurrentSection();
2618 d->updateStickySections();
2620 d->inViewportMoved = false;
2623 void QQuickListView::keyPressEvent(QKeyEvent *event)
2625 Q_D(QQuickListView);
2626 if (d->model && d->model->count() && d->interactive) {
2627 if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left)
2628 || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right)
2629 || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Up)) {
2630 if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) {
2631 decrementCurrentIndex();
2634 } else if (d->wrap) {
2638 } else if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right)
2639 || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left)
2640 || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Down)) {
2641 if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) {
2642 incrementCurrentIndex();
2645 } else if (d->wrap) {
2652 QQuickItemView::keyPressEvent(event);
2655 void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
2657 Q_D(QQuickListView);
2658 if (d->isRightToLeft() && d->orient == QQuickListView::Horizontal) {
2659 // maintain position relative to the right edge
2660 int dx = newGeometry.width() - oldGeometry.width();
2661 setContentX(contentX() - dx);
2663 QQuickItemView::geometryChanged(newGeometry, oldGeometry);
2668 \qmlmethod QtQuick2::ListView::incrementCurrentIndex()
2670 Increments the current index. The current index will wrap
2671 if keyNavigationWraps is true and it is currently at the end.
2672 This method has no effect if the \l count is zero.
2674 \bold Note: methods should only be called after the Component has completed.
2676 void QQuickListView::incrementCurrentIndex()
2678 Q_D(QQuickListView);
2679 int count = d->model ? d->model->count() : 0;
2680 if (count && (currentIndex() < count - 1 || d->wrap)) {
2681 d->moveReason = QQuickListViewPrivate::SetIndex;
2682 int index = currentIndex()+1;
2683 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2688 \qmlmethod QtQuick2::ListView::decrementCurrentIndex()
2690 Decrements the current index. The current index will wrap
2691 if keyNavigationWraps is true and it is currently at the beginning.
2692 This method has no effect if the \l count is zero.
2694 \bold Note: methods should only be called after the Component has completed.
2696 void QQuickListView::decrementCurrentIndex()
2698 Q_D(QQuickListView);
2699 int count = d->model ? d->model->count() : 0;
2700 if (count && (currentIndex() > 0 || d->wrap)) {
2701 d->moveReason = QQuickListViewPrivate::SetIndex;
2702 int index = currentIndex()-1;
2703 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2707 void QQuickListView::updateSections()
2709 Q_D(QQuickListView);
2710 if (isComponentComplete() && d->model) {
2711 QList<QByteArray> roles;
2712 if (d->sectionCriteria && !d->sectionCriteria->property().isEmpty())
2713 roles << d->sectionCriteria->property().toUtf8();
2714 d->model->setWatchedRoles(roles);
2715 d->updateSections();
2717 d->forceLayout = true;
2723 bool QQuickListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::Insert &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
2725 int modelIndex = change.index;
2726 int count = change.count;
2728 qreal tempPos = isRightToLeft() ? -position()-size() : position();
2729 int index = visibleItems.count() ? mapFromModel(modelIndex) : 0;
2732 int i = visibleItems.count() - 1;
2733 while (i > 0 && visibleItems.at(i)->index == -1)
2735 if (i == 0 && visibleItems.first()->index == -1) {
2736 // there are no visible items except items marked for removal
2737 index = visibleItems.count();
2738 } else if (visibleItems.at(i)->index + 1 == modelIndex
2739 && visibleItems.at(i)->endPosition() <= buffer+tempPos+size()) {
2740 // Special case of appending an item to the model.
2741 index = visibleItems.count();
2743 if (modelIndex < visibleIndex) {
2744 // Insert before visible items
2745 visibleIndex += count;
2746 for (int i = 0; i < visibleItems.count(); ++i) {
2747 FxViewItem *item = visibleItems.at(i);
2748 if (item->index != -1 && item->index >= modelIndex)
2749 item->index += count;
2756 // index can be the next item past the end of the visible items list (i.e. appended)
2758 if (visibleItems.count()) {
2759 pos = index < visibleItems.count() ? visibleItems.at(index)->position()
2760 : visibleItems.last()->endPosition()+spacing;
2763 int prevVisibleCount = visibleItems.count();
2764 if (insertResult->visiblePos.isValid() && pos < insertResult->visiblePos) {
2765 // Insert items before the visible item.
2766 int insertionIdx = index;
2768 int from = tempPos - buffer;
2770 for (i = count-1; i >= 0; --i) {
2771 if (pos > from && insertionIdx < visibleIndex) {
2772 // item won't be visible, just note the size for repositioning
2773 insertResult->sizeChangesBeforeVisiblePos += averageSize + spacing;
2774 pos -= averageSize + spacing;
2776 // item is before first visible e.g. in cache buffer
2777 FxViewItem *item = 0;
2778 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2779 item->index = modelIndex + i;
2781 item = createItem(modelIndex + i);
2785 visibleItems.insert(insertionIdx, item);
2786 if (insertionIdx == 0)
2787 insertResult->changedFirstItem = true;
2788 if (!change.isMove()) {
2789 addedItems->append(item);
2791 transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, true);
2793 insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing;
2794 pos -= item->size() + spacing;
2800 int to = buffer+tempPos+size();
2801 for (i = 0; i < count && pos <= to; ++i) {
2802 FxViewItem *item = 0;
2803 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2804 item->index = modelIndex + i;
2805 bool newItem = !item;
2807 item = createItem(modelIndex + i);
2811 visibleItems.insert(index, item);
2813 insertResult->changedFirstItem = true;
2814 if (change.isMove()) {
2815 // we know this is a move target, since move displaced items that are
2816 // shuffled into view due to a move would be added in refill()
2817 if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true))
2818 movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
2820 addedItems->append(item);
2822 transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, true);
2824 insertResult->sizeChangesAfterVisiblePos += item->size() + spacing;
2825 pos += item->size() + spacing;
2830 for (; index < visibleItems.count(); ++index) {
2831 FxViewItem *item = visibleItems.at(index);
2832 if (item->index != -1)
2833 item->index += count;
2835 if (change.isMove())
2836 transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::MoveTransition, false);
2838 transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, false);
2842 updateVisibleIndex();
2844 return visibleItems.count() > prevVisibleCount;
2847 void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult)
2849 Q_UNUSED(insertionResult);
2854 int markerItemIndex = -1;
2855 for (int i=0; i<visibleItems.count(); i++) {
2856 if (visibleItems[i]->index == afterModelIndex) {
2857 markerItemIndex = i;
2861 if (markerItemIndex < 0)
2864 const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
2865 qreal sizeRemoved = -removalResult.sizeChangesAfterVisiblePos
2866 - (removalResult.countChangeAfterVisibleItems * (averageSize + spacing));
2868 for (int i=markerItemIndex+1; i<visibleItems.count() && visibleItems.at(i)->position() < viewEndPos; i++) {
2869 FxListItemSG *listItem = static_cast<FxListItemSG *>(visibleItems[i]);
2870 if (!listItem->transitionScheduledOrRunning()) {
2871 qreal pos = listItem->position();
2872 listItem->setPosition(pos - sizeRemoved);
2873 transitioner->transitionNextReposition(listItem, QQuickItemViewTransitioner::RemoveTransition, false);
2874 listItem->setPosition(pos);
2880 \qmlmethod QtQuick2::ListView::positionViewAtIndex(int index, PositionMode mode)
2882 Positions the view such that the \a index is at the position specified by
2886 \o ListView.Beginning - position item at the top (or left for horizontal orientation) of the view.
2887 \o ListView.Center - position item in the center of the view.
2888 \o ListView.End - position item at bottom (or right for horizontal orientation) of the view.
2889 \o ListView.Visible - if any part of the item is visible then take no action, otherwise
2890 bring the item into view.
2891 \o ListView.Contain - ensure the entire item is visible. If the item is larger than
2892 the view the item is positioned at the top (or left for horizontal orientation) of the view.
2895 If positioning the view at \a index would cause empty space to be displayed at
2896 the beginning or end of the view, the view will be positioned at the boundary.
2898 It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2899 at a particular index. This is unreliable since removing items from the start
2900 of the list does not cause all other items to be repositioned, and because
2901 the actual start of the view can vary based on the size of the delegates.
2902 The correct way to bring an item into view is with \c positionViewAtIndex.
2904 \bold Note: methods should only be called after the Component has completed. To position
2905 the view at startup, this method should be called by Component.onCompleted. For
2906 example, to position the view at the end:
2909 Component.onCompleted: positionViewAtIndex(count - 1, ListView.Beginning)
2914 \qmlmethod QtQuick2::ListView::positionViewAtBeginning()
2915 \qmlmethod QtQuick2::ListView::positionViewAtEnd()
2917 Positions the view at the beginning or end, taking into account any header or footer.
2919 It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2920 at a particular index. This is unreliable since removing items from the start
2921 of the list does not cause all other items to be repositioned, and because
2922 the actual start of the view can vary based on the size of the delegates.
2924 \bold Note: methods should only be called after the Component has completed. To position
2925 the view at startup, this method should be called by Component.onCompleted. For
2926 example, to position the view at the end on startup:
2929 Component.onCompleted: positionViewAtEnd()
2934 \qmlmethod int QtQuick2::ListView::indexAt(int x, int y)
2936 Returns the index of the visible item containing the point \a x, \a y in content
2937 coordinates. If there is no item at the point specified, or the item is
2938 not visible -1 is returned.
2940 If the item is outside the visible area, -1 is returned, regardless of
2941 whether an item will exist at that point when scrolled into view.
2943 \bold Note: methods should only be called after the Component has completed.
2947 \qmlmethod Item QtQuick2::ListView::itemAt(int x, int y)
2949 Returns the visible item containing the point \a x, \a y in content
2950 coordinates. If there is no item at the point specified, or the item is
2951 not visible null is returned.
2953 If the item is outside the visible area, null is returned, regardless of
2954 whether an item will exist at that point when scrolled into view.
2956 \bold Note: methods should only be called after the Component has completed.
2959 QQuickListViewAttached *QQuickListView::qmlAttachedProperties(QObject *obj)
2961 return new QQuickListViewAttached(obj);