1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtQml module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include "qquicklistview_p.h"
43
#include "qquickitemview_p_p.h"
44
#include "qquickvisualitemmodel_p.h"
46
#include <QtQml/qqmlexpression.h>
47
#include <QtQml/qqmlengine.h>
48
#include <QtQml/qqmlinfo.h>
49
#include <QtGui/qevent.h>
50
#include <QtCore/qmath.h>
51
#include <QtCore/qcoreapplication.h>
53
#include <private/qquicksmoothedanimation_p_p.h>
54
#include "qplatformdefs.h"
58
#ifndef QML_FLICK_SNAPONETHRESHOLD
59
#define QML_FLICK_SNAPONETHRESHOLD 30
62
//#define DEBUG_DELEGATE_LIFECYCLE
66
class QQuickListViewPrivate : public QQuickItemViewPrivate
68
Q_DECLARE_PUBLIC(QQuickListView)
70
static QQuickListViewPrivate* get(QQuickListView *item) { return item->d_func(); }
72
virtual Qt::Orientation layoutOrientation() const;
73
virtual bool isContentFlowReversed() const;
74
bool isRightToLeft() const;
75
bool isBottomToTop() 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, qreal bufferFrom, qreal bufferTo, bool doBuffer);
91
virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
92
virtual void visibleItemsChanged();
94
virtual FxViewItem *newViewItem(int index, QQuickItem *item);
95
virtual void initializeViewItem(FxViewItem *item);
96
virtual bool releaseItem(FxViewItem *item);
97
virtual void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer);
98
virtual void repositionPackageItemAt(QQuickItem *item, int index);
99
virtual void resetFirstItemPosition(qreal pos = 0.0);
100
virtual void adjustFirstItem(qreal forwards, qreal backwards, int);
102
virtual void createHighlight();
103
virtual void updateHighlight();
104
virtual void resetHighlightPosition();
106
virtual void setPosition(qreal pos);
107
virtual void layoutVisibleItems(int fromModelIndex = 0);
109
virtual bool applyInsertionChange(const QQuickChangeSet::Insert &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView);
110
virtual void translateAndTransitionItemsAfter(int afterIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult);
112
virtual void updateSectionCriteria();
113
virtual void updateSections();
114
QQuickItem *getSectionItem(const QString §ion);
115
void releaseSectionItem(QQuickItem *item);
116
void releaseSectionItems();
117
void updateInlineSection(FxListItemSG *);
118
void updateCurrentSection();
119
void updateStickySections();
121
virtual qreal headerSize() const;
122
virtual qreal footerSize() const;
123
virtual bool showHeaderForIndex(int index) const;
124
virtual bool showFooterForIndex(int index) const;
125
virtual void updateHeader();
126
virtual void updateFooter();
128
virtual void changedVisibleIndex(int newIndex);
129
virtual void initializeCurrentItem();
131
void updateAverage();
133
void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
134
virtual void fixupPosition();
135
virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
136
virtual bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
137
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity);
139
QQuickListView::Orientation orient;
143
QQuickListView::SnapMode snapMode;
145
QSmoothedAnimation *highlightPosAnimator;
146
QSmoothedAnimation *highlightSizeAnimator;
147
qreal highlightMoveVelocity;
148
qreal highlightResizeVelocity;
149
int highlightResizeDuration;
151
QQuickViewSection *sectionCriteria;
152
QString currentSection;
153
static const int sectionCacheSize = 5;
154
QQuickItem *sectionCache[sectionCacheSize];
155
QQuickItem *currentSectionItem;
156
QString currentStickySection;
157
QQuickItem *nextSectionItem;
158
QString nextStickySection;
159
QString lastVisibleSection;
163
bool correctFlick : 1;
164
bool inFlickCorrection : 1;
166
QQuickListViewPrivate()
167
: orient(QQuickListView::Vertical)
169
, averageSize(100.0), spacing(0.0)
170
, snapMode(QQuickListView::NoSnap)
171
, highlightPosAnimator(0), highlightSizeAnimator(0)
172
, highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
173
, sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
174
, overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
176
~QQuickListViewPrivate() {
177
delete highlightPosAnimator;
178
delete highlightSizeAnimator;
181
friend class QQuickViewSection;
184
//----------------------------------------------------------------------------
186
QQuickViewSection::QQuickViewSection(QQuickListView *parent)
187
: QObject(parent), m_criteria(FullString), m_delegate(0), m_labelPositioning(InlineLabels)
188
, m_view(parent ? QQuickListViewPrivate::get(parent) : 0)
192
void QQuickViewSection::setProperty(const QString &property)
194
if (property != m_property) {
195
m_property = property;
196
emit propertyChanged();
197
// notify view that the contents of the sections must be recalculated
198
m_view->updateSectionCriteria();
202
void QQuickViewSection::setCriteria(QQuickViewSection::SectionCriteria criteria)
204
if (criteria != m_criteria) {
205
m_criteria = criteria;
206
emit criteriaChanged();
207
// notify view that the contents of the sections must be recalculated
208
m_view->updateSectionCriteria();
212
void QQuickViewSection::setDelegate(QQmlComponent *delegate)
214
if (delegate != m_delegate) {
216
m_view->releaseSectionItems();
217
m_delegate = delegate;
218
emit delegateChanged();
219
m_view->forceLayoutPolish();
223
QString QQuickViewSection::sectionString(const QString &value)
225
if (m_criteria == FirstCharacter)
226
return value.isEmpty() ? QString() : value.at(0);
231
void QQuickViewSection::setLabelPositioning(int l)
233
if (m_labelPositioning != l) {
234
m_labelPositioning = l;
235
emit labelPositioningChanged();
236
m_view->forceLayoutPolish();
240
//----------------------------------------------------------------------------
242
class FxListItemSG : public FxViewItem
245
FxListItemSG(QQuickItem *i, QQuickListView *v, bool own, bool trackGeometry) : FxViewItem(i, own, trackGeometry), view(v) {
246
attached = static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(item));
248
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
249
itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
255
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
256
itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
260
inline QQuickItem *section() const {
261
return attached ? static_cast<QQuickListViewAttached*>(attached)->m_sectionItem : 0;
263
void setSection(QQuickItem *s) {
265
attached = static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(item));
266
static_cast<QQuickListViewAttached*>(attached)->m_sectionItem = s;
269
qreal position() const {
271
if (view->orientation() == QQuickListView::Vertical)
272
return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -section()->height()-section()->y() : section()->y());
274
return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section()->width()-section()->x() : section()->x());
276
return itemPosition();
279
qreal itemPosition() const {
280
if (view->orientation() == QQuickListView::Vertical)
281
return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -item->height()-itemY() : itemY());
283
return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX());
287
return (view->orientation() == QQuickListView::Vertical ? item->height()+section()->height() : item->width()+section()->width());
289
return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
291
qreal itemSize() const {
292
return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width());
294
qreal sectionSize() const {
296
return (view->orientation() == QQuickListView::Vertical ? section()->height() : section()->width());
299
qreal endPosition() const {
300
if (view->orientation() == QQuickListView::Vertical) {
301
return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop
303
: itemY() + item->height());
305
return (view->effectiveLayoutDirection() == Qt::RightToLeft
307
: itemX() + item->width());
310
void setPosition(qreal pos, bool immediate = false) {
311
// position the section immediately even if there is a transition
313
if (view->orientation() == QQuickListView::Vertical) {
314
if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop)
315
section()->setY(-section()->height()-pos);
317
section()->setY(pos);
319
if (view->effectiveLayoutDirection() == Qt::RightToLeft)
320
section()->setX(-section()->width()-pos);
322
section()->setX(pos);
325
moveTo(pointForPosition(pos), immediate);
327
void setSize(qreal size) {
328
if (view->orientation() == QQuickListView::Vertical)
329
item->setHeight(size);
331
item->setWidth(size);
333
bool contains(qreal x, qreal y) const {
334
return (x >= itemX() && x < itemX() + item->width() &&
335
y >= itemY() && y < itemY() + item->height());
338
QQuickListView *view;
341
QPointF pointForPosition(qreal pos) const {
342
if (view->orientation() == QQuickListView::Vertical) {
343
if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) {
345
pos += section()->height();
346
return QPointF(itemX(), -item->height() - pos);
349
pos += section()->height();
350
return QPointF(itemX(), pos);
353
if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
355
pos += section()->width();
356
return QPointF(-item->width() - pos, itemY());
359
pos += section()->width();
360
return QPointF(pos, itemY());
366
//----------------------------------------------------------------------------
368
bool QQuickListViewPrivate::isContentFlowReversed() const
370
return isRightToLeft() || isBottomToTop();
373
Qt::Orientation QQuickListViewPrivate::layoutOrientation() const
375
return static_cast<Qt::Orientation>(orient);
378
bool QQuickListViewPrivate::isRightToLeft() const
380
Q_Q(const QQuickListView);
381
return orient == QQuickListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
384
bool QQuickListViewPrivate::isBottomToTop() const
386
return orient == QQuickListView::Vertical && verticalLayoutDirection == QQuickItemView::BottomToTop;
389
// Returns the item before modelIndex, if created.
390
// May return an item marked for removal.
391
FxViewItem *QQuickListViewPrivate::itemBefore(int modelIndex) const
393
if (modelIndex < visibleIndex)
397
while (idx < visibleItems.count()) {
398
FxViewItem *item = visibleItems.at(idx);
399
if (item->index != -1)
400
lastIndex = item->index;
401
if (item->index == modelIndex)
402
return visibleItems.at(idx-1);
405
if (lastIndex == modelIndex-1)
406
return visibleItems.last();
410
void QQuickListViewPrivate::setPosition(qreal pos)
413
if (orient == QQuickListView::Vertical) {
415
q->QQuickFlickable::setContentY(-pos-size());
417
q->QQuickFlickable::setContentY(pos);
420
q->QQuickFlickable::setContentX(-pos-size());
422
q->QQuickFlickable::setContentX(pos);
426
qreal QQuickListViewPrivate::originPosition() const
429
if (!visibleItems.isEmpty()) {
430
pos = (*visibleItems.constBegin())->position();
431
if (visibleIndex > 0)
432
pos -= visibleIndex * (averageSize + spacing);
437
qreal QQuickListViewPrivate::lastPosition() const
440
if (!visibleItems.isEmpty()) {
441
int invisibleCount = visibleItems.count() - visibleIndex;
442
for (int i = visibleItems.count()-1; i >= 0; --i) {
443
if (visibleItems.at(i)->index != -1) {
444
invisibleCount = model->count() - visibleItems.at(i)->index - 1;
448
pos = (*(--visibleItems.constEnd()))->endPosition() + invisibleCount * (averageSize + spacing);
449
} else if (model && model->count()) {
450
pos = (model->count() * averageSize + (model->count()-1) * spacing);
455
qreal QQuickListViewPrivate::positionAt(int modelIndex) const
457
if (FxViewItem *item = visibleItem(modelIndex)) {
458
return item->position();
460
if (!visibleItems.isEmpty()) {
461
if (modelIndex < visibleIndex) {
462
int count = visibleIndex - modelIndex;
464
if (modelIndex == currentIndex && currentItem) {
465
cs = currentItem->size() + spacing;
468
return (*visibleItems.constBegin())->position() - count * (averageSize + spacing) - cs;
470
int count = modelIndex - findLastVisibleIndex(visibleIndex) - 1;
471
return (*(--visibleItems.constEnd()))->endPosition() + spacing + count * (averageSize + spacing);
477
qreal QQuickListViewPrivate::endPositionAt(int modelIndex) const
479
if (FxViewItem *item = visibleItem(modelIndex))
480
return item->endPosition();
481
if (!visibleItems.isEmpty()) {
482
if (modelIndex < visibleIndex) {
483
int count = visibleIndex - modelIndex;
484
return (*visibleItems.constBegin())->position() - (count - 1) * (averageSize + spacing) - spacing;
486
int count = modelIndex - findLastVisibleIndex(visibleIndex) - 1;
487
return (*(--visibleItems.constEnd()))->endPosition() + count * (averageSize + spacing);
493
QString QQuickListViewPrivate::sectionAt(int modelIndex)
495
if (FxViewItem *item = visibleItem(modelIndex))
496
return item->attached->section();
499
if (sectionCriteria) {
500
QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
501
section = sectionCriteria->sectionString(propValue);
507
qreal QQuickListViewPrivate::snapPosAt(qreal pos)
509
if (FxViewItem *snapItem = snapItemAt(pos))
510
return snapItem->position();
511
if (visibleItems.count()) {
512
qreal firstPos = (*visibleItems.constBegin())->position();
513
qreal endPos = (*(--visibleItems.constEnd()))->position();
514
if (pos < firstPos) {
515
return firstPos - qRound((firstPos - pos) / averageSize) * averageSize;
516
} else if (pos > endPos)
517
return endPos + qRound((pos - endPos) / averageSize) * averageSize;
519
return qRound((pos - originPosition()) / averageSize) * averageSize + originPosition();
522
FxViewItem *QQuickListViewPrivate::snapItemAt(qreal pos)
524
FxViewItem *snapItem = 0;
525
qreal prevItemSize = 0;
526
for (int i = 0; i < visibleItems.count(); ++i) {
527
FxViewItem *item = visibleItems.at(i);
528
if (item->index == -1)
530
qreal itemTop = item->position();
531
if (highlight && itemTop >= pos && item->endPosition() <= pos + highlight->size())
533
if (itemTop+item->size()/2 >= pos && itemTop-prevItemSize/2 < pos)
535
prevItemSize = item->size();
540
void QQuickListViewPrivate::changedVisibleIndex(int newIndex)
542
visiblePos = positionAt(newIndex);
543
visibleIndex = newIndex;
546
void QQuickListViewPrivate::init()
548
QQuickItemViewPrivate::init();
549
::memset(sectionCache, 0, sizeof(QQuickItem*) * sectionCacheSize);
552
void QQuickListViewPrivate::clear()
554
for (int i = 0; i < sectionCacheSize; ++i) {
555
delete sectionCache[i];
559
releaseSectionItem(currentSectionItem);
560
currentSectionItem = 0;
561
releaseSectionItem(nextSectionItem);
563
lastVisibleSection = QString();
564
QQuickItemViewPrivate::clear();
567
FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
571
FxListItemSG *listItem = new FxListItemSG(item, q, false, false);
572
listItem->index = modelIndex;
574
// initialise attached properties
575
if (sectionCriteria) {
576
QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
577
listItem->attached->setSection(sectionCriteria->sectionString(propValue));
578
if (modelIndex > 0) {
579
if (FxViewItem *item = itemBefore(modelIndex))
580
listItem->attached->setPrevSection(item->attached->section());
582
listItem->attached->setPrevSection(sectionAt(modelIndex-1));
584
if (modelIndex < model->count()-1) {
585
if (FxViewItem *item = visibleItem(modelIndex+1))
586
listItem->attached->setNextSection(static_cast<QQuickListViewAttached*>(item->attached)->section());
588
listItem->attached->setNextSection(sectionAt(modelIndex+1));
595
void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
597
QQuickItemViewPrivate::initializeViewItem(item);
599
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item->item);
600
itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
602
if (sectionCriteria && sectionCriteria->delegate()) {
603
if (QString::compare(item->attached->m_prevSection, item->attached->m_section, Qt::CaseInsensitive))
604
updateInlineSection(static_cast<FxListItemSG*>(item));
608
bool QQuickListViewPrivate::releaseItem(FxViewItem *item)
613
QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached);
615
bool released = QQuickItemViewPrivate::releaseItem(item);
616
if (released && att && att->m_sectionItem) {
617
// We hold no more references to this item
620
if (!sectionCache[i]) {
621
sectionCache[i] = att->m_sectionItem;
622
sectionCache[i]->setVisible(false);
623
att->m_sectionItem = 0;
627
} while (i < sectionCacheSize);
628
delete att->m_sectionItem;
629
att->m_sectionItem = 0;
635
bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer)
637
qreal itemEnd = visiblePos;
638
if (visibleItems.count()) {
639
visiblePos = (*visibleItems.constBegin())->position();
640
itemEnd = (*(--visibleItems.constEnd()))->endPosition() + spacing;
643
int modelIndex = findLastVisibleIndex();
644
bool haveValidItems = modelIndex >= 0;
645
modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
647
if (haveValidItems && (bufferFrom > itemEnd+averageSize+spacing
648
|| bufferTo < visiblePos - averageSize - spacing)) {
649
// We've jumped more than a page. Estimate which items are now
650
// visible and fill from there.
651
int count = (fillFrom - itemEnd) / (averageSize + spacing);
652
int newModelIdx = qBound(0, modelIndex + count, model->count());
653
count = newModelIdx - modelIndex;
655
for (int i = 0; i < visibleItems.count(); ++i)
656
releaseItem(visibleItems.at(i));
657
visibleItems.clear();
658
modelIndex = newModelIdx;
659
visibleIndex = modelIndex;
660
visiblePos = itemEnd + count * (averageSize + spacing);
661
itemEnd = visiblePos;
665
bool changed = false;
666
FxListItemSG *item = 0;
668
while (modelIndex < model->count() && pos <= fillTo) {
669
#ifdef DEBUG_DELEGATE_LIFECYCLE
670
qDebug() << "refill: append item" << modelIndex << "pos" << pos << "buffer" << doBuffer;
672
if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, doBuffer))))
674
if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
675
item->setPosition(pos, true);
676
QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
677
pos += item->size() + spacing;
678
visibleItems.append(item);
683
if (doBuffer && requestedIndex != -1) // already waiting for an item
686
while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
687
#ifdef DEBUG_DELEGATE_LIFECYCLE
688
qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos << "buffer" << doBuffer;
690
if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, doBuffer))))
693
visiblePos -= item->size() + spacing;
694
if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
695
item->setPosition(visiblePos, true);
696
QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
697
visibleItems.prepend(item);
704
bool QQuickListViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
706
FxViewItem *item = 0;
707
bool changed = false;
709
// Remove items from the start of the view.
710
// Zero-sized items shouldn't be removed unless a non-zero-sized item is also being
711
// removed, otherwise a zero-sized item is infinitely added and removed over and
714
while (visibleItems.count() > 1 && index < visibleItems.count()
715
&& (item = visibleItems.at(index)) && item->endPosition() < bufferFrom) {
716
if (item->attached->delayRemove())
719
if (item->size() > 0) {
720
#ifdef DEBUG_DELEGATE_LIFECYCLE
721
qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
723
// remove this item and all zero-sized items before it
725
if (item->index != -1)
727
visibleItems.removeAt(index);
728
if (item->transitionScheduledOrRunning()) {
729
#ifdef DEBUG_DELEGATE_LIFECYCLE
730
qDebug() << "refill not releasing animating item" << item->index << item->item->objectName();
732
item->releaseAfterTransition = true;
733
releasePendingTransition.append(item);
739
item = visibleItems.at(--index);
747
while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > bufferTo) {
748
if (item->attached->delayRemove())
750
#ifdef DEBUG_DELEGATE_LIFECYCLE
751
qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1 << item->position();
753
visibleItems.removeLast();
754
if (item->transitionScheduledOrRunning()) {
755
#ifdef DEBUG_DELEGATE_LIFECYCLE
756
qDebug() << "refill not releasing animating item" << item->index << item->item->objectName();
758
item->releaseAfterTransition = true;
759
releasePendingTransition.append(item);
769
void QQuickListViewPrivate::visibleItemsChanged()
771
if (visibleItems.count())
772
visiblePos = (*visibleItems.constBegin())->position();
774
if (currentIndex >= 0 && currentItem && !visibleItem(currentIndex)) {
775
static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
779
updateCurrentSection();
780
updateUnrequestedPositions();
783
void QQuickListViewPrivate::layoutVisibleItems(int fromModelIndex)
785
if (!visibleItems.isEmpty()) {
786
const qreal from = isContentFlowReversed() ? -position() - size() : position();
787
const qreal to = isContentFlowReversed() ? -position() : position() + size();
789
FxViewItem *firstItem = *visibleItems.constBegin();
790
bool fixedCurrent = currentItem && firstItem->item == currentItem->item;
791
qreal sum = firstItem->size();
792
qreal pos = firstItem->position() + firstItem->size() + spacing;
793
firstItem->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
795
for (int i=1; i < visibleItems.count(); ++i) {
796
FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.at(i));
797
if (item->index >= fromModelIndex) {
798
item->setPosition(pos);
799
item->setVisible(item->endPosition() >= from && item->position() <= to);
801
pos += item->size() + spacing;
803
fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
805
averageSize = qRound(sum / visibleItems.count());
807
// move current item if it is not a visible item.
808
if (currentIndex >= 0 && currentItem && !fixedCurrent)
809
static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
811
updateCurrentSection();
812
updateStickySections();
816
void QQuickListViewPrivate::repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer)
818
static_cast<FxListItemSG *>(item)->setPosition(positionAt(index) + sizeBuffer);
821
void QQuickListViewPrivate::repositionPackageItemAt(QQuickItem *item, int index)
824
qreal pos = position();
825
if (orient == QQuickListView::Vertical) {
826
if (item->y() + item->height() > pos && item->y() < pos + q->height()) {
828
item->setY(-positionAt(index)-item->height());
830
item->setY(positionAt(index));
833
if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
835
item->setX(-positionAt(index)-item->width());
837
item->setX(positionAt(index));
842
void QQuickListViewPrivate::resetFirstItemPosition(qreal pos)
844
FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.first());
845
item->setPosition(pos);
848
void QQuickListViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int)
850
if (!visibleItems.count())
852
qreal diff = forwards - backwards;
853
static_cast<FxListItemSG*>(visibleItems.first())->setPosition(visibleItems.first()->position() + diff);
856
void QQuickListViewPrivate::createHighlight()
859
bool changed = false;
861
if (trackedItem == highlight)
866
delete highlightPosAnimator;
867
delete highlightSizeAnimator;
868
highlightPosAnimator = 0;
869
highlightSizeAnimator = 0;
875
QQuickItem *item = createHighlightItem();
877
FxListItemSG *newHighlight = new FxListItemSG(item, q, true, true);
880
newHighlight->setSize(static_cast<FxListItemSG*>(currentItem)->itemSize());
881
newHighlight->setPosition(static_cast<FxListItemSG*>(currentItem)->itemPosition());
883
const QLatin1String posProp(orient == QQuickListView::Vertical ? "y" : "x");
884
highlightPosAnimator = new QSmoothedAnimation;
885
highlightPosAnimator->target = QQmlProperty(item, posProp);
886
highlightPosAnimator->velocity = highlightMoveVelocity;
887
highlightPosAnimator->userDuration = highlightMoveDuration;
889
const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
890
highlightSizeAnimator = new QSmoothedAnimation;
891
highlightSizeAnimator->velocity = highlightResizeVelocity;
892
highlightSizeAnimator->userDuration = highlightResizeDuration;
893
highlightSizeAnimator->target = QQmlProperty(item, sizeProp);
895
highlight = newHighlight;
900
emit q->highlightItemChanged();
903
void QQuickListViewPrivate::updateHighlight()
905
applyPendingChanges();
907
if ((!currentItem && highlight) || (currentItem && !highlight))
909
bool strictHighlight = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
910
if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
911
// auto-update highlight
912
FxListItemSG *listItem = static_cast<FxListItemSG*>(currentItem);
913
highlightPosAnimator->to = isContentFlowReversed()
914
? -listItem->itemPosition()-listItem->itemSize()
915
: listItem->itemPosition();
916
highlightSizeAnimator->to = listItem->itemSize();
917
if (orient == QQuickListView::Vertical) {
918
if (highlight->item->width() == 0)
919
highlight->item->setWidth(currentItem->item->width());
921
if (highlight->item->height() == 0)
922
highlight->item->setHeight(currentItem->item->height());
925
highlightPosAnimator->restart();
926
highlightSizeAnimator->restart();
931
void QQuickListViewPrivate::resetHighlightPosition()
933
if (highlight && currentItem)
934
static_cast<FxListItemSG*>(highlight)->setPosition(static_cast<FxListItemSG*>(currentItem)->itemPosition());
937
QQuickItem * QQuickListViewPrivate::getSectionItem(const QString §ion)
940
QQuickItem *sectionItem = 0;
941
int i = sectionCacheSize-1;
942
while (i >= 0 && !sectionCache[i])
945
sectionItem = sectionCache[i];
947
sectionItem->setVisible(true);
948
QQmlContext *context = QQmlEngine::contextForObject(sectionItem)->parentContext();
949
context->setContextProperty(QLatin1String("section"), section);
951
QQmlContext *creationContext = sectionCriteria->delegate()->creationContext();
952
QQmlContext *context = new QQmlContext(
953
creationContext ? creationContext : qmlContext(q));
954
context->setContextProperty(QLatin1String("section"), section);
955
QObject *nobj = sectionCriteria->delegate()->beginCreate(context);
957
QQml_setParent_noEvent(context, nobj);
958
sectionItem = qobject_cast<QQuickItem *>(nobj);
962
sectionItem->setZ(2);
963
QQml_setParent_noEvent(sectionItem, contentItem);
964
sectionItem->setParentItem(contentItem);
969
sectionCriteria->delegate()->completeCreate();
975
void QQuickListViewPrivate::releaseSectionItem(QQuickItem *item)
981
if (!sectionCache[i]) {
982
sectionCache[i] = item;
983
sectionCache[i]->setVisible(false);
987
} while (i < sectionCacheSize);
992
void QQuickListViewPrivate::releaseSectionItems()
994
for (int i = 0; i < visibleItems.count(); ++i) {
995
FxListItemSG *listItem = static_cast<FxListItemSG *>(visibleItems.at(i));
996
if (listItem->section()) {
997
qreal pos = listItem->position();
998
releaseSectionItem(listItem->section());
999
listItem->setSection(0);
1000
listItem->setPosition(pos);
1003
for (int i = 0; i < sectionCacheSize; ++i) {
1004
delete sectionCache[i];
1005
sectionCache[i] = 0;
1009
void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
1011
if (!sectionCriteria || !sectionCriteria->delegate())
1013
if (QString::compare(listItem->attached->m_prevSection, listItem->attached->m_section, Qt::CaseInsensitive)
1014
&& (sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels
1015
|| (listItem->index == 0 && sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart))) {
1016
if (!listItem->section()) {
1017
qreal pos = listItem->position();
1018
listItem->setSection(getSectionItem(listItem->attached->m_section));
1019
listItem->setPosition(pos);
1021
QQmlContext *context = QQmlEngine::contextForObject(listItem->section())->parentContext();
1022
context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
1024
} else if (listItem->section()) {
1025
qreal pos = listItem->position();
1026
releaseSectionItem(listItem->section());
1027
listItem->setSection(0);
1028
listItem->setPosition(pos);
1032
void QQuickListViewPrivate::updateStickySections()
1034
if (!sectionCriteria
1035
|| (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem))
1038
bool isFlowReversed = isContentFlowReversed();
1039
qreal viewPos = isFlowReversed ? -position()-size() : position();
1040
QQuickItem *sectionItem = 0;
1041
QQuickItem *lastSectionItem = 0;
1043
while (index < visibleItems.count()) {
1044
if (QQuickItem *section = static_cast<FxListItemSG *>(visibleItems.at(index))->section()) {
1045
// Find the current section header and last visible section header
1046
// and hide them if they will overlap a static section header.
1047
qreal sectionPos = orient == QQuickListView::Vertical ? section->y() : section->x();
1048
qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width();
1050
if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
1051
visTop = isFlowReversed ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos;
1053
if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd)
1054
visBot = isFlowReversed ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size();
1055
section->setVisible(visBot && visTop);
1056
if (visTop && !sectionItem)
1057
sectionItem = section;
1058
if (isFlowReversed) {
1059
if (-sectionPos <= viewPos + size())
1060
lastSectionItem = section;
1062
if (sectionPos + sectionSize < viewPos + size())
1063
lastSectionItem = section;
1069
// Current section header
1070
if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart && isValid() && visibleItems.count()) {
1071
if (!currentSectionItem) {
1072
currentSectionItem = getSectionItem(currentSection);
1073
} else if (QString::compare(currentStickySection, currentSection, Qt::CaseInsensitive)) {
1074
QQmlContext *context = QQmlEngine::contextForObject(currentSectionItem)->parentContext();
1075
context->setContextProperty(QLatin1String("section"), currentSection);
1077
currentStickySection = currentSection;
1078
if (!currentSectionItem)
1081
qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1082
bool atBeginning = orient == QQuickListView::Vertical ? (isBottomToTop() ? vData.atEnd : vData.atBeginning) : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
1084
currentSectionItem->setVisible(!atBeginning && (!header || header->endPosition() < viewPos));
1085
qreal pos = isFlowReversed ? position() + size() - sectionSize : viewPos;
1087
qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x();
1088
pos = isFlowReversed ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
1091
pos = isFlowReversed ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos);
1093
pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1094
if (orient == QQuickListView::Vertical)
1095
currentSectionItem->setY(pos);
1097
currentSectionItem->setX(pos);
1098
} else if (currentSectionItem) {
1099
releaseSectionItem(currentSectionItem);
1100
currentSectionItem = 0;
1103
// Next section footer
1104
if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd && isValid() && visibleItems.count()) {
1105
if (!nextSectionItem) {
1106
nextSectionItem = getSectionItem(nextSection);
1107
} else if (QString::compare(nextStickySection, nextSection, Qt::CaseInsensitive)) {
1108
QQmlContext *context = QQmlEngine::contextForObject(nextSectionItem)->parentContext();
1109
context->setContextProperty(QLatin1String("section"), nextSection);
1111
nextStickySection = nextSection;
1112
if (!nextSectionItem)
1115
qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1116
nextSectionItem->setVisible(!nextSection.isEmpty());
1117
qreal pos = isFlowReversed ? position() : viewPos + size() - sectionSize;
1118
if (lastSectionItem) {
1119
qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x();
1120
pos = isFlowReversed ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
1123
pos = isFlowReversed ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1124
if (orient == QQuickListView::Vertical)
1125
nextSectionItem->setY(pos);
1127
nextSectionItem->setX(pos);
1128
} else if (nextSectionItem) {
1129
releaseSectionItem(nextSectionItem);
1130
nextSectionItem = 0;
1134
void QQuickListViewPrivate::updateSections()
1136
Q_Q(QQuickListView);
1137
if (!q->isComponentComplete())
1140
QQuickItemViewPrivate::updateSections();
1142
if (sectionCriteria && !visibleItems.isEmpty() && isValid()) {
1143
QString prevSection;
1144
if (visibleIndex > 0)
1145
prevSection = sectionAt(visibleIndex-1);
1146
QQuickListViewAttached *prevAtt = 0;
1148
for (int i = 0; i < visibleItems.count(); ++i) {
1149
QQuickListViewAttached *attached = static_cast<QQuickListViewAttached*>(visibleItems.at(i)->attached);
1150
attached->setPrevSection(prevSection);
1151
if (visibleItems.at(i)->index != -1) {
1152
QString propValue = model->stringValue(visibleItems.at(i)->index, sectionCriteria->property());
1153
attached->setSection(sectionCriteria->sectionString(propValue));
1154
idx = visibleItems.at(i)->index;
1156
updateInlineSection(static_cast<FxListItemSG*>(visibleItems.at(i)));
1158
prevAtt->setNextSection(attached->section());
1159
prevSection = attached->section();
1163
if (idx > 0 && idx < model->count()-1)
1164
prevAtt->setNextSection(sectionAt(idx+1));
1166
prevAtt->setNextSection(QString());
1170
lastVisibleSection = QString();
1173
void QQuickListViewPrivate::updateCurrentSection()
1175
Q_Q(QQuickListView);
1176
if (!sectionCriteria || visibleItems.isEmpty()) {
1177
if (!currentSection.isEmpty()) {
1178
currentSection.clear();
1179
emit q->currentSectionChanged();
1183
bool inlineSections = sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels;
1184
qreal sectionThreshold = position();
1185
if (currentSectionItem && !inlineSections)
1186
sectionThreshold += orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1188
int modelIndex = visibleIndex;
1189
while (index < visibleItems.count() && visibleItems.at(index)->endPosition() <= sectionThreshold) {
1190
if (visibleItems.at(index)->index != -1)
1191
modelIndex = visibleItems.at(index)->index;
1195
QString newSection = currentSection;
1196
if (index < visibleItems.count())
1197
newSection = visibleItems.at(index)->attached->section();
1199
newSection = (*visibleItems.constBegin())->attached->section();
1200
if (newSection != currentSection) {
1201
currentSection = newSection;
1202
updateStickySections();
1203
emit q->currentSectionChanged();
1206
if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
1207
// Don't want to scan for next section on every movement, so remember
1208
// the last section in the visible area and only scan for the next
1209
// section when that changes. Clearing lastVisibleSection will also
1211
QString lastSection = currentSection;
1212
qreal endPos = isContentFlowReversed() ? -position() : position() + size();
1213
if (nextSectionItem && !inlineSections)
1214
endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1215
while (index < visibleItems.count() && static_cast<FxListItemSG*>(visibleItems.at(index))->itemPosition() < endPos) {
1216
if (visibleItems.at(index)->index != -1)
1217
modelIndex = visibleItems.at(index)->index;
1218
lastSection = visibleItems.at(index)->attached->section();
1222
if (lastVisibleSection != lastSection) {
1223
nextSection = QString();
1224
lastVisibleSection = lastSection;
1225
for (int i = modelIndex; i < itemCount; ++i) {
1226
QString section = sectionAt(i);
1227
if (section != lastSection) {
1228
nextSection = section;
1229
updateStickySections();
1237
void QQuickListViewPrivate::initializeCurrentItem()
1239
QQuickItemViewPrivate::initializeCurrentItem();
1242
FxListItemSG *listItem = static_cast<FxListItemSG *>(currentItem);
1244
// don't reposition the item if it is already in the visibleItems list
1245
FxViewItem *actualItem = visibleItem(currentIndex);
1247
if (currentIndex == visibleIndex - 1 && visibleItems.count()) {
1248
// We can calculate exact postion in this case
1249
listItem->setPosition(visibleItems.first()->position() - currentItem->size() - spacing);
1251
// Create current item now and position as best we can.
1252
// Its position will be corrected when it becomes visible.
1253
listItem->setPosition(positionAt(currentIndex));
1257
if (visibleItems.isEmpty())
1258
averageSize = listItem->size();
1262
void QQuickListViewPrivate::updateAverage()
1264
if (!visibleItems.count())
1267
for (int i = 0; i < visibleItems.count(); ++i)
1268
sum += visibleItems.at(i)->size();
1269
averageSize = qRound(sum / visibleItems.count());
1272
qreal QQuickListViewPrivate::headerSize() const
1274
return header ? header->size() : 0.0;
1277
qreal QQuickListViewPrivate::footerSize() const
1279
return footer ? footer->size() : 0.0;
1282
bool QQuickListViewPrivate::showHeaderForIndex(int index) const
1287
bool QQuickListViewPrivate::showFooterForIndex(int index) const
1289
return index == model->count()-1;
1292
void QQuickListViewPrivate::updateFooter()
1294
Q_Q(QQuickListView);
1295
bool created = false;
1297
QQuickItem *item = createComponentItem(footerComponent, 1.0);
1300
footer = new FxListItemSG(item, q, true, true);
1304
FxListItemSG *listItem = static_cast<FxListItemSG*>(footer);
1305
if (visibleItems.count()) {
1306
qreal endPos = lastPosition();
1307
if (findLastVisibleIndex() == model->count()-1) {
1308
listItem->setPosition(endPos);
1310
qreal visiblePos = position() + q->height();
1311
if (endPos <= visiblePos || listItem->position() < endPos)
1312
listItem->setPosition(endPos);
1315
listItem->setPosition(visiblePos);
1319
emit q->footerItemChanged();
1322
void QQuickListViewPrivate::updateHeader()
1324
Q_Q(QQuickListView);
1325
bool created = false;
1327
QQuickItem *item = createComponentItem(headerComponent, 1.0);
1330
header = new FxListItemSG(item, q, true, true);
1334
FxListItemSG *listItem = static_cast<FxListItemSG*>(header);
1336
if (visibleItems.count()) {
1337
qreal startPos = originPosition();
1338
if (visibleIndex == 0) {
1339
listItem->setPosition(startPos - headerSize());
1341
if (position() <= startPos || listItem->position() > startPos - headerSize())
1342
listItem->setPosition(startPos - headerSize());
1345
listItem->setPosition(-headerSize());
1350
emit q->headerItemChanged();
1353
void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
1355
Q_Q(QQuickListView);
1356
QQuickItemViewPrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
1357
if (!q->isComponentComplete())
1360
if (item != contentItem && (!highlight || item != highlight->item)) {
1361
if ((orient == QQuickListView::Vertical && newGeometry.height() != oldGeometry.height())
1362
|| (orient == QQuickListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
1364
// if visibleItems.first() has resized, adjust its pos since it is used to
1365
// position all subsequent items
1366
if (visibleItems.count() && item == visibleItems.first()->item) {
1367
FxListItemSG *listItem = static_cast<FxListItemSG*>(visibleItems.first());
1368
if (orient == QQuickListView::Vertical) {
1369
qreal diff = newGeometry.height() - oldGeometry.height();
1370
if (verticalLayoutDirection == QQuickListView::TopToBottom && listItem->endPosition() < q->contentY())
1371
listItem->setPosition(listItem->position() - diff, true);
1372
else if (verticalLayoutDirection == QQuickListView::BottomToTop && listItem->endPosition() > q->contentY())
1373
listItem->setPosition(listItem->position() + diff, true);
1375
qreal diff = newGeometry.width() - oldGeometry.width();
1376
if (q->effectiveLayoutDirection() == Qt::LeftToRight && listItem->endPosition() < q->contentX())
1377
listItem->setPosition(listItem->position() - diff, true);
1378
else if (q->effectiveLayoutDirection() == Qt::RightToLeft && listItem->endPosition() > q->contentX())
1379
listItem->setPosition(listItem->position() + diff, true);
1382
forceLayoutPolish();
1387
void QQuickListViewPrivate::fixupPosition()
1389
if ((haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange)
1390
|| snapMode != QQuickListView::NoSnap)
1392
if (orient == QQuickListView::Vertical)
1398
void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
1400
if ((orient == QQuickListView::Horizontal && &data == &vData)
1401
|| (orient == QQuickListView::Vertical && &data == &hData))
1404
correctFlick = false;
1405
fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1406
bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
1408
qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
1410
if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) {
1411
qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
1412
if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) {
1413
// if we've been dragged < averageSize/2 then bias towards the next item
1414
qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1416
if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < averageSize/2)
1417
bias = averageSize/2;
1418
else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -averageSize/2)
1419
bias = -averageSize/2;
1420
if (isContentFlowReversed())
1422
tempPosition -= bias;
1424
FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
1425
if (!topItem && strictHighlightRange && currentItem) {
1426
// StrictlyEnforceRange always keeps an item in range
1428
topItem = currentItem;
1430
FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
1431
if (!bottomItem && strictHighlightRange && currentItem) {
1432
// StrictlyEnforceRange always keeps an item in range
1434
bottomItem = currentItem;
1437
bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1438
if (topItem && (isInBounds || strictHighlightRange)) {
1439
if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
1440
pos = isContentFlowReversed() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart;
1442
if (isContentFlowReversed())
1443
pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
1445
pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
1447
} else if (bottomItem && isInBounds) {
1448
if (isContentFlowReversed())
1449
pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
1451
pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
1453
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1457
qreal dist = qAbs(data.move + pos);
1459
timeline.reset(data.move);
1460
if (fixupMode != Immediate) {
1461
timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1462
data.fixingUp = true;
1464
timeline.set(data.move, -pos);
1466
vTime = timeline.time();
1468
} else if (currentItem && strictHighlightRange && moveReason != QQuickListViewPrivate::SetIndex) {
1470
qreal pos = static_cast<FxListItemSG*>(currentItem)->itemPosition();
1471
if (viewPos < pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd)
1472
viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd;
1473
if (viewPos > pos - highlightRangeStart)
1474
viewPos = pos - highlightRangeStart;
1475
if (isContentFlowReversed())
1476
viewPos = -viewPos-size();
1478
timeline.reset(data.move);
1479
if (viewPos != position()) {
1480
if (fixupMode != Immediate) {
1481
timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1482
data.fixingUp = true;
1484
timeline.set(data.move, -viewPos);
1487
vTime = timeline.time();
1489
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1491
data.inOvershoot = false;
1495
bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1496
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity)
1498
data.fixingUp = false;
1500
if ((!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange) && snapMode == QQuickListView::NoSnap) {
1501
correctFlick = true;
1502
return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1504
qreal maxDistance = 0;
1505
qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value();
1507
// -ve velocity means list is moving up/left
1509
if (data.move.value() < minExtent) {
1510
if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1511
// if we've been dragged < averageSize/2 then bias towards the next item
1512
qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1513
qreal bias = dist < averageSize/2 ? averageSize/2 : 0;
1514
if (isContentFlowReversed())
1516
data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart;
1517
maxDistance = qAbs(data.flickTarget - data.move.value());
1518
velocity = maxVelocity;
1520
maxDistance = qAbs(minExtent - data.move.value());
1523
if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1524
data.flickTarget = minExtent;
1526
if (data.move.value() > maxExtent) {
1527
if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1528
// if we've been dragged < averageSize/2 then bias towards the next item
1529
qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1530
qreal bias = -dist < averageSize/2 ? averageSize/2 : 0;
1531
if (isContentFlowReversed())
1533
data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart;
1534
maxDistance = qAbs(data.flickTarget - data.move.value());
1535
velocity = -maxVelocity;
1537
maxDistance = qAbs(maxExtent - data.move.value());
1540
if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1541
data.flickTarget = maxExtent;
1543
bool overShoot = boundsBehavior == QQuickFlickable::DragAndOvershootBounds;
1544
if (maxDistance > 0 || overShoot) {
1545
// These modes require the list to stop exactly on an item boundary.
1546
// The initial flick will estimate the boundary to stop on.
1547
// Since list items can have variable sizes, the boundary will be
1548
// reevaluated and adjusted as we approach the boundary.
1550
if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1556
if (!hData.flicking && !vData.flicking) {
1557
// the initial flick - estimate boundary
1558
qreal accel = deceleration;
1560
overshootDist = 0.0;
1561
// + averageSize/4 to encourage moving at least one item in the flick direction
1562
qreal dist = v2 / (accel * 2.0) + averageSize/4;
1563
if (maxDistance > 0)
1564
dist = qMin(dist, maxDistance);
1567
if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) {
1568
if (snapMode != QQuickListView::SnapOneItem) {
1569
qreal distTemp = isContentFlowReversed() ? -dist : dist;
1570
data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart;
1572
data.flickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
1574
if (data.flickTarget >= minExtent) {
1575
overshootDist = overShootDistance(vSize);
1576
data.flickTarget += overshootDist;
1577
} else if (data.flickTarget <= maxExtent) {
1578
overshootDist = overShootDistance(vSize);
1579
data.flickTarget -= overshootDist;
1582
qreal adjDist = -data.flickTarget + data.move.value();
1583
if (qAbs(adjDist) > qAbs(dist)) {
1584
// Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1585
qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1594
accel = v2 / (2.0f * qAbs(dist));
1595
} else if (overShoot) {
1596
data.flickTarget = data.move.value() - dist;
1597
if (data.flickTarget >= minExtent) {
1598
overshootDist = overShootDistance(vSize);
1599
data.flickTarget += overshootDist;
1600
} else if (data.flickTarget <= maxExtent) {
1601
overshootDist = overShootDistance(vSize);
1602
data.flickTarget -= overshootDist;
1605
timeline.reset(data.move);
1606
timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1607
timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
1608
correctFlick = true;
1611
// reevaluate the target boundary.
1612
qreal newtarget = data.flickTarget;
1613
if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) {
1614
qreal tempFlickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
1615
newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart;
1616
newtarget = isContentFlowReversed() ? -newtarget+size() : newtarget;
1618
if (velocity < 0 && newtarget <= maxExtent)
1619
newtarget = maxExtent - overshootDist;
1620
else if (velocity > 0 && newtarget >= minExtent)
1621
newtarget = minExtent + overshootDist;
1622
if (newtarget == data.flickTarget) { // boundary unchanged - nothing to do
1623
if (qAbs(velocity) < MinimumFlickVelocity)
1624
correctFlick = false;
1627
data.flickTarget = newtarget;
1628
qreal dist = -newtarget + data.move.value();
1629
if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
1630
correctFlick = false;
1631
timeline.reset(data.move);
1632
fixup(data, minExtent, maxExtent);
1635
timeline.reset(data.move);
1636
timeline.accelDistance(data.move, v, -dist);
1637
timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
1641
correctFlick = false;
1642
timeline.reset(data.move);
1643
fixup(data, minExtent, maxExtent);
1648
//----------------------------------------------------------------------------
1652
\instantiates QQuickListView
1653
\inqmlmodule QtQuick 2
1654
\ingroup qtquick-views
1656
\brief Provides a list view of items provided by a model
1658
A ListView displays data from models created from built-in QML types like ListModel
1659
and XmlListModel, or custom model classes defined in C++ that inherit from
1662
A ListView has a \l model, which defines the data to be displayed, and
1663
a \l delegate, which defines how the data should be displayed. Items in a
1664
ListView are laid out horizontally or vertically. List views are inherently
1665
flickable because ListView inherits from \l Flickable.
1667
\section1 Example Usage
1669
The following example shows the definition of a simple list model defined
1670
in a file called \c ContactModel.qml:
1672
\snippet qml/listview/ContactModel.qml 0
1674
Another component can display this model data in a ListView, like this:
1676
\snippet qml/listview/listview.qml import
1678
\snippet qml/listview/listview.qml classdocs simple
1680
\image listview-simple.png
1682
Here, the ListView creates a \c ContactModel component for its model, and a \l Text item
1683
for its delegate. The view will create a new \l Text component for each item in the model. Notice
1684
the delegate is able to access the model's \c name and \c number data directly.
1686
An improved list view is shown below. The delegate is visually improved and is moved
1687
into a separate \c contactDelegate component.
1689
\snippet qml/listview/listview.qml classdocs advanced
1690
\image listview-highlight.png
1692
The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
1693
and \c focus is set to \c true to enable keyboard navigation for the list view.
1694
The list view itself is a focus scope (see \l{Keyboard Focus in Qt Quick} for more details).
1696
Delegates are instantiated as needed and may be destroyed at any time.
1697
State should \e never be stored in a delegate.
1699
ListView attaches a number of properties to the root item of the delegate, for example
1700
\c {ListView:isCurrentItem}. In the following example, the root delegate item can access
1701
this attached property directly as \c ListView.isCurrentItem, while the child
1702
\c contactInfo object must refer to this property as \c wrapper.ListView.isCurrentItem.
1704
\snippet qml/listview/listview.qml isCurrentItem
1706
\note Views do not enable \e clip automatically. If the view
1707
is not clipped by another item or the screen, it will be necessary
1708
to set \e {clip: true} in order to have the out of view items clipped
1712
\section1 ListView layouts
1714
The layout of the items in a ListView can be controlled by these properties:
1717
\li \l orientation - controls whether items flow horizontally or vertically.
1718
This value can be either Qt.Horizontal or Qt.Vertical.
1719
\li \l layoutDirection - controls the horizontal layout direction for a
1720
horizontally-oriented view: that is, whether items are laid out from the left side of
1721
the view to the right, or vice-versa. This value can be either Qt.LeftToRight or Qt.RightToLeft.
1722
\li \l verticalLayoutDirection - controls the vertical layout direction for a vertically-oriented
1723
view: that is, whether items are laid out from the top of the view down towards the bottom of
1724
the view, or vice-versa. This value can be either ListView.TopToBottom or ListView.BottomToTop.
1727
By default, a ListView has a vertical orientation, and items are laid out from top to bottom. The
1728
table below shows the different layouts that a ListView can have, depending on the values of
1729
the properties listed above.
1734
\b ListViews with Qt.Vertical orientation
1737
\image listview-layout-toptobottom.png
1739
\image listview-layout-bottomtotop.png
1742
\b ListViews with Qt.Horizontal orientation
1745
\image listview-layout-lefttoright.png
1747
\image listview-layout-righttoleft.png
1750
\sa {QML Data Models}, GridView, {quick/modelviews/listview}{ListView examples}
1752
QQuickListView::QQuickListView(QQuickItem *parent)
1753
: QQuickItemView(*(new QQuickListViewPrivate), parent)
1757
QQuickListView::~QQuickListView()
1762
\qmlattachedproperty bool QtQuick2::ListView::isCurrentItem
1763
This attached property is true if this delegate is the current item; otherwise false.
1765
It is attached to each instance of the delegate.
1767
This property may be used to adjust the appearance of the current item, for example:
1769
\snippet qml/listview/listview.qml isCurrentItem
1773
\qmlattachedproperty ListView QtQuick2::ListView::view
1774
This attached property holds the view that manages this delegate instance.
1776
It is attached to each instance of the delegate.
1780
\qmlattachedproperty string QtQuick2::ListView::previousSection
1781
This attached property holds the section of the previous element.
1783
It is attached to each instance of the delegate.
1785
The section is evaluated using the \l {ListView::section.property}{section} properties.
1789
\qmlattachedproperty string QtQuick2::ListView::nextSection
1790
This attached property holds the section of the next element.
1792
It is attached to each instance of the delegate.
1794
The section is evaluated using the \l {ListView::section.property}{section} properties.
1798
\qmlattachedproperty string QtQuick2::ListView::section
1799
This attached property holds the section of this element.
1801
It is attached to each instance of the delegate.
1803
The section is evaluated using the \l {ListView::section.property}{section} properties.
1807
\qmlattachedproperty bool QtQuick2::ListView::delayRemove
1809
This attached property holds whether the delegate may be destroyed. It
1810
is attached to each instance of the delegate. The default value is false.
1812
It is sometimes necessary to delay the destruction of an item
1813
until an animation completes. The example delegate below ensures that the
1814
animation completes before the item is removed from the list.
1816
\snippet qml/listview/listview.qml delayRemove
1818
If a \l remove transition has been specified, it will not be applied until
1819
delayRemove is returned to \c false.
1823
\qmlattachedsignal QtQuick2::ListView::onAdd()
1824
This attached signal handler is called immediately after an item is added to the view.
1826
If an \l add transition is specified, it is applied immediately after
1827
this signal handler is called.
1831
\qmlattachedsignal QtQuick2::ListView::onRemove()
1832
This attached handler is called immediately before an item is removed from the view.
1834
If a \l remove transition has been specified, it is applied after
1835
this signal handler is called, providing that delayRemove is false.
1839
\qmlproperty model QtQuick2::ListView::model
1840
This property holds the model providing data for the list.
1842
The model provides the set of data that is used to create the items
1843
in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
1844
or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
1845
used, it must be a subclass of \l QAbstractItemModel or a simple list.
1847
\sa {qml-data-models}{Data Models}
1851
\qmlproperty Component QtQuick2::ListView::delegate
1853
The delegate provides a template defining each item instantiated by the view.
1854
The index is exposed as an accessible \c index property. Properties of the
1855
model are also available depending upon the type of \l {qml-data-models}{Data Model}.
1857
The number of objects and bindings in the delegate has a direct effect on the
1858
flicking performance of the view. If at all possible, place functionality
1859
that is not needed for the normal display of the delegate in a \l Loader which
1860
can load additional components when needed.
1862
The ListView will lay out the items based on the size of the root item
1865
It is recommended that the delegate's size be a whole number to avoid sub-pixel
1868
\note Delegates are instantiated as needed and may be destroyed at any time.
1869
State should \e never be stored in a delegate.
1872
\qmlproperty int QtQuick2::ListView::currentIndex
1873
\qmlproperty Item QtQuick2::ListView::currentItem
1875
The \c currentIndex property holds the index of the current item, and
1876
\c currentItem holds the current item. Setting the currentIndex to -1
1877
will clear the highlight and set currentItem to null.
1879
If highlightFollowsCurrentItem is \c true, setting either of these
1880
properties will smoothly scroll the ListView so that the current
1881
item becomes visible.
1883
Note that the position of the current item
1884
may only be approximate until it becomes visible in the view.
1888
\qmlproperty Item QtQuick2::ListView::highlightItem
1890
This holds the highlight item created from the \l highlight component.
1892
The \c highlightItem is managed by the view unless
1893
\l highlightFollowsCurrentItem is set to false.
1895
\sa highlight, highlightFollowsCurrentItem
1899
\qmlproperty int QtQuick2::ListView::count
1900
This property holds the number of items in the view.
1904
\qmlproperty Component QtQuick2::ListView::highlight
1905
This property holds the component to use as the highlight.
1907
An instance of the highlight component is created for each list.
1908
The geometry of the resulting component instance is managed by the list
1909
so as to stay with the current item, unless the highlightFollowsCurrentItem
1912
\sa highlightItem, highlightFollowsCurrentItem, {quick/modelviews/listview}{ListView examples}
1916
\qmlproperty bool QtQuick2::ListView::highlightFollowsCurrentItem
1917
This property holds whether the highlight is managed by the view.
1919
If this property is true (the default value), the highlight is moved smoothly
1920
to follow the current item. Otherwise, the
1921
highlight is not moved by the view, and any movement must be implemented
1924
Here is a highlight with its motion defined by a \l {SpringAnimation} item:
1926
\snippet qml/listview/listview.qml highlightFollowsCurrentItem
1928
Note that the highlight animation also affects the way that the view
1929
is scrolled. This is because the view moves to maintain the
1930
highlight within the preferred highlight range (or visible viewport).
1932
\sa highlight, highlightMoveVelocity
1934
//###Possibly rename these properties, since they are very useful even without a highlight?
1936
\qmlproperty real QtQuick2::ListView::preferredHighlightBegin
1937
\qmlproperty real QtQuick2::ListView::preferredHighlightEnd
1938
\qmlproperty enumeration QtQuick2::ListView::highlightRangeMode
1940
These properties define the preferred range of the highlight (for the current item)
1941
within the view. The \c preferredHighlightBegin value must be less than the
1942
\c preferredHighlightEnd value.
1944
These properties affect the position of the current item when the list is scrolled.
1945
For example, if the currently selected item should stay in the middle of the
1946
list when the view is scrolled, set the \c preferredHighlightBegin and
1947
\c preferredHighlightEnd values to the top and bottom coordinates of where the middle
1948
item would be. If the \c currentItem is changed programmatically, the list will
1949
automatically scroll so that the current item is in the middle of the view.
1950
Furthermore, the behavior of the current item index will occur whether or not a
1953
Valid values for \c highlightRangeMode are:
1956
\li ListView.ApplyRange - the view attempts to maintain the highlight within the range.
1957
However, the highlight can move outside of the range at the ends of the list or due
1958
to mouse interaction.
1959
\li ListView.StrictlyEnforceRange - the highlight never moves outside of the range.
1960
The current item changes if a keyboard or mouse action would cause the highlight to move
1961
outside of the range.
1962
\li ListView.NoHighlightRange - this is the default value.
1965
void QQuickListView::setHighlightFollowsCurrentItem(bool autoHighlight)
1967
Q_D(QQuickListView);
1968
if (d->autoHighlight != autoHighlight) {
1969
if (!autoHighlight) {
1970
if (d->highlightPosAnimator)
1971
d->highlightPosAnimator->stop();
1972
if (d->highlightSizeAnimator)
1973
d->highlightSizeAnimator->stop();
1975
QQuickItemView::setHighlightFollowsCurrentItem(autoHighlight);
1980
\qmlproperty real QtQuick2::ListView::spacing
1982
This property holds the spacing between items.
1984
The default value is 0.
1986
qreal QQuickListView::spacing() const
1988
Q_D(const QQuickListView);
1992
void QQuickListView::setSpacing(qreal spacing)
1994
Q_D(QQuickListView);
1995
if (spacing != d->spacing) {
1996
d->spacing = spacing;
1997
d->forceLayoutPolish();
1998
emit spacingChanged();
2003
\qmlproperty enumeration QtQuick2::ListView::orientation
2004
This property holds the orientation of the list.
2009
\li ListView.Horizontal - Items are laid out horizontally
2010
\li ListView.Vertical (default) - Items are laid out vertically
2015
\li Horizontal orientation:
2016
\image ListViewHorizontal.png
2019
\li Vertical orientation:
2020
\image listview-highlight.png
2023
QQuickListView::Orientation QQuickListView::orientation() const
2025
Q_D(const QQuickListView);
2029
void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
2031
Q_D(QQuickListView);
2032
if (d->orient != orientation) {
2033
d->orient = orientation;
2034
if (d->orient == Vertical) {
2035
setContentWidth(-1);
2036
setFlickableDirection(VerticalFlick);
2039
setContentHeight(-1);
2040
setFlickableDirection(HorizontalFlick);
2044
emit orientationChanged();
2049
\qmlproperty enumeration QtQuick2::ListView::layoutDirection
2050
This property holds the layout direction of a horizontally-oriented list.
2055
\li Qt.LeftToRight (default) - Items will be laid out from left to right.
2056
\li Qt.RightToLeft - Items will be laid out from right to let.
2059
Setting this property has no effect if the \l orientation is Qt.Vertical.
2061
\sa ListView::effectiveLayoutDirection, ListView::verticalLayoutDirection
2066
\qmlproperty enumeration QtQuick2::ListView::effectiveLayoutDirection
2067
This property holds the effective layout direction of a horizontally-oriented list.
2069
When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
2070
the visual layout direction of the horizontal list will be mirrored. However, the
2071
property \l {ListView::layoutDirection}{layoutDirection} will remain unchanged.
2073
\sa ListView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
2078
\qmlproperty enumeration QtQuick2::ListView::verticalLayoutDirection
2079
This property holds the layout direction of a vertically-oriented list.
2084
\li ListView.TopToBottom (default) - Items are laid out from the top of the view down to the bottom of the view.
2085
\li ListView.BottomToTop - Items are laid out from the bottom of the view up to the top of the view.
2088
Setting this property has no effect if the \l orientation is Qt.Horizontal.
2090
\sa ListView::layoutDirection
2095
\qmlproperty bool QtQuick2::ListView::keyNavigationWraps
2096
This property holds whether the list wraps key navigation.
2098
If this is true, key navigation that would move the current item selection
2099
past the end of the list instead wraps around and moves the selection to
2100
the start of the list, and vice-versa.
2102
By default, key navigation is not wrapped.
2107
\qmlproperty int QtQuick2::ListView::cacheBuffer
2108
This property determines whether delegates are retained outside the
2109
visible area of the view.
2111
If this value is non-zero, the view may keep as many delegates
2112
instantiated as it can fit within the buffer specified. For example,
2113
if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
2114
set to 40, then up to 2 delegates above and 2 delegates below the visible
2115
area may be created/retained. The buffered delegates are created asynchronously,
2116
allowing creation to occur across multiple frames and reducing the
2117
likelihood of skipping frames. In order to improve painting performance
2118
delegates outside the visible area are not painted.
2120
The default value of this property is platform dependent, but will usually
2121
be a non-zero value.
2123
Note that cacheBuffer is not a pixel buffer - it only maintains additional
2124
instantiated delegates.
2126
Setting this value can improve the smoothness of scrolling behavior at the expense
2127
of additional memory usage. It is not a substitute for creating efficient
2128
delegates; the fewer objects and bindings in a delegate, the faster a view can be
2134
\qmlproperty string QtQuick2::ListView::section.property
2135
\qmlproperty enumeration QtQuick2::ListView::section.criteria
2136
\qmlproperty Component QtQuick2::ListView::section.delegate
2137
\qmlproperty enumeration QtQuick2::ListView::section.labelPositioning
2139
These properties determine the expression to be evaluated and appearance
2140
of the section labels.
2142
\c section.property holds the name of the property that is the basis
2145
\c section.criteria holds the criteria for forming each section based on
2146
\c section.property. This value can be one of:
2149
\li ViewSection.FullString (default) - sections are created based on the
2150
\c section.property value.
2151
\li ViewSection.FirstCharacter - sections are created based on the first
2152
character of the \c section.property value (for example, 'A', 'B', 'C'
2153
sections, etc. for an address book)
2156
A case insensitive comparison is used when determining section
2159
\c section.delegate holds the delegate component for each section.
2161
\c section.labelPositioning determines whether the current and/or
2162
next section labels stick to the start/end of the view, and whether
2163
the labels are shown inline. This value can be a combination of:
2166
\li ViewSection.InlineLabels - section labels are shown inline between
2167
the item delegates separating sections (default).
2168
\li ViewSection.CurrentLabelAtStart - the current section label sticks to the
2169
start of the view as it is moved.
2170
\li ViewSection.NextLabelAtEnd - the next section label (beyond all visible
2171
sections) sticks to the end of the view as it is moved. \note Enabling
2172
\c ViewSection.NextLabelAtEnd requires the view to scan ahead for the next
2173
section, which has performance implications, especially for slower models.
2176
Each item in the list has attached properties named \c ListView.section,
2177
\c ListView.previousSection and \c ListView.nextSection.
2179
For example, here is a ListView that displays a list of animals, separated
2180
into sections. Each item in the ListView is placed in a different section
2181
depending on the "size" property of the model item. The \c sectionHeading
2182
delegate component provides the light blue bar that marks the beginning of
2186
\snippet examples/quick/modelviews/listview/sections.qml 0
2188
\image qml-listview-sections-example.png
2190
\note Adding sections to a ListView does not automatically re-order the
2191
list items by the section criteria.
2192
If the model is not ordered by section, then it is possible that
2193
the sections created will not be unique; each boundary between
2194
differing sections will result in a section header being created
2195
even if that section exists elsewhere.
2197
\sa {quick/modelviews/listview}{ListView examples}
2199
QQuickViewSection *QQuickListView::sectionCriteria()
2201
Q_D(QQuickListView);
2202
if (!d->sectionCriteria)
2203
d->sectionCriteria = new QQuickViewSection(this);
2204
return d->sectionCriteria;
2208
\qmlproperty string QtQuick2::ListView::currentSection
2209
This property holds the section that is currently at the beginning of the view.
2211
QString QQuickListView::currentSection() const
2213
Q_D(const QQuickListView);
2214
return d->currentSection;
2218
\qmlproperty real QtQuick2::ListView::highlightMoveVelocity
2219
\qmlproperty int QtQuick2::ListView::highlightMoveDuration
2220
\qmlproperty real QtQuick2::ListView::highlightResizeVelocity
2221
\qmlproperty int QtQuick2::ListView::highlightResizeDuration
2223
These properties control the speed of the move and resize animations for the
2226
\l highlightFollowsCurrentItem must be true for these properties
2229
The default value for the velocity properties is 400 pixels/second.
2230
The default value for the duration properties is -1, i.e. the
2231
highlight will take as much time as necessary to move at the set speed.
2233
These properties have the same characteristics as a SmoothedAnimation.
2235
\sa highlightFollowsCurrentItem
2237
qreal QQuickListView::highlightMoveVelocity() const
2239
Q_D(const QQuickListView);
2240
return d->highlightMoveVelocity;
2243
void QQuickListView::setHighlightMoveVelocity(qreal speed)
2245
Q_D(QQuickListView);
2246
if (d->highlightMoveVelocity != speed) {
2247
d->highlightMoveVelocity = speed;
2248
if (d->highlightPosAnimator)
2249
d->highlightPosAnimator->velocity = d->highlightMoveVelocity;
2250
emit highlightMoveVelocityChanged();
2254
void QQuickListView::setHighlightMoveDuration(int duration)
2256
Q_D(QQuickListView);
2257
if (d->highlightMoveDuration != duration) {
2258
if (d->highlightPosAnimator)
2259
d->highlightPosAnimator->userDuration = duration;
2260
QQuickItemView::setHighlightMoveDuration(duration);
2264
qreal QQuickListView::highlightResizeVelocity() const
2266
Q_D(const QQuickListView);
2267
return d->highlightResizeVelocity;
2270
void QQuickListView::setHighlightResizeVelocity(qreal speed)
2272
Q_D(QQuickListView);
2273
if (d->highlightResizeVelocity != speed) {
2274
d->highlightResizeVelocity = speed;
2275
if (d->highlightSizeAnimator)
2276
d->highlightSizeAnimator->velocity = d->highlightResizeVelocity;
2277
emit highlightResizeVelocityChanged();
2281
int QQuickListView::highlightResizeDuration() const
2283
Q_D(const QQuickListView);
2284
return d->highlightResizeDuration;
2287
void QQuickListView::setHighlightResizeDuration(int duration)
2289
Q_D(QQuickListView);
2290
if (d->highlightResizeDuration != duration) {
2291
d->highlightResizeDuration = duration;
2292
if (d->highlightSizeAnimator)
2293
d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
2294
emit highlightResizeDurationChanged();
2299
\qmlproperty enumeration QtQuick2::ListView::snapMode
2301
This property determines how the view scrolling will settle following a drag or flick.
2302
The possible values are:
2305
\li ListView.NoSnap (default) - the view stops anywhere within the visible area.
2306
\li ListView.SnapToItem - the view settles with an item aligned with the start of
2308
\li ListView.SnapOneItem - the view settles no more than one item away from the first
2309
visible item at the time the mouse button is released. This mode is particularly
2310
useful for moving one page at a time.
2313
\c snapMode does not affect the \l currentIndex. To update the
2314
\l currentIndex as the list is moved, set \l highlightRangeMode
2315
to \c ListView.StrictlyEnforceRange.
2317
\sa highlightRangeMode
2319
QQuickListView::SnapMode QQuickListView::snapMode() const
2321
Q_D(const QQuickListView);
2325
void QQuickListView::setSnapMode(SnapMode mode)
2327
Q_D(QQuickListView);
2328
if (d->snapMode != mode) {
2330
emit snapModeChanged();
2336
\qmlproperty Component QtQuick2::ListView::footer
2337
This property holds the component to use as the footer.
2339
An instance of the footer component is created for each view. The
2340
footer is positioned at the end of the view, after any items.
2342
\sa header, footerItem
2347
\qmlproperty Component QtQuick2::ListView::header
2348
This property holds the component to use as the header.
2350
An instance of the header component is created for each view. The
2351
header is positioned at the beginning of the view, before any items.
2353
\sa footer, headerItem
2357
\qmlproperty Item QtQuick2::ListView::headerItem
2358
This holds the header item created from the \l header component.
2360
An instance of the header component is created for each view. The
2361
header is positioned at the beginning of the view, before any items.
2363
\sa header, footerItem
2367
\qmlproperty Item QtQuick2::ListView::footerItem
2368
This holds the footer item created from the \l footer component.
2370
An instance of the footer component is created for each view. The
2371
footer is positioned at the end of the view, after any items.
2373
\sa footer, headerItem
2377
\qmlproperty Transition QtQuick2::ListView::populate
2379
This property holds the transition to apply to the items that are initially created
2382
It is applied to all items that are created when:
2385
\li The view is first created
2386
\li The view's \l model changes
2387
\li The view's \l model is \l {QAbstractItemModel::reset()}{reset}, if the model is a QAbstractItemModel subclass
2390
For example, here is a view that specifies such a transition:
2395
populate: Transition {
2396
NumberAnimation { properties: "x,y"; duration: 1000 }
2401
When the view is initialized, the view will create all the necessary items for the view,
2402
then animate them to their correct positions within the view over one second.
2404
For more details and examples on how to use view transitions, see the ViewTransition
2407
\sa add, ViewTransition
2411
\qmlproperty Transition QtQuick2::ListView::add
2413
This property holds the transition to apply to items that are added to the view.
2415
For example, here is a view that specifies such a transition:
2421
NumberAnimation { properties: "x,y"; from: 100; duration: 1000 }
2426
Whenever an item is added to the above view, the item will be animated from the position (100,100)
2427
to its final x,y position within the view, over one second. The transition only applies to
2428
the new items that are added to the view; it does not apply to the items below that are
2429
displaced by the addition of the new items. To animate the displaced items, set the \l displaced
2430
or \l addDisplaced properties.
2432
For more details and examples on how to use view transitions, see the ViewTransition
2435
\note This transition is not applied to the items that are created when the view is initially
2436
populated, or when the view's \l model changes. (In those cases, the \l populate transition is
2437
applied instead.) Additionally, this transition should \e not animate the height of the new item;
2438
doing so will cause any items beneath the new item to be laid out at the wrong position. Instead,
2439
the height can be animated within a \l {ListView::onAdd()}{ListView.onAdd} in the delegate.
2441
\sa addDisplaced, populate, ViewTransition
2445
\qmlproperty Transition QtQuick2::ListView::addDisplaced
2447
This property holds the transition to apply to items within the view that are displaced by
2448
the addition of other items to the view.
2450
For example, here is a view that specifies such a transition:
2455
addDisplaced: Transition {
2456
NumberAnimation { properties: "x,y"; duration: 1000 }
2461
Whenever an item is added to the above view, all items beneath the new item are displaced, causing
2462
them to move down (or sideways, if horizontally orientated) within the view. As this
2463
displacement occurs, the items' movement to their new x,y positions within the view will be
2464
animated by a NumberAnimation over one second, as specified. This transition is not applied to
2465
the new item that has been added to the view; to animate the added items, set the \l add
2468
If an item is displaced by multiple types of operations at the same time, it is not defined as to
2469
whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2470
if it is not necessary to specify different transitions depending on whether an item is displaced
2471
by an add, move or remove operation, consider setting the \l displaced property instead.
2473
For more details and examples on how to use view transitions, see the ViewTransition
2476
\note This transition is not applied to the items that are created when the view is initially
2477
populated, or when the view's \l model changes. In those cases, the \l populate transition is
2480
\sa displaced, add, populate, ViewTransition
2484
\qmlproperty Transition QtQuick2::ListView::move
2486
This property holds the transition to apply to items in the view that are being moved due
2487
to a move operation in the view's \l model.
2489
For example, here is a view that specifies such a transition:
2495
NumberAnimation { properties: "x,y"; duration: 1000 }
2500
Whenever the \l model performs a move operation to move a particular set of indexes, the
2501
respective items in the view will be animated to their new positions in the view over one
2502
second. The transition only applies to the items that are the subject of the move operation
2503
in the model; it does not apply to items below them that are displaced by the move operation.
2504
To animate the displaced items, set the \l displaced or \l moveDisplaced properties.
2506
For more details and examples on how to use view transitions, see the ViewTransition
2509
\sa moveDisplaced, ViewTransition
2513
\qmlproperty Transition QtQuick2::ListView::moveDisplaced
2515
This property holds the transition to apply to items that are displaced by a move operation in
2516
the view's \l model.
2518
For example, here is a view that specifies such a transition:
2523
moveDisplaced: Transition {
2524
NumberAnimation { properties: "x,y"; duration: 1000 }
2529
Whenever the \l model performs a move operation to move a particular set of indexes, the items
2530
between the source and destination indexes of the move operation are displaced, causing them
2531
to move upwards or downwards (or sideways, if horizontally orientated) within the view. As this
2532
displacement occurs, the items' movement to their new x,y positions within the view will be
2533
animated by a NumberAnimation over one second, as specified. This transition is not applied to
2534
the items that are the actual subjects of the move operation; to animate the moved items, set
2535
the \l move property.
2537
If an item is displaced by multiple types of operations at the same time, it is not defined as to
2538
whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2539
if it is not necessary to specify different transitions depending on whether an item is displaced
2540
by an add, move or remove operation, consider setting the \l displaced property instead.
2542
For more details and examples on how to use view transitions, see the ViewTransition
2545
\sa displaced, move, ViewTransition
2549
\qmlproperty Transition QtQuick2::ListView::remove
2551
This property holds the transition to apply to items that are removed from the view.
2553
For example, here is a view that specifies such a transition:
2558
remove: Transition {
2560
NumberAnimation { property: "opacity"; to: 0; duration: 1000 }
2561
NumberAnimation { properties: "x,y"; to: 100; duration: 1000 }
2567
Whenever an item is removed from the above view, the item will be animated to the position (100,100)
2568
over one second, and in parallel will also change its opacity to 0. The transition
2569
only applies to the items that are removed from the view; it does not apply to the items below
2570
them that are displaced by the removal of the items. To animate the displaced items, set the
2571
\l displaced or \l removeDisplaced properties.
2573
Note that by the time the transition is applied, the item has already been removed from the
2574
model; any references to the model data for the removed index will not be valid.
2576
Additionally, if the \l delayRemove attached property has been set for a delegate item, the
2577
remove transition will not be applied until \l delayRemove becomes false again.
2579
For more details and examples on how to use view transitions, see the ViewTransition
2582
\sa removeDisplaced, ViewTransition
2586
\qmlproperty Transition QtQuick2::ListView::removeDisplaced
2588
This property holds the transition to apply to items in the view that are displaced by the
2589
removal of other items in the view.
2591
For example, here is a view that specifies such a transition:
2596
removeDisplaced: Transition {
2597
NumberAnimation { properties: "x,y"; duration: 1000 }
2602
Whenever an item is removed from the above view, all items beneath it are displaced, causing
2603
them to move upwards (or sideways, if horizontally orientated) within the view. As this
2604
displacement occurs, the items' movement to their new x,y positions within the view will be
2605
animated by a NumberAnimation over one second, as specified. This transition is not applied to
2606
the item that has actually been removed from the view; to animate the removed items, set the
2609
If an item is displaced by multiple types of operations at the same time, it is not defined as to
2610
whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
2611
if it is not necessary to specify different transitions depending on whether an item is displaced
2612
by an add, move or remove operation, consider setting the \l displaced property instead.
2614
For more details and examples on how to use view transitions, see the ViewTransition
2617
\sa displaced, remove, ViewTransition
2621
\qmlproperty Transition QtQuick2::ListView::displaced
2622
This property holds the generic transition to apply to items that have been displaced by
2623
any model operation that affects the view.
2625
This is a convenience for specifying the generic transition to be applied to any items
2626
that are displaced by an add, move or remove operation, without having to specify the
2627
individual addDisplaced, moveDisplaced and removeDisplaced properties. For example, here
2628
is a view that specifies a displaced transition:
2633
displaced: Transition {
2634
NumberAnimation { properties: "x,y"; duration: 1000 }
2639
When any item is added, moved or removed within the above view, the items below it are
2640
displaced, causing them to move down (or sideways, if horizontally orientated) within the
2641
view. As this displacement occurs, the items' movement to their new x,y positions within
2642
the view will be animated by a NumberAnimation over one second, as specified.
2644
If a view specifies this generic displaced transition as well as a specific addDisplaced,
2645
moveDisplaced or removeDisplaced transition, the more specific transition will be used
2646
instead of the generic displaced transition when the relevant operation occurs, providing that
2647
the more specific transition has not been disabled (by setting \l {Transition::enabled}{enabled}
2648
to false). If it has indeed been disabled, the generic displaced transition is applied instead.
2650
For more details and examples on how to use view transitions, see the ViewTransition
2653
\sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition
2656
void QQuickListView::viewportMoved(Qt::Orientations orient)
2658
Q_D(QQuickListView);
2659
QQuickItemView::viewportMoved(orient);
2662
// Recursion can occur due to refill changing the content size.
2663
if (d->inViewportMoved)
2665
d->inViewportMoved = true;
2668
if (d->isBottomToTop())
2669
d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
2671
d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
2673
if (d->isRightToLeft())
2674
d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
2676
d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
2679
d->refillOrLayout();
2681
// Set visibility of items to eliminate cost of items outside the visible area.
2682
qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
2683
qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
2684
for (int i = 0; i < d->visibleItems.count(); ++i) {
2685
FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i));
2686
QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to);
2689
QQuickItemPrivate::get(d->currentItem->item)->setCulled(d->currentItem->endPosition() < from || d->currentItem->position() > to);
2691
if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2692
d->moveReason = QQuickListViewPrivate::Mouse;
2693
if (d->moveReason != QQuickListViewPrivate::SetIndex) {
2694
if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2695
// reposition highlight
2696
qreal pos = d->highlight->position();
2697
qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
2698
if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
2699
pos = viewPos + d->highlightRangeEnd - d->highlight->size();
2700
if (pos < viewPos + d->highlightRangeStart)
2701
pos = viewPos + d->highlightRangeStart;
2702
if (pos != d->highlight->position()) {
2703
d->highlightPosAnimator->stop();
2704
static_cast<FxListItemSG*>(d->highlight)->setPosition(pos);
2706
d->updateHighlight();
2709
// update current index
2710
if (FxViewItem *snapItem = d->snapItemAt(d->highlight->position())) {
2711
if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
2712
d->updateCurrent(snapItem->index);
2717
if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
2718
d->inFlickCorrection = true;
2719
// Near an end and it seems that the extent has changed?
2720
// Recalculate the flick so that we don't end up in an odd position.
2721
if (yflick() && !d->vData.inOvershoot) {
2722
if (d->vData.velocity > 0) {
2723
const qreal minY = minYExtent();
2724
if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
2725
&& minY != d->vData.flickTarget)
2726
d->flickY(-d->vData.smoothVelocity.value());
2727
} else if (d->vData.velocity < 0) {
2728
const qreal maxY = maxYExtent();
2729
if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
2730
&& maxY != d->vData.flickTarget)
2731
d->flickY(-d->vData.smoothVelocity.value());
2735
if (xflick() && !d->hData.inOvershoot) {
2736
if (d->hData.velocity > 0) {
2737
const qreal minX = minXExtent();
2738
if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
2739
&& minX != d->hData.flickTarget)
2740
d->flickX(-d->hData.smoothVelocity.value());
2741
} else if (d->hData.velocity < 0) {
2742
const qreal maxX = maxXExtent();
2743
if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
2744
&& maxX != d->hData.flickTarget)
2745
d->flickX(-d->hData.smoothVelocity.value());
2748
d->inFlickCorrection = false;
2750
if (d->sectionCriteria) {
2751
d->updateCurrentSection();
2752
d->updateStickySections();
2754
d->inViewportMoved = false;
2757
void QQuickListView::keyPressEvent(QKeyEvent *event)
2759
Q_D(QQuickListView);
2760
if (d->model && d->model->count() && d->interactive) {
2761
if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left)
2762
|| (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right)
2763
|| (d->orient == QQuickListView::Vertical && !d->isBottomToTop() && event->key() == Qt::Key_Up)
2764
|| (d->orient == QQuickListView::Vertical && d->isBottomToTop() && event->key() == Qt::Key_Down)) {
2765
if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) {
2766
decrementCurrentIndex();
2769
} else if (d->wrap) {
2773
} else if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right)
2774
|| (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left)
2775
|| (d->orient == QQuickListView::Vertical && !d->isBottomToTop() && event->key() == Qt::Key_Down)
2776
|| (d->orient == QQuickListView::Vertical && d->isBottomToTop() && event->key() == Qt::Key_Up)) {
2777
if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) {
2778
incrementCurrentIndex();
2781
} else if (d->wrap) {
2788
QQuickItemView::keyPressEvent(event);
2791
void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
2793
Q_D(QQuickListView);
2794
if (d->isRightToLeft()) {
2795
// maintain position relative to the right edge
2796
int dx = newGeometry.width() - oldGeometry.width();
2797
setContentX(contentX() - dx);
2798
} else if (d->isBottomToTop()) {
2799
// maintain position relative to the bottom edge
2800
int dy = newGeometry.height() - oldGeometry.height();
2801
setContentY(contentY() - dy);
2803
QQuickItemView::geometryChanged(newGeometry, oldGeometry);
2806
void QQuickListView::initItem(int index, QQuickItem *item)
2808
QQuickItemView::initItem(index, item);
2809
QQuickListViewAttached *attached = static_cast<QQuickListViewAttached *>(
2810
qmlAttachedPropertiesObject<QQuickListView>(item));
2812
attached->setView(this);
2817
\qmlmethod QtQuick2::ListView::incrementCurrentIndex()
2819
Increments the current index. The current index will wrap
2820
if keyNavigationWraps is true and it is currently at the end.
2821
This method has no effect if the \l count is zero.
2823
\b Note: methods should only be called after the Component has completed.
2825
void QQuickListView::incrementCurrentIndex()
2827
Q_D(QQuickListView);
2828
int count = d->model ? d->model->count() : 0;
2829
if (count && (currentIndex() < count - 1 || d->wrap)) {
2830
d->moveReason = QQuickListViewPrivate::SetIndex;
2831
int index = currentIndex()+1;
2832
setCurrentIndex((index >= 0 && index < count) ? index : 0);
2837
\qmlmethod QtQuick2::ListView::decrementCurrentIndex()
2839
Decrements the current index. The current index will wrap
2840
if keyNavigationWraps is true and it is currently at the beginning.
2841
This method has no effect if the \l count is zero.
2843
\b Note: methods should only be called after the Component has completed.
2845
void QQuickListView::decrementCurrentIndex()
2847
Q_D(QQuickListView);
2848
int count = d->model ? d->model->count() : 0;
2849
if (count && (currentIndex() > 0 || d->wrap)) {
2850
d->moveReason = QQuickListViewPrivate::SetIndex;
2851
int index = currentIndex()-1;
2852
setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2856
void QQuickListViewPrivate::updateSectionCriteria()
2858
Q_Q(QQuickListView);
2859
if (q->isComponentComplete() && model) {
2860
QList<QByteArray> roles;
2861
if (sectionCriteria && !sectionCriteria->property().isEmpty())
2862
roles << sectionCriteria->property().toUtf8();
2863
model->setWatchedRoles(roles);
2866
forceLayoutPolish();
2870
bool QQuickListViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
2872
int modelIndex = change.index;
2873
int count = change.count;
2875
qreal tempPos = isContentFlowReversed() ? -position()-size() : position();
2876
int index = visibleItems.count() ? mapFromModel(modelIndex) : 0;
2879
int i = visibleItems.count() - 1;
2880
while (i > 0 && visibleItems.at(i)->index == -1)
2882
if (i == 0 && visibleItems.first()->index == -1) {
2883
// there are no visible items except items marked for removal
2884
index = visibleItems.count();
2885
} else if (visibleItems.at(i)->index + 1 == modelIndex
2886
&& visibleItems.at(i)->endPosition() <= buffer+tempPos+size()) {
2887
// Special case of appending an item to the model.
2888
index = visibleItems.count();
2890
if (modelIndex < visibleIndex) {
2891
// Insert before visible items
2892
visibleIndex += count;
2893
for (int i = 0; i < visibleItems.count(); ++i) {
2894
FxViewItem *item = visibleItems.at(i);
2895
if (item->index != -1 && item->index >= modelIndex)
2896
item->index += count;
2903
// index can be the next item past the end of the visible items list (i.e. appended)
2905
if (visibleItems.count()) {
2906
pos = index < visibleItems.count() ? visibleItems.at(index)->position()
2907
: visibleItems.last()->endPosition()+spacing;
2910
int prevVisibleCount = visibleItems.count();
2911
if (insertResult->visiblePos.isValid() && pos < insertResult->visiblePos) {
2912
// Insert items before the visible item.
2913
int insertionIdx = index;
2915
int from = tempPos - buffer;
2917
for (i = count-1; i >= 0; --i) {
2918
if (pos > from && insertionIdx < visibleIndex) {
2919
// item won't be visible, just note the size for repositioning
2920
insertResult->sizeChangesBeforeVisiblePos += averageSize + spacing;
2921
pos -= averageSize + spacing;
2923
// item is before first visible e.g. in cache buffer
2924
FxViewItem *item = 0;
2925
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2926
item->index = modelIndex + i;
2928
item = createItem(modelIndex + i);
2932
visibleItems.insert(insertionIdx, item);
2933
if (insertionIdx == 0)
2934
insertResult->changedFirstItem = true;
2935
if (!change.isMove()) {
2936
addedItems->append(item);
2937
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2939
insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing;
2940
pos -= item->size() + spacing;
2946
int to = buffer+tempPos+size();
2947
for (i = 0; i < count && pos <= to; ++i) {
2948
FxViewItem *item = 0;
2949
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
2950
item->index = modelIndex + i;
2951
bool newItem = !item;
2953
item = createItem(modelIndex + i);
2957
visibleItems.insert(index, item);
2959
insertResult->changedFirstItem = true;
2960
if (change.isMove()) {
2961
// we know this is a move target, since move displaced items that are
2962
// shuffled into view due to a move would be added in refill()
2963
if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true))
2964
movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
2966
addedItems->append(item);
2967
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
2969
insertResult->sizeChangesAfterVisiblePos += item->size() + spacing;
2970
pos += item->size() + spacing;
2975
for (; index < visibleItems.count(); ++index) {
2976
FxViewItem *item = visibleItems.at(index);
2977
if (item->index != -1) {
2978
item->index += count;
2979
if (change.isMove())
2980
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false);
2982
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, false);
2986
updateVisibleIndex();
2988
return visibleItems.count() > prevVisibleCount;
2991
void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult)
2993
Q_UNUSED(insertionResult);
2998
int markerItemIndex = -1;
2999
for (int i=0; i<visibleItems.count(); i++) {
3000
if (visibleItems[i]->index == afterModelIndex) {
3001
markerItemIndex = i;
3005
if (markerItemIndex < 0)
3008
const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
3009
qreal sizeRemoved = -removalResult.sizeChangesAfterVisiblePos
3010
- (removalResult.countChangeAfterVisibleItems * (averageSize + spacing));
3012
for (int i=markerItemIndex+1; i<visibleItems.count() && visibleItems.at(i)->position() < viewEndPos; i++) {
3013
FxListItemSG *listItem = static_cast<FxListItemSG *>(visibleItems[i]);
3014
if (!listItem->transitionScheduledOrRunning()) {
3015
qreal pos = listItem->position();
3016
listItem->setPosition(pos - sizeRemoved);
3017
listItem->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
3018
listItem->setPosition(pos);
3024
\qmlmethod QtQuick2::ListView::positionViewAtIndex(int index, PositionMode mode)
3026
Positions the view such that the \a index is at the position specified by
3030
\li ListView.Beginning - position item at the top (or left for horizontal orientation) of the view.
3031
\li ListView.Center - position item in the center of the view.
3032
\li ListView.End - position item at bottom (or right for horizontal orientation) of the view.
3033
\li ListView.Visible - if any part of the item is visible then take no action, otherwise
3034
bring the item into view.
3035
\li ListView.Contain - ensure the entire item is visible. If the item is larger than
3036
the view the item is positioned at the top (or left for horizontal orientation) of the view.
3037
\li ListView.SnapPosition - position the item at \l preferredHighlightBegin. This mode
3038
is only valid if \l highlightRangeMode is StrictlyEnforceRange or snapping is enabled
3042
If positioning the view at \a index would cause empty space to be displayed at
3043
the beginning or end of the view, the view will be positioned at the boundary.
3045
It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
3046
at a particular index. This is unreliable since removing items from the start
3047
of the list does not cause all other items to be repositioned, and because
3048
the actual start of the view can vary based on the size of the delegates.
3049
The correct way to bring an item into view is with \c positionViewAtIndex.
3051
\b Note: methods should only be called after the Component has completed. To position
3052
the view at startup, this method should be called by Component.onCompleted. For
3053
example, to position the view at the end:
3056
Component.onCompleted: positionViewAtIndex(count - 1, ListView.Beginning)
3061
\qmlmethod QtQuick2::ListView::positionViewAtBeginning()
3062
\qmlmethod QtQuick2::ListView::positionViewAtEnd()
3064
Positions the view at the beginning or end, taking into account any header or footer.
3066
It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
3067
at a particular index. This is unreliable since removing items from the start
3068
of the list does not cause all other items to be repositioned, and because
3069
the actual start of the view can vary based on the size of the delegates.
3071
\b Note: methods should only be called after the Component has completed. To position
3072
the view at startup, this method should be called by Component.onCompleted. For
3073
example, to position the view at the end on startup:
3076
Component.onCompleted: positionViewAtEnd()
3081
\qmlmethod int QtQuick2::ListView::indexAt(int x, int y)
3083
Returns the index of the visible item containing the point \a x, \a y in content
3084
coordinates. If there is no item at the point specified, or the item is
3085
not visible -1 is returned.
3087
If the item is outside the visible area, -1 is returned, regardless of
3088
whether an item will exist at that point when scrolled into view.
3090
\b Note: methods should only be called after the Component has completed.
3094
\qmlmethod Item QtQuick2::ListView::itemAt(int x, int y)
3096
Returns the visible item containing the point \a x, \a y in content
3097
coordinates. If there is no item at the point specified, or the item is
3098
not visible null is returned.
3100
If the item is outside the visible area, null is returned, regardless of
3101
whether an item will exist at that point when scrolled into view.
3103
\b Note: methods should only be called after the Component has completed.
3106
QQuickListViewAttached *QQuickListView::qmlAttachedProperties(QObject *obj)
3108
return new QQuickListViewAttached(obj);