1 // Commit: cc6408ccd5453d1bed9f98b9caa14861cea5742b
2 /****************************************************************************
4 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
5 ** All rights reserved.
6 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 ** This file is part of the QtDeclarative module of the Qt Toolkit.
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** No Commercial Usage
12 ** This file contains pre-release code and may not be distributed.
13 ** You may use this file in accordance with the terms and conditions
14 ** contained in the Technology Preview License Agreement accompanying
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
41 ****************************************************************************/
43 #include "qsggridview_p.h"
44 #include "qsgvisualitemmodel_p.h"
45 #include "qsgflickable_p_p.h"
47 #include <private/qdeclarativesmoothedanimation_p_p.h>
48 #include <private/qlistmodelinterface_p.h>
50 #include <QtGui/qevent.h>
51 #include <QtCore/qmath.h>
52 #include <QtCore/qcoreapplication.h>
57 //----------------------------------------------------------------------------
62 FxGridItemSG(QSGItem *i, QSGGridView *v) : item(i), view(v) {
63 attached = static_cast<QSGGridViewAttached*>(qmlAttachedPropertiesObject<QSGGridView>(item));
65 attached->setView(view);
69 qreal rowPos() const {
71 if (view->flow() == QSGGridView::LeftToRight) {
74 if (view->effectiveLayoutDirection() == Qt::RightToLeft)
75 rowPos = -view->cellWidth()-item->x();
81 qreal colPos() const {
83 if (view->flow() == QSGGridView::LeftToRight) {
84 if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
85 int colSize = view->cellWidth();
86 int columns = view->width()/colSize;
87 colPos = colSize * (columns-1) - item->x();
97 qreal endRowPos() const {
98 if (view->flow() == QSGGridView::LeftToRight) {
99 return item->y() + view->cellHeight() - 1;
101 if (view->effectiveLayoutDirection() == Qt::RightToLeft)
102 return -item->x() - 1;
104 return item->x() + view->cellWidth() - 1;
107 void setPosition(qreal col, qreal row) {
108 if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
109 if (view->flow() == QSGGridView::LeftToRight) {
110 int columns = view->width()/view->cellWidth();
111 item->setPos(QPointF((view->cellWidth() * (columns-1) - col), row));
113 item->setPos(QPointF(-view->cellWidth()-row, col));
116 if (view->flow() == QSGGridView::LeftToRight)
117 item->setPos(QPointF(col, row));
119 item->setPos(QPointF(row, col));
122 bool contains(qreal x, qreal y) const {
123 return (x >= item->x() && x < item->x() + view->cellWidth() &&
124 y >= item->y() && y < item->y() + view->cellHeight());
129 QSGGridViewAttached *attached;
133 //----------------------------------------------------------------------------
135 class QSGGridViewPrivate : public QSGFlickablePrivate
137 Q_DECLARE_PUBLIC(QSGGridView)
141 : currentItem(0), layoutDirection(Qt::LeftToRight), flow(QSGGridView::LeftToRight)
142 , visibleIndex(0) , currentIndex(-1)
143 , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1), itemCount(0)
144 , highlightRangeStart(0), highlightRangeEnd(0)
145 , highlightRange(QSGGridView::NoHighlightRange)
146 , highlightComponent(0), highlight(0), trackedItem(0)
147 , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0)
148 , highlightMoveDuration(150)
149 , footerComponent(0), footer(0), headerComponent(0), header(0)
150 , bufferMode(BufferBefore | BufferAfter), snapMode(QSGGridView::NoSnap)
151 , ownModel(false), wrap(false), autoHighlight(true)
152 , fixCurrentVisibility(false), lazyRelease(false), layoutScheduled(false)
153 , deferredRelease(false), haveHighlightRange(false), currentIndexCleared(false)
154 , highlightRangeStartValid(false), highlightRangeEndValid(false) {}
158 FxGridItemSG *createItem(int modelIndex);
159 void releaseItem(FxGridItemSG *item);
160 void refill(qreal from, qreal to, bool doBuffer=false);
163 void scheduleLayout();
165 void updateUnrequestedIndexes();
166 void updateUnrequestedPositions();
167 void updateTrackedItem();
168 void createHighlight();
169 void updateHighlight();
170 void updateCurrent(int modelIndex);
173 void fixupPosition();
175 FxGridItemSG *visibleItem(int modelIndex) const {
176 if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
177 for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
178 FxGridItemSG *item = visibleItems.at(i);
179 if (item->index == modelIndex)
186 bool isRightToLeftTopToBottom() const {
187 Q_Q(const QSGGridView);
188 return flow == QSGGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft;
193 if (q->isComponentComplete()) {
198 updateCurrent(currentIndex);
202 void mirrorChange() {
205 emit q->effectiveLayoutDirectionChanged();
208 qreal position() const {
209 Q_Q(const QSGGridView);
210 return flow == QSGGridView::LeftToRight ? q->contentY() : q->contentX();
212 void setPosition(qreal pos) {
214 if (flow == QSGGridView::LeftToRight) {
215 q->QSGFlickable::setContentY(pos);
216 q->QSGFlickable::setContentX(0);
218 if (q->effectiveLayoutDirection() == Qt::LeftToRight)
219 q->QSGFlickable::setContentX(pos);
221 q->QSGFlickable::setContentX(-pos-size());
222 q->QSGFlickable::setContentY(0);
226 Q_Q(const QSGGridView);
227 return flow == QSGGridView::LeftToRight ? q->height() : q->width();
229 qreal originPosition() const {
231 if (!visibleItems.isEmpty())
232 pos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
236 qreal lastPosition() const {
238 if (model && model->count())
239 pos = rowPosAt(model->count() - 1) + rowSize();
243 qreal startPosition() const {
244 return isRightToLeftTopToBottom() ? -lastPosition()+1 : originPosition();
247 qreal endPosition() const {
248 return isRightToLeftTopToBottom() ? -originPosition()+1 : lastPosition();
252 bool isValid() const {
253 return model && model->count() && model->isValid();
256 int rowSize() const {
257 return flow == QSGGridView::LeftToRight ? cellHeight : cellWidth;
259 int colSize() const {
260 return flow == QSGGridView::LeftToRight ? cellWidth : cellHeight;
263 qreal colPosAt(int modelIndex) const {
264 if (FxGridItemSG *item = visibleItem(modelIndex))
265 return item->colPos();
266 if (!visibleItems.isEmpty()) {
267 if (modelIndex < visibleIndex) {
268 int count = (visibleIndex - modelIndex) % columns;
269 int col = visibleItems.first()->colPos() / colSize();
270 col = (columns - count + col) % columns;
271 return col * colSize();
273 int count = columns - 1 - (modelIndex - visibleItems.last()->index - 1) % columns;
274 return visibleItems.last()->colPos() - count * colSize();
277 return (modelIndex % columns) * colSize();
281 qreal rowPosAt(int modelIndex) const {
282 if (FxGridItemSG *item = visibleItem(modelIndex))
283 return item->rowPos();
284 if (!visibleItems.isEmpty()) {
285 if (modelIndex < visibleIndex) {
286 int firstCol = visibleItems.first()->colPos() / colSize();
287 int col = visibleIndex - modelIndex + (columns - firstCol - 1);
288 int rows = col / columns;
289 return visibleItems.first()->rowPos() - rows * rowSize();
291 int count = modelIndex - visibleItems.last()->index;
292 int col = visibleItems.last()->colPos() + count * colSize();
293 int rows = col / (columns * colSize());
294 return visibleItems.last()->rowPos() + rows * rowSize();
297 qreal pos = (modelIndex / columns) * rowSize();
305 FxGridItemSG *firstVisibleItem() const {
306 const qreal pos = isRightToLeftTopToBottom() ? -position()-size() : position();
307 for (int i = 0; i < visibleItems.count(); ++i) {
308 FxGridItemSG *item = visibleItems.at(i);
309 if (item->index != -1 && item->endRowPos() > pos)
312 return visibleItems.count() ? visibleItems.first() : 0;
315 int lastVisibleIndex() const {
316 for (int i = 0; i < visibleItems.count(); ++i) {
317 FxGridItemSG *item = visibleItems.at(i);
318 if (item->index != -1)
324 // Map a model index to visibleItems list index.
325 // These may differ if removed items are still present in the visible list,
326 // e.g. doing a removal animation
327 int mapFromModel(int modelIndex) const {
328 if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
330 for (int i = 0; i < visibleItems.count(); ++i) {
331 FxGridItemSG *listItem = visibleItems.at(i);
332 if (listItem->index == modelIndex)
333 return i + visibleIndex;
334 if (listItem->index > modelIndex)
337 return -1; // Not in visibleList
340 qreal snapPosAt(qreal pos) const {
341 Q_Q(const QSGGridView);
343 if (!visibleItems.isEmpty()) {
345 snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
346 snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
349 if (isRightToLeftTopToBottom()) {
350 maxExtent = q->minXExtent();
351 minExtent = q->maxXExtent();
353 maxExtent = flow == QSGGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
354 minExtent = flow == QSGGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
356 if (snapPos > maxExtent)
358 if (snapPos < minExtent)
364 FxGridItemSG *snapItemAt(qreal pos) {
365 for (int i = 0; i < visibleItems.count(); ++i) {
366 FxGridItemSG *item = visibleItems[i];
367 if (item->index == -1)
369 qreal itemTop = item->rowPos();
370 if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
377 int index = currentIndex;
378 for (int i = 0; i < visibleItems.count(); ++i) {
379 FxGridItemSG *item = visibleItems[i];
380 if (item->index == -1)
382 qreal itemTop = item->rowPos();
383 if (itemTop >= highlight->rowPos()-rowSize()/2 && itemTop < highlight->rowPos()+rowSize()/2) {
385 if (item->colPos() >= highlight->colPos()-colSize()/2 && item->colPos() < highlight->colPos()+colSize()/2)
392 qreal headerSize() const {
396 return flow == QSGGridView::LeftToRight
397 ? header->item->height()
398 : header->item->width();
402 virtual void itemGeometryChanged(QSGItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
403 Q_Q(const QSGGridView);
404 QSGFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
406 if (newGeometry.height() != oldGeometry.height()
407 || newGeometry.width() != oldGeometry.width()) {
408 if (q->isComponentComplete()) {
413 } else if ((header && header->item == item) || (footer && footer->item == item)) {
421 void positionViewAtIndex(int index, int mode);
422 virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
423 virtual void flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
424 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity);
426 // for debugging only
427 void checkVisible() const {
429 for (int i = 0; i < visibleItems.count(); ++i) {
430 FxGridItemSG *listItem = visibleItems.at(i);
431 if (listItem->index == -1) {
433 } else if (listItem->index != visibleIndex + i - skip) {
434 for (int j = 0; j < visibleItems.count(); j++)
435 qDebug() << " index" << j << "item index" << visibleItems.at(j)->index;
436 qFatal("index %d %d %d", visibleIndex, i, listItem->index);
441 QDeclarativeGuard<QSGVisualModel> model;
442 QVariant modelVariant;
443 QList<FxGridItemSG*> visibleItems;
444 QHash<QSGItem*,int> unrequestedItems;
445 FxGridItemSG *currentItem;
446 Qt::LayoutDirection layoutDirection;
447 QSGGridView::Flow flow;
455 qreal highlightRangeStart;
456 qreal highlightRangeEnd;
457 QSGGridView::HighlightRangeMode highlightRange;
458 QDeclarativeComponent *highlightComponent;
459 FxGridItemSG *highlight;
460 FxGridItemSG *trackedItem;
461 enum MovementReason { Other, SetIndex, Mouse };
462 MovementReason moveReason;
464 QSmoothedAnimation *highlightXAnimator;
465 QSmoothedAnimation *highlightYAnimator;
466 int highlightMoveDuration;
467 QDeclarativeComponent *footerComponent;
468 FxGridItemSG *footer;
469 QDeclarativeComponent *headerComponent;
470 FxGridItemSG *header;
471 enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
473 QSGGridView::SnapMode snapMode;
477 bool autoHighlight : 1;
478 bool fixCurrentVisibility : 1;
479 bool lazyRelease : 1;
480 bool layoutScheduled : 1;
481 bool deferredRelease : 1;
482 bool haveHighlightRange : 1;
483 bool currentIndexCleared : 1;
484 bool highlightRangeStartValid : 1;
485 bool highlightRangeEndValid : 1;
488 void QSGGridViewPrivate::init()
491 QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped()));
492 q->setFlag(QSGItem::ItemIsFocusScope);
493 q->setFlickableDirection(QSGFlickable::VerticalFlick);
494 addItemChangeListener(this, Geometry);
497 void QSGGridViewPrivate::clear()
499 for (int i = 0; i < visibleItems.count(); ++i)
500 releaseItem(visibleItems.at(i));
501 visibleItems.clear();
503 releaseItem(currentItem);
510 FxGridItemSG *QSGGridViewPrivate::createItem(int modelIndex)
514 requestedIndex = modelIndex;
515 FxGridItemSG *listItem = 0;
516 if (QSGItem *item = model->item(modelIndex, false)) {
517 listItem = new FxGridItemSG(item, q);
518 listItem->index = modelIndex;
519 if (model->completePending()) {
521 listItem->item->setZ(1);
522 listItem->item->setParentItem(q->contentItem());
523 model->completeItem();
525 listItem->item->setParentItem(q->contentItem());
527 unrequestedItems.remove(listItem->item);
534 void QSGGridViewPrivate::releaseItem(FxGridItemSG *item)
539 if (trackedItem == item) {
540 QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
541 QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
544 if (model->release(item->item) == 0) {
545 // item was not destroyed, and we no longer reference it.
546 unrequestedItems.insert(item->item, model->indexOf(item->item, q));
551 void QSGGridViewPrivate::refill(qreal from, qreal to, bool doBuffer)
554 if (!isValid() || !q->isComponentComplete())
556 itemCount = model->count();
557 qreal bufferFrom = from - buffer;
558 qreal bufferTo = to + buffer;
559 qreal fillFrom = from;
561 if (doBuffer && (bufferMode & BufferAfter))
563 if (doBuffer && (bufferMode & BufferBefore))
564 fillFrom = bufferFrom;
566 bool changed = false;
568 int colPos = colPosAt(visibleIndex);
569 int rowPos = rowPosAt(visibleIndex);
570 int modelIndex = visibleIndex;
571 if (visibleItems.count()) {
572 rowPos = visibleItems.last()->rowPos();
573 colPos = visibleItems.last()->colPos() + colSize();
574 if (colPos > colSize() * (columns-1)) {
578 int i = visibleItems.count() - 1;
579 while (i > 0 && visibleItems.at(i)->index == -1)
581 modelIndex = visibleItems.at(i)->index + 1;
583 int colNum = colPos / colSize();
585 FxGridItemSG *item = 0;
587 // Item creation and release is staggered in order to avoid
588 // creating/releasing multiple items in one frame
589 // while flicking (as much as possible).
590 while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
591 // qDebug() << "refill: append item" << modelIndex;
592 if (!(item = createItem(modelIndex)))
594 item->setPosition(colPos, rowPos);
595 visibleItems.append(item);
598 if (colPos > colSize() * (columns-1)) {
605 if (doBuffer) // never buffer more than one item per frame
609 if (visibleItems.count()) {
610 rowPos = visibleItems.first()->rowPos();
611 colPos = visibleItems.first()->colPos() - colSize();
613 colPos = colSize() * (columns - 1);
617 colNum = colPos / colSize();
618 while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
619 // qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
620 if (!(item = createItem(visibleIndex-1)))
623 item->setPosition(colPos, rowPos);
624 visibleItems.prepend(item);
628 colPos = colSize() * (columns - 1);
633 if (doBuffer) // never buffer more than one item per frame
637 if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
638 while (visibleItems.count() > 1
639 && (item = visibleItems.first())
640 && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
641 if (item->attached->delayRemove())
643 // qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
644 if (item->index != -1)
646 visibleItems.removeFirst();
650 while (visibleItems.count() > 1
651 && (item = visibleItems.last())
652 && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
653 if (item->attached->delayRemove())
655 // qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
656 visibleItems.removeLast();
660 deferredRelease = false;
662 deferredRelease = true;
669 if (flow == QSGGridView::LeftToRight)
670 q->setContentHeight(endPosition() - startPosition());
672 q->setContentWidth(endPosition() - startPosition());
673 } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
674 refill(from, to, true);
679 void QSGGridViewPrivate::updateGrid()
682 columns = (int)qMax((flow == QSGGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.));
684 if (flow == QSGGridView::LeftToRight)
685 q->setContentHeight(endPosition() - startPosition());
687 q->setContentWidth(lastPosition() - originPosition());
691 void QSGGridViewPrivate::scheduleLayout()
694 if (!layoutScheduled) {
695 layoutScheduled = true;
700 void QSGGridViewPrivate::layout()
703 layoutScheduled = false;
704 if (!isValid() && !visibleItems.count()) {
708 if (visibleItems.count()) {
709 qreal rowPos = visibleItems.first()->rowPos();
710 qreal colPos = visibleItems.first()->colPos();
711 int col = visibleIndex % columns;
712 if (colPos != col * colSize()) {
713 colPos = col * colSize();
714 visibleItems.first()->setPosition(colPos, rowPos);
716 for (int i = 1; i < visibleItems.count(); ++i) {
717 FxGridItemSG *item = visibleItems.at(i);
719 if (colPos > colSize() * (columns-1)) {
723 item->setPosition(colPos, rowPos);
733 if (flow == QSGGridView::LeftToRight) {
734 q->setContentHeight(endPosition() - startPosition());
737 q->setContentWidth(endPosition() - startPosition());
740 updateUnrequestedPositions();
743 void QSGGridViewPrivate::updateUnrequestedIndexes()
746 QHash<QSGItem*,int>::iterator it;
747 for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
748 *it = model->indexOf(it.key(), q);
751 void QSGGridViewPrivate::updateUnrequestedPositions()
753 QHash<QSGItem*,int>::const_iterator it;
754 for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
755 QSGItem *item = it.key();
756 if (flow == QSGGridView::LeftToRight) {
757 item->setPos(QPointF(colPosAt(*it), rowPosAt(*it)));
759 if (isRightToLeftTopToBottom())
760 item->setPos(QPointF(-rowPosAt(*it)-item->width(), colPosAt(*it)));
762 item->setPos(QPointF(rowPosAt(*it), colPosAt(*it)));
767 void QSGGridViewPrivate::updateTrackedItem()
770 FxGridItemSG *item = currentItem;
774 if (trackedItem && item != trackedItem) {
775 QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
776 QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
780 if (!trackedItem && item) {
782 QObject::connect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
783 QObject::connect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
786 q->trackedPositionChanged();
789 void QSGGridViewPrivate::createHighlight()
792 bool changed = false;
794 if (trackedItem == highlight)
796 delete highlight->item;
799 delete highlightXAnimator;
800 delete highlightYAnimator;
801 highlightXAnimator = 0;
802 highlightYAnimator = 0;
808 if (highlightComponent) {
809 QDeclarativeContext *highlightContext = new QDeclarativeContext(qmlContext(q));
810 QObject *nobj = highlightComponent->create(highlightContext);
812 QDeclarative_setParent_noEvent(highlightContext, nobj);
813 item = qobject_cast<QSGItem *>(nobj);
817 delete highlightContext;
821 QDeclarative_setParent_noEvent(item, q->contentItem());
822 item->setParentItem(q->contentItem());
825 QDeclarative_setParent_noEvent(item, q->contentItem());
826 item->setParentItem(q->contentItem());
827 highlight = new FxGridItemSG(item, q);
828 if (currentItem && autoHighlight)
829 highlight->setPosition(currentItem->colPos(), currentItem->rowPos());
830 highlightXAnimator = new QSmoothedAnimation(q);
831 highlightXAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("x"));
832 highlightXAnimator->userDuration = highlightMoveDuration;
833 highlightYAnimator = new QSmoothedAnimation(q);
834 highlightYAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("y"));
835 highlightYAnimator->userDuration = highlightMoveDuration;
837 highlightXAnimator->restart();
838 highlightYAnimator->restart();
844 emit q->highlightItemChanged();
847 void QSGGridViewPrivate::updateHighlight()
849 if ((!currentItem && highlight) || (currentItem && !highlight))
851 if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) {
852 // auto-update highlight
853 highlightXAnimator->to = currentItem->item->x();
854 highlightYAnimator->to = currentItem->item->y();
855 highlight->item->setWidth(currentItem->item->width());
856 highlight->item->setHeight(currentItem->item->height());
857 highlightXAnimator->restart();
858 highlightYAnimator->restart();
863 void QSGGridViewPrivate::updateCurrent(int modelIndex)
866 if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
868 currentItem->attached->setIsCurrentItem(false);
869 releaseItem(currentItem);
871 currentIndex = modelIndex;
872 emit q->currentIndexChanged();
874 } else if (currentIndex != modelIndex) {
875 currentIndex = modelIndex;
876 emit q->currentIndexChanged();
881 if (currentItem && currentIndex == modelIndex) {
886 FxGridItemSG *oldCurrentItem = currentItem;
887 currentIndex = modelIndex;
888 currentItem = createItem(modelIndex);
889 fixCurrentVisibility = true;
890 if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
891 oldCurrentItem->attached->setIsCurrentItem(false);
893 currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex));
894 currentItem->item->setFocus(true);
895 currentItem->attached->setIsCurrentItem(true);
898 emit q->currentIndexChanged();
899 releaseItem(oldCurrentItem);
902 void QSGGridViewPrivate::updateFooter()
905 if (!footer && footerComponent) {
907 QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
908 QObject *nobj = footerComponent->create(context);
910 QDeclarative_setParent_noEvent(context, nobj);
911 item = qobject_cast<QSGItem *>(nobj);
918 QDeclarative_setParent_noEvent(item, q->contentItem());
919 item->setParentItem(q->contentItem());
921 QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
922 itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
923 footer = new FxGridItemSG(item, q);
929 if (isRightToLeftTopToBottom()) {
930 rowOffset = footer->item->width()-cellWidth;
933 if (q->effectiveLayoutDirection() == Qt::RightToLeft)
934 colOffset = footer->item->width()-cellWidth;
936 if (visibleItems.count()) {
937 qreal endPos = lastPosition();
938 if (lastVisibleIndex() == model->count()-1) {
939 footer->setPosition(colOffset, endPos + rowOffset);
941 qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size();
942 if (endPos <= visiblePos || footer->endRowPos() < endPos + rowOffset)
943 footer->setPosition(colOffset, endPos + rowOffset);
948 endPos += (flow == QSGGridView::LeftToRight) ? header->item->height() : header->item->width();
950 footer->setPosition(colOffset, endPos);
955 void QSGGridViewPrivate::updateHeader()
958 if (!header && headerComponent) {
960 QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
961 QObject *nobj = headerComponent->create(context);
963 QDeclarative_setParent_noEvent(context, nobj);
964 item = qobject_cast<QSGItem *>(nobj);
971 QDeclarative_setParent_noEvent(item, q->contentItem());
972 item->setParentItem(q->contentItem());
974 QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
975 itemPrivate->addItemChangeListener(this, QSGItemPrivate::Geometry);
976 header = new FxGridItemSG(item, q);
982 if (isRightToLeftTopToBottom()) {
983 rowOffset = -cellWidth;
985 rowOffset = -headerSize();
986 if (q->effectiveLayoutDirection() == Qt::RightToLeft)
987 colOffset = header->item->width()-cellWidth;
989 if (visibleItems.count()) {
990 qreal startPos = originPosition();
991 if (visibleIndex == 0) {
992 header->setPosition(colOffset, startPos + rowOffset);
994 qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position();
995 qreal headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
996 if (tempPos <= startPos || headerPos > startPos + rowOffset)
997 header->setPosition(colOffset, startPos + rowOffset);
1000 header->setPosition(colOffset, 0);
1005 void QSGGridViewPrivate::fixupPosition()
1008 if (flow == QSGGridView::LeftToRight)
1014 void QSGGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
1016 if ((flow == QSGGridView::TopToBottom && &data == &vData)
1017 || (flow == QSGGridView::LeftToRight && &data == &hData))
1020 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1022 qreal highlightStart;
1025 if (isRightToLeftTopToBottom()) {
1026 // Handle Right-To-Left exceptions
1027 viewPos = -position()-size();
1028 highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
1029 highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd;
1031 viewPos = position();
1032 highlightStart = highlightRangeStart;
1033 highlightEnd = highlightRangeEnd;
1036 if (snapMode != QSGGridView::NoSnap) {
1037 qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
1038 FxGridItemSG *topItem = snapItemAt(tempPosition+highlightStart);
1039 FxGridItemSG *bottomItem = snapItemAt(tempPosition+highlightEnd);
1041 if (topItem && bottomItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
1042 qreal topPos = qMin(topItem->rowPos() - highlightStart, -maxExtent);
1043 qreal bottomPos = qMax(bottomItem->rowPos() - highlightEnd, -minExtent);
1044 pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos;
1045 } else if (topItem) {
1046 qreal headerPos = 0;
1048 headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
1049 if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2) {
1050 pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart;
1052 if (isRightToLeftTopToBottom())
1053 pos = qMax(qMin(-topItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
1055 pos = qMax(qMin(topItem->rowPos() - highlightStart, -maxExtent), -minExtent);
1057 } else if (bottomItem) {
1058 if (isRightToLeftTopToBottom())
1059 pos = qMax(qMin(-bottomItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
1061 pos = qMax(qMin(bottomItem->rowPos() - highlightStart, -maxExtent), -minExtent);
1063 QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
1066 if (currentItem && haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
1068 qreal currPos = currentItem->rowPos();
1069 if (isRightToLeftTopToBottom())
1070 pos = -pos-size(); // Transform Pos if required
1071 if (pos < currPos + rowSize() - highlightEnd)
1072 pos = currPos + rowSize() - highlightEnd;
1073 if (pos > currPos - highlightStart)
1074 pos = currPos - highlightStart;
1075 if (isRightToLeftTopToBottom())
1076 pos = -pos-size(); // Untransform
1079 qreal dist = qAbs(data.move + pos);
1081 timeline.reset(data.move);
1082 if (fixupMode != Immediate) {
1083 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1084 data.fixingUp = true;
1086 timeline.set(data.move, -pos);
1088 vTime = timeline.time();
1090 } else if (haveHighlightRange && highlightRange == QSGGridView::StrictlyEnforceRange) {
1093 qreal pos = currentItem->rowPos();
1094 if (viewPos < pos + rowSize() - highlightEnd)
1095 viewPos = pos + rowSize() - highlightEnd;
1096 if (viewPos > pos - highlightStart)
1097 viewPos = pos - highlightStart;
1098 if (isRightToLeftTopToBottom())
1099 viewPos = -viewPos-size();
1100 timeline.reset(data.move);
1101 if (viewPos != position()) {
1102 if (fixupMode != Immediate) {
1103 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1104 data.fixingUp = true;
1106 timeline.set(data.move, -viewPos);
1109 vTime = timeline.time();
1112 QSGFlickablePrivate::fixup(data, minExtent, maxExtent);
1117 void QSGGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1118 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
1121 data.fixingUp = false;
1123 if ((!haveHighlightRange || highlightRange != QSGGridView::StrictlyEnforceRange)
1124 && snapMode == QSGGridView::NoSnap) {
1125 QSGFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1128 qreal maxDistance = 0;
1129 qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value();
1130 // -ve velocity means list is moving up/left
1132 if (data.move.value() < minExtent) {
1133 if (snapMode == QSGGridView::SnapOneRow) {
1134 if (FxGridItemSG *item = firstVisibleItem())
1135 maxDistance = qAbs(item->rowPos() + dataValue);
1137 maxDistance = qAbs(minExtent - data.move.value());
1140 if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
1141 data.flickTarget = minExtent;
1143 if (data.move.value() > maxExtent) {
1144 if (snapMode == QSGGridView::SnapOneRow) {
1145 qreal pos = snapPosAt(-dataValue) + (isRightToLeftTopToBottom() ? 0 : rowSize());
1146 maxDistance = qAbs(pos + dataValue);
1148 maxDistance = qAbs(maxExtent - data.move.value());
1151 if (snapMode == QSGGridView::NoSnap && highlightRange != QSGGridView::StrictlyEnforceRange)
1152 data.flickTarget = maxExtent;
1154 bool overShoot = boundsBehavior == QSGFlickable::DragAndOvershootBounds;
1155 qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
1156 if (maxDistance > 0 || overShoot) {
1157 // This mode requires the grid to stop exactly on a row boundary.
1159 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1165 qreal accel = deceleration;
1167 qreal overshootDist = 0.0;
1168 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QSGGridView::SnapOneRow) {
1169 // + rowSize()/4 to encourage moving at least one item in the flick direction
1170 qreal dist = v2 / (accel * 2.0) + rowSize()/4;
1171 dist = qMin(dist, maxDistance);
1174 qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
1175 data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
1176 data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
1177 qreal adjDist = -data.flickTarget + data.move.value();
1178 if (qAbs(adjDist) > qAbs(dist)) {
1179 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1180 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1189 accel = v2 / (2.0f * qAbs(dist));
1191 data.flickTarget = velocity > 0 ? minExtent : maxExtent;
1192 overshootDist = overShoot ? overShootDistance(v, vSize) : 0;
1194 timeline.reset(data.move);
1195 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1196 timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1197 if (!flickingHorizontally && q->xflick()) {
1198 flickingHorizontally = true;
1199 emit q->flickingChanged();
1200 emit q->flickingHorizontallyChanged();
1201 emit q->flickStarted();
1203 if (!flickingVertically && q->yflick()) {
1204 flickingVertically = true;
1205 emit q->flickingChanged();
1206 emit q->flickingVerticallyChanged();
1207 emit q->flickStarted();
1210 timeline.reset(data.move);
1211 fixup(data, minExtent, maxExtent);
1216 //----------------------------------------------------------------------------
1218 QSGGridView::QSGGridView(QSGItem *parent)
1219 : QSGFlickable(*(new QSGGridViewPrivate), parent)
1225 QSGGridView::~QSGGridView()
1236 int QSGGridView::modelCount() const
1238 Q_D(const QSGGridView);
1239 return d->model->count();
1242 QVariant QSGGridView::model() const
1244 Q_D(const QSGGridView);
1245 return d->modelVariant;
1248 void QSGGridView::setModel(const QVariant &model)
1251 if (d->modelVariant == model)
1254 disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1255 disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1256 disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1257 disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1258 disconnect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
1259 disconnect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
1262 d->modelVariant = model;
1263 QObject *object = qvariant_cast<QObject*>(model);
1264 QSGVisualModel *vim = 0;
1265 if (object && (vim = qobject_cast<QSGVisualModel *>(object))) {
1268 d->ownModel = false;
1273 d->model = new QSGVisualDataModel(qmlContext(this), this);
1276 if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
1277 dataModel->setModel(model);
1280 d->bufferMode = QSGGridViewPrivate::BufferBefore | QSGGridViewPrivate::BufferAfter;
1281 if (isComponentComplete()) {
1283 if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
1286 d->moveReason = QSGGridViewPrivate::SetIndex;
1287 d->updateCurrent(d->currentIndex);
1288 if (d->highlight && d->currentItem) {
1289 if (d->autoHighlight)
1290 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1291 d->updateTrackedItem();
1293 d->moveReason = QSGGridViewPrivate::Other;
1296 connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1297 connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1298 connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1299 connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1300 connect(d->model, SIGNAL(createdItem(int,QSGItem*)), this, SLOT(createdItem(int,QSGItem*)));
1301 connect(d->model, SIGNAL(destroyingItem(QSGItem*)), this, SLOT(destroyingItem(QSGItem*)));
1302 emit countChanged();
1304 emit modelChanged();
1307 QDeclarativeComponent *QSGGridView::delegate() const
1309 Q_D(const QSGGridView);
1311 if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model))
1312 return dataModel->delegate();
1318 void QSGGridView::setDelegate(QDeclarativeComponent *delegate)
1321 if (delegate == this->delegate())
1325 d->model = new QSGVisualDataModel(qmlContext(this));
1328 if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(d->model)) {
1329 dataModel->setDelegate(delegate);
1330 if (isComponentComplete()) {
1331 for (int i = 0; i < d->visibleItems.count(); ++i)
1332 d->releaseItem(d->visibleItems.at(i));
1333 d->visibleItems.clear();
1334 d->releaseItem(d->currentItem);
1337 d->moveReason = QSGGridViewPrivate::SetIndex;
1338 d->updateCurrent(d->currentIndex);
1339 if (d->highlight && d->currentItem) {
1340 if (d->autoHighlight)
1341 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1342 d->updateTrackedItem();
1344 d->moveReason = QSGGridViewPrivate::Other;
1346 emit delegateChanged();
1350 int QSGGridView::currentIndex() const
1352 Q_D(const QSGGridView);
1353 return d->currentIndex;
1356 void QSGGridView::setCurrentIndex(int index)
1359 if (d->requestedIndex >= 0) // currently creating item
1361 d->currentIndexCleared = (index == -1);
1362 if (index == d->currentIndex)
1364 if (isComponentComplete() && d->isValid()) {
1365 d->moveReason = QSGGridViewPrivate::SetIndex;
1366 d->updateCurrent(index);
1368 d->currentIndex = index;
1369 emit currentIndexChanged();
1373 QSGItem *QSGGridView::currentItem()
1376 if (!d->currentItem)
1378 return d->currentItem->item;
1381 QSGItem *QSGGridView::highlightItem()
1386 return d->highlight->item;
1389 int QSGGridView::count() const
1391 Q_D(const QSGGridView);
1393 return d->model->count();
1397 QDeclarativeComponent *QSGGridView::highlight() const
1399 Q_D(const QSGGridView);
1400 return d->highlightComponent;
1403 void QSGGridView::setHighlight(QDeclarativeComponent *highlight)
1406 if (highlight != d->highlightComponent) {
1407 d->highlightComponent = highlight;
1408 d->updateCurrent(d->currentIndex);
1409 emit highlightChanged();
1413 bool QSGGridView::highlightFollowsCurrentItem() const
1415 Q_D(const QSGGridView);
1416 return d->autoHighlight;
1419 void QSGGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
1422 if (d->autoHighlight != autoHighlight) {
1423 d->autoHighlight = autoHighlight;
1424 if (autoHighlight) {
1425 d->updateHighlight();
1426 } else if (d->highlightXAnimator) {
1427 d->highlightXAnimator->stop();
1428 d->highlightYAnimator->stop();
1433 int QSGGridView::highlightMoveDuration() const
1435 Q_D(const QSGGridView);
1436 return d->highlightMoveDuration;
1439 void QSGGridView::setHighlightMoveDuration(int duration)
1442 if (d->highlightMoveDuration != duration) {
1443 d->highlightMoveDuration = duration;
1444 if (d->highlightYAnimator) {
1445 d->highlightXAnimator->userDuration = d->highlightMoveDuration;
1446 d->highlightYAnimator->userDuration = d->highlightMoveDuration;
1448 emit highlightMoveDurationChanged();
1452 qreal QSGGridView::preferredHighlightBegin() const
1454 Q_D(const QSGGridView);
1455 return d->highlightRangeStart;
1458 void QSGGridView::setPreferredHighlightBegin(qreal start)
1461 d->highlightRangeStartValid = true;
1462 if (d->highlightRangeStart == start)
1464 d->highlightRangeStart = start;
1465 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1466 emit preferredHighlightBeginChanged();
1469 void QSGGridView::resetPreferredHighlightBegin()
1472 d->highlightRangeStartValid = false;
1473 if (d->highlightRangeStart == 0)
1475 d->highlightRangeStart = 0;
1476 emit preferredHighlightBeginChanged();
1479 qreal QSGGridView::preferredHighlightEnd() const
1481 Q_D(const QSGGridView);
1482 return d->highlightRangeEnd;
1485 void QSGGridView::setPreferredHighlightEnd(qreal end)
1488 d->highlightRangeEndValid = true;
1489 if (d->highlightRangeEnd == end)
1491 d->highlightRangeEnd = end;
1492 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1493 emit preferredHighlightEndChanged();
1496 void QSGGridView::resetPreferredHighlightEnd()
1499 d->highlightRangeEndValid = false;
1500 if (d->highlightRangeEnd == 0)
1502 d->highlightRangeEnd = 0;
1503 emit preferredHighlightEndChanged();
1506 QSGGridView::HighlightRangeMode QSGGridView::highlightRangeMode() const
1508 Q_D(const QSGGridView);
1509 return d->highlightRange;
1512 void QSGGridView::setHighlightRangeMode(HighlightRangeMode mode)
1515 if (d->highlightRange == mode)
1517 d->highlightRange = mode;
1518 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1519 emit highlightRangeModeChanged();
1522 Qt::LayoutDirection QSGGridView::layoutDirection() const
1524 Q_D(const QSGGridView);
1525 return d->layoutDirection;
1528 void QSGGridView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1531 if (d->layoutDirection != layoutDirection) {
1532 d->layoutDirection = layoutDirection;
1534 emit layoutDirectionChanged();
1535 emit effectiveLayoutDirectionChanged();
1539 Qt::LayoutDirection QSGGridView::effectiveLayoutDirection() const
1541 Q_D(const QSGGridView);
1542 if (d->effectiveLayoutMirror)
1543 return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
1545 return d->layoutDirection;
1548 QSGGridView::Flow QSGGridView::flow() const
1550 Q_D(const QSGGridView);
1554 void QSGGridView::setFlow(Flow flow)
1557 if (d->flow != flow) {
1559 if (d->flow == LeftToRight) {
1560 setContentWidth(-1);
1561 setFlickableDirection(QSGFlickable::VerticalFlick);
1563 setContentHeight(-1);
1564 setFlickableDirection(QSGFlickable::HorizontalFlick);
1573 bool QSGGridView::isWrapEnabled() const
1575 Q_D(const QSGGridView);
1579 void QSGGridView::setWrapEnabled(bool wrap)
1582 if (d->wrap == wrap)
1585 emit keyNavigationWrapsChanged();
1588 int QSGGridView::cacheBuffer() const
1590 Q_D(const QSGGridView);
1594 void QSGGridView::setCacheBuffer(int buffer)
1597 if (d->buffer != buffer) {
1599 if (isComponentComplete())
1601 emit cacheBufferChanged();
1605 int QSGGridView::cellWidth() const
1607 Q_D(const QSGGridView);
1608 return d->cellWidth;
1611 void QSGGridView::setCellWidth(int cellWidth)
1614 if (cellWidth != d->cellWidth && cellWidth > 0) {
1615 d->cellWidth = qMax(1, cellWidth);
1617 emit cellWidthChanged();
1622 int QSGGridView::cellHeight() const
1624 Q_D(const QSGGridView);
1625 return d->cellHeight;
1628 void QSGGridView::setCellHeight(int cellHeight)
1631 if (cellHeight != d->cellHeight && cellHeight > 0) {
1632 d->cellHeight = qMax(1, cellHeight);
1634 emit cellHeightChanged();
1639 QSGGridView::SnapMode QSGGridView::snapMode() const
1641 Q_D(const QSGGridView);
1645 void QSGGridView::setSnapMode(SnapMode mode)
1648 if (d->snapMode != mode) {
1650 emit snapModeChanged();
1654 QDeclarativeComponent *QSGGridView::footer() const
1656 Q_D(const QSGGridView);
1657 return d->footerComponent;
1660 void QSGGridView::setFooter(QDeclarativeComponent *footer)
1663 if (d->footerComponent != footer) {
1665 // XXX todo - the original did scene()->removeItem(). Why?
1666 d->footer->item->setParentItem(0);
1667 d->footer->item->deleteLater();
1671 d->footerComponent = footer;
1672 if (isComponentComplete()) {
1677 emit footerChanged();
1681 QDeclarativeComponent *QSGGridView::header() const
1683 Q_D(const QSGGridView);
1684 return d->headerComponent;
1687 void QSGGridView::setHeader(QDeclarativeComponent *header)
1690 if (d->headerComponent != header) {
1692 // XXX todo - the original did scene()->removeItem(). Why?
1693 d->header->item->setParentItem(0);
1694 d->header->item->deleteLater();
1698 d->headerComponent = header;
1699 if (isComponentComplete()) {
1705 emit headerChanged();
1709 void QSGGridView::setContentX(qreal pos)
1712 // Positioning the view manually should override any current movement state
1713 d->moveReason = QSGGridViewPrivate::Other;
1714 QSGFlickable::setContentX(pos);
1717 void QSGGridView::setContentY(qreal pos)
1720 // Positioning the view manually should override any current movement state
1721 d->moveReason = QSGGridViewPrivate::Other;
1722 QSGFlickable::setContentY(pos);
1725 void QSGGridView::updatePolish()
1728 QSGFlickable::updatePolish();
1732 void QSGGridView::viewportMoved()
1735 QSGFlickable::viewportMoved();
1738 d->lazyRelease = true;
1739 if (d->flickingHorizontally || d->flickingVertically) {
1741 if (d->vData.velocity > 0)
1742 d->bufferMode = QSGGridViewPrivate::BufferBefore;
1743 else if (d->vData.velocity < 0)
1744 d->bufferMode = QSGGridViewPrivate::BufferAfter;
1748 if (d->hData.velocity > 0)
1749 d->bufferMode = QSGGridViewPrivate::BufferBefore;
1750 else if (d->hData.velocity < 0)
1751 d->bufferMode = QSGGridViewPrivate::BufferAfter;
1755 if (d->flickingHorizontally || d->flickingVertically || d->movingHorizontally || d->movingVertically)
1756 d->moveReason = QSGGridViewPrivate::Mouse;
1757 if (d->moveReason != QSGGridViewPrivate::SetIndex) {
1758 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
1759 // reposition highlight
1760 qreal pos = d->highlight->rowPos();
1762 qreal highlightStart;
1764 if (d->isRightToLeftTopToBottom()) {
1765 highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
1766 highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
1767 viewPos = -d->position()-d->size();
1769 highlightStart = d->highlightRangeStart;
1770 highlightEnd = d->highlightRangeEnd;
1771 viewPos = d->position();
1773 if (pos > viewPos + highlightEnd - d->rowSize())
1774 pos = viewPos + highlightEnd - d->rowSize();
1775 if (pos < viewPos + highlightStart)
1776 pos = viewPos + highlightStart;
1777 d->highlight->setPosition(d->highlight->colPos(), qRound(pos));
1779 // update current index
1780 int idx = d->snapIndex();
1781 if (idx >= 0 && idx != d->currentIndex) {
1782 d->updateCurrent(idx);
1783 if (d->currentItem && d->currentItem->colPos() != d->highlight->colPos() && d->autoHighlight) {
1784 if (d->flow == LeftToRight)
1785 d->highlightXAnimator->to = d->currentItem->item->x();
1787 d->highlightYAnimator->to = d->currentItem->item->y();
1794 qreal QSGGridView::minYExtent() const
1796 Q_D(const QSGGridView);
1797 if (d->flow == QSGGridView::TopToBottom)
1798 return QSGFlickable::minYExtent();
1799 qreal extent = -d->startPosition();
1800 if (d->header && d->visibleItems.count())
1801 extent += d->header->item->height();
1802 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
1803 extent += d->highlightRangeStart;
1804 extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd));
1809 qreal QSGGridView::maxYExtent() const
1811 Q_D(const QSGGridView);
1812 if (d->flow == QSGGridView::TopToBottom)
1813 return QSGFlickable::maxYExtent();
1815 if (!d->model || !d->model->count()) {
1817 } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
1818 extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart);
1819 if (d->highlightRangeEnd != d->highlightRangeStart)
1820 extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1));
1822 extent = -(d->endPosition() - height());
1825 extent -= d->footer->item->height();
1826 const qreal minY = minYExtent();
1832 qreal QSGGridView::minXExtent() const
1834 Q_D(const QSGGridView);
1835 if (d->flow == QSGGridView::LeftToRight)
1836 return QSGFlickable::minXExtent();
1837 qreal extent = -d->startPosition();
1838 qreal highlightStart;
1840 qreal endPositionFirstItem;
1841 if (d->isRightToLeftTopToBottom()) {
1842 endPositionFirstItem = d->rowPosAt(d->model->count()-1);
1843 highlightStart = d->highlightRangeStartValid
1844 ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
1845 : d->size() - (d->lastPosition()-endPositionFirstItem);
1846 highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
1847 if (d->footer && d->visibleItems.count())
1848 extent += d->footer->item->width();
1850 endPositionFirstItem = d->rowPosAt(0)+d->rowSize();
1851 highlightStart = d->highlightRangeStart;
1852 highlightEnd = d->highlightRangeEnd;
1853 if (d->header && d->visibleItems.count())
1854 extent += d->header->item->width();
1856 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
1857 extent += highlightStart;
1858 extent = qMax(extent, -(endPositionFirstItem - highlightEnd));
1863 qreal QSGGridView::maxXExtent() const
1865 Q_D(const QSGGridView);
1866 if (d->flow == QSGGridView::LeftToRight)
1867 return QSGFlickable::maxXExtent();
1869 qreal highlightStart;
1871 qreal lastItemPosition;
1872 if (d->isRightToLeftTopToBottom()){
1873 highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
1874 highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
1875 lastItemPosition = d->endPosition();
1877 highlightStart = d->highlightRangeStart;
1878 highlightEnd = d->highlightRangeEnd;
1879 if (d->model && d->model->count())
1880 lastItemPosition = d->rowPosAt(d->model->count()-1);
1882 if (!d->model || !d->model->count()) {
1884 } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
1885 extent = -(lastItemPosition - highlightStart);
1886 if (highlightEnd != highlightStart)
1887 extent = d->isRightToLeftTopToBottom()
1888 ? qMax(extent, -(d->endPosition() - highlightEnd + 1))
1889 : qMin(extent, -(d->endPosition() - highlightEnd + 1));
1891 extent = -(d->endPosition() - width());
1893 if (d->isRightToLeftTopToBottom()) {
1895 extent -= d->header->item->width();
1898 extent -= d->footer->item->width();
1901 const qreal minX = minXExtent();
1907 void QSGGridView::keyPressEvent(QKeyEvent *event)
1910 if (d->model && d->model->count() && d->interactive) {
1911 d->moveReason = QSGGridViewPrivate::SetIndex;
1912 int oldCurrent = currentIndex();
1913 switch (event->key()) {
1915 moveCurrentIndexUp();
1918 moveCurrentIndexDown();
1921 moveCurrentIndexLeft();
1924 moveCurrentIndexRight();
1929 if (oldCurrent != currentIndex()) {
1934 d->moveReason = QSGGridViewPrivate::Other;
1936 QSGFlickable::keyPressEvent(event);
1939 void QSGGridView::moveCurrentIndexUp()
1942 const int count = d->model ? d->model->count() : 0;
1945 if (d->flow == QSGGridView::LeftToRight) {
1946 if (currentIndex() >= d->columns || d->wrap) {
1947 int index = currentIndex() - d->columns;
1948 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1951 if (currentIndex() > 0 || d->wrap) {
1952 int index = currentIndex() - 1;
1953 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1958 void QSGGridView::moveCurrentIndexDown()
1961 const int count = d->model ? d->model->count() : 0;
1964 if (d->flow == QSGGridView::LeftToRight) {
1965 if (currentIndex() < count - d->columns || d->wrap) {
1966 int index = currentIndex()+d->columns;
1967 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1970 if (currentIndex() < count - 1 || d->wrap) {
1971 int index = currentIndex() + 1;
1972 setCurrentIndex((index >= 0 && index < count) ? index : 0);
1977 void QSGGridView::moveCurrentIndexLeft()
1980 const int count = d->model ? d->model->count() : 0;
1983 if (effectiveLayoutDirection() == Qt::LeftToRight) {
1984 if (d->flow == QSGGridView::LeftToRight) {
1985 if (currentIndex() > 0 || d->wrap) {
1986 int index = currentIndex() - 1;
1987 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1990 if (currentIndex() >= d->columns || d->wrap) {
1991 int index = currentIndex() - d->columns;
1992 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
1996 if (d->flow == QSGGridView::LeftToRight) {
1997 if (currentIndex() < count - 1 || d->wrap) {
1998 int index = currentIndex() + 1;
1999 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2002 if (currentIndex() < count - d->columns || d->wrap) {
2003 int index = currentIndex() + d->columns;
2004 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2010 void QSGGridView::moveCurrentIndexRight()
2013 const int count = d->model ? d->model->count() : 0;
2016 if (effectiveLayoutDirection() == Qt::LeftToRight) {
2017 if (d->flow == QSGGridView::LeftToRight) {
2018 if (currentIndex() < count - 1 || d->wrap) {
2019 int index = currentIndex() + 1;
2020 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2023 if (currentIndex() < count - d->columns || d->wrap) {
2024 int index = currentIndex()+d->columns;
2025 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2029 if (d->flow == QSGGridView::LeftToRight) {
2030 if (currentIndex() > 0 || d->wrap) {
2031 int index = currentIndex() - 1;
2032 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2035 if (currentIndex() >= d->columns || d->wrap) {
2036 int index = currentIndex() - d->columns;
2037 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2043 void QSGGridViewPrivate::positionViewAtIndex(int index, int mode)
2048 if (mode < QSGGridView::Beginning || mode > QSGGridView::Contain)
2051 int idx = qMax(qMin(index, model->count()-1), 0);
2053 if (layoutScheduled)
2055 qreal pos = isRightToLeftTopToBottom() ? -position() - size() : position();
2056 FxGridItemSG *item = visibleItem(idx);
2058 if (flow == QSGGridView::LeftToRight)
2059 maxExtent = -q->maxYExtent();
2061 maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2063 int itemPos = rowPosAt(idx);
2064 // save the currently visible items in case any of them end up visible again
2065 QList<FxGridItemSG*> oldVisible = visibleItems;
2066 visibleItems.clear();
2067 visibleIndex = idx - idx % columns;
2068 if (flow == QSGGridView::LeftToRight)
2069 maxExtent = -q->maxYExtent();
2071 maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2072 setPosition(qMin(qreal(itemPos), maxExtent));
2073 // now release the reference to all the old visible items.
2074 for (int i = 0; i < oldVisible.count(); ++i)
2075 releaseItem(oldVisible.at(i));
2076 item = visibleItem(idx);
2079 qreal itemPos = item->rowPos();
2081 case QSGGridView::Beginning:
2083 if (index < 0 && header) {
2084 pos -= flow == QSGGridView::LeftToRight
2085 ? header->item->height()
2086 : header->item->width();
2089 case QSGGridView::Center:
2090 pos = itemPos - (size() - rowSize())/2;
2092 case QSGGridView::End:
2093 pos = itemPos - size() + rowSize();
2094 if (index >= model->count() && footer) {
2095 pos += flow == QSGGridView::LeftToRight
2096 ? footer->item->height()
2097 : footer->item->width();
2100 case QSGGridView::Visible:
2101 if (itemPos > pos + size())
2102 pos = itemPos - size() + rowSize();
2103 else if (item->endRowPos() < pos)
2106 case QSGGridView::Contain:
2107 if (item->endRowPos() > pos + size())
2108 pos = itemPos - size() + rowSize();
2112 pos = qMin(pos, maxExtent);
2114 if (flow == QSGGridView::LeftToRight)
2115 minExtent = -q->minYExtent();
2117 minExtent = isRightToLeftTopToBottom() ? q->maxXExtent()-size() : -q->minXExtent();
2118 pos = qMax(pos, minExtent);
2119 moveReason = QSGGridViewPrivate::Other;
2126 void QSGGridView::positionViewAtIndex(int index, int mode)
2129 if (!d->isValid() || index < 0 || index >= d->model->count())
2131 d->positionViewAtIndex(index, mode);
2134 void QSGGridView::positionViewAtBeginning()
2139 d->positionViewAtIndex(-1, Beginning);
2142 void QSGGridView::positionViewAtEnd()
2147 d->positionViewAtIndex(d->model->count(), End);
2150 int QSGGridView::indexAt(qreal x, qreal y) const
2152 Q_D(const QSGGridView);
2153 for (int i = 0; i < d->visibleItems.count(); ++i) {
2154 const FxGridItemSG *listItem = d->visibleItems.at(i);
2155 if(listItem->contains(x, y))
2156 return listItem->index;
2162 void QSGGridView::componentComplete()
2165 QSGFlickable::componentComplete();
2171 d->moveReason = QSGGridViewPrivate::SetIndex;
2172 if (d->currentIndex < 0 && !d->currentIndexCleared)
2173 d->updateCurrent(0);
2175 d->updateCurrent(d->currentIndex);
2176 if (d->highlight && d->currentItem) {
2177 if (d->autoHighlight)
2178 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
2179 d->updateTrackedItem();
2181 d->moveReason = QSGGridViewPrivate::Other;
2186 void QSGGridView::trackedPositionChanged()
2189 if (!d->trackedItem || !d->currentItem)
2191 if (d->moveReason == QSGGridViewPrivate::SetIndex) {
2192 const qreal trackedPos = d->trackedItem->rowPos();
2194 qreal highlightStart;
2196 if (d->isRightToLeftTopToBottom()) {
2197 viewPos = -d->position()-d->size();
2198 highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
2199 highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
2201 viewPos = d->position();
2202 highlightStart = d->highlightRangeStart;
2203 highlightEnd = d->highlightRangeEnd;
2205 qreal pos = viewPos;
2206 if (d->haveHighlightRange) {
2207 if (d->highlightRange == StrictlyEnforceRange) {
2208 if (trackedPos > pos + highlightEnd - d->rowSize())
2209 pos = trackedPos - highlightEnd + d->rowSize();
2210 if (trackedPos < pos + highlightStart)
2211 pos = trackedPos - highlightStart;
2213 if (trackedPos < d->startPosition() + highlightStart) {
2214 pos = d->startPosition();
2215 } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + highlightEnd) {
2216 pos = d->endPosition() - d->size() + 1;
2217 if (pos < d->startPosition())
2218 pos = d->startPosition();
2220 if (trackedPos < viewPos + highlightStart) {
2221 pos = trackedPos - highlightStart;
2222 } else if (trackedPos > viewPos + highlightEnd - d->rowSize()) {
2223 pos = trackedPos - highlightEnd + d->rowSize();
2228 if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) {
2229 pos = qMax(trackedPos, d->currentItem->rowPos());
2230 } else if (d->trackedItem->endRowPos() >= viewPos + d->size()
2231 && d->currentItem->endRowPos() >= viewPos + d->size()) {
2232 if (d->trackedItem->endRowPos() <= d->currentItem->endRowPos()) {
2233 pos = d->trackedItem->endRowPos() - d->size() + 1;
2234 if (d->rowSize() > d->size())
2237 pos = d->currentItem->endRowPos() - d->size() + 1;
2238 if (d->rowSize() > d->size())
2239 pos = d->currentItem->rowPos();
2243 if (viewPos != pos) {
2245 d->calcVelocity = true;
2246 d->setPosition(pos);
2247 d->calcVelocity = false;
2252 void QSGGridView::itemsInserted(int modelIndex, int count)
2255 if (!isComponentComplete())
2258 int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
2260 int i = d->visibleItems.count() - 1;
2261 while (i > 0 && d->visibleItems.at(i)->index == -1)
2263 if (d->visibleItems.at(i)->index + 1 == modelIndex) {
2264 // Special case of appending an item to the model.
2265 index = d->visibleIndex + d->visibleItems.count();
2267 if (modelIndex <= d->visibleIndex) {
2268 // Insert before visible items
2269 d->visibleIndex += count;
2270 for (int i = 0; i < d->visibleItems.count(); ++i) {
2271 FxGridItemSG *listItem = d->visibleItems.at(i);
2272 if (listItem->index != -1 && listItem->index >= modelIndex)
2273 listItem->index += count;
2276 if (d->currentIndex >= modelIndex) {
2277 // adjust current item index
2278 d->currentIndex += count;
2280 d->currentItem->index = d->currentIndex;
2281 emit currentIndexChanged();
2283 d->scheduleLayout();
2284 d->itemCount += count;
2285 emit countChanged();
2290 int insertCount = count;
2291 if (index < d->visibleIndex && d->visibleItems.count()) {
2292 insertCount -= d->visibleIndex - index;
2293 index = d->visibleIndex;
2294 modelIndex = d->visibleIndex;
2297 qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+width()+1 : d->position();
2298 int to = d->buffer+tempPos+d->size()-1;
2301 if (d->visibleItems.count()) {
2302 index -= d->visibleIndex;
2303 if (index < d->visibleItems.count()) {
2304 colPos = d->visibleItems.at(index)->colPos();
2305 rowPos = d->visibleItems.at(index)->rowPos();
2307 // appending items to visible list
2308 colPos = d->visibleItems.at(index-1)->colPos() + d->colSize();
2309 rowPos = d->visibleItems.at(index-1)->rowPos();
2310 if (colPos > d->colSize() * (d->columns-1)) {
2312 rowPos += d->rowSize();
2315 } else if (d->itemCount == 0 && d->header) {
2316 rowPos = d->headerSize();
2319 // Update the indexes of the following visible items.
2320 for (int i = 0; i < d->visibleItems.count(); ++i) {
2321 FxGridItemSG *listItem = d->visibleItems.at(i);
2322 if (listItem->index != -1 && listItem->index >= modelIndex)
2323 listItem->index += count;
2326 bool addedVisible = false;
2327 QList<FxGridItemSG*> added;
2329 while (i < insertCount && rowPos <= to + d->rowSize()*(d->columns - (colPos/d->colSize()))/qreal(d->columns)) {
2330 if (!addedVisible) {
2331 d->scheduleLayout();
2332 addedVisible = true;
2334 FxGridItemSG *item = d->createItem(modelIndex + i);
2335 d->visibleItems.insert(index, item);
2336 item->setPosition(colPos, rowPos);
2338 colPos += d->colSize();
2339 if (colPos > d->colSize() * (d->columns-1)) {
2341 rowPos += d->rowSize();
2346 if (i < insertCount) {
2347 // We didn't insert all our new items, which means anything
2348 // beyond the current index is not visible - remove it.
2349 while (d->visibleItems.count() > index) {
2350 d->releaseItem(d->visibleItems.takeLast());
2354 // update visibleIndex
2355 d->visibleIndex = 0;
2356 for (QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2357 if ((*it)->index != -1) {
2358 d->visibleIndex = (*it)->index;
2363 if (d->itemCount && d->currentIndex >= modelIndex) {
2364 // adjust current item index
2365 d->currentIndex += count;
2366 if (d->currentItem) {
2367 d->currentItem->index = d->currentIndex;
2368 d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
2369 } else if (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared)) {
2370 d->updateCurrent(0);
2372 emit currentIndexChanged();
2373 } else if (d->itemCount == 0 && d->currentIndex == -1) {
2377 // everything is in order now - emit add() signal
2378 for (int j = 0; j < added.count(); ++j)
2379 added.at(j)->attached->emitAdd();
2381 d->itemCount += count;
2382 emit countChanged();
2385 void QSGGridView::itemsRemoved(int modelIndex, int count)
2388 if (!isComponentComplete())
2391 d->itemCount -= count;
2392 bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count;
2393 bool removedVisible = false;
2395 // Remove the items from the visible list, skipping anything already marked for removal
2396 QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
2397 while (it != d->visibleItems.end()) {
2398 FxGridItemSG *item = *it;
2399 if (item->index == -1 || item->index < modelIndex) {
2400 // already removed, or before removed items
2401 if (item->index < modelIndex && !removedVisible) {
2402 d->scheduleLayout();
2403 removedVisible = true;
2406 } else if (item->index >= modelIndex + count) {
2407 // after removed items
2408 item->index -= count;
2412 if (!removedVisible) {
2413 d->scheduleLayout();
2414 removedVisible = true;
2416 item->attached->emitRemove();
2417 if (item->attached->delayRemove()) {
2419 connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
2422 it = d->visibleItems.erase(it);
2423 d->releaseItem(item);
2429 if (d->currentIndex >= modelIndex + count) {
2430 d->currentIndex -= count;
2432 d->currentItem->index -= count;
2433 emit currentIndexChanged();
2434 } else if (currentRemoved) {
2435 // current item has been removed.
2436 d->releaseItem(d->currentItem);
2438 d->currentIndex = -1;
2440 d->updateCurrent(qMin(modelIndex, d->itemCount-1));
2443 // update visibleIndex
2444 d->visibleIndex = 0;
2445 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2446 if ((*it)->index != -1) {
2447 d->visibleIndex = (*it)->index;
2452 if (removedVisible && d->visibleItems.isEmpty()) {
2453 d->timeline.clear();
2454 if (d->itemCount == 0) {
2461 emit countChanged();
2464 void QSGGridView::destroyRemoved()
2467 for (QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
2468 it != d->visibleItems.end();) {
2469 FxGridItemSG *listItem = *it;
2470 if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
2471 d->releaseItem(listItem);
2472 it = d->visibleItems.erase(it);
2478 // Correct the positioning of the items
2482 void QSGGridView::itemsMoved(int from, int to, int count)
2485 if (!isComponentComplete())
2487 QHash<int,FxGridItemSG*> moved;
2489 FxGridItemSG *firstItem = d->firstVisibleItem();
2491 QList<FxGridItemSG*>::Iterator it = d->visibleItems.begin();
2492 while (it != d->visibleItems.end()) {
2493 FxGridItemSG *item = *it;
2494 if (item->index >= from && item->index < from + count) {
2495 // take the items that are moving
2496 item->index += (to-from);
2497 moved.insert(item->index, item);
2498 it = d->visibleItems.erase(it);
2500 if (item->index > from && item->index != -1) {
2501 // move everything after the moved items.
2502 item->index -= count;
2503 if (item->index < d->visibleIndex)
2504 d->visibleIndex = item->index;
2510 int remaining = count;
2511 int endIndex = d->visibleIndex;
2512 it = d->visibleItems.begin();
2513 while (it != d->visibleItems.end()) {
2514 FxGridItemSG *item = *it;
2515 if (remaining && item->index >= to && item->index < to + count) {
2516 // place items in the target position, reusing any existing items
2517 FxGridItemSG *movedItem = moved.take(item->index);
2519 movedItem = d->createItem(item->index);
2520 it = d->visibleItems.insert(it, movedItem);
2521 if (it == d->visibleItems.begin() && firstItem)
2522 movedItem->setPosition(firstItem->colPos(), firstItem->rowPos());
2526 if (item->index != -1) {
2527 if (item->index >= to) {
2528 // update everything after the moved items.
2529 item->index += count;
2531 endIndex = item->index;
2537 // If we have moved items to the end of the visible items
2538 // then add any existing moved items that we have
2539 while (FxGridItemSG *item = moved.take(endIndex+1)) {
2540 d->visibleItems.append(item);
2544 // update visibleIndex
2545 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2546 if ((*it)->index != -1) {
2547 d->visibleIndex = (*it)->index;
2552 // Fix current index
2553 if (d->currentIndex >= 0 && d->currentItem) {
2554 int oldCurrent = d->currentIndex;
2555 d->currentIndex = d->model->indexOf(d->currentItem->item, this);
2556 if (oldCurrent != d->currentIndex) {
2557 d->currentItem->index = d->currentIndex;
2558 emit currentIndexChanged();
2562 // Whatever moved items remain are no longer visible items.
2563 while (moved.count()) {
2564 int idx = moved.begin().key();
2565 FxGridItemSG *item = moved.take(idx);
2566 if (d->currentItem && item->item == d->currentItem->item)
2567 item->setPosition(d->colPosAt(idx), d->rowPosAt(idx));
2568 d->releaseItem(item);
2574 void QSGGridView::modelReset()
2579 d->moveReason = QSGGridViewPrivate::SetIndex;
2580 d->updateCurrent(d->currentIndex);
2581 if (d->highlight && d->currentItem) {
2582 if (d->autoHighlight)
2583 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
2584 d->updateTrackedItem();
2586 d->moveReason = QSGGridViewPrivate::Other;
2588 emit countChanged();
2591 void QSGGridView::createdItem(int index, QSGItem *item)
2594 if (d->requestedIndex != index) {
2595 item->setParentItem(this);
2596 d->unrequestedItems.insert(item, index);
2597 if (d->flow == QSGGridView::LeftToRight) {
2598 item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index)));
2600 item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index)));
2605 void QSGGridView::destroyingItem(QSGItem *item)
2608 d->unrequestedItems.remove(item);
2611 void QSGGridView::animStopped()
2614 d->bufferMode = QSGGridViewPrivate::NoBuffer;
2615 if (d->haveHighlightRange && d->highlightRange == QSGGridView::StrictlyEnforceRange)
2616 d->updateHighlight();
2619 void QSGGridView::refill()
2622 if (d->isRightToLeftTopToBottom())
2623 d->refill(-d->position()-d->size()+1, -d->position());
2625 d->refill(d->position(), d->position()+d->size()-1);
2629 QSGGridViewAttached *QSGGridView::qmlAttachedProperties(QObject *obj)
2631 return new QSGGridViewAttached(obj);