1
/****************************************************************************
3
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/
6
** This file is part of the QtQml module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** GNU Lesser General Public License Usage
10
** This file may be used under the terms of the GNU Lesser General Public
11
** License version 2.1 as published by the Free Software Foundation and
12
** appearing in the file LICENSE.LGPL included in the packaging of this
13
** file. Please review the following information to ensure the GNU Lesser
14
** General Public License version 2.1 requirements will be met:
15
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
** In addition, as a special exception, Nokia gives you certain additional
18
** rights. These rights are described in the Nokia Qt LGPL Exception
19
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
** GNU General Public License Usage
22
** Alternatively, this file may be used under the terms of the GNU General
23
** Public License version 3.0 as published by the Free Software Foundation
24
** and appearing in the file LICENSE.GPL included in the packaging of this
25
** file. Please review the following information to ensure the GNU General
26
** Public License version 3.0 requirements will be met:
27
** http://www.gnu.org/copyleft/gpl.html.
30
** Alternatively, this file may be used in accordance with the terms and
31
** conditions contained in a signed written agreement between you and Nokia.
40
****************************************************************************/
42
#include "qquickitemview_p_p.h"
43
#include <QtQuick/private/qquicktransition_p.h>
48
FxViewItem::FxViewItem(QQuickItem *i, bool own, bool trackGeometry)
50
, transitionableItem(0)
52
, releaseAfterTransition(false)
53
, trackGeom(trackGeometry)
57
FxViewItem::~FxViewItem()
59
delete transitionableItem;
60
if (ownItem && item) {
61
item->setParentItem(0);
67
qreal FxViewItem::itemX() const
69
return transitionableItem ? transitionableItem->itemX() : item->x();
72
qreal FxViewItem::itemY() const
74
return transitionableItem ? transitionableItem->itemY() : item->y();
77
void FxViewItem::moveTo(const QPointF &pos, bool immediate)
79
if (transitionableItem)
80
transitionableItem->moveTo(pos, immediate);
85
void FxViewItem::setVisible(bool visible)
87
if (!visible && transitionableItem && transitionableItem->transitionScheduledOrRunning())
89
item->setVisible(visible);
92
QQuickItemViewTransitioner::TransitionType FxViewItem::scheduledTransitionType() const
94
return transitionableItem ? transitionableItem->nextTransitionType : QQuickItemViewTransitioner::NoTransition;
97
bool FxViewItem::transitionScheduledOrRunning() const
99
return transitionableItem ? transitionableItem->transitionScheduledOrRunning() : false;
102
bool FxViewItem::transitionRunning() const
104
return transitionableItem ? transitionableItem->transitionRunning() : false;
107
bool FxViewItem::isPendingRemoval() const
109
return transitionableItem ? transitionableItem->isPendingRemoval() : false;
112
void FxViewItem::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
116
if (!transitionableItem)
117
transitionableItem = new QQuickItemViewTransitionableItem(item);
118
transitioner->transitionNextReposition(transitionableItem, type, asTarget);
121
bool FxViewItem::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds)
123
return transitionableItem ? transitionableItem->prepareTransition(transitioner, index, viewBounds) : false;
126
void FxViewItem::startTransition(QQuickItemViewTransitioner *transitioner)
128
if (transitionableItem)
129
transitionableItem->startTransition(transitioner, index);
133
QQuickItemViewChangeSet::QQuickItemViewChangeSet()
139
bool QQuickItemViewChangeSet::hasPendingChanges() const
141
return !pendingChanges.isEmpty();
144
void QQuickItemViewChangeSet::applyChanges(const QQuickChangeSet &changeSet)
146
pendingChanges.apply(changeSet);
151
foreach (const QQuickChangeSet::Remove &r, changeSet.removes()) {
152
itemCount -= r.count;
153
if (moveId == -1 && newCurrentIndex >= r.index + r.count) {
154
newCurrentIndex -= r.count;
155
currentChanged = true;
156
} else if (moveId == -1 && newCurrentIndex >= r.index && newCurrentIndex < r.index + r.count) {
157
// current item has been removed.
160
moveOffset = newCurrentIndex - r.index;
162
currentRemoved = true;
163
newCurrentIndex = -1;
165
newCurrentIndex = qMin(r.index, itemCount - 1);
167
currentChanged = true;
170
foreach (const QQuickChangeSet::Insert &i, changeSet.inserts()) {
172
if (itemCount && newCurrentIndex >= i.index) {
173
newCurrentIndex += i.count;
174
currentChanged = true;
175
} else if (newCurrentIndex < 0) {
177
currentChanged = true;
178
} else if (newCurrentIndex == 0 && !itemCount) {
179
// this is the first item, set the initial current index
180
currentChanged = true;
182
} else if (moveId == i.moveId) {
183
newCurrentIndex = i.index + moveOffset;
185
itemCount += i.count;
189
void QQuickItemViewChangeSet::applyBufferedChanges(const QQuickItemViewChangeSet &other)
191
if (!other.hasPendingChanges())
194
pendingChanges.apply(other.pendingChanges);
195
itemCount = other.itemCount;
196
newCurrentIndex = other.newCurrentIndex;
197
currentChanged = other.currentChanged;
198
currentRemoved = other.currentRemoved;
201
void QQuickItemViewChangeSet::prepare(int currentIndex, int count)
208
newCurrentIndex = currentIndex;
211
void QQuickItemViewChangeSet::reset()
214
newCurrentIndex = -1;
215
pendingChanges.clear();
216
removedItems.clear();
218
currentChanged = false;
219
currentRemoved = false;
222
//-----------------------------------
224
QQuickItemView::QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent)
225
: QQuickFlickable(dd, parent)
231
QQuickItemView::~QQuickItemView()
242
QQuickItem *QQuickItemView::currentItem() const
244
Q_D(const QQuickItemView);
247
const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
248
return d->currentItem->item;
251
QVariant QQuickItemView::model() const
253
Q_D(const QQuickItemView);
254
return d->modelVariant;
257
void QQuickItemView::setModel(const QVariant &model)
260
if (d->modelVariant == model)
263
disconnect(d->model, SIGNAL(modelUpdated(QQuickChangeSet,bool)),
264
this, SLOT(modelUpdated(QQuickChangeSet,bool)));
265
disconnect(d->model, SIGNAL(initItem(int,QQuickItem*)), this, SLOT(initItem(int,QQuickItem*)));
266
disconnect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*)));
267
disconnect(d->model, SIGNAL(destroyingItem(QQuickItem*)), this, SLOT(destroyingItem(QQuickItem*)));
270
QQuickVisualModel *oldModel = d->model;
274
d->setPosition(d->contentStartOffset());
275
d->modelVariant = model;
277
QObject *object = qvariant_cast<QObject*>(model);
278
QQuickVisualModel *vim = 0;
279
if (object && (vim = qobject_cast<QQuickVisualModel *>(object))) {
287
d->model = new QQuickVisualDataModel(qmlContext(this), this);
289
if (isComponentComplete())
290
static_cast<QQuickVisualDataModel *>(d->model.data())->componentComplete();
294
if (QQuickVisualDataModel *dataModel = qobject_cast<QQuickVisualDataModel*>(d->model))
295
dataModel->setModel(model);
299
d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
300
connect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*)));
301
connect(d->model, SIGNAL(initItem(int,QQuickItem*)), this, SLOT(initItem(int,QQuickItem*)));
302
connect(d->model, SIGNAL(destroyingItem(QQuickItem*)), this, SLOT(destroyingItem(QQuickItem*)));
303
if (isComponentComplete()) {
306
if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
309
d->moveReason = QQuickItemViewPrivate::SetIndex;
310
d->updateCurrent(d->currentIndex);
311
if (d->highlight && d->currentItem) {
312
if (d->autoHighlight)
313
d->resetHighlightPosition();
314
d->updateTrackedItem();
316
d->moveReason = QQuickItemViewPrivate::Other;
320
if (d->transitioner && d->transitioner->populateTransition) {
321
d->forceLayout = true;
322
d->transitioner->setPopulateTransitionEnabled(true);
326
connect(d->model, SIGNAL(modelUpdated(QQuickChangeSet,bool)),
327
this, SLOT(modelUpdated(QQuickChangeSet,bool)));
333
QQmlComponent *QQuickItemView::delegate() const
335
Q_D(const QQuickItemView);
337
if (QQuickVisualDataModel *dataModel = qobject_cast<QQuickVisualDataModel*>(d->model))
338
return dataModel->delegate();
344
void QQuickItemView::setDelegate(QQmlComponent *delegate)
347
if (delegate == this->delegate())
350
d->model = new QQuickVisualDataModel(qmlContext(this));
353
if (QQuickVisualDataModel *dataModel = qobject_cast<QQuickVisualDataModel*>(d->model)) {
354
int oldCount = dataModel->count();
355
dataModel->setDelegate(delegate);
356
if (isComponentComplete()) {
357
for (int i = 0; i < d->visibleItems.count(); ++i)
358
d->releaseItem(d->visibleItems.at(i));
359
d->visibleItems.clear();
360
d->releaseItem(d->currentItem);
364
d->moveReason = QQuickItemViewPrivate::SetIndex;
365
d->updateCurrent(d->currentIndex);
366
if (d->highlight && d->currentItem) {
367
if (d->autoHighlight)
368
d->resetHighlightPosition();
369
d->updateTrackedItem();
371
d->moveReason = QQuickItemViewPrivate::Other;
374
if (oldCount != dataModel->count())
377
emit delegateChanged();
381
int QQuickItemView::count() const
383
Q_D(const QQuickItemView);
386
const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
387
return d->model->count();
390
int QQuickItemView::currentIndex() const
392
Q_D(const QQuickItemView);
393
const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
394
return d->currentIndex;
397
void QQuickItemView::setCurrentIndex(int index)
400
if (d->requestedIndex >= 0 && !d->requestedAsync) // currently creating item
402
d->currentIndexCleared = (index == -1);
404
d->applyPendingChanges();
405
if (index == d->currentIndex)
407
if (isComponentComplete() && d->isValid()) {
408
d->moveReason = QQuickItemViewPrivate::SetIndex;
409
d->updateCurrent(index);
410
} else if (d->currentIndex != index) {
411
d->currentIndex = index;
412
emit currentIndexChanged();
417
bool QQuickItemView::isWrapEnabled() const
419
Q_D(const QQuickItemView);
423
void QQuickItemView::setWrapEnabled(bool wrap)
429
emit keyNavigationWrapsChanged();
432
int QQuickItemView::cacheBuffer() const
434
Q_D(const QQuickItemView);
438
void QQuickItemView::setCacheBuffer(int b)
441
if (d->buffer != b) {
443
if (isComponentComplete()) {
444
d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
447
emit cacheBufferChanged();
452
Qt::LayoutDirection QQuickItemView::layoutDirection() const
454
Q_D(const QQuickItemView);
455
return d->layoutDirection;
458
void QQuickItemView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
461
if (d->layoutDirection != layoutDirection) {
462
d->layoutDirection = layoutDirection;
464
emit layoutDirectionChanged();
465
emit effectiveLayoutDirectionChanged();
469
Qt::LayoutDirection QQuickItemView::effectiveLayoutDirection() const
471
Q_D(const QQuickItemView);
472
if (d->effectiveLayoutMirror)
473
return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
475
return d->layoutDirection;
478
QQuickItemView::VerticalLayoutDirection QQuickItemView::verticalLayoutDirection() const
480
Q_D(const QQuickItemView);
481
return d->verticalLayoutDirection;
484
void QQuickItemView::setVerticalLayoutDirection(VerticalLayoutDirection layoutDirection)
487
if (d->verticalLayoutDirection != layoutDirection) {
488
d->verticalLayoutDirection = layoutDirection;
490
emit verticalLayoutDirectionChanged();
494
QQmlComponent *QQuickItemView::header() const
496
Q_D(const QQuickItemView);
497
return d->headerComponent;
500
QQuickItem *QQuickItemView::headerItem() const
502
Q_D(const QQuickItemView);
503
const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
504
return d->header ? d->header->item : 0;
507
void QQuickItemView::setHeader(QQmlComponent *headerComponent)
510
if (d->headerComponent != headerComponent) {
511
d->applyPendingChanges();
514
d->headerComponent = headerComponent;
516
d->markExtentsDirty();
518
if (isComponentComplete()) {
524
emit headerItemChanged();
526
emit headerChanged();
530
QQmlComponent *QQuickItemView::footer() const
532
Q_D(const QQuickItemView);
533
return d->footerComponent;
536
QQuickItem *QQuickItemView::footerItem() const
538
Q_D(const QQuickItemView);
539
const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
540
return d->footer ? d->footer->item : 0;
543
void QQuickItemView::setFooter(QQmlComponent *footerComponent)
546
if (d->footerComponent != footerComponent) {
547
d->applyPendingChanges();
550
d->footerComponent = footerComponent;
552
if (isComponentComplete()) {
557
emit footerItemChanged();
559
emit footerChanged();
563
QQmlComponent *QQuickItemView::highlight() const
565
Q_D(const QQuickItemView);
566
const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
567
return d->highlightComponent;
570
void QQuickItemView::setHighlight(QQmlComponent *highlightComponent)
573
if (highlightComponent != d->highlightComponent) {
574
d->applyPendingChanges();
575
d->highlightComponent = highlightComponent;
576
d->createHighlight();
578
d->updateHighlight();
579
emit highlightChanged();
583
QQuickItem *QQuickItemView::highlightItem() const
585
Q_D(const QQuickItemView);
586
const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
587
return d->highlight ? d->highlight->item : 0;
590
bool QQuickItemView::highlightFollowsCurrentItem() const
592
Q_D(const QQuickItemView);
593
return d->autoHighlight;
596
void QQuickItemView::setHighlightFollowsCurrentItem(bool autoHighlight)
599
if (d->autoHighlight != autoHighlight) {
600
d->autoHighlight = autoHighlight;
602
d->updateHighlight();
603
emit highlightFollowsCurrentItemChanged();
607
QQuickItemView::HighlightRangeMode QQuickItemView::highlightRangeMode() const
609
Q_D(const QQuickItemView);
610
return static_cast<QQuickItemView::HighlightRangeMode>(d->highlightRange);
613
void QQuickItemView::setHighlightRangeMode(HighlightRangeMode mode)
616
if (d->highlightRange == mode)
618
d->highlightRange = mode;
619
d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
620
emit highlightRangeModeChanged();
623
//###Possibly rename these properties, since they are very useful even without a highlight?
624
qreal QQuickItemView::preferredHighlightBegin() const
626
Q_D(const QQuickItemView);
627
return d->highlightRangeStart;
630
void QQuickItemView::setPreferredHighlightBegin(qreal start)
633
d->highlightRangeStartValid = true;
634
if (d->highlightRangeStart == start)
636
d->highlightRangeStart = start;
637
d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
638
emit preferredHighlightBeginChanged();
641
void QQuickItemView::resetPreferredHighlightBegin()
644
d->highlightRangeStartValid = false;
645
if (d->highlightRangeStart == 0)
647
d->highlightRangeStart = 0;
648
emit preferredHighlightBeginChanged();
651
qreal QQuickItemView::preferredHighlightEnd() const
653
Q_D(const QQuickItemView);
654
return d->highlightRangeEnd;
657
void QQuickItemView::setPreferredHighlightEnd(qreal end)
660
d->highlightRangeEndValid = true;
661
if (d->highlightRangeEnd == end)
663
d->highlightRangeEnd = end;
664
d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
665
emit preferredHighlightEndChanged();
668
void QQuickItemView::resetPreferredHighlightEnd()
671
d->highlightRangeEndValid = false;
672
if (d->highlightRangeEnd == 0)
674
d->highlightRangeEnd = 0;
675
emit preferredHighlightEndChanged();
678
int QQuickItemView::highlightMoveDuration() const
680
Q_D(const QQuickItemView);
681
return d->highlightMoveDuration;
684
void QQuickItemView::setHighlightMoveDuration(int duration)
687
if (d->highlightMoveDuration != duration) {
688
d->highlightMoveDuration = duration;
689
emit highlightMoveDurationChanged();
693
QQuickTransition *QQuickItemView::populateTransition() const
695
Q_D(const QQuickItemView);
696
return d->transitioner ? d->transitioner->populateTransition : 0;
699
void QQuickItemView::setPopulateTransition(QQuickTransition *transition)
702
d->createTransitioner();
703
if (d->transitioner->populateTransition != transition) {
704
d->transitioner->populateTransition = transition;
705
emit populateTransitionChanged();
709
QQuickTransition *QQuickItemView::addTransition() const
711
Q_D(const QQuickItemView);
712
return d->transitioner ? d->transitioner->addTransition : 0;
715
void QQuickItemView::setAddTransition(QQuickTransition *transition)
718
d->createTransitioner();
719
if (d->transitioner->addTransition != transition) {
720
d->transitioner->addTransition = transition;
721
emit addTransitionChanged();
725
QQuickTransition *QQuickItemView::addDisplacedTransition() const
727
Q_D(const QQuickItemView);
728
return d->transitioner ? d->transitioner->addDisplacedTransition : 0;
731
void QQuickItemView::setAddDisplacedTransition(QQuickTransition *transition)
734
d->createTransitioner();
735
if (d->transitioner->addDisplacedTransition != transition) {
736
d->transitioner->addDisplacedTransition = transition;
737
emit addDisplacedTransitionChanged();
741
QQuickTransition *QQuickItemView::moveTransition() const
743
Q_D(const QQuickItemView);
744
return d->transitioner ? d->transitioner->moveTransition : 0;
747
void QQuickItemView::setMoveTransition(QQuickTransition *transition)
750
d->createTransitioner();
751
if (d->transitioner->moveTransition != transition) {
752
d->transitioner->moveTransition = transition;
753
emit moveTransitionChanged();
757
QQuickTransition *QQuickItemView::moveDisplacedTransition() const
759
Q_D(const QQuickItemView);
760
return d->transitioner ? d->transitioner->moveDisplacedTransition : 0;
763
void QQuickItemView::setMoveDisplacedTransition(QQuickTransition *transition)
766
d->createTransitioner();
767
if (d->transitioner->moveDisplacedTransition != transition) {
768
d->transitioner->moveDisplacedTransition = transition;
769
emit moveDisplacedTransitionChanged();
773
QQuickTransition *QQuickItemView::removeTransition() const
775
Q_D(const QQuickItemView);
776
return d->transitioner ? d->transitioner->removeTransition : 0;
779
void QQuickItemView::setRemoveTransition(QQuickTransition *transition)
782
d->createTransitioner();
783
if (d->transitioner->removeTransition != transition) {
784
d->transitioner->removeTransition = transition;
785
emit removeTransitionChanged();
789
QQuickTransition *QQuickItemView::removeDisplacedTransition() const
791
Q_D(const QQuickItemView);
792
return d->transitioner ? d->transitioner->removeDisplacedTransition : 0;
795
void QQuickItemView::setRemoveDisplacedTransition(QQuickTransition *transition)
798
d->createTransitioner();
799
if (d->transitioner->removeDisplacedTransition != transition) {
800
d->transitioner->removeDisplacedTransition = transition;
801
emit removeDisplacedTransitionChanged();
805
QQuickTransition *QQuickItemView::displacedTransition() const
807
Q_D(const QQuickItemView);
808
return d->transitioner ? d->transitioner->displacedTransition : 0;
811
void QQuickItemView::setDisplacedTransition(QQuickTransition *transition)
814
d->createTransitioner();
815
if (d->transitioner->displacedTransition != transition) {
816
d->transitioner->displacedTransition = transition;
817
emit displacedTransitionChanged();
821
void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode)
826
if (mode < QQuickItemView::Beginning || mode > QQuickItemView::Contain)
829
applyPendingChanges();
830
int idx = qMax(qMin(index, model->count()-1), 0);
832
qreal pos = isContentFlowReversed() ? -position() - size() : position();
833
FxViewItem *item = visibleItem(idx);
835
if (layoutOrientation() == Qt::Vertical)
836
maxExtent = isContentFlowReversed() ? q->minYExtent()-size(): -q->maxYExtent();
838
maxExtent = isContentFlowReversed() ? q->minXExtent()-size(): -q->maxXExtent();
840
int itemPos = positionAt(idx);
841
changedVisibleIndex(idx);
842
// save the currently visible items in case any of them end up visible again
843
QList<FxViewItem *> oldVisible = visibleItems;
844
visibleItems.clear();
845
setPosition(qMin(qreal(itemPos), maxExtent));
846
// now release the reference to all the old visible items.
847
for (int i = 0; i < oldVisible.count(); ++i)
848
releaseItem(oldVisible.at(i));
849
item = visibleItem(idx);
852
const qreal itemPos = item->position();
854
case QQuickItemView::Beginning:
856
if (index < 0 && header)
859
case QQuickItemView::Center:
860
pos = itemPos - (size() - item->size())/2;
862
case QQuickItemView::End:
863
pos = itemPos - size() + item->size();
864
if (index >= model->count() && footer)
867
case QQuickItemView::Visible:
868
if (itemPos > pos + size())
869
pos = itemPos - size() + item->size();
870
else if (item->endPosition() <= pos)
873
case QQuickItemView::Contain:
874
if (item->endPosition() >= pos + size())
875
pos = itemPos - size() + item->size();
879
pos = qMin(pos, maxExtent);
881
if (layoutOrientation() == Qt::Vertical)
882
minExtent = isContentFlowReversed() ? q->maxYExtent()-size(): -q->minYExtent();
884
minExtent = isContentFlowReversed() ? q->maxXExtent()-size(): -q->minXExtent();
885
pos = qMax(pos, minExtent);
886
moveReason = QQuickItemViewPrivate::Other;
892
resetHighlightPosition();
899
void QQuickItemView::positionViewAtIndex(int index, int mode)
902
if (!d->isValid() || index < 0 || index >= d->model->count())
904
d->positionViewAtIndex(index, mode);
908
void QQuickItemView::positionViewAtBeginning()
913
d->positionViewAtIndex(-1, Beginning);
916
void QQuickItemView::positionViewAtEnd()
921
d->positionViewAtIndex(d->model->count(), End);
924
int QQuickItemView::indexAt(qreal x, qreal y) const
926
Q_D(const QQuickItemView);
927
for (int i = 0; i < d->visibleItems.count(); ++i) {
928
const FxViewItem *item = d->visibleItems.at(i);
929
if (item->contains(x, y))
936
QQuickItem *QQuickItemView::itemAt(qreal x, qreal y) const
938
Q_D(const QQuickItemView);
939
for (int i = 0; i < d->visibleItems.count(); ++i) {
940
const FxViewItem *item = d->visibleItems.at(i);
941
if (item->contains(x, y))
948
void QQuickItemViewPrivate::applyPendingChanges()
951
if (q->isComponentComplete() && currentChanges.hasPendingChanges())
955
int QQuickItemViewPrivate::findMoveKeyIndex(QQuickChangeSet::MoveKey key, const QVector<QQuickChangeSet::Remove> &changes) const
957
for (int i=0; i<changes.count(); i++) {
958
for (int j=changes[i].index; j<changes[i].index + changes[i].count; j++) {
959
if (changes[i].moveKey(j) == key)
966
qreal QQuickItemViewPrivate::minExtentForAxis(const AxisData &axisData, bool forXAxis) const
968
Q_Q(const QQuickItemView);
970
qreal highlightStart;
972
qreal endPositionFirstItem = 0;
973
qreal extent = -startPosition() + axisData.startMargin;
974
if (isContentFlowReversed()) {
975
if (model && model->count())
976
endPositionFirstItem = positionAt(model->count()-1);
978
extent += headerSize();
979
highlightStart = highlightRangeEndValid ? size() - highlightRangeEnd : size();
980
highlightEnd = highlightRangeStartValid ? size() - highlightRangeStart : size();
981
extent += footerSize();
982
qreal maxExtentAlongAxis = forXAxis ? q->maxXExtent() : q->maxYExtent();
983
if (extent < maxExtentAlongAxis)
984
extent = maxExtentAlongAxis;
986
endPositionFirstItem = endPositionAt(0);
987
highlightStart = highlightRangeStart;
988
highlightEnd = highlightRangeEnd;
989
extent += headerSize();
991
if (haveHighlightRange && highlightRange == QQuickItemView::StrictlyEnforceRange) {
992
extent += highlightStart;
993
FxViewItem *firstItem = visibleItem(0);
995
extent -= firstItem->sectionSize();
996
extent = isContentFlowReversed()
997
? qMin(extent, endPositionFirstItem + highlightEnd)
998
: qMax(extent, -(endPositionFirstItem - highlightEnd));
1003
qreal QQuickItemViewPrivate::maxExtentForAxis(const AxisData &axisData, bool forXAxis) const
1005
Q_Q(const QQuickItemView);
1007
qreal highlightStart;
1009
qreal lastItemPosition = 0;
1011
if (isContentFlowReversed()) {
1012
highlightStart = highlightRangeEndValid ? size() - highlightRangeEnd : size();
1013
highlightEnd = highlightRangeStartValid ? size() - highlightRangeStart : size();
1014
lastItemPosition = endPosition();
1016
highlightStart = highlightRangeStart;
1017
highlightEnd = highlightRangeEnd;
1018
if (model && model->count())
1019
lastItemPosition = positionAt(model->count()-1);
1021
if (!model || !model->count()) {
1022
if (!isContentFlowReversed())
1023
maxExtent = header ? -headerSize() : 0;
1024
extent += forXAxis ? q->width() : q->height();
1025
} else if (haveHighlightRange && highlightRange == QQuickItemView::StrictlyEnforceRange) {
1026
extent = -(lastItemPosition - highlightStart);
1027
if (highlightEnd != highlightStart) {
1028
extent = isContentFlowReversed()
1029
? qMax(extent, -(endPosition() - highlightEnd))
1030
: qMin(extent, -(endPosition() - highlightEnd));
1033
extent = -(endPosition() - (forXAxis ? q->width() : q->height()));
1035
if (isContentFlowReversed()) {
1036
extent -= headerSize();
1037
extent -= axisData.endMargin;
1039
extent -= footerSize();
1040
extent -= axisData.endMargin;
1041
qreal minExtentAlongAxis = forXAxis ? q->minXExtent() : q->minYExtent();
1042
if (extent > minExtentAlongAxis)
1043
extent = minExtentAlongAxis;
1049
// for debugging only
1050
void QQuickItemViewPrivate::checkVisible() const
1053
for (int i = 0; i < visibleItems.count(); ++i) {
1054
FxViewItem *item = visibleItems.at(i);
1055
if (item->index == -1) {
1057
} else if (item->index != visibleIndex + i - skip) {
1058
qFatal("index %d %d %d", visibleIndex, i, item->index);
1063
// for debugging only
1064
void QQuickItemViewPrivate::showVisibleItems() const
1066
qDebug() << "Visible items:";
1067
for (int i = 0; i < visibleItems.count(); ++i) {
1068
qDebug() << "\t" << visibleItems[i]->index
1069
<< visibleItems[i]->item->objectName()
1070
<< visibleItems[i]->position();
1074
void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
1076
Q_Q(QQuickItemView);
1077
QQuickFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
1078
if (!q->isComponentComplete())
1081
if (header && header->item == item) {
1084
if (!q->isMoving() && !q->isFlicking())
1086
} else if (footer && footer->item == item) {
1089
if (!q->isMoving() && !q->isFlicking())
1093
if (currentItem && currentItem->item == item) {
1094
// don't allow item movement transitions to trigger a re-layout and
1095
// start new transitions
1096
bool prevDisableLayout = disableLayout;
1097
if (!disableLayout) {
1098
FxViewItem *actualItem = transitioner ? visibleItem(currentIndex) : 0;
1099
if (actualItem && actualItem->transitionRunning())
1100
disableLayout = true;
1103
disableLayout = prevDisableLayout;
1106
if (trackedItem && trackedItem->item == item)
1107
q->trackedPositionChanged();
1110
void QQuickItemView::destroyRemoved()
1112
Q_D(QQuickItemView);
1113
for (QList<FxViewItem*>::Iterator it = d->visibleItems.begin();
1114
it != d->visibleItems.end();) {
1115
FxViewItem *item = *it;
1116
if (item->index == -1 && item->attached->delayRemove() == false) {
1117
if (d->transitioner && d->transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, true)) {
1118
// don't remove from visibleItems until next layout()
1119
d->runDelayedRemoveTransition = true;
1120
QObject::disconnect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()));
1123
d->releaseItem(item);
1124
it = d->visibleItems.erase(it);
1131
// Correct the positioning of the items
1132
d->updateSections();
1133
d->forceLayout = true;
1137
void QQuickItemView::modelUpdated(const QQuickChangeSet &changeSet, bool reset)
1139
Q_D(QQuickItemView);
1141
if (d->transitioner)
1142
d->transitioner->setPopulateTransitionEnabled(true);
1143
d->moveReason = QQuickItemViewPrivate::SetIndex;
1145
if (d->highlight && d->currentItem) {
1146
if (d->autoHighlight)
1147
d->resetHighlightPosition();
1148
d->updateTrackedItem();
1150
d->moveReason = QQuickItemViewPrivate::Other;
1151
emit countChanged();
1152
if (d->transitioner && d->transitioner->populateTransition) {
1153
d->forceLayout = true;
1157
if (d->disableLayout) {
1158
d->bufferedChanges.prepare(d->currentIndex, d->itemCount);
1159
d->bufferedChanges.applyChanges(changeSet);
1161
if (d->bufferedChanges.hasPendingChanges()) {
1162
d->currentChanges.applyBufferedChanges(d->bufferedChanges);
1163
d->bufferedChanges.reset();
1165
d->currentChanges.prepare(d->currentIndex, d->itemCount);
1166
d->currentChanges.applyChanges(changeSet);
1172
void QQuickItemView::animStopped()
1174
Q_D(QQuickItemView);
1175
d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
1176
d->refillOrLayout();
1177
if (d->haveHighlightRange && d->highlightRange == QQuickItemView::StrictlyEnforceRange)
1178
d->updateHighlight();
1182
void QQuickItemView::trackedPositionChanged()
1184
Q_D(QQuickItemView);
1185
if (!d->trackedItem || !d->currentItem)
1187
if (d->moveReason == QQuickItemViewPrivate::SetIndex) {
1188
qreal trackedPos = d->trackedItem->position();
1189
qreal trackedSize = d->trackedItem->size();
1190
qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
1191
qreal pos = viewPos;
1192
if (d->haveHighlightRange) {
1193
if (trackedPos > pos + d->highlightRangeEnd - trackedSize)
1194
pos = trackedPos - d->highlightRangeEnd + trackedSize;
1195
if (trackedPos < pos + d->highlightRangeStart)
1196
pos = trackedPos - d->highlightRangeStart;
1197
if (d->highlightRange != StrictlyEnforceRange) {
1198
if (pos > d->endPosition() - d->size())
1199
pos = d->endPosition() - d->size();
1200
if (pos < d->startPosition())
1201
pos = d->startPosition();
1204
if (d->trackedItem != d->currentItem) {
1205
// also make section header visible
1206
trackedPos -= d->currentItem->sectionSize();
1207
trackedSize += d->currentItem->sectionSize();
1209
qreal trackedEndPos = d->trackedItem->endPosition();
1210
qreal toItemPos = d->currentItem->position();
1211
qreal toItemEndPos = d->currentItem->endPosition();
1212
if (d->showHeaderForIndex(d->currentIndex)) {
1213
qreal startOffset = -d->contentStartOffset();
1214
trackedPos -= startOffset;
1215
trackedEndPos -= startOffset;
1216
toItemPos -= startOffset;
1217
toItemEndPos -= startOffset;
1218
} else if (d->showFooterForIndex(d->currentIndex)) {
1219
qreal endOffset = d->footerSize();
1220
if (d->layoutOrientation() == Qt::Vertical) {
1221
if (d->isContentFlowReversed())
1222
endOffset += d->vData.startMargin;
1224
endOffset += d->vData.endMargin;
1226
if (d->isContentFlowReversed())
1227
endOffset += d->hData.startMargin;
1229
endOffset += d->hData.endMargin;
1231
trackedPos += endOffset;
1232
trackedEndPos += endOffset;
1233
toItemPos += endOffset;
1234
toItemEndPos += endOffset;
1237
if (trackedEndPos >= viewPos + d->size()
1238
&& toItemEndPos >= viewPos + d->size()) {
1239
if (trackedEndPos <= toItemEndPos) {
1240
pos = trackedEndPos - d->size();
1241
if (trackedSize > d->size())
1244
pos = toItemEndPos - d->size();
1245
if (d->currentItem->size() > d->size())
1246
pos = d->currentItem->position();
1249
if (trackedPos < pos && toItemPos < pos)
1250
pos = qMax(trackedPos, toItemPos);
1252
if (viewPos != pos) {
1254
d->calcVelocity = true;
1255
d->setPosition(pos);
1256
d->calcVelocity = false;
1261
void QQuickItemView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
1263
Q_D(QQuickItemView);
1264
d->markExtentsDirty();
1265
if (isComponentComplete() && d->isValid()) {
1266
d->forceLayout = true;
1269
QQuickFlickable::geometryChanged(newGeometry, oldGeometry);
1272
qreal QQuickItemView::minYExtent() const
1274
Q_D(const QQuickItemView);
1275
if (d->layoutOrientation() == Qt::Horizontal)
1276
return QQuickFlickable::minYExtent();
1278
if (d->vData.minExtentDirty) {
1279
d->minExtent = d->minExtentForAxis(d->vData, false);
1280
d->vData.minExtentDirty = false;
1283
return d->minExtent;
1286
qreal QQuickItemView::maxYExtent() const
1288
Q_D(const QQuickItemView);
1289
if (d->layoutOrientation() == Qt::Horizontal)
1292
if (d->vData.maxExtentDirty) {
1293
d->maxExtent = d->maxExtentForAxis(d->vData, false);
1294
d->vData.maxExtentDirty = false;
1297
return d->maxExtent;
1300
qreal QQuickItemView::minXExtent() const
1302
Q_D(const QQuickItemView);
1303
if (d->layoutOrientation() == Qt::Vertical)
1304
return QQuickFlickable::minXExtent();
1306
if (d->hData.minExtentDirty) {
1307
d->minExtent = d->minExtentForAxis(d->hData, true);
1308
d->hData.minExtentDirty = false;
1311
return d->minExtent;
1314
qreal QQuickItemView::maxXExtent() const
1316
Q_D(const QQuickItemView);
1317
if (d->layoutOrientation() == Qt::Vertical)
1320
if (d->hData.maxExtentDirty) {
1321
d->maxExtent = d->maxExtentForAxis(d->hData, true);
1322
d->hData.maxExtentDirty = false;
1325
return d->maxExtent;
1328
void QQuickItemView::setContentX(qreal pos)
1330
Q_D(QQuickItemView);
1331
// Positioning the view manually should override any current movement state
1332
d->moveReason = QQuickItemViewPrivate::Other;
1333
QQuickFlickable::setContentX(pos);
1336
void QQuickItemView::setContentY(qreal pos)
1338
Q_D(QQuickItemView);
1339
// Positioning the view manually should override any current movement state
1340
d->moveReason = QQuickItemViewPrivate::Other;
1341
QQuickFlickable::setContentY(pos);
1344
qreal QQuickItemView::xOrigin() const
1346
Q_D(const QQuickItemView);
1347
if (d->isContentFlowReversed())
1348
return -maxXExtent() + d->size() - d->hData.endMargin;
1350
return -minXExtent() + d->hData.startMargin;
1353
qreal QQuickItemView::yOrigin() const
1355
Q_D(const QQuickItemView);
1356
if (d->isContentFlowReversed())
1357
return -maxYExtent() + d->size() - d->vData.endMargin;
1359
return -minYExtent() + d->vData.startMargin;
1362
void QQuickItemView::updatePolish()
1364
Q_D(QQuickItemView);
1365
QQuickFlickable::updatePolish();
1369
void QQuickItemView::componentComplete()
1371
Q_D(QQuickItemView);
1372
if (d->model && d->ownModel)
1373
static_cast<QQuickVisualDataModel *>(d->model.data())->componentComplete();
1375
QQuickFlickable::componentComplete();
1380
d->updateViewport();
1381
d->setPosition(d->contentStartOffset());
1382
if (d->transitioner)
1383
d->transitioner->setPopulateTransitionEnabled(true);
1387
d->moveReason = QQuickItemViewPrivate::SetIndex;
1388
if (d->currentIndex < 0 && !d->currentIndexCleared)
1389
d->updateCurrent(0);
1391
d->updateCurrent(d->currentIndex);
1392
if (d->highlight && d->currentItem) {
1393
if (d->autoHighlight)
1394
d->resetHighlightPosition();
1395
d->updateTrackedItem();
1397
d->moveReason = QQuickItemViewPrivate::Other;
1400
if (d->model && d->model->count())
1401
emit countChanged();
1406
QQuickItemViewPrivate::QQuickItemViewPrivate()
1408
, buffer(0), bufferMode(BufferBefore | BufferAfter)
1409
, layoutDirection(Qt::LeftToRight), verticalLayoutDirection(QQuickItemView::TopToBottom)
1412
, currentIndex(-1), currentItem(0)
1413
, trackedItem(0), requestedIndex(-1), requestedItem(0)
1414
, highlightComponent(0), highlight(0)
1415
, highlightRange(QQuickItemView::NoHighlightRange)
1416
, highlightRangeStart(0), highlightRangeEnd(0)
1417
, highlightMoveDuration(150)
1418
, headerComponent(0), header(0), footerComponent(0), footer(0)
1420
, minExtent(0), maxExtent(0)
1421
, ownModel(false), wrap(false)
1422
, disableLayout(false), inViewportMoved(false), forceLayout(false), currentIndexCleared(false)
1423
, haveHighlightRange(false), autoHighlight(true), highlightRangeStartValid(false), highlightRangeEndValid(false)
1424
, fillCacheBuffer(false), inRequest(false), requestedAsync(false)
1425
, runDelayedRemoveTransition(false)
1429
QQuickItemViewPrivate::~QQuickItemViewPrivate()
1432
transitioner->setChangeListener(0);
1433
delete transitioner;
1436
bool QQuickItemViewPrivate::isValid() const
1438
return model && model->count() && model->isValid();
1441
qreal QQuickItemViewPrivate::position() const
1443
Q_Q(const QQuickItemView);
1444
return layoutOrientation() == Qt::Vertical ? q->contentY() : q->contentX();
1447
qreal QQuickItemViewPrivate::size() const
1449
Q_Q(const QQuickItemView);
1450
return layoutOrientation() == Qt::Vertical ? q->height() : q->width();
1453
qreal QQuickItemViewPrivate::startPosition() const
1455
return isContentFlowReversed() ? -lastPosition() : originPosition();
1458
qreal QQuickItemViewPrivate::endPosition() const
1460
return isContentFlowReversed() ? -originPosition() : lastPosition();
1463
qreal QQuickItemViewPrivate::contentStartOffset() const
1465
qreal pos = -headerSize();
1466
if (layoutOrientation() == Qt::Vertical) {
1467
if (isContentFlowReversed())
1468
pos -= vData.endMargin;
1470
pos -= vData.startMargin;
1472
if (isContentFlowReversed())
1473
pos -= hData.endMargin;
1475
pos -= hData.startMargin;
1480
int QQuickItemViewPrivate::findLastVisibleIndex(int defaultValue) const
1482
if (visibleItems.count()) {
1483
int i = visibleItems.count() - 1;
1484
while (i > 0 && visibleItems.at(i)->index == -1)
1486
if (visibleItems.at(i)->index != -1)
1487
return visibleItems.at(i)->index;
1489
return defaultValue;
1492
FxViewItem *QQuickItemViewPrivate::visibleItem(int modelIndex) const {
1493
if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
1494
for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
1495
FxViewItem *item = visibleItems.at(i);
1496
if (item->index == modelIndex)
1503
// should rename to firstItemInView() to avoid confusion with other "*visible*" methods
1504
// that don't look at the view position and size
1505
FxViewItem *QQuickItemViewPrivate::firstVisibleItem() const {
1506
const qreal pos = isContentFlowReversed() ? -position()-size() : position();
1507
for (int i = 0; i < visibleItems.count(); ++i) {
1508
FxViewItem *item = visibleItems.at(i);
1509
if (item->index != -1 && item->endPosition() > pos)
1512
return visibleItems.count() ? visibleItems.first() : 0;
1515
int QQuickItemViewPrivate::findLastIndexInView() const
1517
const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
1518
for (int i=visibleItems.count() - 1; i>=0; i--) {
1519
if (visibleItems.at(i)->position() <= viewEndPos && visibleItems.at(i)->index != -1)
1520
return visibleItems.at(i)->index;
1525
// Map a model index to visibleItems list index.
1526
// These may differ if removed items are still present in the visible list,
1527
// e.g. doing a removal animation
1528
int QQuickItemViewPrivate::mapFromModel(int modelIndex) const
1530
if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
1532
for (int i = 0; i < visibleItems.count(); ++i) {
1533
FxViewItem *item = visibleItems.at(i);
1534
if (item->index == modelIndex)
1536
if (item->index > modelIndex)
1539
return -1; // Not in visibleList
1542
void QQuickItemViewPrivate::init()
1544
Q_Q(QQuickItemView);
1545
QQuickItemPrivate::get(contentItem)->childrenDoNotOverlap = true;
1546
q->setFlag(QQuickItem::ItemIsFocusScope);
1547
QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
1548
q->setFlickableDirection(QQuickFlickable::VerticalFlick);
1551
void QQuickItemViewPrivate::updateCurrent(int modelIndex)
1553
Q_Q(QQuickItemView);
1554
applyPendingChanges();
1555
if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
1557
currentItem->attached->setIsCurrentItem(false);
1558
releaseItem(currentItem);
1560
currentIndex = modelIndex;
1561
emit q->currentIndexChanged();
1562
emit q->currentItemChanged();
1564
} else if (currentIndex != modelIndex) {
1565
currentIndex = modelIndex;
1566
emit q->currentIndexChanged();
1571
if (currentItem && currentIndex == modelIndex) {
1576
FxViewItem *oldCurrentItem = currentItem;
1577
int oldCurrentIndex = currentIndex;
1578
currentIndex = modelIndex;
1579
currentItem = createItem(modelIndex, false);
1580
if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
1581
oldCurrentItem->attached->setIsCurrentItem(false);
1583
currentItem->item->setFocus(true);
1584
currentItem->attached->setIsCurrentItem(true);
1585
initializeCurrentItem();
1589
if (oldCurrentIndex != currentIndex)
1590
emit q->currentIndexChanged();
1591
if (oldCurrentItem != currentItem)
1592
emit q->currentItemChanged();
1593
releaseItem(oldCurrentItem);
1596
void QQuickItemViewPrivate::clear()
1598
currentChanges.reset();
1601
for (int i = 0; i < visibleItems.count(); ++i)
1602
releaseItem(visibleItems.at(i));
1603
visibleItems.clear();
1606
for (int i = 0; i < releasePendingTransition.count(); ++i) {
1607
releasePendingTransition.at(i)->releaseAfterTransition = false;
1608
releaseItem(releasePendingTransition.at(i));
1610
releasePendingTransition.clear();
1612
releaseItem(currentItem);
1617
if (requestedIndex >= 0 && requestedAsync) {
1619
model->cancel(requestedIndex);
1620
requestedIndex = -1;
1628
void QQuickItemViewPrivate::mirrorChange()
1630
Q_Q(QQuickItemView);
1632
emit q->effectiveLayoutDirectionChanged();
1635
void QQuickItemViewPrivate::refill()
1637
qreal s = qMax(size(), qreal(0.));
1638
if (isContentFlowReversed())
1639
refill(-position()-s, -position());
1641
refill(position(), position()+s);
1644
void QQuickItemViewPrivate::refill(qreal from, qreal to)
1646
Q_Q(QQuickItemView);
1647
if (!isValid() || !q->isComponentComplete())
1650
currentChanges.reset();
1652
int prevCount = itemCount;
1653
itemCount = model->count();
1654
qreal bufferFrom = from - buffer;
1655
qreal bufferTo = to + buffer;
1656
qreal fillFrom = from;
1659
bool added = addVisibleItems(fillFrom, fillTo, false);
1660
bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
1662
if (buffer && bufferMode != NoBuffer) {
1663
if (bufferMode & BufferAfter)
1665
if (bufferMode & BufferBefore)
1666
fillFrom = bufferFrom;
1667
added |= addVisibleItems(fillFrom, fillTo, true);
1670
if (added || removed) {
1672
updateBeginningEnd();
1673
visibleItemsChanged();
1679
if (prevCount != itemCount)
1680
emit q->countChanged();
1683
void QQuickItemViewPrivate::regenerate()
1685
Q_Q(QQuickItemView);
1686
if (q->isComponentComplete()) {
1687
currentChanges.reset();
1696
setPosition(contentStartOffset());
1698
updateCurrent(currentIndex);
1702
void QQuickItemViewPrivate::updateViewport()
1704
Q_Q(QQuickItemView);
1706
qreal extra = headerSize() + footerSize();
1707
if (layoutOrientation() == Qt::Vertical)
1708
q->setContentHeight(endPosition() - startPosition() + extra);
1710
q->setContentWidth(endPosition() - startPosition() + extra);
1714
void QQuickItemViewPrivate::layout()
1716
Q_Q(QQuickItemView);
1720
if (!isValid() && !visibleItems.count()) {
1722
setPosition(contentStartOffset());
1724
transitioner->setPopulateTransitionEnabled(false);
1728
if (runDelayedRemoveTransition && transitioner
1729
&& transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false)) {
1730
// assume that any items moving now are moving due to the remove - if they schedule
1731
// a different transition, that will override this one anyway
1732
for (int i=0; i<visibleItems.count(); i++)
1733
visibleItems[i]->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
1736
ChangeResult insertionPosChanges;
1737
ChangeResult removalPosChanges;
1738
if (!applyModelChanges(&insertionPosChanges, &removalPosChanges) && !forceLayout) {
1739
if (fillCacheBuffer) {
1740
fillCacheBuffer = false;
1745
forceLayout = false;
1747
if (transitioner && transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) {
1748
for (int i=0; i<visibleItems.count(); i++)
1749
visibleItems.at(i)->transitionNextReposition(transitioner, QQuickItemViewTransitioner::PopulateTransition, true);
1751
layoutVisibleItems();
1753
int lastIndexInView = findLastIndexInView();
1758
if (!q->isMoving() && !q->isFlicking()) {
1766
updateUnrequestedPositions();
1769
// items added in the last refill() may need to be transitioned in - e.g. a remove
1770
// causes items to slide up into view
1771
if (transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, false)
1772
|| transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false)) {
1773
translateAndTransitionItemsAfter(lastIndexInView, insertionPosChanges, removalPosChanges);
1776
prepareVisibleItemTransitions();
1778
QRectF viewBounds(0, position(), q->width(), q->height());
1779
for (QList<FxViewItem*>::Iterator it = releasePendingTransition.begin();
1780
it != releasePendingTransition.end(); ) {
1781
FxViewItem *item = *it;
1782
if (prepareNonVisibleItemTransition(item, viewBounds)) {
1786
it = releasePendingTransition.erase(it);
1790
for (int i=0; i<visibleItems.count(); i++)
1791
visibleItems[i]->startTransition(transitioner);
1792
for (int i=0; i<releasePendingTransition.count(); i++)
1793
releasePendingTransition[i]->startTransition(transitioner);
1795
transitioner->setPopulateTransitionEnabled(false);
1796
transitioner->resetTargetLists();
1799
runDelayedRemoveTransition = false;
1802
bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult, ChangeResult *totalRemovalResult)
1804
Q_Q(QQuickItemView);
1805
if (!q->isComponentComplete() || !hasPendingChanges() || disableLayout)
1808
disableLayout = true;
1810
if (bufferedChanges.hasPendingChanges()) {
1811
currentChanges.applyBufferedChanges(bufferedChanges);
1812
bufferedChanges.reset();
1815
updateUnrequestedIndexes();
1816
moveReason = QQuickItemViewPrivate::Other;
1818
FxViewItem *prevVisibleItemsFirst = visibleItems.count() ? *visibleItems.constBegin() : 0;
1819
int prevItemCount = itemCount;
1820
int prevVisibleItemsCount = visibleItems.count();
1821
bool visibleAffected = false;
1822
bool viewportChanged = !currentChanges.pendingChanges.removes().isEmpty()
1823
|| !currentChanges.pendingChanges.inserts().isEmpty();
1825
FxViewItem *prevFirstVisible = firstVisibleItem();
1826
QQmlNullableValue<qreal> prevViewPos;
1827
int prevFirstVisibleIndex = -1;
1828
if (prevFirstVisible) {
1829
prevViewPos = prevFirstVisible->position();
1830
prevFirstVisibleIndex = prevFirstVisible->index;
1832
qreal prevVisibleItemsFirstPos = visibleItems.count() ? visibleItems.first()->position() : 0.0;
1834
totalInsertionResult->visiblePos = prevViewPos;
1835
totalRemovalResult->visiblePos = prevViewPos;
1837
const QVector<QQuickChangeSet::Remove> &removals = currentChanges.pendingChanges.removes();
1838
const QVector<QQuickChangeSet::Insert> &insertions = currentChanges.pendingChanges.inserts();
1839
ChangeResult insertionResult(prevViewPos);
1840
ChangeResult removalResult(prevViewPos);
1842
int removedCount = 0;
1843
for (int i=0; i<removals.count(); i++) {
1844
itemCount -= removals[i].count;
1845
if (applyRemovalChange(removals[i], &removalResult, &removedCount))
1846
visibleAffected = true;
1847
if (!visibleAffected && needsRefillForAddedOrRemovedIndex(removals[i].index))
1848
visibleAffected = true;
1849
if (prevFirstVisibleIndex >= 0 && removals[i].index < prevFirstVisibleIndex) {
1850
if (removals[i].index + removals[i].count < prevFirstVisibleIndex)
1851
removalResult.countChangeBeforeVisible += removals[i].count;
1853
removalResult.countChangeBeforeVisible += (prevFirstVisibleIndex - removals[i].index);
1856
if (runDelayedRemoveTransition) {
1857
QQuickChangeSet::Remove removal;
1858
for (QList<FxViewItem*>::Iterator it = visibleItems.begin(); it != visibleItems.end();) {
1859
FxViewItem *item = *it;
1860
if (item->index == -1 && !item->attached->delayRemove()) {
1861
removeItem(item, removal, &removalResult);
1863
it = visibleItems.erase(it);
1869
*totalRemovalResult += removalResult;
1870
if (!removals.isEmpty()) {
1871
updateVisibleIndex();
1873
// set positions correctly for the next insertion
1874
if (!insertions.isEmpty()) {
1875
repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, &insertionResult, &removalResult);
1876
layoutVisibleItems(removals.first().index);
1880
QList<FxViewItem *> newItems;
1881
QList<MovedItem> movingIntoView;
1883
for (int i=0; i<insertions.count(); i++) {
1884
bool wasEmpty = visibleItems.isEmpty();
1885
if (applyInsertionChange(insertions[i], &insertionResult, &newItems, &movingIntoView))
1886
visibleAffected = true;
1887
if (!visibleAffected && needsRefillForAddedOrRemovedIndex(insertions[i].index))
1888
visibleAffected = true;
1889
if (wasEmpty && !visibleItems.isEmpty())
1890
resetFirstItemPosition();
1891
*totalInsertionResult += insertionResult;
1893
// set positions correctly for the next insertion
1894
if (i < insertions.count() - 1) {
1895
repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, &insertionResult, &removalResult);
1896
layoutVisibleItems(insertions[i].index);
1898
itemCount += insertions[i].count;
1900
for (int i=0; i<newItems.count(); i++)
1901
newItems.at(i)->attached->emitAdd();
1903
// for each item that was moved directly into the view as a result of a move(),
1904
// find the index it was moved from in order to set its initial position, so that we
1905
// can transition it from this "original" position to its new position in the view
1906
if (transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true)) {
1907
for (int i=0; i<movingIntoView.count(); i++) {
1908
int fromIndex = findMoveKeyIndex(movingIntoView[i].moveKey, removals);
1909
if (fromIndex >= 0) {
1910
if (prevFirstVisibleIndex >= 0 && fromIndex < prevFirstVisibleIndex)
1911
repositionItemAt(movingIntoView[i].item, fromIndex, -totalInsertionResult->sizeChangesAfterVisiblePos);
1913
repositionItemAt(movingIntoView[i].item, fromIndex, totalInsertionResult->sizeChangesAfterVisiblePos);
1914
movingIntoView[i].item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, true);
1919
// reposition visibleItems.first() correctly so that the content y doesn't jump
1920
if (removedCount != prevVisibleItemsCount)
1921
repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible, &insertionResult, &removalResult);
1923
// Whatever removed/moved items remain are no longer visible items.
1924
prepareRemoveTransitions(¤tChanges.removedItems);
1925
for (QHash<QQuickChangeSet::MoveKey, FxViewItem *>::Iterator it = currentChanges.removedItems.begin();
1926
it != currentChanges.removedItems.end(); ++it) {
1927
releaseItem(it.value());
1929
currentChanges.removedItems.clear();
1931
if (currentChanges.currentChanged) {
1932
if (currentChanges.currentRemoved && currentItem) {
1933
currentItem->attached->setIsCurrentItem(false);
1934
releaseItem(currentItem);
1937
if (!currentIndexCleared)
1938
updateCurrent(currentChanges.newCurrentIndex);
1941
if (!visibleAffected)
1942
visibleAffected = !currentChanges.pendingChanges.changes().isEmpty();
1943
currentChanges.reset();
1946
if (prevItemCount != itemCount)
1947
emit q->countChanged();
1948
if (!visibleAffected && viewportChanged)
1951
disableLayout = false;
1952
return visibleAffected;
1955
bool QQuickItemViewPrivate::applyRemovalChange(const QQuickChangeSet::Remove &removal, ChangeResult *removeResult, int *removedCount)
1957
Q_Q(QQuickItemView);
1958
bool visibleAffected = false;
1960
if (visibleItems.count() && removal.index + removal.count > visibleItems.last()->index) {
1961
if (removal.index > visibleItems.last()->index)
1962
removeResult->countChangeAfterVisibleItems += removal.count;
1964
removeResult->countChangeAfterVisibleItems += ((removal.index + removal.count - 1) - visibleItems.last()->index);
1967
QList<FxViewItem*>::Iterator it = visibleItems.begin();
1968
while (it != visibleItems.end()) {
1969
FxViewItem *item = *it;
1970
if (item->index == -1 || item->index < removal.index) {
1971
// already removed, or before removed items
1972
if (!visibleAffected && item->index < removal.index)
1973
visibleAffected = true;
1975
} else if (item->index >= removal.index + removal.count) {
1976
// after removed items
1977
item->index -= removal.count;
1978
if (removal.isMove())
1979
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false);
1981
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
1985
visibleAffected = true;
1986
if (!removal.isMove())
1987
item->attached->emitRemove();
1989
if (item->attached->delayRemove() && !removal.isMove()) {
1991
QObject::connect(item->attached, SIGNAL(delayRemoveChanged()), q, SLOT(destroyRemoved()), Qt::QueuedConnection);
1994
removeItem(item, removal, removeResult);
1995
if (!removal.isMove())
1997
it = visibleItems.erase(it);
2002
return visibleAffected;
2005
void QQuickItemViewPrivate::removeItem(FxViewItem *item, const QQuickChangeSet::Remove &removal, ChangeResult *removeResult)
2007
if (removeResult->visiblePos.isValid()) {
2008
if (item->position() < removeResult->visiblePos)
2009
removeResult->sizeChangesBeforeVisiblePos += item->size();
2011
removeResult->sizeChangesAfterVisiblePos += item->size();
2013
if (removal.isMove()) {
2014
currentChanges.removedItems.insert(removal.moveKey(item->index), item);
2015
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, true);
2017
// track item so it is released later
2018
currentChanges.removedItems.insertMulti(QQuickChangeSet::MoveKey(), item);
2020
if (!removeResult->changedFirstItem && item == *visibleItems.constBegin())
2021
removeResult->changedFirstItem = true;
2024
void QQuickItemViewPrivate::repositionFirstItem(FxViewItem *prevVisibleItemsFirst,
2025
qreal prevVisibleItemsFirstPos,
2026
FxViewItem *prevFirstVisible,
2027
ChangeResult *insertionResult,
2028
ChangeResult *removalResult)
2030
const QQmlNullableValue<qreal> prevViewPos = insertionResult->visiblePos;
2032
// reposition visibleItems.first() correctly so that the content y doesn't jump
2033
if (visibleItems.count()) {
2034
if (prevVisibleItemsFirst && insertionResult->changedFirstItem)
2035
resetFirstItemPosition(prevVisibleItemsFirstPos);
2037
if (prevFirstVisible && prevVisibleItemsFirst == prevFirstVisible
2038
&& prevFirstVisible != *visibleItems.constBegin()) {
2039
// the previous visibleItems.first() was also the first visible item, and it has been
2040
// moved/removed, so move the new visibleItems.first() to the pos of the previous one
2041
if (!insertionResult->changedFirstItem)
2042
resetFirstItemPosition(prevVisibleItemsFirstPos);
2044
} else if (prevViewPos.isValid()) {
2045
qreal moveForwardsBy = 0;
2046
qreal moveBackwardsBy = 0;
2048
// shift visibleItems.first() relative to the number of added/removed items
2049
if (visibleItems.first()->position() > prevViewPos) {
2050
moveForwardsBy = insertionResult->sizeChangesAfterVisiblePos;
2051
moveBackwardsBy = removalResult->sizeChangesAfterVisiblePos;
2052
} else if (visibleItems.first()->position() < prevViewPos) {
2053
moveForwardsBy = removalResult->sizeChangesBeforeVisiblePos;
2054
moveBackwardsBy = insertionResult->sizeChangesBeforeVisiblePos;
2056
adjustFirstItem(moveForwardsBy, moveBackwardsBy, insertionResult->countChangeBeforeVisible - removalResult->countChangeBeforeVisible);
2058
insertionResult->reset();
2059
removalResult->reset();
2063
void QQuickItemViewPrivate::createTransitioner()
2065
if (!transitioner) {
2066
transitioner = new QQuickItemViewTransitioner;
2067
transitioner->setChangeListener(this);
2071
void QQuickItemViewPrivate::prepareVisibleItemTransitions()
2073
Q_Q(QQuickItemView);
2077
// must call for every visible item to init or discard transitions
2078
QRectF viewBounds(0, position(), q->width(), q->height());
2079
for (int i=0; i<visibleItems.count(); i++)
2080
visibleItems[i]->prepareTransition(transitioner, viewBounds);
2083
void QQuickItemViewPrivate::prepareRemoveTransitions(QHash<QQuickChangeSet::MoveKey, FxViewItem *> *removedItems)
2088
if (transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, true)
2089
|| transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false)) {
2090
for (QHash<QQuickChangeSet::MoveKey, FxViewItem *>::Iterator it = removedItems->begin();
2091
it != removedItems->end(); ) {
2092
bool isRemove = it.key().moveId < 0;
2094
FxViewItem *item = *it;
2095
item->releaseAfterTransition = true;
2096
releasePendingTransition.append(item);
2097
item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, true);
2098
it = removedItems->erase(it);
2106
bool QQuickItemViewPrivate::prepareNonVisibleItemTransition(FxViewItem *item, const QRectF &viewBounds)
2108
// Called for items that have been removed from visibleItems and may now be
2109
// transitioned out of the view. This applies to items that are being directly
2110
// removed, or moved to outside of the view, as well as those that are
2111
// displaced to a position outside of the view due to an insert or move.
2116
if (item->scheduledTransitionType() == QQuickItemViewTransitioner::MoveTransition)
2117
repositionItemAt(item, item->index, 0);
2119
if (item->prepareTransition(transitioner, viewBounds)) {
2120
item->releaseAfterTransition = true;
2126
void QQuickItemViewPrivate::viewItemTransitionFinished(QQuickItemViewTransitionableItem *item)
2128
for (int i=0; i<releasePendingTransition.count(); i++) {
2129
if (releasePendingTransition[i]->transitionableItem == item) {
2130
releaseItem(releasePendingTransition.takeAt(i));
2137
This may return 0 if the item is being created asynchronously.
2138
When the item becomes available, refill() will be called and the item
2139
will be returned on the next call to createItem().
2141
FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, bool asynchronous)
2143
Q_Q(QQuickItemView);
2145
if (requestedIndex == modelIndex && (asynchronous || requestedAsync == asynchronous))
2148
if (requestedIndex != -1 && requestedIndex != modelIndex) {
2149
if (requestedItem && requestedItem->item)
2150
requestedItem->item->setParentItem(0);
2151
delete requestedItem;
2155
for (int i=0; i<releasePendingTransition.count(); i++) {
2156
if (releasePendingTransition[i]->index == modelIndex
2157
&& !releasePendingTransition[i]->isPendingRemoval()) {
2158
releasePendingTransition[i]->releaseAfterTransition = false;
2159
return releasePendingTransition.takeAt(i);
2163
requestedIndex = modelIndex;
2164
requestedAsync = asynchronous;
2167
if (QQuickItem *item = model->item(modelIndex, asynchronous)) {
2168
item->setParentItem(q->contentItem());
2169
QQml_setParent_noEvent(item, q->contentItem());
2170
requestedIndex = -1;
2171
FxViewItem *viewItem = requestedItem;
2173
viewItem = newViewItem(modelIndex, item); // already in cache, so viewItem not initialized in initItem()
2175
viewItem->index = modelIndex;
2176
// do other set up for the new item that should not happen
2177
// until after bindings are evaluated
2178
initializeViewItem(viewItem);
2179
unrequestedItems.remove(item);
2190
void QQuickItemView::createdItem(int index, QQuickItem *item)
2192
Q_D(QQuickItemView);
2193
if (d->requestedIndex != index) {
2194
item->setParentItem(contentItem());
2195
d->unrequestedItems.insert(item, index);
2196
item->setVisible(false);
2197
d->repositionPackageItemAt(item, index);
2199
d->requestedIndex = -1;
2200
if (!d->inRequest) {
2201
if (index == d->currentIndex)
2202
d->updateCurrent(index);
2208
void QQuickItemView::initItem(int index, QQuickItem *item)
2210
Q_D(QQuickItemView);
2212
if (d->requestedIndex == index) {
2213
if (d->requestedAsync)
2214
item->setVisible(false);
2215
item->setParentItem(contentItem());
2216
QQml_setParent_noEvent(item, contentItem());
2217
d->requestedItem = d->newViewItem(index, item);
2221
void QQuickItemView::destroyingItem(QQuickItem *item)
2223
Q_D(QQuickItemView);
2224
d->unrequestedItems.remove(item);
2227
bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
2229
Q_Q(QQuickItemView);
2230
if (!item || !model)
2232
if (trackedItem == item)
2234
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item->item);
2235
itemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
2236
QQuickVisualModel::ReleaseFlags flags = model->release(item->item);
2238
// item was not destroyed, and we no longer reference it.
2239
item->item->setVisible(false);
2240
unrequestedItems.insert(item->item, model->indexOf(item->item, q));
2243
return flags != QQuickVisualModel::Referenced;
2246
QQuickItem *QQuickItemViewPrivate::createHighlightItem()
2248
return createComponentItem(highlightComponent, true);
2251
QQuickItem *QQuickItemViewPrivate::createComponentItem(QQmlComponent *component, bool createDefault)
2253
Q_Q(QQuickItemView);
2255
QQuickItem *item = 0;
2257
QQmlContext *creationContext = component->creationContext();
2258
QQmlContext *context = new QQmlContext(
2259
creationContext ? creationContext : qmlContext(q));
2260
QObject *nobj = component->create(context);
2262
QQml_setParent_noEvent(context, nobj);
2263
item = qobject_cast<QQuickItem *>(nobj);
2269
} else if (createDefault) {
2270
item = new QQuickItem;
2273
QQml_setParent_noEvent(item, q->contentItem());
2274
item->setParentItem(q->contentItem());
2279
void QQuickItemViewPrivate::updateTrackedItem()
2281
Q_Q(QQuickItemView);
2282
FxViewItem *item = currentItem;
2288
q->trackedPositionChanged();
2291
void QQuickItemViewPrivate::updateUnrequestedIndexes()
2293
Q_Q(QQuickItemView);
2294
for (QHash<QQuickItem*,int>::iterator it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
2295
*it = model->indexOf(it.key(), q);
2298
void QQuickItemViewPrivate::updateUnrequestedPositions()
2300
for (QHash<QQuickItem*,int>::const_iterator it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
2301
repositionPackageItemAt(it.key(), it.value());
2304
void QQuickItemViewPrivate::updateVisibleIndex()
2307
for (QList<FxViewItem*>::Iterator it = visibleItems.begin(); it != visibleItems.end(); ++it) {
2308
if ((*it)->index != -1) {
2309
visibleIndex = (*it)->index;