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 "private/qdeclarativegridview_p.h"
44 #include "private/qdeclarativevisualitemmodel_p.h"
45 #include "private/qdeclarativeflickable_p_p.h"
47 #include "private/qdeclarativesmoothedanimation_p_p.h"
48 #include <qdeclarativeguard_p.h>
50 #include <qlistmodelinterface_p.h>
55 #include "qplatformdefs.h"
59 #ifndef QML_FLICK_SNAPONETHRESHOLD
60 #define QML_FLICK_SNAPONETHRESHOLD 30
63 //----------------------------------------------------------------------------
68 FxGridItem(QDeclarativeItem *i, QDeclarativeGridView *v) : item(i), view(v) {
69 attached = static_cast<QDeclarativeGridViewAttached*>(qmlAttachedPropertiesObject<QDeclarativeGridView>(item));
71 attached->setView(view);
75 qreal rowPos() const {
77 if (view->flow() == QDeclarativeGridView::LeftToRight) {
80 if (view->effectiveLayoutDirection() == Qt::RightToLeft)
81 rowPos = -view->cellWidth()-item->x();
87 qreal colPos() const {
89 if (view->flow() == QDeclarativeGridView::LeftToRight) {
90 if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
91 int colSize = view->cellWidth();
92 int columns = view->width()/colSize;
93 colPos = colSize * (columns-1) - item->x();
104 qreal endRowPos() const {
105 if (view->flow() == QDeclarativeGridView::LeftToRight) {
106 return item->y() + view->cellHeight() - 1;
108 if (view->effectiveLayoutDirection() == Qt::RightToLeft)
109 return -item->x() - 1;
111 return item->x() + view->cellWidth() - 1;
114 void setPosition(qreal col, qreal row) {
115 if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
116 if (view->flow() == QDeclarativeGridView::LeftToRight) {
117 int columns = view->width()/view->cellWidth();
118 item->setPos(QPointF((view->cellWidth() * (columns-1) - col), row));
120 item->setPos(QPointF(-view->cellWidth()-row, col));
123 if (view->flow() == QDeclarativeGridView::LeftToRight)
124 item->setPos(QPointF(col, row));
126 item->setPos(QPointF(row, col));
130 bool contains(qreal x, qreal y) const {
131 return (x >= item->x() && x < item->x() + view->cellWidth() &&
132 y >= item->y() && y < item->y() + view->cellHeight());
135 QDeclarativeItem *item;
136 QDeclarativeGridView *view;
137 QDeclarativeGridViewAttached *attached;
141 //----------------------------------------------------------------------------
143 class QDeclarativeGridViewPrivate : public QDeclarativeFlickablePrivate
145 Q_DECLARE_PUBLIC(QDeclarativeGridView)
148 QDeclarativeGridViewPrivate()
149 : currentItem(0), layoutDirection(Qt::LeftToRight), flow(QDeclarativeGridView::LeftToRight)
150 , visibleIndex(0) , currentIndex(-1)
151 , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1), itemCount(0)
152 , highlightRangeStart(0), highlightRangeEnd(0)
153 , highlightRangeStartValid(false), highlightRangeEndValid(false)
154 , highlightRange(QDeclarativeGridView::NoHighlightRange)
155 , highlightComponent(0), highlight(0), trackedItem(0)
156 , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0)
157 , highlightMoveDuration(150)
158 , footerComponent(0), footer(0), headerComponent(0), header(0)
159 , bufferMode(BufferBefore | BufferAfter), snapMode(QDeclarativeGridView::NoSnap)
160 , ownModel(false), wrap(false), autoHighlight(true)
161 , fixCurrentVisibility(false), lazyRelease(false), layoutScheduled(false)
162 , deferredRelease(false), haveHighlightRange(false), currentIndexCleared(false) {}
166 FxGridItem *createItem(int modelIndex);
167 void releaseItem(FxGridItem *item);
168 void refill(qreal from, qreal to, bool doBuffer=false);
171 void scheduleLayout();
173 void updateUnrequestedIndexes();
174 void updateUnrequestedPositions();
175 void updateTrackedItem();
176 void createHighlight();
177 void updateHighlight();
178 void updateCurrent(int modelIndex);
181 void fixupPosition();
183 FxGridItem *visibleItem(int modelIndex) const {
184 if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
185 for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
186 FxGridItem *item = visibleItems.at(i);
187 if (item->index == modelIndex)
194 bool isRightToLeftTopToBottom() const {
195 Q_Q(const QDeclarativeGridView);
196 return flow == QDeclarativeGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft;
200 Q_Q(QDeclarativeGridView);
201 if (q->isComponentComplete()) {
206 updateCurrent(currentIndex);
210 void mirrorChange() {
211 Q_Q(QDeclarativeGridView);
215 qreal position() const {
216 Q_Q(const QDeclarativeGridView);
217 return flow == QDeclarativeGridView::LeftToRight ? q->contentY() : q->contentX();
219 void setPosition(qreal pos) {
220 Q_Q(QDeclarativeGridView);
221 if (flow == QDeclarativeGridView::LeftToRight) {
222 q->QDeclarativeFlickable::setContentY(pos);
223 q->QDeclarativeFlickable::setContentX(0);
225 if (q->effectiveLayoutDirection() == Qt::LeftToRight)
226 q->QDeclarativeFlickable::setContentX(pos);
228 q->QDeclarativeFlickable::setContentX(-pos-size());
229 q->QDeclarativeFlickable::setContentY(0);
233 Q_Q(const QDeclarativeGridView);
234 return flow == QDeclarativeGridView::LeftToRight ? q->height() : q->width();
236 qreal originPosition() const {
238 if (!visibleItems.isEmpty())
239 pos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
243 qreal lastPosition() const {
245 if (model && model->count())
246 pos = rowPosAt(model->count() - 1) + rowSize();
250 qreal startPosition() const {
251 return isRightToLeftTopToBottom() ? -lastPosition()+1 : originPosition();
254 qreal endPosition() const {
255 return isRightToLeftTopToBottom() ? -originPosition()+1 : lastPosition();
259 bool isValid() const {
260 return model && model->count() && model->isValid();
263 int rowSize() const {
264 return flow == QDeclarativeGridView::LeftToRight ? cellHeight : cellWidth;
266 int colSize() const {
267 return flow == QDeclarativeGridView::LeftToRight ? cellWidth : cellHeight;
270 qreal colPosAt(int modelIndex) const {
271 if (FxGridItem *item = visibleItem(modelIndex))
272 return item->colPos();
273 if (!visibleItems.isEmpty()) {
274 if (modelIndex < visibleIndex) {
275 int count = (visibleIndex - modelIndex) % columns;
276 int col = visibleItems.first()->colPos() / colSize();
277 col = (columns - count + col) % columns;
278 return col * colSize();
280 int count = columns - 1 - (modelIndex - visibleItems.last()->index - 1) % columns;
281 return visibleItems.last()->colPos() - count * colSize();
284 return (modelIndex % columns) * colSize();
288 qreal rowPosAt(int modelIndex) const {
289 if (FxGridItem *item = visibleItem(modelIndex))
290 return item->rowPos();
291 if (!visibleItems.isEmpty()) {
292 if (modelIndex < visibleIndex) {
293 int firstCol = visibleItems.first()->colPos() / colSize();
294 int col = visibleIndex - modelIndex + (columns - firstCol - 1);
295 int rows = col / columns;
296 return visibleItems.first()->rowPos() - rows * rowSize();
298 int count = modelIndex - visibleItems.last()->index;
299 int col = visibleItems.last()->colPos() + count * colSize();
300 int rows = col / (columns * colSize());
301 return visibleItems.last()->rowPos() + rows * rowSize();
304 qreal pos = (modelIndex / columns) * rowSize();
312 FxGridItem *firstVisibleItem() const {
313 const qreal pos = isRightToLeftTopToBottom() ? -position()-size() : position();
314 for (int i = 0; i < visibleItems.count(); ++i) {
315 FxGridItem *item = visibleItems.at(i);
316 if (item->index != -1 && item->endRowPos() > pos)
319 return visibleItems.count() ? visibleItems.first() : 0;
322 int lastVisibleIndex() const {
323 for (int i = 0; i < visibleItems.count(); ++i) {
324 FxGridItem *item = visibleItems.at(i);
325 if (item->index != -1)
331 // Map a model index to visibleItems list index.
332 // These may differ if removed items are still present in the visible list,
333 // e.g. doing a removal animation
334 int mapFromModel(int modelIndex) const {
335 if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
337 for (int i = 0; i < visibleItems.count(); ++i) {
338 FxGridItem *listItem = visibleItems.at(i);
339 if (listItem->index == modelIndex)
340 return i + visibleIndex;
341 if (listItem->index > modelIndex)
344 return -1; // Not in visibleList
347 qreal snapPosAt(qreal pos) const {
348 Q_Q(const QDeclarativeGridView);
350 if (!visibleItems.isEmpty()) {
351 qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
352 pos += highlightStart;
354 snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
355 snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
356 snapPos -= highlightStart;
359 if (isRightToLeftTopToBottom()) {
360 maxExtent = q->minXExtent();
361 minExtent = q->maxXExtent();
363 maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
364 minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
366 if (snapPos > maxExtent)
368 if (snapPos < minExtent)
374 FxGridItem *snapItemAt(qreal pos) {
375 for (int i = 0; i < visibleItems.count(); ++i) {
376 FxGridItem *item = visibleItems[i];
377 if (item->index == -1)
379 qreal itemTop = item->rowPos();
380 if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
387 int index = currentIndex;
388 for (int i = 0; i < visibleItems.count(); ++i) {
389 FxGridItem *item = visibleItems[i];
390 if (item->index == -1)
392 qreal itemTop = item->rowPos();
393 if (itemTop >= highlight->rowPos()-rowSize()/2 && itemTop < highlight->rowPos()+rowSize()/2) {
395 if (item->colPos() >= highlight->colPos()-colSize()/2 && item->colPos() < highlight->colPos()+colSize()/2)
402 qreal headerSize() const {
406 return flow == QDeclarativeGridView::LeftToRight
407 ? header->item->height()
408 : header->item->width();
412 virtual void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
413 Q_Q(const QDeclarativeGridView);
414 QDeclarativeFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
416 if (newGeometry.height() != oldGeometry.height()
417 || newGeometry.width() != oldGeometry.width()) {
418 if (q->isComponentComplete()) {
423 } else if ((header && header->item == item) || (footer && footer->item == item)) {
431 void positionViewAtIndex(int index, int mode);
432 virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
433 virtual void flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
434 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
436 // for debugging only
437 void checkVisible() const {
439 for (int i = 0; i < visibleItems.count(); ++i) {
440 FxGridItem *listItem = visibleItems.at(i);
441 if (listItem->index == -1) {
443 } else if (listItem->index != visibleIndex + i - skip) {
444 for (int j = 0; j < visibleItems.count(); j++)
445 qDebug() << " index" << j << "item index" << visibleItems.at(j)->index;
446 qFatal("index %d %d %d", visibleIndex, i, listItem->index);
451 QDeclarativeGuard<QDeclarativeVisualModel> model;
452 QVariant modelVariant;
453 QList<FxGridItem*> visibleItems;
454 QHash<QDeclarativeItem*,int> unrequestedItems;
455 FxGridItem *currentItem;
456 Qt::LayoutDirection layoutDirection;
457 QDeclarativeGridView::Flow flow;
465 qreal highlightRangeStart;
466 qreal highlightRangeEnd;
467 bool highlightRangeStartValid;
468 bool highlightRangeEndValid;
469 QDeclarativeGridView::HighlightRangeMode highlightRange;
470 QDeclarativeComponent *highlightComponent;
471 FxGridItem *highlight;
472 FxGridItem *trackedItem;
473 enum MovementReason { Other, SetIndex, Mouse };
474 MovementReason moveReason;
476 QSmoothedAnimation *highlightXAnimator;
477 QSmoothedAnimation *highlightYAnimator;
478 int highlightMoveDuration;
479 QDeclarativeComponent *footerComponent;
481 QDeclarativeComponent *headerComponent;
483 enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
485 QDeclarativeGridView::SnapMode snapMode;
489 bool autoHighlight : 1;
490 bool fixCurrentVisibility : 1;
491 bool lazyRelease : 1;
492 bool layoutScheduled : 1;
493 bool deferredRelease : 1;
494 bool haveHighlightRange : 1;
495 bool currentIndexCleared : 1;
498 void QDeclarativeGridViewPrivate::init()
500 Q_Q(QDeclarativeGridView);
501 QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
502 q->setFlag(QGraphicsItem::ItemIsFocusScope);
503 q->setFlickableDirection(QDeclarativeFlickable::VerticalFlick);
504 addItemChangeListener(this, Geometry);
507 void QDeclarativeGridViewPrivate::clear()
509 for (int i = 0; i < visibleItems.count(); ++i)
510 releaseItem(visibleItems.at(i));
511 visibleItems.clear();
513 releaseItem(currentItem);
520 FxGridItem *QDeclarativeGridViewPrivate::createItem(int modelIndex)
522 Q_Q(QDeclarativeGridView);
524 requestedIndex = modelIndex;
525 FxGridItem *listItem = 0;
526 if (QDeclarativeItem *item = model->item(modelIndex, false)) {
527 listItem = new FxGridItem(item, q);
528 listItem->index = modelIndex;
529 if (model->completePending()) {
531 listItem->item->setZValue(1);
532 listItem->item->setParentItem(q->contentItem());
533 model->completeItem();
535 listItem->item->setParentItem(q->contentItem());
537 unrequestedItems.remove(listItem->item);
544 void QDeclarativeGridViewPrivate::releaseItem(FxGridItem *item)
546 Q_Q(QDeclarativeGridView);
549 if (trackedItem == item) {
550 QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
551 QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
554 if (model->release(item->item) == 0) {
555 // item was not destroyed, and we no longer reference it.
556 unrequestedItems.insert(item->item, model->indexOf(item->item, q));
561 void QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer)
563 Q_Q(QDeclarativeGridView);
564 if (!isValid() || !q->isComponentComplete())
566 itemCount = model->count();
567 qreal bufferFrom = from - buffer;
568 qreal bufferTo = to + buffer;
569 qreal fillFrom = from;
571 if (doBuffer && (bufferMode & BufferAfter))
573 if (doBuffer && (bufferMode & BufferBefore))
574 fillFrom = bufferFrom;
576 bool changed = false;
578 int colPos = colPosAt(visibleIndex);
579 int rowPos = rowPosAt(visibleIndex);
580 int modelIndex = visibleIndex;
581 if (visibleItems.count()) {
582 rowPos = visibleItems.last()->rowPos();
583 colPos = visibleItems.last()->colPos() + colSize();
584 if (colPos > colSize() * (columns-1)) {
588 int i = visibleItems.count() - 1;
589 while (i > 0 && visibleItems.at(i)->index == -1)
591 modelIndex = visibleItems.at(i)->index + 1;
594 if (visibleItems.count() && (fillFrom > rowPos + rowSize()*2
595 || fillTo < rowPosAt(visibleIndex) - rowSize())) {
596 // We've jumped more than a page. Estimate which items are now
597 // visible and fill from there.
598 int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
599 for (int i = 0; i < visibleItems.count(); ++i)
600 releaseItem(visibleItems.at(i));
601 visibleItems.clear();
603 if (modelIndex >= model->count())
604 modelIndex = model->count() - 1;
605 else if (modelIndex < 0)
607 modelIndex = modelIndex / columns * columns;
608 visibleIndex = modelIndex;
609 colPos = colPosAt(visibleIndex);
610 rowPos = rowPosAt(visibleIndex);
613 int colNum = colPos / colSize();
615 FxGridItem *item = 0;
617 // Item creation and release is staggered in order to avoid
618 // creating/releasing multiple items in one frame
619 // while flicking (as much as possible).
620 while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
621 // qDebug() << "refill: append item" << modelIndex;
622 if (!(item = createItem(modelIndex)))
624 item->setPosition(colPos, rowPos);
625 visibleItems.append(item);
628 if (colPos > colSize() * (columns-1)) {
635 if (doBuffer) // never buffer more than one item per frame
639 if (visibleItems.count()) {
640 rowPos = visibleItems.first()->rowPos();
641 colPos = visibleItems.first()->colPos() - colSize();
643 colPos = colSize() * (columns - 1);
647 colNum = colPos / colSize();
648 while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
649 // qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
650 if (!(item = createItem(visibleIndex-1)))
653 item->setPosition(colPos, rowPos);
654 visibleItems.prepend(item);
658 colPos = colSize() * (columns - 1);
663 if (doBuffer) // never buffer more than one item per frame
667 if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
668 while (visibleItems.count() > 1
669 && (item = visibleItems.first())
670 && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
671 if (item->attached->delayRemove())
673 // qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
674 if (item->index != -1)
676 visibleItems.removeFirst();
680 while (visibleItems.count() > 1
681 && (item = visibleItems.last())
682 && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
683 if (item->attached->delayRemove())
685 // qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
686 visibleItems.removeLast();
690 deferredRelease = false;
692 deferredRelease = true;
699 if (flow == QDeclarativeGridView::LeftToRight)
700 q->setContentHeight(endPosition() - startPosition());
702 q->setContentWidth(endPosition() - startPosition());
703 } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
704 refill(from, to, true);
709 void QDeclarativeGridViewPrivate::updateGrid()
711 Q_Q(QDeclarativeGridView);
713 columns = (int)qMax((flow == QDeclarativeGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.));
715 if (flow == QDeclarativeGridView::LeftToRight)
716 q->setContentHeight(endPosition() - startPosition());
718 q->setContentWidth(lastPosition() - originPosition());
722 void QDeclarativeGridViewPrivate::scheduleLayout()
724 Q_Q(QDeclarativeGridView);
725 if (!layoutScheduled) {
726 layoutScheduled = true;
727 QCoreApplication::postEvent(q, new QEvent(QEvent::User), Qt::HighEventPriority);
731 void QDeclarativeGridViewPrivate::layout()
733 Q_Q(QDeclarativeGridView);
734 layoutScheduled = false;
735 if (!isValid() && !visibleItems.count()) {
739 if (visibleItems.count()) {
740 qreal rowPos = visibleItems.first()->rowPos();
741 qreal colPos = visibleItems.first()->colPos();
742 int col = visibleIndex % columns;
743 if (colPos != col * colSize()) {
744 colPos = col * colSize();
745 visibleItems.first()->setPosition(colPos, rowPos);
747 for (int i = 1; i < visibleItems.count(); ++i) {
748 FxGridItem *item = visibleItems.at(i);
750 if (colPos > colSize() * (columns-1)) {
754 item->setPosition(colPos, rowPos);
764 if (flow == QDeclarativeGridView::LeftToRight) {
765 q->setContentHeight(endPosition() - startPosition());
768 q->setContentWidth(endPosition() - startPosition());
771 updateUnrequestedPositions();
774 void QDeclarativeGridViewPrivate::updateUnrequestedIndexes()
776 Q_Q(QDeclarativeGridView);
777 QHash<QDeclarativeItem*,int>::iterator it;
778 for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
779 *it = model->indexOf(it.key(), q);
782 void QDeclarativeGridViewPrivate::updateUnrequestedPositions()
784 QHash<QDeclarativeItem*,int>::const_iterator it;
785 for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
786 QDeclarativeItem *item = it.key();
787 if (flow == QDeclarativeGridView::LeftToRight) {
788 item->setPos(QPointF(colPosAt(*it), rowPosAt(*it)));
790 if (isRightToLeftTopToBottom())
791 item->setPos(QPointF(-rowPosAt(*it)-item->width(), colPosAt(*it)));
793 item->setPos(QPointF(rowPosAt(*it), colPosAt(*it)));
798 void QDeclarativeGridViewPrivate::updateTrackedItem()
800 Q_Q(QDeclarativeGridView);
801 FxGridItem *item = currentItem;
805 if (trackedItem && item != trackedItem) {
806 QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
807 QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
811 if (!trackedItem && item) {
813 QObject::connect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
814 QObject::connect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
817 q->trackedPositionChanged();
820 void QDeclarativeGridViewPrivate::createHighlight()
822 Q_Q(QDeclarativeGridView);
823 bool changed = false;
825 if (trackedItem == highlight)
827 if (highlight->item->scene())
828 highlight->item->scene()->removeItem(highlight->item);
829 highlight->item->deleteLater();
832 delete highlightXAnimator;
833 delete highlightYAnimator;
834 highlightXAnimator = 0;
835 highlightYAnimator = 0;
840 QDeclarativeItem *item = 0;
841 if (highlightComponent) {
842 QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q));
843 QObject *nobj = highlightComponent->create(highlightContext);
845 QDeclarative_setParent_noEvent(highlightContext, nobj);
846 item = qobject_cast<QDeclarativeItem *>(nobj);
850 delete highlightContext;
853 item = new QDeclarativeItem;
854 QDeclarative_setParent_noEvent(item, q->contentItem());
855 item->setParentItem(q->contentItem());
858 QDeclarative_setParent_noEvent(item, q->contentItem());
859 item->setParentItem(q->contentItem());
860 highlight = new FxGridItem(item, q);
861 if (currentItem && autoHighlight)
862 highlight->setPosition(currentItem->colPos(), currentItem->rowPos());
863 highlightXAnimator = new QSmoothedAnimation(q);
864 highlightXAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("x"));
865 highlightXAnimator->userDuration = highlightMoveDuration;
866 highlightYAnimator = new QSmoothedAnimation(q);
867 highlightYAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("y"));
868 highlightYAnimator->userDuration = highlightMoveDuration;
870 highlightXAnimator->restart();
871 highlightYAnimator->restart();
877 emit q->highlightItemChanged();
880 void QDeclarativeGridViewPrivate::updateHighlight()
882 if ((!currentItem && highlight) || (currentItem && !highlight))
884 if (currentItem && autoHighlight && highlight && !hData.moving && !vData.moving) {
885 // auto-update highlight
886 highlightXAnimator->to = currentItem->item->x();
887 highlightYAnimator->to = currentItem->item->y();
888 highlight->item->setWidth(currentItem->item->width());
889 highlight->item->setHeight(currentItem->item->height());
890 highlightXAnimator->restart();
891 highlightYAnimator->restart();
896 void QDeclarativeGridViewPrivate::updateCurrent(int modelIndex)
898 Q_Q(QDeclarativeGridView);
899 if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
901 currentItem->attached->setIsCurrentItem(false);
902 releaseItem(currentItem);
904 currentIndex = modelIndex;
905 emit q->currentIndexChanged();
907 } else if (currentIndex != modelIndex) {
908 currentIndex = modelIndex;
909 emit q->currentIndexChanged();
914 if (currentItem && currentIndex == modelIndex) {
919 FxGridItem *oldCurrentItem = currentItem;
920 currentIndex = modelIndex;
921 currentItem = createItem(modelIndex);
922 fixCurrentVisibility = true;
923 if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
924 oldCurrentItem->attached->setIsCurrentItem(false);
926 currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex));
927 currentItem->item->setFocus(true);
928 currentItem->attached->setIsCurrentItem(true);
931 emit q->currentIndexChanged();
932 releaseItem(oldCurrentItem);
935 void QDeclarativeGridViewPrivate::updateFooter()
937 Q_Q(QDeclarativeGridView);
938 if (!footer && footerComponent) {
939 QDeclarativeItem *item = 0;
940 QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
941 QObject *nobj = footerComponent->create(context);
943 QDeclarative_setParent_noEvent(context, nobj);
944 item = qobject_cast<QDeclarativeItem *>(nobj);
951 QDeclarative_setParent_noEvent(item, q->contentItem());
952 item->setParentItem(q->contentItem());
954 QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
955 itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
956 footer = new FxGridItem(item, q);
962 if (isRightToLeftTopToBottom()) {
963 rowOffset = footer->item->width()-cellWidth;
966 if (q->effectiveLayoutDirection() == Qt::RightToLeft)
967 colOffset = footer->item->width()-cellWidth;
969 if (visibleItems.count()) {
970 qreal endPos = lastPosition();
971 if (lastVisibleIndex() == model->count()-1) {
972 footer->setPosition(colOffset, endPos + rowOffset);
974 qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size();
975 if (endPos <= visiblePos || footer->endRowPos() < endPos + rowOffset)
976 footer->setPosition(colOffset, endPos + rowOffset);
981 endPos += flow == QDeclarativeGridView::LeftToRight ? header->item->height() : header->item->width();
983 footer->setPosition(colOffset, endPos);
988 void QDeclarativeGridViewPrivate::updateHeader()
990 Q_Q(QDeclarativeGridView);
991 if (!header && headerComponent) {
992 QDeclarativeItem *item = 0;
993 QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
994 QObject *nobj = headerComponent->create(context);
996 QDeclarative_setParent_noEvent(context, nobj);
997 item = qobject_cast<QDeclarativeItem *>(nobj);
1004 QDeclarative_setParent_noEvent(item, q->contentItem());
1005 item->setParentItem(q->contentItem());
1007 QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
1008 itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
1009 header = new FxGridItem(item, q);
1013 qreal colOffset = 0;
1015 if (isRightToLeftTopToBottom()) {
1016 rowOffset = -cellWidth;
1018 rowOffset = -headerSize();
1019 if (q->effectiveLayoutDirection() == Qt::RightToLeft)
1020 colOffset = header->item->width()-cellWidth;
1022 if (visibleItems.count()) {
1023 qreal startPos = originPosition();
1024 if (visibleIndex == 0) {
1025 header->setPosition(colOffset, startPos + rowOffset);
1027 qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position();
1028 qreal headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
1029 if (tempPos <= startPos || headerPos > startPos + rowOffset)
1030 header->setPosition(colOffset, startPos + rowOffset);
1033 header->setPosition(colOffset, 0);
1038 void QDeclarativeGridViewPrivate::fixupPosition()
1041 if (flow == QDeclarativeGridView::LeftToRight)
1047 void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
1049 if ((flow == QDeclarativeGridView::TopToBottom && &data == &vData)
1050 || (flow == QDeclarativeGridView::LeftToRight && &data == &hData))
1053 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1055 qreal highlightStart;
1058 if (isRightToLeftTopToBottom()) {
1059 // Handle Right-To-Left exceptions
1060 viewPos = -position()-size();
1061 highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
1062 highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd;
1064 viewPos = position();
1065 highlightStart = highlightRangeStart;
1066 highlightEnd = highlightRangeEnd;
1069 bool strictHighlightRange = haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange;
1071 if (snapMode != QDeclarativeGridView::NoSnap) {
1072 qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
1073 if (snapMode == QDeclarativeGridView::SnapOneRow && moveReason == Mouse) {
1074 // if we've been dragged < rowSize()/2 then bias towards the next row
1075 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1077 if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < rowSize()/2)
1079 else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -rowSize()/2)
1080 bias = -rowSize()/2;
1081 if (isRightToLeftTopToBottom())
1083 tempPosition -= bias;
1085 FxGridItem *topItem = snapItemAt(tempPosition+highlightStart);
1086 if (!topItem && strictHighlightRange && currentItem) {
1087 // StrictlyEnforceRange always keeps an item in range
1089 topItem = currentItem;
1091 FxGridItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
1092 if (!bottomItem && strictHighlightRange && currentItem) {
1093 // StrictlyEnforceRange always keeps an item in range
1095 bottomItem = currentItem;
1098 bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1099 if (topItem && (isInBounds || strictHighlightRange)) {
1100 if (topItem->index == 0 && header && tempPosition+highlightStart < header->rowPos()+headerSize()/2 && !strictHighlightRange) {
1101 pos = isRightToLeftTopToBottom() ? - header->rowPos() + highlightStart - size() : header->rowPos() - highlightStart;
1103 if (isRightToLeftTopToBottom())
1104 pos = qMax(qMin(-topItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
1106 pos = qMax(qMin(topItem->rowPos() - highlightStart, -maxExtent), -minExtent);
1108 } else if (bottomItem && isInBounds) {
1109 if (isRightToLeftTopToBottom())
1110 pos = qMax(qMin(-bottomItem->rowPos() + highlightEnd - size(), -maxExtent), -minExtent);
1112 pos = qMax(qMin(bottomItem->rowPos() - highlightEnd, -maxExtent), -minExtent);
1114 QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
1117 qreal dist = qAbs(data.move + pos);
1119 timeline.reset(data.move);
1120 if (fixupMode != Immediate) {
1121 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1122 data.fixingUp = true;
1124 timeline.set(data.move, -pos);
1126 vTime = timeline.time();
1128 } else if (haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) {
1131 qreal pos = currentItem->rowPos();
1132 if (viewPos < pos + rowSize() - highlightEnd)
1133 viewPos = pos + rowSize() - highlightEnd;
1134 if (viewPos > pos - highlightStart)
1135 viewPos = pos - highlightStart;
1136 if (isRightToLeftTopToBottom())
1137 viewPos = -viewPos-size();
1138 timeline.reset(data.move);
1139 if (viewPos != position()) {
1140 if (fixupMode != Immediate) {
1141 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1142 data.fixingUp = true;
1144 timeline.set(data.move, -viewPos);
1147 vTime = timeline.time();
1150 QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
1152 data.inOvershoot = false;
1156 void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1157 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
1159 Q_Q(QDeclarativeGridView);
1160 data.fixingUp = false;
1162 if ((!haveHighlightRange || highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1163 && snapMode == QDeclarativeGridView::NoSnap) {
1164 QDeclarativeFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1167 qreal maxDistance = 0;
1168 qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value();
1169 // -ve velocity means list is moving up/left
1171 if (data.move.value() < minExtent) {
1172 if (snapMode == QDeclarativeGridView::SnapOneRow) {
1173 // if we've been dragged < averageSize/2 then bias towards the next item
1174 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1175 qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0;
1176 if (isRightToLeftTopToBottom())
1178 data.flickTarget = -snapPosAt(-dataValue - bias);
1179 maxDistance = qAbs(data.flickTarget - data.move.value());
1180 velocity = maxVelocity;
1182 maxDistance = qAbs(minExtent - data.move.value());
1185 if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1186 data.flickTarget = minExtent;
1188 if (data.move.value() > maxExtent) {
1189 if (snapMode == QDeclarativeGridView::SnapOneRow) {
1190 // if we've been dragged < averageSize/2 then bias towards the next item
1191 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1192 qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0;
1193 if (isRightToLeftTopToBottom())
1195 data.flickTarget = -snapPosAt(-dataValue + bias);
1196 maxDistance = qAbs(data.flickTarget - data.move.value());
1197 velocity = -maxVelocity;
1199 maxDistance = qAbs(maxExtent - data.move.value());
1202 if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1203 data.flickTarget = maxExtent;
1206 bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds;
1208 if (maxDistance > 0 || overShoot) {
1209 // This mode requires the grid to stop exactly on a row boundary.
1211 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1217 qreal accel = deceleration;
1219 qreal overshootDist = qreal(0.0);
1220 if ((maxDistance > qreal(0.0) && v2 / (2.0f * maxDistance) < accel) || snapMode == QDeclarativeGridView::SnapOneRow) {
1221 // + rowSize()/4 to encourage moving at least one item in the flick direction
1222 qreal dist = v2 / (accel * qreal(2.0)) + rowSize()/4;
1223 dist = qMin(dist, maxDistance);
1226 if (snapMode != QDeclarativeGridView::SnapOneRow) {
1227 qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
1228 data.flickTarget = -snapPosAt(-dataValue + distTemp);
1230 data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
1232 if (data.flickTarget >= minExtent) {
1233 overshootDist = overShootDistance(vSize);
1234 data.flickTarget += overshootDist;
1235 } else if (data.flickTarget <= maxExtent) {
1236 overshootDist = overShootDistance(vSize);
1237 data.flickTarget -= overshootDist;
1240 qreal adjDist = -data.flickTarget + data.move.value();
1241 if (qAbs(adjDist) > qAbs(dist)) {
1242 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1243 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1252 accel = v2 / (2.0f * qAbs(dist));
1254 data.flickTarget = velocity > 0 ? minExtent : maxExtent;
1255 overshootDist = overShoot ? overShootDistance(vSize) : 0;
1257 timeline.reset(data.move);
1258 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1259 timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1260 if (!hData.flicking && q->xflick()) {
1261 hData.flicking = true;
1262 emit q->flickingChanged();
1263 emit q->flickingHorizontallyChanged();
1264 emit q->flickStarted();
1266 if (!vData.flicking && q->yflick()) {
1267 vData.flicking = true;
1268 emit q->flickingChanged();
1269 emit q->flickingVerticallyChanged();
1270 emit q->flickStarted();
1273 timeline.reset(data.move);
1274 fixup(data, minExtent, maxExtent);
1279 //----------------------------------------------------------------------------
1282 \qmlclass GridView QDeclarativeGridView
1284 \ingroup qml-view-elements
1287 \brief The GridView item provides a grid view of items provided by a model.
1289 A GridView displays data from models created from built-in QML elements like ListModel
1290 and XmlListModel, or custom model classes defined in C++ that inherit from
1293 A GridView has a \l model, which defines the data to be displayed, and
1294 a \l delegate, which defines how the data should be displayed. Items in a
1295 GridView are laid out horizontally or vertically. Grid views are inherently flickable
1296 as GridView inherits from \l Flickable.
1298 \section1 Example Usage
1300 The following example shows the definition of a simple list model defined
1301 in a file called \c ContactModel.qml:
1303 \snippet doc/src/snippets/declarative/gridview/ContactModel.qml 0
1305 \div {class="float-right"}
1306 \inlineimage gridview-simple.png
1309 This model can be referenced as \c ContactModel in other QML files. See \l{QML Modules}
1310 for more information about creating reusable components like this.
1312 Another component can display this model data in a GridView, as in the following
1313 example, which creates a \c ContactModel component for its model, and a \l Column element
1314 (containing \l Image and \l Text elements) for its delegate.
1317 \snippet doc/src/snippets/declarative/gridview/gridview.qml import
1319 \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs simple
1321 \div {class="float-right"}
1322 \inlineimage gridview-highlight.png
1325 The view will create a new delegate for each item in the model. Note that the delegate
1326 is able to access the model's \c name and \c portrait data directly.
1328 An improved grid view is shown below. The delegate is visually improved and is moved
1329 into a separate \c contactDelegate component.
1332 \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs advanced
1334 The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
1335 and \c focus is set to \c true to enable keyboard navigation for the grid view.
1336 The grid view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
1338 Delegates are instantiated as needed and may be destroyed at any time.
1339 State should \e never be stored in a delegate.
1341 GridView attaches a number of properties to the root item of the delegate, for example
1342 \c {GridView.isCurrentItem}. In the following example, the root delegate item can access
1343 this attached property directly as \c GridView.isCurrentItem, while the child
1344 \c contactInfo object must refer to this property as \c wrapper.GridView.isCurrentItem.
1346 \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem
1348 \note Views do not set the \l{Item::}{clip} property automatically.
1349 If the view is not clipped by another item or the screen, it will be necessary
1350 to set this property to true in order to clip the items that are partially or
1351 fully outside the view.
1353 \sa {declarative/modelviews/gridview}{GridView example}
1355 QDeclarativeGridView::QDeclarativeGridView(QDeclarativeItem *parent)
1356 : QDeclarativeFlickable(*(new QDeclarativeGridViewPrivate), parent)
1358 Q_D(QDeclarativeGridView);
1362 QDeclarativeGridView::~QDeclarativeGridView()
1364 Q_D(QDeclarativeGridView);
1373 \qmlattachedproperty bool GridView::isCurrentItem
1374 This attached property is true if this delegate is the current item; otherwise false.
1376 It is attached to each instance of the delegate.
1380 \qmlattachedproperty GridView GridView::view
1381 This attached property holds the view that manages this delegate instance.
1383 It is attached to each instance of the delegate.
1385 \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem
1389 \qmlattachedproperty bool GridView::delayRemove
1390 This attached property holds whether the delegate may be destroyed.
1392 It is attached to each instance of the delegate.
1394 It is sometimes necessary to delay the destruction of an item
1395 until an animation completes.
1397 The example below ensures that the animation completes before
1398 the item is removed from the grid.
1400 \snippet doc/src/snippets/declarative/gridview/gridview.qml delayRemove
1404 \qmlattachedsignal GridView::onAdd()
1405 This attached handler is called immediately after an item is added to the view.
1409 \qmlattachedsignal GridView::onRemove()
1410 This attached handler is called immediately before an item is removed from the view.
1415 \qmlproperty model GridView::model
1416 This property holds the model providing data for the grid.
1418 The model provides the set of data that is used to create the items
1419 in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
1420 or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
1421 used, it must be a subclass of \l QAbstractItemModel or a simple list.
1423 \sa {qmlmodels}{Data Models}
1425 QVariant QDeclarativeGridView::model() const
1427 Q_D(const QDeclarativeGridView);
1428 return d->modelVariant;
1432 int QDeclarativeGridView::modelCount() const
1434 Q_D(const QDeclarativeGridView);
1435 return d->model->count();
1438 void QDeclarativeGridView::setModel(const QVariant &model)
1440 Q_D(QDeclarativeGridView);
1441 if (d->modelVariant == model)
1444 disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1445 disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1446 disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1447 disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1448 disconnect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
1449 disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
1452 d->modelVariant = model;
1453 QObject *object = qvariant_cast<QObject*>(model);
1454 QDeclarativeVisualModel *vim = 0;
1455 if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
1458 d->ownModel = false;
1463 d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
1466 if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
1467 dataModel->setModel(model);
1470 d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore | QDeclarativeGridViewPrivate::BufferAfter;
1471 if (isComponentComplete()) {
1473 if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
1476 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1477 d->updateCurrent(d->currentIndex);
1478 if (d->highlight && d->currentItem) {
1479 if (d->autoHighlight)
1480 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1481 d->updateTrackedItem();
1483 d->moveReason = QDeclarativeGridViewPrivate::Other;
1486 connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1487 connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1488 connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1489 connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1490 connect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
1491 connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
1492 emit countChanged();
1494 emit modelChanged();
1498 \qmlproperty Component GridView::delegate
1500 The delegate provides a template defining each item instantiated by the view.
1501 The index is exposed as an accessible \c index property. Properties of the
1502 model are also available depending upon the type of \l {qmlmodels}{Data Model}.
1504 The number of elements in the delegate has a direct effect on the
1505 flicking performance of the view. If at all possible, place functionality
1506 that is not needed for the normal display of the delegate in a \l Loader which
1507 can load additional elements when needed.
1509 The GridView will layout the items based on the size of the root item
1512 \note Delegates are instantiated as needed and may be destroyed at any time.
1513 State should \e never be stored in a delegate.
1515 QDeclarativeComponent *QDeclarativeGridView::delegate() const
1517 Q_D(const QDeclarativeGridView);
1519 if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
1520 return dataModel->delegate();
1526 void QDeclarativeGridView::setDelegate(QDeclarativeComponent *delegate)
1528 Q_D(QDeclarativeGridView);
1529 if (delegate == this->delegate())
1533 d->model = new QDeclarativeVisualDataModel(qmlContext(this));
1536 if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model)) {
1537 int oldCount = dataModel->count();
1538 dataModel->setDelegate(delegate);
1539 if (isComponentComplete()) {
1540 for (int i = 0; i < d->visibleItems.count(); ++i)
1541 d->releaseItem(d->visibleItems.at(i));
1542 d->visibleItems.clear();
1543 d->releaseItem(d->currentItem);
1546 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1547 d->updateCurrent(d->currentIndex);
1548 if (d->highlight && d->currentItem) {
1549 if (d->autoHighlight)
1550 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1551 d->updateTrackedItem();
1553 d->moveReason = QDeclarativeGridViewPrivate::Other;
1555 if (oldCount != dataModel->count())
1556 emit countChanged();
1557 emit delegateChanged();
1562 \qmlproperty int GridView::currentIndex
1563 \qmlproperty Item GridView::currentItem
1565 The \c currentIndex property holds the index of the current item, and
1566 \c currentItem holds the current item. Setting the currentIndex to -1
1567 will clear the highlight and set currentItem to null.
1569 If highlightFollowsCurrentItem is \c true, setting either of these
1570 properties will smoothly scroll the GridView so that the current
1571 item becomes visible.
1573 Note that the position of the current item
1574 may only be approximate until it becomes visible in the view.
1576 int QDeclarativeGridView::currentIndex() const
1578 Q_D(const QDeclarativeGridView);
1579 return d->currentIndex;
1582 void QDeclarativeGridView::setCurrentIndex(int index)
1584 Q_D(QDeclarativeGridView);
1585 if (d->requestedIndex >= 0) // currently creating item
1587 d->currentIndexCleared = (index == -1);
1588 if (index == d->currentIndex)
1590 if (isComponentComplete() && d->isValid()) {
1591 if (d->layoutScheduled)
1593 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1594 d->updateCurrent(index);
1596 d->currentIndex = index;
1597 emit currentIndexChanged();
1601 QDeclarativeItem *QDeclarativeGridView::currentItem()
1603 Q_D(QDeclarativeGridView);
1604 if (!d->currentItem)
1606 return d->currentItem->item;
1610 \qmlproperty Item GridView::highlightItem
1612 This holds the highlight item created from the \l highlight component.
1614 The highlightItem is managed by the view unless
1615 \l highlightFollowsCurrentItem is set to false.
1617 \sa highlight, highlightFollowsCurrentItem
1619 QDeclarativeItem *QDeclarativeGridView::highlightItem()
1621 Q_D(QDeclarativeGridView);
1624 return d->highlight->item;
1628 \qmlproperty int GridView::count
1629 This property holds the number of items in the view.
1631 int QDeclarativeGridView::count() const
1633 Q_D(const QDeclarativeGridView);
1635 return d->model->count();
1640 \qmlproperty Component GridView::highlight
1641 This property holds the component to use as the highlight.
1643 An instance of the highlight component is created for each view.
1644 The geometry of the resulting component instance will be managed by the view
1645 so as to stay with the current item, unless the highlightFollowsCurrentItem property is false.
1647 \sa highlightItem, highlightFollowsCurrentItem
1649 QDeclarativeComponent *QDeclarativeGridView::highlight() const
1651 Q_D(const QDeclarativeGridView);
1652 return d->highlightComponent;
1655 void QDeclarativeGridView::setHighlight(QDeclarativeComponent *highlight)
1657 Q_D(QDeclarativeGridView);
1658 if (highlight != d->highlightComponent) {
1659 d->highlightComponent = highlight;
1660 d->updateCurrent(d->currentIndex);
1661 emit highlightChanged();
1666 \qmlproperty bool GridView::highlightFollowsCurrentItem
1667 This property sets whether the highlight is managed by the view.
1669 If this property is true (the default value), the highlight is moved smoothly
1670 to follow the current item. Otherwise, the
1671 highlight is not moved by the view, and any movement must be implemented
1674 Here is a highlight with its motion defined by a \l {SpringAnimation} item:
1676 \snippet doc/src/snippets/declarative/gridview/gridview.qml highlightFollowsCurrentItem
1678 bool QDeclarativeGridView::highlightFollowsCurrentItem() const
1680 Q_D(const QDeclarativeGridView);
1681 return d->autoHighlight;
1684 void QDeclarativeGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
1686 Q_D(QDeclarativeGridView);
1687 if (d->autoHighlight != autoHighlight) {
1688 d->autoHighlight = autoHighlight;
1689 if (autoHighlight) {
1690 d->updateHighlight();
1691 } else if (d->highlightXAnimator) {
1692 d->highlightXAnimator->stop();
1693 d->highlightYAnimator->stop();
1699 \qmlproperty int GridView::highlightMoveDuration
1700 This property holds the move animation duration of the highlight delegate.
1702 highlightFollowsCurrentItem must be true for this property
1705 The default value for the duration is 150ms.
1707 \sa highlightFollowsCurrentItem
1709 int QDeclarativeGridView::highlightMoveDuration() const
1711 Q_D(const QDeclarativeGridView);
1712 return d->highlightMoveDuration;
1715 void QDeclarativeGridView::setHighlightMoveDuration(int duration)
1717 Q_D(QDeclarativeGridView);
1718 if (d->highlightMoveDuration != duration) {
1719 d->highlightMoveDuration = duration;
1720 if (d->highlightYAnimator) {
1721 d->highlightXAnimator->userDuration = d->highlightMoveDuration;
1722 d->highlightYAnimator->userDuration = d->highlightMoveDuration;
1724 emit highlightMoveDurationChanged();
1730 \qmlproperty real GridView::preferredHighlightBegin
1731 \qmlproperty real GridView::preferredHighlightEnd
1732 \qmlproperty enumeration GridView::highlightRangeMode
1734 These properties define the preferred range of the highlight (for the current item)
1735 within the view. The \c preferredHighlightBegin value must be less than the
1736 \c preferredHighlightEnd value.
1738 These properties affect the position of the current item when the view is scrolled.
1739 For example, if the currently selected item should stay in the middle of the
1740 view when it is scrolled, set the \c preferredHighlightBegin and
1741 \c preferredHighlightEnd values to the top and bottom coordinates of where the middle
1742 item would be. If the \c currentItem is changed programmatically, the view will
1743 automatically scroll so that the current item is in the middle of the view.
1744 Furthermore, the behavior of the current item index will occur whether or not a
1747 Valid values for \c highlightRangeMode are:
1750 \o GridView.ApplyRange - the view attempts to maintain the highlight within the range.
1751 However, the highlight can move outside of the range at the ends of the view or due
1752 to mouse interaction.
1753 \o GridView.StrictlyEnforceRange - the highlight never moves outside of the range.
1754 The current item changes if a keyboard or mouse action would cause the highlight to move
1755 outside of the range.
1756 \o GridView.NoHighlightRange - this is the default value.
1759 qreal QDeclarativeGridView::preferredHighlightBegin() const
1761 Q_D(const QDeclarativeGridView);
1762 return d->highlightRangeStart;
1765 void QDeclarativeGridView::setPreferredHighlightBegin(qreal start)
1767 Q_D(QDeclarativeGridView);
1768 d->highlightRangeStartValid = true;
1769 if (d->highlightRangeStart == start)
1771 d->highlightRangeStart = start;
1772 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1773 emit preferredHighlightBeginChanged();
1776 void QDeclarativeGridView::resetPreferredHighlightBegin()
1778 Q_D(QDeclarativeGridView);
1779 d->highlightRangeStartValid = false;
1780 if (d->highlightRangeStart == 0)
1782 d->highlightRangeStart = 0;
1783 emit preferredHighlightBeginChanged();
1786 qreal QDeclarativeGridView::preferredHighlightEnd() const
1788 Q_D(const QDeclarativeGridView);
1789 return d->highlightRangeEnd;
1792 void QDeclarativeGridView::setPreferredHighlightEnd(qreal end)
1794 Q_D(QDeclarativeGridView);
1795 d->highlightRangeEndValid = true;
1796 if (d->highlightRangeEnd == end)
1798 d->highlightRangeEnd = end;
1799 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1800 emit preferredHighlightEndChanged();
1803 void QDeclarativeGridView::resetPreferredHighlightEnd()
1805 Q_D(QDeclarativeGridView);
1806 d->highlightRangeEndValid = false;
1807 if (d->highlightRangeEnd == 0)
1809 d->highlightRangeEnd = 0;
1810 emit preferredHighlightEndChanged();
1813 QDeclarativeGridView::HighlightRangeMode QDeclarativeGridView::highlightRangeMode() const
1815 Q_D(const QDeclarativeGridView);
1816 return d->highlightRange;
1819 void QDeclarativeGridView::setHighlightRangeMode(HighlightRangeMode mode)
1821 Q_D(QDeclarativeGridView);
1822 if (d->highlightRange == mode)
1824 d->highlightRange = mode;
1825 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1826 emit highlightRangeModeChanged();
1830 \qmlproperty enumeration GridView::layoutDirection
1831 This property holds the layout direction of the grid.
1836 \o Qt.LeftToRight (default) - Items will be laid out starting in the top, left corner. The flow is
1837 dependent on the \l GridView::flow property.
1838 \o Qt.RightToLeft - Items will be laid out starting in the top, right corner. The flow is dependent
1839 on the \l GridView::flow property.
1842 When using the attached property \l {LayoutMirroring::enabled} for locale layouts,
1843 the layout direction of the grid view will be mirrored. However, the actual property
1844 \c layoutDirection will remain unchanged. You can use the property
1845 \l {LayoutMirroring::enabled} to determine whether the direction has been mirrored.
1847 \sa {LayoutMirroring}{LayoutMirroring}
1850 Qt::LayoutDirection QDeclarativeGridView::layoutDirection() const
1852 Q_D(const QDeclarativeGridView);
1853 return d->layoutDirection;
1856 void QDeclarativeGridView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1858 Q_D(QDeclarativeGridView);
1859 if (d->layoutDirection != layoutDirection) {
1860 d->layoutDirection = layoutDirection;
1862 emit layoutDirectionChanged();
1866 Qt::LayoutDirection QDeclarativeGridView::effectiveLayoutDirection() const
1868 Q_D(const QDeclarativeGridView);
1869 if (d->effectiveLayoutMirror)
1870 return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
1872 return d->layoutDirection;
1876 \qmlproperty enumeration GridView::flow
1877 This property holds the flow of the grid.
1882 \o GridView.LeftToRight (default) - Items are laid out from left to right, and the view scrolls vertically
1883 \o GridView.TopToBottom - Items are laid out from top to bottom, and the view scrolls horizontally
1886 QDeclarativeGridView::Flow QDeclarativeGridView::flow() const
1888 Q_D(const QDeclarativeGridView);
1892 void QDeclarativeGridView::setFlow(Flow flow)
1894 Q_D(QDeclarativeGridView);
1895 if (d->flow != flow) {
1897 if (d->flow == LeftToRight) {
1898 setContentWidth(-1);
1899 setFlickableDirection(QDeclarativeFlickable::VerticalFlick);
1901 setContentHeight(-1);
1902 setFlickableDirection(QDeclarativeFlickable::HorizontalFlick);
1912 \qmlproperty bool GridView::keyNavigationWraps
1913 This property holds whether the grid wraps key navigation
1915 If this is true, key navigation that would move the current item selection
1916 past one end of the view instead wraps around and moves the selection to
1917 the other end of the view.
1919 By default, key navigation is not wrapped.
1921 bool QDeclarativeGridView::isWrapEnabled() const
1923 Q_D(const QDeclarativeGridView);
1927 void QDeclarativeGridView::setWrapEnabled(bool wrap)
1929 Q_D(QDeclarativeGridView);
1930 if (d->wrap == wrap)
1933 emit keyNavigationWrapsChanged();
1937 \qmlproperty int GridView::cacheBuffer
1938 This property determines whether delegates are retained outside the
1939 visible area of the view.
1941 If non-zero the view will keep as many delegates
1942 instantiated as will fit within the buffer specified. For example,
1943 if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
1944 set to 40, then up to 2 delegates above and 2 delegates below the visible
1945 area may be retained.
1947 Note that cacheBuffer is not a pixel buffer - it only maintains additional
1948 instantiated delegates.
1950 Setting this value can make scrolling the list smoother at the expense
1951 of additional memory usage. It is not a substitute for creating efficient
1952 delegates; the fewer elements in a delegate, the faster a view may be
1955 int QDeclarativeGridView::cacheBuffer() const
1957 Q_D(const QDeclarativeGridView);
1961 void QDeclarativeGridView::setCacheBuffer(int buffer)
1963 Q_D(QDeclarativeGridView);
1964 if (d->buffer != buffer) {
1966 if (isComponentComplete())
1968 emit cacheBufferChanged();
1973 \qmlproperty int GridView::cellWidth
1974 \qmlproperty int GridView::cellHeight
1976 These properties holds the width and height of each cell in the grid.
1978 The default cell size is 100x100.
1980 int QDeclarativeGridView::cellWidth() const
1982 Q_D(const QDeclarativeGridView);
1983 return d->cellWidth;
1986 void QDeclarativeGridView::setCellWidth(int cellWidth)
1988 Q_D(QDeclarativeGridView);
1989 if (cellWidth != d->cellWidth && cellWidth > 0) {
1990 d->cellWidth = qMax(1, cellWidth);
1992 emit cellWidthChanged();
1997 int QDeclarativeGridView::cellHeight() const
1999 Q_D(const QDeclarativeGridView);
2000 return d->cellHeight;
2003 void QDeclarativeGridView::setCellHeight(int cellHeight)
2005 Q_D(QDeclarativeGridView);
2006 if (cellHeight != d->cellHeight && cellHeight > 0) {
2007 d->cellHeight = qMax(1, cellHeight);
2009 emit cellHeightChanged();
2014 \qmlproperty enumeration GridView::snapMode
2016 This property determines how the view scrolling will settle following a drag or flick.
2017 The possible values are:
2020 \o GridView.NoSnap (default) - the view stops anywhere within the visible area.
2021 \o GridView.SnapToRow - the view settles with a row (or column for \c GridView.TopToBottom flow)
2022 aligned with the start of the view.
2023 \o GridView.SnapOneRow - the view will settle no more than one row (or column for \c GridView.TopToBottom flow)
2024 away from the first visible row at the time the mouse button is released.
2025 This mode is particularly useful for moving one page at a time.
2029 QDeclarativeGridView::SnapMode QDeclarativeGridView::snapMode() const
2031 Q_D(const QDeclarativeGridView);
2035 void QDeclarativeGridView::setSnapMode(SnapMode mode)
2037 Q_D(QDeclarativeGridView);
2038 if (d->snapMode != mode) {
2040 emit snapModeChanged();
2045 \qmlproperty Component GridView::footer
2046 This property holds the component to use as the footer.
2048 An instance of the footer component is created for each view. The
2049 footer is positioned at the end of the view, after any items.
2053 QDeclarativeComponent *QDeclarativeGridView::footer() const
2055 Q_D(const QDeclarativeGridView);
2056 return d->footerComponent;
2059 void QDeclarativeGridView::setFooter(QDeclarativeComponent *footer)
2061 Q_D(QDeclarativeGridView);
2062 if (d->footerComponent != footer) {
2065 scene()->removeItem(d->footer->item);
2066 d->footer->item->deleteLater();
2070 d->footerComponent = footer;
2071 if (isComponentComplete()) {
2076 emit footerChanged();
2081 \qmlproperty Component GridView::header
2082 This property holds the component to use as the header.
2084 An instance of the header component is created for each view. The
2085 header is positioned at the beginning of the view, before any items.
2089 QDeclarativeComponent *QDeclarativeGridView::header() const
2091 Q_D(const QDeclarativeGridView);
2092 return d->headerComponent;
2095 void QDeclarativeGridView::setHeader(QDeclarativeComponent *header)
2097 Q_D(QDeclarativeGridView);
2098 if (d->headerComponent != header) {
2101 scene()->removeItem(d->header->item);
2102 d->header->item->deleteLater();
2106 d->headerComponent = header;
2107 if (isComponentComplete()) {
2113 emit headerChanged();
2117 void QDeclarativeGridView::setContentX(qreal pos)
2119 Q_D(QDeclarativeGridView);
2120 // Positioning the view manually should override any current movement state
2121 d->moveReason = QDeclarativeGridViewPrivate::Other;
2122 QDeclarativeFlickable::setContentX(pos);
2125 void QDeclarativeGridView::setContentY(qreal pos)
2127 Q_D(QDeclarativeGridView);
2128 // Positioning the view manually should override any current movement state
2129 d->moveReason = QDeclarativeGridViewPrivate::Other;
2130 QDeclarativeFlickable::setContentY(pos);
2133 bool QDeclarativeGridView::event(QEvent *event)
2135 Q_D(QDeclarativeGridView);
2136 if (event->type() == QEvent::User) {
2137 if (d->layoutScheduled)
2142 return QDeclarativeFlickable::event(event);
2145 void QDeclarativeGridView::viewportMoved()
2147 Q_D(QDeclarativeGridView);
2148 QDeclarativeFlickable::viewportMoved();
2151 d->lazyRelease = true;
2152 if (d->hData.flicking || d->vData.flicking) {
2154 if (d->vData.velocity > 0)
2155 d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore;
2156 else if (d->vData.velocity < 0)
2157 d->bufferMode = QDeclarativeGridViewPrivate::BufferAfter;
2161 if (d->hData.velocity > 0)
2162 d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore;
2163 else if (d->hData.velocity < 0)
2164 d->bufferMode = QDeclarativeGridViewPrivate::BufferAfter;
2168 if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2169 d->moveReason = QDeclarativeGridViewPrivate::Mouse;
2170 if (d->moveReason != QDeclarativeGridViewPrivate::SetIndex) {
2171 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2172 // reposition highlight
2173 qreal pos = d->highlight->rowPos();
2175 qreal highlightStart;
2177 if (d->isRightToLeftTopToBottom()) {
2178 highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
2179 highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
2180 viewPos = -d->position()-d->size();
2182 highlightStart = d->highlightRangeStart;
2183 highlightEnd = d->highlightRangeEnd;
2184 viewPos = d->position();
2186 if (pos > viewPos + highlightEnd - d->rowSize())
2187 pos = viewPos + highlightEnd - d->rowSize();
2188 if (pos < viewPos + highlightStart)
2189 pos = viewPos + highlightStart;
2191 d->highlight->setPosition(d->highlight->colPos(), qRound(pos));
2193 // update current index
2194 int idx = d->snapIndex();
2195 if (idx >= 0 && idx != d->currentIndex) {
2196 d->updateCurrent(idx);
2197 if (d->currentItem && d->currentItem->colPos() != d->highlight->colPos() && d->autoHighlight) {
2198 if (d->flow == LeftToRight)
2199 d->highlightXAnimator->to = d->currentItem->item->x();
2201 d->highlightYAnimator->to = d->currentItem->item->y();
2208 qreal QDeclarativeGridView::minYExtent() const
2210 Q_D(const QDeclarativeGridView);
2211 if (d->flow == QDeclarativeGridView::TopToBottom)
2212 return QDeclarativeFlickable::minYExtent();
2213 qreal extent = -d->startPosition();
2214 if (d->header && d->visibleItems.count())
2215 extent += d->header->item->height();
2216 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2217 extent += d->highlightRangeStart;
2218 extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd));
2223 qreal QDeclarativeGridView::maxYExtent() const
2225 Q_D(const QDeclarativeGridView);
2226 if (d->flow == QDeclarativeGridView::TopToBottom)
2227 return QDeclarativeFlickable::maxYExtent();
2229 if (!d->model || !d->model->count()) {
2231 } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2232 extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart);
2233 if (d->highlightRangeEnd != d->highlightRangeStart)
2234 extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1));
2236 extent = -(d->endPosition() - height());
2239 extent -= d->footer->item->height();
2240 const qreal minY = minYExtent();
2246 qreal QDeclarativeGridView::minXExtent() const
2248 Q_D(const QDeclarativeGridView);
2249 if (d->flow == QDeclarativeGridView::LeftToRight)
2250 return QDeclarativeFlickable::minXExtent();
2251 qreal extent = -d->startPosition();
2252 qreal highlightStart;
2254 qreal endPositionFirstItem = 0;
2255 if (d->isRightToLeftTopToBottom()) {
2256 if (d->model && d->model->count())
2257 endPositionFirstItem = d->rowPosAt(d->model->count()-1);
2258 highlightStart = d->highlightRangeStartValid
2259 ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
2260 : d->size() - (d->lastPosition()-endPositionFirstItem);
2261 highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
2262 if (d->footer && d->visibleItems.count())
2263 extent += d->footer->item->width();
2265 endPositionFirstItem = d->rowPosAt(0)+d->rowSize();
2266 highlightStart = d->highlightRangeStart;
2267 highlightEnd = d->highlightRangeEnd;
2268 if (d->header && d->visibleItems.count())
2269 extent += d->header->item->width();
2271 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2272 extent += d->isRightToLeftTopToBottom() ? -highlightStart : highlightStart;
2273 extent = qMax(extent, -(endPositionFirstItem - highlightEnd));
2278 qreal QDeclarativeGridView::maxXExtent() const
2280 Q_D(const QDeclarativeGridView);
2281 if (d->flow == QDeclarativeGridView::LeftToRight)
2282 return QDeclarativeFlickable::maxXExtent();
2284 qreal highlightStart;
2286 qreal lastItemPosition = 0;
2287 if (d->isRightToLeftTopToBottom()){
2288 highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
2289 highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
2290 lastItemPosition = d->endPosition();
2292 highlightStart = d->highlightRangeStart;
2293 highlightEnd = d->highlightRangeEnd;
2294 lastItemPosition = 0;
2295 if (d->model && d->model->count())
2296 lastItemPosition = d->rowPosAt(d->model->count()-1);
2298 if (!d->model || !d->model->count()) {
2300 } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2301 extent = -(lastItemPosition - highlightStart);
2302 if (highlightEnd != highlightStart)
2303 extent = d->isRightToLeftTopToBottom()
2304 ? qMax(extent, -(d->endPosition() - highlightEnd + 1))
2305 : qMin(extent, -(d->endPosition() - highlightEnd + 1));
2307 extent = -(d->endPosition() - width());
2309 if (d->isRightToLeftTopToBottom()) {
2311 extent -= d->header->item->width();
2314 extent -= d->footer->item->width();
2317 const qreal minX = minXExtent();
2323 void QDeclarativeGridView::keyPressEvent(QKeyEvent *event)
2325 Q_D(QDeclarativeGridView);
2326 keyPressPreHandler(event);
2327 if (event->isAccepted())
2329 if (d->model && d->model->count() && d->interactive) {
2330 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
2331 int oldCurrent = currentIndex();
2332 switch (event->key()) {
2334 moveCurrentIndexUp();
2337 moveCurrentIndexDown();
2340 moveCurrentIndexLeft();
2343 moveCurrentIndexRight();
2348 if (oldCurrent != currentIndex()) {
2353 d->moveReason = QDeclarativeGridViewPrivate::Other;
2355 QDeclarativeFlickable::keyPressEvent(event);
2359 \qmlmethod GridView::moveCurrentIndexUp()
2361 Move the currentIndex up one item in the view.
2362 The current index will wrap if keyNavigationWraps is true and it
2363 is currently at the end. This method has no effect if the \l count is zero.
2365 \bold Note: methods should only be called after the Component has completed.
2367 void QDeclarativeGridView::moveCurrentIndexUp()
2369 Q_D(QDeclarativeGridView);
2370 const int count = d->model ? d->model->count() : 0;
2373 if (d->flow == QDeclarativeGridView::LeftToRight) {
2374 if (currentIndex() >= d->columns || d->wrap) {
2375 int index = currentIndex() - d->columns;
2376 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2379 if (currentIndex() > 0 || d->wrap) {
2380 int index = currentIndex() - 1;
2381 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2387 \qmlmethod GridView::moveCurrentIndexDown()
2389 Move the currentIndex down one item in the view.
2390 The current index will wrap if keyNavigationWraps is true and it
2391 is currently at the end. This method has no effect if the \l count is zero.
2393 \bold Note: methods should only be called after the Component has completed.
2395 void QDeclarativeGridView::moveCurrentIndexDown()
2397 Q_D(QDeclarativeGridView);
2398 const int count = d->model ? d->model->count() : 0;
2401 if (d->flow == QDeclarativeGridView::LeftToRight) {
2402 if (currentIndex() < count - d->columns || d->wrap) {
2403 int index = currentIndex()+d->columns;
2404 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2407 if (currentIndex() < count - 1 || d->wrap) {
2408 int index = currentIndex() + 1;
2409 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2415 \qmlmethod GridView::moveCurrentIndexLeft()
2417 Move the currentIndex left one item in the view.
2418 The current index will wrap if keyNavigationWraps is true and it
2419 is currently at the end. This method has no effect if the \l count is zero.
2421 \bold Note: methods should only be called after the Component has completed.
2423 void QDeclarativeGridView::moveCurrentIndexLeft()
2425 Q_D(QDeclarativeGridView);
2426 const int count = d->model ? d->model->count() : 0;
2430 if (effectiveLayoutDirection() == Qt::LeftToRight) {
2431 if (d->flow == QDeclarativeGridView::LeftToRight) {
2432 if (currentIndex() > 0 || d->wrap) {
2433 int index = currentIndex() - 1;
2434 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2437 if (currentIndex() >= d->columns || d->wrap) {
2438 int index = currentIndex() - d->columns;
2439 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2443 if (d->flow == QDeclarativeGridView::LeftToRight) {
2444 if (currentIndex() < count - 1 || d->wrap) {
2445 int index = currentIndex() + 1;
2446 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2449 if (currentIndex() < count - d->columns || d->wrap) {
2450 int index = currentIndex() + d->columns;
2451 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2458 \qmlmethod GridView::moveCurrentIndexRight()
2460 Move the currentIndex right one item in the view.
2461 The current index will wrap if keyNavigationWraps is true and it
2462 is currently at the end. This method has no effect if the \l count is zero.
2464 \bold Note: methods should only be called after the Component has completed.
2466 void QDeclarativeGridView::moveCurrentIndexRight()
2468 Q_D(QDeclarativeGridView);
2469 const int count = d->model ? d->model->count() : 0;
2473 if (effectiveLayoutDirection() == Qt::LeftToRight) {
2474 if (d->flow == QDeclarativeGridView::LeftToRight) {
2475 if (currentIndex() < count - 1 || d->wrap) {
2476 int index = currentIndex() + 1;
2477 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2480 if (currentIndex() < count - d->columns || d->wrap) {
2481 int index = currentIndex()+d->columns;
2482 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2486 if (d->flow == QDeclarativeGridView::LeftToRight) {
2487 if (currentIndex() > 0 || d->wrap) {
2488 int index = currentIndex() - 1;
2489 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2492 if (currentIndex() >= d->columns || d->wrap) {
2493 int index = currentIndex() - d->columns;
2494 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2500 void QDeclarativeGridViewPrivate::positionViewAtIndex(int index, int mode)
2502 Q_Q(QDeclarativeGridView);
2505 if (mode < QDeclarativeGridView::Beginning || mode > QDeclarativeGridView::Contain)
2508 int idx = qMax(qMin(index, model->count()-1), 0);
2510 if (layoutScheduled)
2512 qreal pos = isRightToLeftTopToBottom() ? -position() - size() : position();
2513 FxGridItem *item = visibleItem(idx);
2515 if (flow == QDeclarativeGridView::LeftToRight)
2516 maxExtent = -q->maxYExtent();
2518 maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2521 int itemPos = rowPosAt(idx);
2522 // save the currently visible items in case any of them end up visible again
2523 QList<FxGridItem*> oldVisible = visibleItems;
2524 visibleItems.clear();
2525 visibleIndex = idx - idx % columns;
2526 if (flow == QDeclarativeGridView::LeftToRight)
2527 maxExtent = -q->maxYExtent();
2529 maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2530 setPosition(qMin(qreal(itemPos), maxExtent));
2531 // now release the reference to all the old visible items.
2532 for (int i = 0; i < oldVisible.count(); ++i)
2533 releaseItem(oldVisible.at(i));
2534 item = visibleItem(idx);
2537 qreal itemPos = item->rowPos();
2539 case QDeclarativeGridView::Beginning:
2541 if (index < 0 && header) {
2542 pos -= flow == QDeclarativeGridView::LeftToRight
2543 ? header->item->height()
2544 : header->item->width();
2547 case QDeclarativeGridView::Center:
2548 pos = itemPos - (size() - rowSize())/2;
2550 case QDeclarativeGridView::End:
2551 pos = itemPos - size() + rowSize();
2552 if (index >= model->count() && footer) {
2553 pos += flow == QDeclarativeGridView::LeftToRight
2554 ? footer->item->height()
2555 : footer->item->width();
2558 case QDeclarativeGridView::Visible:
2559 if (itemPos > pos + size())
2560 pos = itemPos - size() + rowSize();
2561 else if (item->endRowPos() < pos)
2564 case QDeclarativeGridView::Contain:
2565 if (item->endRowPos() > pos + size())
2566 pos = itemPos - size() + rowSize();
2571 pos = qMin(pos, maxExtent);
2573 if (flow == QDeclarativeGridView::LeftToRight)
2574 minExtent = -q->minYExtent();
2576 minExtent = isRightToLeftTopToBottom() ? q->maxXExtent()-size() : -q->minXExtent();
2577 pos = qMax(pos, minExtent);
2578 moveReason = QDeclarativeGridViewPrivate::Other;
2586 \qmlmethod GridView::positionViewAtIndex(int index, PositionMode mode)
2588 Positions the view such that the \a index is at the position specified by
2592 \o GridView.Beginning - position item at the top (or left for \c GridView.TopToBottom flow) of the view.
2593 \o GridView.Center - position item in the center of the view.
2594 \o GridView.End - position item at bottom (or right for horizontal orientation) of the view.
2595 \o GridView.Visible - if any part of the item is visible then take no action, otherwise
2596 bring the item into view.
2597 \o GridView.Contain - ensure the entire item is visible. If the item is larger than
2598 the view the item is positioned at the top (or left for \c GridView.TopToBottom flow) of the view.
2601 If positioning the view at the index would cause empty space to be displayed at
2602 the beginning or end of the view, the view will be positioned at the boundary.
2604 It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2605 at a particular index. This is unreliable since removing items from the start
2606 of the view does not cause all other items to be repositioned.
2607 The correct way to bring an item into view is with \c positionViewAtIndex.
2609 \bold Note: methods should only be called after the Component has completed. To position
2610 the view at startup, this method should be called by Component.onCompleted. For
2611 example, to position the view at the end:
2614 Component.onCompleted: positionViewAtIndex(count - 1, GridView.Beginning)
2617 void QDeclarativeGridView::positionViewAtIndex(int index, int mode)
2619 Q_D(QDeclarativeGridView);
2620 if (!d->isValid() || index < 0 || index >= d->model->count())
2622 d->positionViewAtIndex(index, mode);
2626 \qmlmethod GridView::positionViewAtBeginning()
2627 \qmlmethod GridView::positionViewAtEnd()
2630 Positions the view at the beginning or end, taking into account any header or footer.
2632 It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2633 at a particular index. This is unreliable since removing items from the start
2634 of the list does not cause all other items to be repositioned, and because
2635 the actual start of the view can vary based on the size of the delegates.
2637 \bold Note: methods should only be called after the Component has completed. To position
2638 the view at startup, this method should be called by Component.onCompleted. For
2639 example, to position the view at the end on startup:
2642 Component.onCompleted: positionViewAtEnd()
2645 void QDeclarativeGridView::positionViewAtBeginning()
2647 Q_D(QDeclarativeGridView);
2650 d->positionViewAtIndex(-1, Beginning);
2653 void QDeclarativeGridView::positionViewAtEnd()
2655 Q_D(QDeclarativeGridView);
2658 d->positionViewAtIndex(d->model->count(), End);
2662 \qmlmethod int GridView::indexAt(int x, int y)
2664 Returns the index of the visible item containing the point \a x, \a y in content
2665 coordinates. If there is no item at the point specified, or the item is
2666 not visible -1 is returned.
2668 If the item is outside the visible area, -1 is returned, regardless of
2669 whether an item will exist at that point when scrolled into view.
2671 \bold Note: methods should only be called after the Component has completed.
2673 int QDeclarativeGridView::indexAt(qreal x, qreal y) const
2675 Q_D(const QDeclarativeGridView);
2676 for (int i = 0; i < d->visibleItems.count(); ++i) {
2677 const FxGridItem *listItem = d->visibleItems.at(i);
2678 if(listItem->contains(x, y))
2679 return listItem->index;
2685 void QDeclarativeGridView::componentComplete()
2687 Q_D(QDeclarativeGridView);
2688 QDeclarativeFlickable::componentComplete();
2694 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
2695 if (d->currentIndex < 0 && !d->currentIndexCleared)
2696 d->updateCurrent(0);
2698 d->updateCurrent(d->currentIndex);
2699 if (d->highlight && d->currentItem) {
2700 if (d->autoHighlight)
2701 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
2702 d->updateTrackedItem();
2704 d->moveReason = QDeclarativeGridViewPrivate::Other;
2709 void QDeclarativeGridView::trackedPositionChanged()
2711 Q_D(QDeclarativeGridView);
2712 if (!d->trackedItem || !d->currentItem)
2714 if (d->moveReason == QDeclarativeGridViewPrivate::SetIndex) {
2715 const qreal trackedPos = d->trackedItem->rowPos();
2717 qreal highlightStart;
2719 if (d->isRightToLeftTopToBottom()) {
2720 viewPos = -d->position()-d->size();
2721 highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
2722 highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
2724 viewPos = d->position();
2725 highlightStart = d->highlightRangeStart;
2726 highlightEnd = d->highlightRangeEnd;
2728 qreal pos = viewPos;
2729 if (d->haveHighlightRange) {
2730 if (d->highlightRange == StrictlyEnforceRange) {
2731 if (trackedPos > pos + highlightEnd - d->rowSize())
2732 pos = trackedPos - highlightEnd + d->rowSize();
2733 if (trackedPos < pos + highlightStart)
2734 pos = trackedPos - highlightStart;
2736 if (trackedPos < d->startPosition() + highlightStart) {
2737 pos = d->startPosition();
2738 } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + highlightEnd) {
2739 pos = d->endPosition() - d->size() + 1;
2740 if (pos < d->startPosition())
2741 pos = d->startPosition();
2743 if (trackedPos < viewPos + highlightStart) {
2744 pos = trackedPos - highlightStart;
2745 } else if (trackedPos > viewPos + highlightEnd - d->rowSize()) {
2746 pos = trackedPos - highlightEnd + d->rowSize();
2751 if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) {
2752 pos = qMax(trackedPos, d->currentItem->rowPos());
2753 } else if (d->trackedItem->endRowPos() >= viewPos + d->size()
2754 && d->currentItem->endRowPos() >= viewPos + d->size()) {
2755 if (d->trackedItem->endRowPos() <= d->currentItem->endRowPos()) {
2756 pos = d->trackedItem->endRowPos() - d->size() + 1;
2757 if (d->rowSize() > d->size())
2760 pos = d->currentItem->endRowPos() - d->size() + 1;
2761 if (d->rowSize() > d->size())
2762 pos = d->currentItem->rowPos();
2766 if (viewPos != pos) {
2768 d->calcVelocity = true;
2769 d->setPosition(pos);
2770 d->calcVelocity = false;
2775 void QDeclarativeGridView::itemsInserted(int modelIndex, int count)
2777 Q_D(QDeclarativeGridView);
2778 if (!isComponentComplete())
2781 int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
2783 int i = d->visibleItems.count() - 1;
2784 while (i > 0 && d->visibleItems.at(i)->index == -1)
2786 if (d->visibleItems.at(i)->index + 1 == modelIndex) {
2787 // Special case of appending an item to the model.
2788 index = d->visibleIndex + d->visibleItems.count();
2790 if (modelIndex <= d->visibleIndex) {
2791 // Insert before visible items
2792 d->visibleIndex += count;
2793 for (int i = 0; i < d->visibleItems.count(); ++i) {
2794 FxGridItem *listItem = d->visibleItems.at(i);
2795 if (listItem->index != -1 && listItem->index >= modelIndex)
2796 listItem->index += count;
2799 if (d->currentIndex >= modelIndex) {
2800 // adjust current item index
2801 d->currentIndex += count;
2803 d->currentItem->index = d->currentIndex;
2804 emit currentIndexChanged();
2806 d->scheduleLayout();
2807 d->itemCount += count;
2808 emit countChanged();
2813 int insertCount = count;
2814 if (index < d->visibleIndex && d->visibleItems.count()) {
2815 insertCount -= d->visibleIndex - index;
2816 index = d->visibleIndex;
2817 modelIndex = d->visibleIndex;
2820 qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+d->width()+1 : d->position();
2821 int to = d->buffer+tempPos+d->size()-1;
2824 if (d->visibleItems.count()) {
2825 index -= d->visibleIndex;
2826 if (index < d->visibleItems.count()) {
2827 colPos = d->visibleItems.at(index)->colPos();
2828 rowPos = d->visibleItems.at(index)->rowPos();
2830 // appending items to visible list
2831 colPos = d->visibleItems.at(index-1)->colPos() + d->colSize();
2832 rowPos = d->visibleItems.at(index-1)->rowPos();
2833 if (colPos > d->colSize() * (d->columns-1)) {
2835 rowPos += d->rowSize();
2838 } else if (d->itemCount == 0 && d->header) {
2839 rowPos = d->headerSize();
2842 // Update the indexes of the following visible items.
2843 for (int i = 0; i < d->visibleItems.count(); ++i) {
2844 FxGridItem *listItem = d->visibleItems.at(i);
2845 if (listItem->index != -1 && listItem->index >= modelIndex)
2846 listItem->index += count;
2849 bool addedVisible = false;
2850 QList<FxGridItem*> added;
2852 while (i < insertCount && rowPos <= to + d->rowSize()*(d->columns - (colPos/d->colSize()))/qreal(d->columns)) {
2853 if (!addedVisible) {
2854 d->scheduleLayout();
2855 addedVisible = true;
2857 FxGridItem *item = d->createItem(modelIndex + i);
2859 // broken or no delegate
2863 d->visibleItems.insert(index, item);
2864 item->setPosition(colPos, rowPos);
2866 colPos += d->colSize();
2867 if (colPos > d->colSize() * (d->columns-1)) {
2869 rowPos += d->rowSize();
2874 if (i < insertCount) {
2875 // We didn't insert all our new items, which means anything
2876 // beyond the current index is not visible - remove it.
2877 while (d->visibleItems.count() > index) {
2878 d->releaseItem(d->visibleItems.takeLast());
2882 // update visibleIndex
2883 d->visibleIndex = 0;
2884 for (QList<FxGridItem*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2885 if ((*it)->index != -1) {
2886 d->visibleIndex = (*it)->index;
2891 if (d->itemCount && d->currentIndex >= modelIndex) {
2892 // adjust current item index
2893 d->currentIndex += count;
2894 if (d->currentItem) {
2895 d->currentItem->index = d->currentIndex;
2896 d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
2898 emit currentIndexChanged();
2899 } else if (d->itemCount == 0 && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
2903 // everything is in order now - emit add() signal
2904 for (int j = 0; j < added.count(); ++j)
2905 added.at(j)->attached->emitAdd();
2907 d->itemCount += count;
2908 emit countChanged();
2911 void QDeclarativeGridView::itemsRemoved(int modelIndex, int count)
2913 Q_D(QDeclarativeGridView);
2914 if (!isComponentComplete())
2917 d->itemCount -= count;
2918 bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count;
2919 bool removedVisible = false;
2920 // Remove the items from the visible list, skipping anything already marked for removal
2921 QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
2922 while (it != d->visibleItems.end()) {
2923 FxGridItem *item = *it;
2924 if (item->index == -1 || item->index < modelIndex) {
2925 // already removed, or before removed items
2926 if (item->index < modelIndex && !removedVisible) {
2927 d->scheduleLayout();
2928 removedVisible = true;
2931 } else if (item->index >= modelIndex + count) {
2932 // after removed items
2933 item->index -= count;
2937 if (!removedVisible) {
2938 d->scheduleLayout();
2939 removedVisible = true;
2941 item->attached->emitRemove();
2942 if (item->attached->delayRemove()) {
2944 connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
2947 it = d->visibleItems.erase(it);
2948 d->releaseItem(item);
2953 // If we removed items before visible items a layout may be
2954 // required to ensure item 0 is in the first column.
2955 if (!removedVisible && modelIndex < d->visibleIndex)
2956 d->scheduleLayout();
2959 if (d->currentIndex >= modelIndex + count) {
2960 d->currentIndex -= count;
2962 d->currentItem->index -= count;
2963 emit currentIndexChanged();
2964 } else if (currentRemoved) {
2965 // current item has been removed.
2966 d->releaseItem(d->currentItem);
2968 d->currentIndex = -1;
2970 d->updateCurrent(qMin(modelIndex, d->itemCount-1));
2972 emit currentIndexChanged();
2975 // update visibleIndex
2976 d->visibleIndex = 0;
2977 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2978 if ((*it)->index != -1) {
2979 d->visibleIndex = (*it)->index;
2984 if (removedVisible && d->visibleItems.isEmpty()) {
2985 d->timeline.clear();
2986 if (d->itemCount == 0) {
2994 emit countChanged();
2997 void QDeclarativeGridView::destroyRemoved()
2999 Q_D(QDeclarativeGridView);
3000 for (QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
3001 it != d->visibleItems.end();) {
3002 FxGridItem *listItem = *it;
3003 if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
3004 d->releaseItem(listItem);
3005 it = d->visibleItems.erase(it);
3011 // Correct the positioning of the items
3015 void QDeclarativeGridView::itemsMoved(int from, int to, int count)
3017 Q_D(QDeclarativeGridView);
3018 if (!isComponentComplete())
3020 QHash<int,FxGridItem*> moved;
3022 FxGridItem *firstItem = d->firstVisibleItem();
3024 QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
3025 while (it != d->visibleItems.end()) {
3026 FxGridItem *item = *it;
3027 if (item->index >= from && item->index < from + count) {
3028 // take the items that are moving
3029 item->index += (to-from);
3030 moved.insert(item->index, item);
3031 it = d->visibleItems.erase(it);
3033 if (item->index > from && item->index != -1) {
3034 // move everything after the moved items.
3035 item->index -= count;
3036 if (item->index < d->visibleIndex)
3037 d->visibleIndex = item->index;
3043 int remaining = count;
3044 int endIndex = d->visibleIndex;
3045 it = d->visibleItems.begin();
3046 while (it != d->visibleItems.end()) {
3047 FxGridItem *item = *it;
3048 if (remaining && item->index >= to && item->index < to + count) {
3049 // place items in the target position, reusing any existing items
3050 FxGridItem *movedItem = moved.take(item->index);
3052 movedItem = d->createItem(item->index);
3054 // broken or no delegate
3058 it = d->visibleItems.insert(it, movedItem);
3059 if (it == d->visibleItems.begin() && firstItem)
3060 movedItem->setPosition(firstItem->colPos(), firstItem->rowPos());
3064 if (item->index != -1) {
3065 if (item->index >= to) {
3066 // update everything after the moved items.
3067 item->index += count;
3069 endIndex = item->index;
3075 // If we have moved items to the end of the visible items
3076 // then add any existing moved items that we have
3077 while (FxGridItem *item = moved.take(endIndex+1)) {
3078 d->visibleItems.append(item);
3082 // update visibleIndex
3083 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
3084 if ((*it)->index != -1) {
3085 d->visibleIndex = (*it)->index;
3090 // Fix current index
3091 if (d->currentIndex >= 0 && d->currentItem) {
3092 int oldCurrent = d->currentIndex;
3093 d->currentIndex = d->model->indexOf(d->currentItem->item, this);
3094 if (oldCurrent != d->currentIndex) {
3095 d->currentItem->index = d->currentIndex;
3096 emit currentIndexChanged();
3100 // Whatever moved items remain are no longer visible items.
3101 while (moved.count()) {
3102 int idx = moved.begin().key();
3103 FxGridItem *item = moved.take(idx);
3104 if (d->currentItem && item->item == d->currentItem->item)
3105 item->setPosition(d->colPosAt(idx), d->rowPosAt(idx));
3106 d->releaseItem(item);
3112 void QDeclarativeGridView::modelReset()
3114 Q_D(QDeclarativeGridView);
3117 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
3118 d->updateCurrent(d->currentIndex);
3119 if (d->highlight && d->currentItem) {
3120 if (d->autoHighlight)
3121 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
3122 d->updateTrackedItem();
3124 d->moveReason = QDeclarativeGridViewPrivate::Other;
3126 emit countChanged();
3129 void QDeclarativeGridView::createdItem(int index, QDeclarativeItem *item)
3131 Q_D(QDeclarativeGridView);
3132 if (d->requestedIndex != index) {
3133 item->setParentItem(this);
3134 d->unrequestedItems.insert(item, index);
3135 if (d->flow == QDeclarativeGridView::LeftToRight) {
3136 item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index)));
3138 item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index)));
3143 void QDeclarativeGridView::destroyingItem(QDeclarativeItem *item)
3145 Q_D(QDeclarativeGridView);
3146 d->unrequestedItems.remove(item);
3149 void QDeclarativeGridView::animStopped()
3151 Q_D(QDeclarativeGridView);
3152 d->bufferMode = QDeclarativeGridViewPrivate::NoBuffer;
3153 if (d->haveHighlightRange && d->highlightRange == QDeclarativeGridView::StrictlyEnforceRange)
3154 d->updateHighlight();
3157 void QDeclarativeGridView::refill()
3159 Q_D(QDeclarativeGridView);
3160 if (d->isRightToLeftTopToBottom())
3161 d->refill(-d->position()-d->size()+1, -d->position());
3163 d->refill(d->position(), d->position()+d->size()-1);
3167 QDeclarativeGridViewAttached *QDeclarativeGridView::qmlAttachedProperties(QObject *obj)
3169 return new QDeclarativeGridViewAttached(obj);