1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickitemview_p_p.h"
47 FxViewItem::FxViewItem(QQuickItem *i, bool own)
48 : item(i), ownItem(own), index(-1)
52 FxViewItem::~FxViewItem()
54 if (ownItem && item) {
55 item->setParentItem(0);
62 QQuickItemViewChangeSet::QQuickItemViewChangeSet()
68 bool QQuickItemViewChangeSet::hasPendingChanges() const
70 return !pendingChanges.isEmpty();
73 void QQuickItemViewChangeSet::applyChanges(const QDeclarativeChangeSet &changeSet)
75 pendingChanges.apply(changeSet);
80 foreach (const QDeclarativeChangeSet::Remove &r, changeSet.removes()) {
82 if (moveId == -1 && newCurrentIndex >= r.index + r.count) {
83 newCurrentIndex -= r.count;
84 currentChanged = true;
85 } else if (moveId == -1 && newCurrentIndex >= r.index && newCurrentIndex < r.index + r.count) {
86 // current item has been removed.
89 moveOffset = newCurrentIndex - r.index;
91 currentRemoved = true;
94 newCurrentIndex = qMin(r.index, itemCount - 1);
96 currentChanged = true;
99 foreach (const QDeclarativeChangeSet::Insert &i, changeSet.inserts()) {
101 if (itemCount && newCurrentIndex >= i.index) {
102 newCurrentIndex += i.count;
103 currentChanged = true;
104 } else if (newCurrentIndex < 0) {
106 currentChanged = true;
107 } else if (newCurrentIndex == 0 && !itemCount) {
108 // this is the first item, set the initial current index
109 currentChanged = true;
111 } else if (moveId == i.moveId) {
112 newCurrentIndex = i.index + moveOffset;
114 itemCount += i.count;
118 void QQuickItemViewChangeSet::prepare(int currentIndex, int count)
125 newCurrentIndex = currentIndex;
128 void QQuickItemViewChangeSet::reset()
131 newCurrentIndex = -1;
132 pendingChanges.clear();
133 removedItems.clear();
135 currentChanged = false;
136 currentRemoved = false;
140 QQuickItemView::QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent)
141 : QQuickFlickable(dd, parent)
147 QQuickItemView::~QQuickItemView()
158 QQuickItem *QQuickItemView::currentItem() const
160 Q_D(const QQuickItemView);
163 const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
164 return d->currentItem->item;
167 QVariant QQuickItemView::model() const
169 Q_D(const QQuickItemView);
170 return d->modelVariant;
173 void QQuickItemView::setModel(const QVariant &model)
176 if (d->modelVariant == model)
179 disconnect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
180 this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
181 disconnect(d->model, SIGNAL(initItem(int,QQuickItem*)), this, SLOT(initItem(int,QQuickItem*)));
182 disconnect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*)));
183 disconnect(d->model, SIGNAL(destroyingItem(QQuickItem*)), this, SLOT(destroyingItem(QQuickItem*)));
186 QQuickVisualModel *oldModel = d->model;
189 d->setPosition(d->contentStartPosition());
191 d->modelVariant = model;
193 QObject *object = qvariant_cast<QObject*>(model);
194 QQuickVisualModel *vim = 0;
195 if (object && (vim = qobject_cast<QQuickVisualModel *>(object))) {
203 d->model = new QQuickVisualDataModel(qmlContext(this), this);
205 if (isComponentComplete())
206 static_cast<QQuickVisualDataModel *>(d->model.data())->componentComplete();
210 if (QQuickVisualDataModel *dataModel = qobject_cast<QQuickVisualDataModel*>(d->model))
211 dataModel->setModel(model);
215 d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
216 connect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*)));
217 connect(d->model, SIGNAL(initItem(int,QQuickItem*)), this, SLOT(initItem(int,QQuickItem*)));
218 connect(d->model, SIGNAL(destroyingItem(QQuickItem*)), this, SLOT(destroyingItem(QQuickItem*)));
219 if (isComponentComplete()) {
222 if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
225 d->moveReason = QQuickItemViewPrivate::SetIndex;
226 d->updateCurrent(d->currentIndex);
227 if (d->highlight && d->currentItem) {
228 if (d->autoHighlight)
229 d->resetHighlightPosition();
230 d->updateTrackedItem();
232 d->moveReason = QQuickItemViewPrivate::Other;
236 connect(d->model, SIGNAL(modelUpdated(QDeclarativeChangeSet,bool)),
237 this, SLOT(modelUpdated(QDeclarativeChangeSet,bool)));
243 QDeclarativeComponent *QQuickItemView::delegate() const
245 Q_D(const QQuickItemView);
247 if (QQuickVisualDataModel *dataModel = qobject_cast<QQuickVisualDataModel*>(d->model))
248 return dataModel->delegate();
254 void QQuickItemView::setDelegate(QDeclarativeComponent *delegate)
257 if (delegate == this->delegate())
260 d->model = new QQuickVisualDataModel(qmlContext(this));
263 if (QQuickVisualDataModel *dataModel = qobject_cast<QQuickVisualDataModel*>(d->model)) {
264 int oldCount = dataModel->count();
265 dataModel->setDelegate(delegate);
266 if (isComponentComplete()) {
267 for (int i = 0; i < d->visibleItems.count(); ++i)
268 d->releaseItem(d->visibleItems.at(i));
269 d->visibleItems.clear();
270 d->releaseItem(d->currentItem);
274 d->moveReason = QQuickItemViewPrivate::SetIndex;
275 d->updateCurrent(d->currentIndex);
276 if (d->highlight && d->currentItem) {
277 if (d->autoHighlight)
278 d->resetHighlightPosition();
279 d->updateTrackedItem();
281 d->moveReason = QQuickItemViewPrivate::Other;
284 if (oldCount != dataModel->count())
287 emit delegateChanged();
291 int QQuickItemView::count() const
293 Q_D(const QQuickItemView);
296 const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
297 return d->model->count();
300 int QQuickItemView::currentIndex() const
302 Q_D(const QQuickItemView);
303 const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
304 return d->currentIndex;
307 void QQuickItemView::setCurrentIndex(int index)
310 if (d->requestedIndex >= 0 && !d->requestedAsync) // currently creating item
312 d->currentIndexCleared = (index == -1);
314 d->applyPendingChanges();
315 if (index == d->currentIndex)
317 if (isComponentComplete() && d->isValid()) {
318 d->moveReason = QQuickItemViewPrivate::SetIndex;
319 d->updateCurrent(index);
320 } else if (d->currentIndex != index) {
321 d->currentIndex = index;
322 emit currentIndexChanged();
327 bool QQuickItemView::isWrapEnabled() const
329 Q_D(const QQuickItemView);
333 void QQuickItemView::setWrapEnabled(bool wrap)
339 emit keyNavigationWrapsChanged();
342 int QQuickItemView::cacheBuffer() const
344 Q_D(const QQuickItemView);
348 void QQuickItemView::setCacheBuffer(int b)
351 if (d->buffer != b) {
353 if (isComponentComplete()) {
354 d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
357 emit cacheBufferChanged();
362 Qt::LayoutDirection QQuickItemView::layoutDirection() const
364 Q_D(const QQuickItemView);
365 return d->layoutDirection;
368 void QQuickItemView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
371 if (d->layoutDirection != layoutDirection) {
372 d->layoutDirection = layoutDirection;
374 emit layoutDirectionChanged();
375 emit effectiveLayoutDirectionChanged();
379 Qt::LayoutDirection QQuickItemView::effectiveLayoutDirection() const
381 Q_D(const QQuickItemView);
382 if (d->effectiveLayoutMirror)
383 return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
385 return d->layoutDirection;
389 QDeclarativeComponent *QQuickItemView::header() const
391 Q_D(const QQuickItemView);
392 return d->headerComponent;
395 QQuickItem *QQuickItemView::headerItem() const
397 Q_D(const QQuickItemView);
398 const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
399 return d->header ? d->header->item : 0;
402 void QQuickItemView::setHeader(QDeclarativeComponent *headerComponent)
405 if (d->headerComponent != headerComponent) {
406 d->applyPendingChanges();
409 d->headerComponent = headerComponent;
411 d->markExtentsDirty();
413 if (isComponentComplete()) {
419 emit headerItemChanged();
421 emit headerChanged();
425 QDeclarativeComponent *QQuickItemView::footer() const
427 Q_D(const QQuickItemView);
428 return d->footerComponent;
431 QQuickItem *QQuickItemView::footerItem() const
433 Q_D(const QQuickItemView);
434 const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
435 return d->footer ? d->footer->item : 0;
438 void QQuickItemView::setFooter(QDeclarativeComponent *footerComponent)
441 if (d->footerComponent != footerComponent) {
442 d->applyPendingChanges();
445 d->footerComponent = footerComponent;
447 if (isComponentComplete()) {
452 emit footerItemChanged();
454 emit footerChanged();
458 QDeclarativeComponent *QQuickItemView::highlight() const
460 Q_D(const QQuickItemView);
461 const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
462 return d->highlightComponent;
465 void QQuickItemView::setHighlight(QDeclarativeComponent *highlightComponent)
468 if (highlightComponent != d->highlightComponent) {
469 d->applyPendingChanges();
470 d->highlightComponent = highlightComponent;
471 d->createHighlight();
473 d->updateHighlight();
474 emit highlightChanged();
478 QQuickItem *QQuickItemView::highlightItem() const
480 Q_D(const QQuickItemView);
481 const_cast<QQuickItemViewPrivate*>(d)->applyPendingChanges();
482 return d->highlight ? d->highlight->item : 0;
485 bool QQuickItemView::highlightFollowsCurrentItem() const
487 Q_D(const QQuickItemView);
488 return d->autoHighlight;
491 void QQuickItemView::setHighlightFollowsCurrentItem(bool autoHighlight)
494 if (d->autoHighlight != autoHighlight) {
495 d->autoHighlight = autoHighlight;
497 d->updateHighlight();
498 emit highlightFollowsCurrentItemChanged();
502 QQuickItemView::HighlightRangeMode QQuickItemView::highlightRangeMode() const
504 Q_D(const QQuickItemView);
505 return static_cast<QQuickItemView::HighlightRangeMode>(d->highlightRange);
508 void QQuickItemView::setHighlightRangeMode(HighlightRangeMode mode)
511 if (d->highlightRange == mode)
513 d->highlightRange = mode;
514 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
515 emit highlightRangeModeChanged();
518 //###Possibly rename these properties, since they are very useful even without a highlight?
519 qreal QQuickItemView::preferredHighlightBegin() const
521 Q_D(const QQuickItemView);
522 return d->highlightRangeStart;
525 void QQuickItemView::setPreferredHighlightBegin(qreal start)
528 d->highlightRangeStartValid = true;
529 if (d->highlightRangeStart == start)
531 d->highlightRangeStart = start;
532 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
533 emit preferredHighlightBeginChanged();
536 void QQuickItemView::resetPreferredHighlightBegin()
539 d->highlightRangeStartValid = false;
540 if (d->highlightRangeStart == 0)
542 d->highlightRangeStart = 0;
543 emit preferredHighlightBeginChanged();
546 qreal QQuickItemView::preferredHighlightEnd() const
548 Q_D(const QQuickItemView);
549 return d->highlightRangeEnd;
552 void QQuickItemView::setPreferredHighlightEnd(qreal end)
555 d->highlightRangeEndValid = true;
556 if (d->highlightRangeEnd == end)
558 d->highlightRangeEnd = end;
559 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
560 emit preferredHighlightEndChanged();
563 void QQuickItemView::resetPreferredHighlightEnd()
566 d->highlightRangeEndValid = false;
567 if (d->highlightRangeEnd == 0)
569 d->highlightRangeEnd = 0;
570 emit preferredHighlightEndChanged();
573 int QQuickItemView::highlightMoveDuration() const
575 Q_D(const QQuickItemView);
576 return d->highlightMoveDuration;
579 void QQuickItemView::setHighlightMoveDuration(int duration)
582 if (d->highlightMoveDuration != duration) {
583 d->highlightMoveDuration = duration;
584 emit highlightMoveDurationChanged();
588 void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode)
593 if (mode < QQuickItemView::Beginning || mode > QQuickItemView::Contain)
596 applyPendingChanges();
597 int idx = qMax(qMin(index, model->count()-1), 0);
599 qreal pos = isContentFlowReversed() ? -position() - size() : position();
600 FxViewItem *item = visibleItem(idx);
602 if (layoutOrientation() == Qt::Vertical)
603 maxExtent = -q->maxYExtent();
605 maxExtent = isContentFlowReversed() ? q->minXExtent()-size(): -q->maxXExtent();
607 int itemPos = positionAt(idx);
608 changedVisibleIndex(idx);
609 // save the currently visible items in case any of them end up visible again
610 QList<FxViewItem *> oldVisible = visibleItems;
611 visibleItems.clear();
612 setPosition(qMin(qreal(itemPos), maxExtent));
613 // now release the reference to all the old visible items.
614 for (int i = 0; i < oldVisible.count(); ++i)
615 releaseItem(oldVisible.at(i));
616 item = visibleItem(idx);
619 const qreal itemPos = item->position();
621 case QQuickItemView::Beginning:
623 if (index < 0 && header)
626 case QQuickItemView::Center:
627 pos = itemPos - (size() - item->size())/2;
629 case QQuickItemView::End:
630 pos = itemPos - size() + item->size();
631 if (index >= model->count() && footer)
634 case QQuickItemView::Visible:
635 if (itemPos > pos + size())
636 pos = itemPos - size() + item->size();
637 else if (item->endPosition() <= pos)
640 case QQuickItemView::Contain:
641 if (item->endPosition() >= pos + size())
642 pos = itemPos - size() + item->size();
646 pos = qMin(pos, maxExtent);
648 if (layoutOrientation() == Qt::Vertical)
649 minExtent = -q->minYExtent();
651 minExtent = isContentFlowReversed() ? q->maxXExtent()-size(): -q->minXExtent();
652 pos = qMax(pos, minExtent);
653 moveReason = QQuickItemViewPrivate::Other;
659 resetHighlightPosition();
666 void QQuickItemView::positionViewAtIndex(int index, int mode)
669 if (!d->isValid() || index < 0 || index >= d->model->count())
671 d->positionViewAtIndex(index, mode);
675 void QQuickItemView::positionViewAtBeginning()
680 d->positionViewAtIndex(-1, Beginning);
683 void QQuickItemView::positionViewAtEnd()
688 d->positionViewAtIndex(d->model->count(), End);
691 int QQuickItemView::indexAt(qreal x, qreal y) const
693 Q_D(const QQuickItemView);
694 for (int i = 0; i < d->visibleItems.count(); ++i) {
695 const FxViewItem *item = d->visibleItems.at(i);
696 if (item->contains(x, y))
703 void QQuickItemViewPrivate::applyPendingChanges()
706 if (q->isComponentComplete() && currentChanges.hasPendingChanges())
710 // for debugging only
711 void QQuickItemViewPrivate::checkVisible() const
714 for (int i = 0; i < visibleItems.count(); ++i) {
715 FxViewItem *item = visibleItems.at(i);
716 if (item->index == -1) {
718 } else if (item->index != visibleIndex + i - skip) {
719 qFatal("index %d %d %d", visibleIndex, i, item->index);
724 void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
727 QQuickFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
728 if (!q->isComponentComplete())
731 if (header && header->item == item) {
734 if (!q->isMoving() && !q->isFlicking())
736 } else if (footer && footer->item == item) {
739 if (!q->isMoving() && !q->isFlicking())
743 if (currentItem && currentItem->item == item)
745 if (trackedItem && trackedItem->item == item)
746 q->trackedPositionChanged();
749 void QQuickItemView::destroyRemoved()
752 for (QList<FxViewItem*>::Iterator it = d->visibleItems.begin();
753 it != d->visibleItems.end();) {
754 FxViewItem *item = *it;
755 if (item->index == -1 && item->attached->delayRemove() == false) {
756 d->releaseItem(item);
757 it = d->visibleItems.erase(it);
763 // Correct the positioning of the items
765 d->forceLayout = true;
769 void QQuickItemView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool reset)
773 d->moveReason = QQuickItemViewPrivate::SetIndex;
775 if (d->highlight && d->currentItem) {
776 if (d->autoHighlight)
777 d->resetHighlightPosition();
778 d->updateTrackedItem();
780 d->moveReason = QQuickItemViewPrivate::Other;
784 d->currentChanges.prepare(d->currentIndex, d->itemCount);
785 d->currentChanges.applyChanges(changeSet);
790 void QQuickItemView::animStopped()
793 d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
795 if (d->haveHighlightRange && d->highlightRange == QQuickItemView::StrictlyEnforceRange)
796 d->updateHighlight();
800 void QQuickItemView::trackedPositionChanged()
803 if (!d->trackedItem || !d->currentItem)
805 if (d->moveReason == QQuickItemViewPrivate::SetIndex) {
806 qreal trackedPos = d->trackedItem->position();
807 qreal trackedSize = d->trackedItem->size();
808 if (d->trackedItem != d->currentItem) {
809 trackedSize += d->currentItem->sectionSize();
811 qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
813 if (d->haveHighlightRange) {
814 if (trackedPos > pos + d->highlightRangeEnd - trackedSize)
815 pos = trackedPos - d->highlightRangeEnd + trackedSize;
816 if (trackedPos < pos + d->highlightRangeStart)
817 pos = trackedPos - d->highlightRangeStart;
818 if (d->highlightRange != StrictlyEnforceRange) {
819 if (pos > d->endPosition() - d->size())
820 pos = d->endPosition() - d->size();
821 if (pos < d->startPosition())
822 pos = d->startPosition();
825 qreal trackedEndPos = d->trackedItem->endPosition();
826 qreal toItemPos = d->currentItem->position();
827 qreal toItemEndPos = d->currentItem->endPosition();
829 if (d->header && d->showHeaderForIndex(d->currentIndex)) {
830 trackedPos -= d->headerSize();
831 trackedEndPos -= d->headerSize();
832 toItemPos -= d->headerSize();
833 toItemEndPos -= d->headerSize();
834 } else if (d->footer && d->showFooterForIndex(d->currentIndex)) {
835 trackedPos += d->footerSize();
836 trackedEndPos += d->footerSize();
837 toItemPos += d->footerSize();
838 toItemEndPos += d->footerSize();
841 if (trackedPos < viewPos && toItemPos < viewPos) {
842 pos = qMax(trackedPos, toItemPos);
843 } else if (trackedEndPos >= viewPos + d->size()
844 && toItemEndPos >= viewPos + d->size()) {
845 if (trackedEndPos <= toItemEndPos) {
846 pos = trackedEndPos - d->size();
847 if (trackedSize > d->size())
850 pos = toItemEndPos - d->size();
851 if (d->currentItem->size() > d->size())
852 pos = d->currentItem->position();
856 if (viewPos != pos) {
858 d->calcVelocity = true;
860 d->calcVelocity = false;
865 void QQuickItemView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
868 d->markExtentsDirty();
869 QQuickFlickable::geometryChanged(newGeometry, oldGeometry);
873 qreal QQuickItemView::minYExtent() const
875 Q_D(const QQuickItemView);
876 if (d->layoutOrientation() == Qt::Horizontal)
877 return QQuickFlickable::minYExtent();
879 if (d->vData.minExtentDirty) {
880 d->minExtent = d->vData.startMargin-d->startPosition();
882 d->minExtent += d->headerSize();
883 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
884 d->minExtent += d->highlightRangeStart;
885 if (d->visibleItem(0))
886 d->minExtent -= d->visibleItem(0)->sectionSize();
887 d->minExtent = qMax(d->minExtent, -(d->endPositionAt(0) - d->highlightRangeEnd));
889 d->vData.minExtentDirty = false;
895 qreal QQuickItemView::maxYExtent() const
897 Q_D(const QQuickItemView);
898 if (d->layoutOrientation() == Qt::Horizontal)
901 if (d->vData.maxExtentDirty) {
902 if (!d->model || !d->model->count()) {
903 d->maxExtent = d->header ? -d->headerSize() : 0;
904 d->maxExtent += height();
905 } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
906 d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart);
907 if (d->highlightRangeEnd != d->highlightRangeStart)
908 d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd));
910 d->maxExtent = -(d->endPosition() - height());
914 d->maxExtent -= d->footerSize();
915 d->maxExtent -= d->vData.endMargin;
916 qreal minY = minYExtent();
917 if (d->maxExtent > minY)
919 d->vData.maxExtentDirty = false;
924 qreal QQuickItemView::minXExtent() const
926 Q_D(const QQuickItemView);
927 if (d->layoutOrientation() == Qt::Vertical)
928 return QQuickFlickable::minXExtent();
930 if (d->hData.minExtentDirty) {
931 d->minExtent = -d->startPosition();
932 qreal highlightStart;
934 qreal endPositionFirstItem = 0;
935 if (d->isContentFlowReversed()) {
936 d->minExtent += d->hData.endMargin;
937 if (d->model && d->model->count())
938 endPositionFirstItem = d->positionAt(d->model->count()-1);
940 d->minExtent += d->headerSize();
941 highlightStart = d->highlightRangeEndValid ? d->size() - d->highlightRangeEnd : d->size();
942 highlightEnd = d->highlightRangeStartValid ? d->size() - d->highlightRangeStart : d->size();
944 d->minExtent += d->footerSize();
945 qreal maxX = maxXExtent();
946 if (d->minExtent < maxX)
949 d->minExtent += d->hData.startMargin;
950 endPositionFirstItem = d->endPositionAt(0);
951 highlightStart = d->highlightRangeStart;
952 highlightEnd = d->highlightRangeEnd;
954 d->minExtent += d->headerSize();
956 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
957 d->minExtent += highlightStart;
958 d->minExtent = d->isContentFlowReversed()
959 ? qMin(d->minExtent, endPositionFirstItem + highlightEnd)
960 : qMax(d->minExtent, -(endPositionFirstItem - highlightEnd));
962 d->hData.minExtentDirty = false;
968 qreal QQuickItemView::maxXExtent() const
970 Q_D(const QQuickItemView);
971 if (d->layoutOrientation() == Qt::Vertical)
974 if (d->hData.maxExtentDirty) {
975 qreal highlightStart;
977 qreal lastItemPosition = 0;
979 if (d->isContentFlowReversed()) {
980 highlightStart = d->highlightRangeEndValid ? d->size() - d->highlightRangeEnd : d->size();
981 highlightEnd = d->highlightRangeStartValid ? d->size() - d->highlightRangeStart : d->size();
982 lastItemPosition = d->endPosition();
984 highlightStart = d->highlightRangeStart;
985 highlightEnd = d->highlightRangeEnd;
986 if (d->model && d->model->count())
987 lastItemPosition = d->positionAt(d->model->count()-1);
989 if (!d->model || !d->model->count()) {
990 if (!d->isContentFlowReversed())
991 d->maxExtent = d->header ? -d->headerSize() : 0;
992 d->maxExtent += width();
993 } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
994 d->maxExtent = -(lastItemPosition - highlightStart);
995 if (highlightEnd != highlightStart) {
996 d->maxExtent = d->isContentFlowReversed()
997 ? qMax(d->maxExtent, -(d->endPosition() - highlightEnd))
998 : qMin(d->maxExtent, -(d->endPosition() - highlightEnd));
1001 d->maxExtent = -(d->endPosition() - width());
1003 if (d->isContentFlowReversed()) {
1005 d->maxExtent -= d->headerSize();
1006 d->maxExtent -= d->hData.startMargin;
1009 d->maxExtent -= d->footerSize();
1010 d->maxExtent -= d->hData.endMargin;
1011 qreal minX = minXExtent();
1012 if (d->maxExtent > minX)
1013 d->maxExtent = minX;
1015 d->hData.maxExtentDirty = false;
1018 return d->maxExtent;
1021 void QQuickItemView::setContentX(qreal pos)
1023 Q_D(QQuickItemView);
1024 // Positioning the view manually should override any current movement state
1025 d->moveReason = QQuickItemViewPrivate::Other;
1026 QQuickFlickable::setContentX(pos);
1029 void QQuickItemView::setContentY(qreal pos)
1031 Q_D(QQuickItemView);
1032 // Positioning the view manually should override any current movement state
1033 d->moveReason = QQuickItemViewPrivate::Other;
1034 QQuickFlickable::setContentY(pos);
1037 qreal QQuickItemView::xOrigin() const
1039 Q_D(const QQuickItemView);
1040 if (d->isContentFlowReversed())
1041 return -maxXExtent() + d->size() - d->hData.startMargin;
1043 return -minXExtent() + d->hData.startMargin;
1046 void QQuickItemView::updatePolish()
1048 Q_D(QQuickItemView);
1049 QQuickFlickable::updatePolish();
1053 void QQuickItemView::componentComplete()
1055 Q_D(QQuickItemView);
1056 if (d->model && d->ownModel)
1057 static_cast<QQuickVisualDataModel *>(d->model.data())->componentComplete();
1059 QQuickFlickable::componentComplete();
1064 d->updateViewport();
1065 d->setPosition(d->contentStartPosition());
1068 d->moveReason = QQuickItemViewPrivate::SetIndex;
1069 if (d->currentIndex < 0 && !d->currentIndexCleared)
1070 d->updateCurrent(0);
1072 d->updateCurrent(d->currentIndex);
1073 if (d->highlight && d->currentItem) {
1074 if (d->autoHighlight)
1075 d->resetHighlightPosition();
1076 d->updateTrackedItem();
1078 d->moveReason = QQuickItemViewPrivate::Other;
1081 if (d->model && d->model->count())
1082 emit countChanged();
1087 QQuickItemViewPrivate::QQuickItemViewPrivate()
1089 , buffer(0), bufferMode(BufferBefore | BufferAfter)
1090 , layoutDirection(Qt::LeftToRight)
1093 , currentIndex(-1), currentItem(0)
1094 , trackedItem(0), requestedIndex(-1), requestedItem(0)
1095 , highlightComponent(0), highlight(0)
1096 , highlightRange(QQuickItemView::NoHighlightRange)
1097 , highlightRangeStart(0), highlightRangeEnd(0)
1098 , highlightMoveDuration(150)
1099 , headerComponent(0), header(0), footerComponent(0), footer(0)
1100 , minExtent(0), maxExtent(0)
1101 , ownModel(false), wrap(false), deferredRelease(false)
1102 , inApplyModelChanges(false), inViewportMoved(false), forceLayout(false), currentIndexCleared(false)
1103 , haveHighlightRange(false), autoHighlight(true), highlightRangeStartValid(false), highlightRangeEndValid(false)
1104 , fillCacheBuffer(false), inRequest(false), requestedAsync(false)
1108 bool QQuickItemViewPrivate::isValid() const
1110 return model && model->count() && model->isValid();
1113 qreal QQuickItemViewPrivate::position() const
1115 Q_Q(const QQuickItemView);
1116 return layoutOrientation() == Qt::Vertical ? q->contentY() : q->contentX();
1119 qreal QQuickItemViewPrivate::size() const
1121 Q_Q(const QQuickItemView);
1122 return layoutOrientation() == Qt::Vertical ? q->height() : q->width();
1125 qreal QQuickItemViewPrivate::startPosition() const
1127 return isContentFlowReversed() ? -lastPosition() : originPosition();
1130 qreal QQuickItemViewPrivate::endPosition() const
1132 return isContentFlowReversed() ? -originPosition() : lastPosition();
1135 qreal QQuickItemViewPrivate::contentStartPosition() const
1137 qreal pos = -headerSize();
1138 if (layoutOrientation() == Qt::Vertical)
1139 pos -= vData.startMargin;
1140 else if (isContentFlowReversed())
1141 pos -= hData.endMargin;
1143 pos -= hData.startMargin;
1148 int QQuickItemViewPrivate::findLastVisibleIndex(int defaultValue) const
1150 if (visibleItems.count()) {
1151 int i = visibleItems.count() - 1;
1152 while (i > 0 && visibleItems.at(i)->index == -1)
1154 if (visibleItems.at(i)->index != -1)
1155 return visibleItems.at(i)->index;
1157 return defaultValue;
1160 FxViewItem *QQuickItemViewPrivate::visibleItem(int modelIndex) const {
1161 if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
1162 for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
1163 FxViewItem *item = visibleItems.at(i);
1164 if (item->index == modelIndex)
1171 FxViewItem *QQuickItemViewPrivate::firstVisibleItem() const {
1172 const qreal pos = isContentFlowReversed() ? -position()-size() : position();
1173 for (int i = 0; i < visibleItems.count(); ++i) {
1174 FxViewItem *item = visibleItems.at(i);
1175 if (item->index != -1 && item->endPosition() > pos)
1178 return visibleItems.count() ? visibleItems.first() : 0;
1181 // Map a model index to visibleItems list index.
1182 // These may differ if removed items are still present in the visible list,
1183 // e.g. doing a removal animation
1184 int QQuickItemViewPrivate::mapFromModel(int modelIndex) const
1186 if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
1188 for (int i = 0; i < visibleItems.count(); ++i) {
1189 FxViewItem *item = visibleItems.at(i);
1190 if (item->index == modelIndex)
1192 if (item->index > modelIndex)
1195 return -1; // Not in visibleList
1198 void QQuickItemViewPrivate::init()
1200 Q_Q(QQuickItemView);
1201 QQuickItemPrivate::get(contentItem)->childrenDoNotOverlap = true;
1202 q->setFlag(QQuickItem::ItemIsFocusScope);
1203 addItemChangeListener(this, Geometry);
1204 QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
1205 q->setFlickableDirection(QQuickFlickable::VerticalFlick);
1208 void QQuickItemViewPrivate::updateCurrent(int modelIndex)
1210 Q_Q(QQuickItemView);
1211 applyPendingChanges();
1213 if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
1215 currentItem->attached->setIsCurrentItem(false);
1216 releaseItem(currentItem);
1218 currentIndex = modelIndex;
1219 emit q->currentIndexChanged();
1220 emit q->currentItemChanged();
1222 } else if (currentIndex != modelIndex) {
1223 currentIndex = modelIndex;
1224 emit q->currentIndexChanged();
1229 if (currentItem && currentIndex == modelIndex) {
1234 FxViewItem *oldCurrentItem = currentItem;
1235 int oldCurrentIndex = currentIndex;
1236 currentIndex = modelIndex;
1237 currentItem = createItem(modelIndex, false);
1238 if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
1239 oldCurrentItem->attached->setIsCurrentItem(false);
1241 currentItem->item->setFocus(true);
1242 currentItem->attached->setIsCurrentItem(true);
1243 initializeCurrentItem();
1247 if (oldCurrentIndex != currentIndex)
1248 emit q->currentIndexChanged();
1249 if (oldCurrentItem != currentItem)
1250 emit q->currentItemChanged();
1251 releaseItem(oldCurrentItem);
1254 void QQuickItemViewPrivate::clear()
1256 currentChanges.reset();
1259 for (int i = 0; i < visibleItems.count(); ++i)
1260 releaseItem(visibleItems.at(i));
1261 visibleItems.clear();
1264 releaseItem(currentItem);
1274 void QQuickItemViewPrivate::mirrorChange()
1276 Q_Q(QQuickItemView);
1278 emit q->effectiveLayoutDirectionChanged();
1281 void QQuickItemViewPrivate::refill()
1283 if (isContentFlowReversed())
1284 refill(-position()-size(), -position());
1286 refill(position(), position()+size());
1289 void QQuickItemViewPrivate::refill(qreal from, qreal to, bool doBuffer)
1291 Q_Q(QQuickItemView);
1292 if (!isValid() || !q->isComponentComplete())
1295 currentChanges.reset();
1297 int prevCount = itemCount;
1298 itemCount = model->count();
1299 qreal bufferFrom = from - buffer;
1300 qreal bufferTo = to + buffer;
1301 qreal fillFrom = from;
1303 if (doBuffer && (bufferMode & BufferAfter))
1305 if (doBuffer && (bufferMode & BufferBefore))
1306 fillFrom = bufferFrom;
1308 // Item creation and release is staggered in order to avoid
1309 // creating/releasing multiple items in one frame
1310 // while flicking (as much as possible).
1312 bool changed = addVisibleItems(fillFrom, fillTo, doBuffer);
1314 if (!changed || deferredRelease) { // avoid destroying items in the same frame that we create
1315 if (removeNonVisibleItems(bufferFrom, bufferTo))
1317 deferredRelease = false;
1319 deferredRelease = true;
1324 visibleItemsChanged();
1325 } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
1326 refill(from, to, true);
1329 if (!q->isMoving() && changed) {
1330 fillCacheBuffer = true;
1334 if (prevCount != itemCount)
1335 emit q->countChanged();
1338 void QQuickItemViewPrivate::regenerate()
1340 Q_Q(QQuickItemView);
1341 if (q->isComponentComplete()) {
1342 currentChanges.reset();
1351 setPosition(contentStartPosition());
1353 updateCurrent(currentIndex);
1357 void QQuickItemViewPrivate::updateViewport()
1359 Q_Q(QQuickItemView);
1361 if (layoutOrientation() == Qt::Vertical)
1362 q->setContentHeight(endPosition() - startPosition());
1364 q->setContentWidth(endPosition() - startPosition());
1368 void QQuickItemViewPrivate::layout()
1370 Q_Q(QQuickItemView);
1371 if (inApplyModelChanges)
1374 if (!isValid() && !visibleItems.count()) {
1376 setPosition(contentStartPosition());
1380 if (!applyModelChanges() && !forceLayout) {
1381 if (fillCacheBuffer)
1385 forceLayout = false;
1387 layoutVisibleItems();
1394 if (!q->isMoving() && !q->isFlicking()) {
1402 updateUnrequestedPositions();
1405 bool QQuickItemViewPrivate::applyModelChanges()
1407 Q_Q(QQuickItemView);
1408 if (!q->isComponentComplete() || !currentChanges.hasPendingChanges() || inApplyModelChanges)
1411 inApplyModelChanges = true;
1413 updateUnrequestedIndexes();
1414 moveReason = QQuickItemViewPrivate::Other;
1416 int prevCount = itemCount;
1417 bool visibleAffected = false;
1418 bool viewportChanged = !currentChanges.pendingChanges.removes().isEmpty()
1419 || !currentChanges.pendingChanges.inserts().isEmpty();
1421 FxViewItem *firstVisible = firstVisibleItem();
1422 FxViewItem *origVisibleItemsFirst = visibleItems.count() ? visibleItems.first() : 0;
1423 int firstItemIndex = firstVisible ? firstVisible->index : -1;
1424 qreal removedBeforeFirstVisibleBy = 0;
1426 const QVector<QDeclarativeChangeSet::Remove> &removals = currentChanges.pendingChanges.removes();
1427 for (int i=0; i<removals.count(); i++) {
1428 itemCount -= removals[i].count;
1430 // Remove the items from the visible list, skipping anything already marked for removal
1431 QList<FxViewItem*>::Iterator it = visibleItems.begin();
1432 while (it != visibleItems.end()) {
1433 FxViewItem *item = *it;
1434 if (item->index == -1 || item->index < removals[i].index) {
1435 // already removed, or before removed items
1436 if (!visibleAffected && item->index < removals[i].index)
1437 visibleAffected = true;
1439 } else if (item->index >= removals[i].index + removals[i].count) {
1440 // after removed items
1441 item->index -= removals[i].count;
1445 visibleAffected = true;
1446 if (!removals[i].isMove())
1447 item->attached->emitRemove();
1449 if (item->attached->delayRemove() && !removals[i].isMove()) {
1451 QObject::connect(item->attached, SIGNAL(delayRemoveChanged()), q, SLOT(destroyRemoved()), Qt::QueuedConnection);
1454 if (firstVisible && item->position() < firstVisible->position() && item != visibleItems.first())
1455 removedBeforeFirstVisibleBy += item->size();
1456 if (removals[i].isMove()) {
1457 currentChanges.removedItems.insert(removals[i].moveKey(item->index), item);
1459 if (item == firstVisible)
1461 currentChanges.removedItems.insertMulti(QDeclarativeChangeSet::MoveKey(), item);
1463 it = visibleItems.erase(it);
1467 if (!visibleAffected && needsRefillForAddedOrRemovedIndex(removals[i].index))
1468 visibleAffected = true;
1470 if (!removals.isEmpty())
1471 updateVisibleIndex();
1473 const QVector<QDeclarativeChangeSet::Insert> &insertions = currentChanges.pendingChanges.inserts();
1474 InsertionsResult insertResult;
1475 bool allInsertionsBeforeVisible = true;
1477 for (int i=0; i<insertions.count(); i++) {
1478 bool wasEmpty = visibleItems.isEmpty();
1479 if (applyInsertionChange(insertions[i], firstVisible, &insertResult))
1480 visibleAffected = true;
1481 if (!visibleAffected && needsRefillForAddedOrRemovedIndex(insertions[i].index))
1482 visibleAffected = true;
1483 if (insertions[i].index >= visibleIndex)
1484 allInsertionsBeforeVisible = false;
1485 if (wasEmpty && !visibleItems.isEmpty())
1486 resetFirstItemPosition();
1487 itemCount += insertions[i].count;
1489 for (int i=0; i<insertResult.addedItems.count(); ++i)
1490 insertResult.addedItems.at(i)->attached->emitAdd();
1492 // if the first visible item has moved, ensure another one takes its place
1493 // so that we avoid shifting all content forwards
1494 // (if an item is removed from before the first visible, the first visible should not move upwards)
1495 bool movedBackToFirstVisible = false;
1496 if (firstVisible && firstItemIndex >= 0) {
1497 for (int i=0; i<insertResult.movedBackwards.count(); i++) {
1498 if (insertResult.movedBackwards[i]->index == firstItemIndex) {
1499 // an item has moved backwards up to the first visible's position
1500 resetItemPosition(insertResult.movedBackwards[i], firstVisible);
1501 insertResult.movedBackwards.removeAt(i);
1502 movedBackToFirstVisible = true;
1506 if (!movedBackToFirstVisible && !allInsertionsBeforeVisible) {
1507 // first visible item has moved forward, another visible item takes its place
1508 FxViewItem *item = visibleItem(firstItemIndex);
1510 resetItemPosition(item, firstVisible);
1514 // Ensure we don't cause an ugly list scroll
1515 if (firstVisible && visibleItems.count() && visibleItems.first() != firstVisible) {
1516 // ensure first item is placed at correct postion if moving backward
1517 // since it will be used to position all subsequent items
1518 if (insertResult.movedBackwards.count() && origVisibleItemsFirst)
1519 resetItemPosition(visibleItems.first(), origVisibleItemsFirst);
1521 // correct the first item position (unless it has already been fixed)
1522 if (!movedBackToFirstVisible) {
1523 qreal moveBackwardsBy = insertResult.sizeAddedBeforeVisible;
1524 for (int i=0; i<insertResult.movedBackwards.count(); i++)
1525 moveBackwardsBy += insertResult.movedBackwards[i]->size();
1526 moveItemBy(visibleItems.first(), removedBeforeFirstVisibleBy, moveBackwardsBy);
1530 // Whatever removed/moved items remain are no longer visible items.
1531 for (QHash<QDeclarativeChangeSet::MoveKey, FxViewItem *>::Iterator it = currentChanges.removedItems.begin();
1532 it != currentChanges.removedItems.end(); ++it) {
1533 releaseItem(it.value());
1535 currentChanges.removedItems.clear();
1537 if (currentChanges.currentChanged) {
1538 if (currentChanges.currentRemoved && currentItem) {
1539 currentItem->attached->setIsCurrentItem(false);
1540 releaseItem(currentItem);
1543 if (!currentIndexCleared)
1544 updateCurrent(currentChanges.newCurrentIndex);
1546 currentChanges.reset();
1549 if (prevCount != itemCount)
1550 emit q->countChanged();
1552 if (!visibleAffected)
1553 visibleAffected = !currentChanges.pendingChanges.changes().isEmpty();
1554 if (!visibleAffected && viewportChanged)
1557 inApplyModelChanges = false;
1558 return visibleAffected;
1562 This may return 0 if the item is being created asynchronously.
1563 When the item becomes available, refill() will be called and the item
1564 will be returned on the next call to createItem().
1566 FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, bool asynchronous)
1568 Q_Q(QQuickItemView);
1569 if (requestedIndex == modelIndex && (asynchronous || requestedAsync == asynchronous))
1572 if (requestedIndex != -1 && requestedIndex != modelIndex) {
1573 delete requestedItem;
1577 requestedIndex = modelIndex;
1578 requestedAsync = asynchronous;
1581 if (QQuickItem *item = model->item(modelIndex, asynchronous)) {
1582 item->setParentItem(q->contentItem());
1583 QDeclarative_setParent_noEvent(item, q->contentItem());
1584 requestedIndex = -1;
1585 fillCacheBuffer = false;
1586 FxViewItem *viewItem = requestedItem;
1588 viewItem = newViewItem(modelIndex, item); // already in cache, so viewItem not initialized in initItem()
1590 viewItem->index = modelIndex;
1591 // do other set up for the new item that should not happen
1592 // until after bindings are evaluated
1593 initializeViewItem(viewItem);
1594 unrequestedItems.remove(item);
1605 void QQuickItemView::createdItem(int index, QQuickItem *item)
1607 Q_D(QQuickItemView);
1608 if (d->requestedIndex != index) {
1609 item->setParentItem(contentItem());
1610 d->unrequestedItems.insert(item, index);
1611 item->setVisible(false);
1612 d->repositionPackageItemAt(item, index);
1614 d->requestedIndex = -1;
1615 if (!d->inRequest) {
1616 if (index == d->currentIndex)
1617 d->updateCurrent(index);
1620 d->fillCacheBuffer = true;
1626 void QQuickItemView::initItem(int index, QQuickItem *item)
1628 Q_D(QQuickItemView);
1630 if (d->requestedIndex == index) {
1631 item->setParentItem(contentItem());
1632 QDeclarative_setParent_noEvent(item, contentItem());
1633 d->requestedItem = d->newViewItem(index, item);
1637 void QQuickItemView::destroyingItem(QQuickItem *item)
1639 Q_D(QQuickItemView);
1640 d->unrequestedItems.remove(item);
1643 void QQuickItemViewPrivate::releaseItem(FxViewItem *item)
1645 Q_Q(QQuickItemView);
1646 if (!item || !model)
1648 if (trackedItem == item)
1650 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item->item);
1651 itemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
1652 if (model->release(item->item) == 0) {
1653 // item was not destroyed, and we no longer reference it.
1654 item->item->setVisible(false);
1655 unrequestedItems.insert(item->item, model->indexOf(item->item, q));
1660 QQuickItem *QQuickItemViewPrivate::createHighlightItem()
1662 return createComponentItem(highlightComponent, true, true);
1665 QQuickItem *QQuickItemViewPrivate::createComponentItem(QDeclarativeComponent *component, bool receiveItemGeometryChanges, bool createDefault)
1667 Q_Q(QQuickItemView);
1669 QQuickItem *item = 0;
1671 QDeclarativeContext *creationContext = component->creationContext();
1672 QDeclarativeContext *context = new QDeclarativeContext(
1673 creationContext ? creationContext : qmlContext(q));
1674 QObject *nobj = component->create(context);
1676 QDeclarative_setParent_noEvent(context, nobj);
1677 item = qobject_cast<QQuickItem *>(nobj);
1683 } else if (createDefault) {
1684 item = new QQuickItem;
1687 QDeclarative_setParent_noEvent(item, q->contentItem());
1688 item->setParentItem(q->contentItem());
1689 if (receiveItemGeometryChanges) {
1690 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1691 itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
1697 void QQuickItemViewPrivate::updateTrackedItem()
1699 Q_Q(QQuickItemView);
1700 FxViewItem *item = currentItem;
1706 q->trackedPositionChanged();
1709 void QQuickItemViewPrivate::updateUnrequestedIndexes()
1711 Q_Q(QQuickItemView);
1712 for (QHash<QQuickItem*,int>::iterator it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
1713 *it = model->indexOf(it.key(), q);
1716 void QQuickItemViewPrivate::updateUnrequestedPositions()
1718 for (QHash<QQuickItem*,int>::const_iterator it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
1719 repositionPackageItemAt(it.key(), it.value());
1722 void QQuickItemViewPrivate::updateVisibleIndex()
1725 for (QList<FxViewItem*>::Iterator it = visibleItems.begin(); it != visibleItems.end(); ++it) {
1726 if ((*it)->index != -1) {
1727 visibleIndex = (*it)->index;