1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativegridview_p.h"
43
44 #include "private/qdeclarativevisualitemmodel_p.h"
45 #include "private/qdeclarativeflickable_p_p.h"
46
47 #include "private/qdeclarativesmoothedanimation_p_p.h"
48 #include <qdeclarativeguard_p.h>
49
50 #include <qlistmodelinterface_p.h>
51 #include <QKeyEvent>
52
53 #include <qmath.h>
54 #include <math.h>
55 #include "qplatformdefs.h"
56
57 QT_BEGIN_NAMESPACE
58
59 #ifndef QML_FLICK_SNAPONETHRESHOLD
60 #define QML_FLICK_SNAPONETHRESHOLD 30
61 #endif
62
63 //----------------------------------------------------------------------------
64
65 class FxGridItem
66 {
67 public:
FxGridItem(QDeclarativeItem * i,QDeclarativeGridView * v)68 FxGridItem(QDeclarativeItem *i, QDeclarativeGridView *v) : item(i), view(v) {
69 attached = static_cast<QDeclarativeGridViewAttached*>(qmlAttachedPropertiesObject<QDeclarativeGridView>(item));
70 if (attached)
71 attached->setView(view);
72 }
~FxGridItem()73 ~FxGridItem() {}
74
rowPos() const75 qreal rowPos() const {
76 qreal rowPos = 0;
77 if (view->flow() == QDeclarativeGridView::LeftToRight) {
78 rowPos = item->y();
79 } else {
80 if (view->effectiveLayoutDirection() == Qt::RightToLeft)
81 rowPos = -view->cellWidth()-item->x();
82 else
83 rowPos = item->x();
84 }
85 return rowPos;
86 }
colPos() const87 qreal colPos() const {
88 qreal colPos = 0;
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();
94 } else {
95 colPos = item->x();
96 }
97 } else {
98 colPos = item->y();
99 }
100
101 return colPos;
102 }
103
endRowPos() const104 qreal endRowPos() const {
105 if (view->flow() == QDeclarativeGridView::LeftToRight) {
106 return item->y() + view->cellHeight() - 1;
107 } else {
108 if (view->effectiveLayoutDirection() == Qt::RightToLeft)
109 return -item->x() - 1;
110 else
111 return item->x() + view->cellWidth() - 1;
112 }
113 }
setPosition(qreal col,qreal row)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));
119 } else {
120 item->setPos(QPointF(-view->cellWidth()-row, col));
121 }
122 } else {
123 if (view->flow() == QDeclarativeGridView::LeftToRight)
124 item->setPos(QPointF(col, row));
125 else
126 item->setPos(QPointF(row, col));
127 }
128
129 }
contains(qreal x,qreal y) const130 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());
133 }
134
135 QDeclarativeItem *item;
136 QDeclarativeGridView *view;
137 QDeclarativeGridViewAttached *attached;
138 int index;
139 };
140
141 //----------------------------------------------------------------------------
142
143 class QDeclarativeGridViewPrivate : public QDeclarativeFlickablePrivate
144 {
145 Q_DECLARE_PUBLIC(QDeclarativeGridView)
146
147 public:
QDeclarativeGridViewPrivate()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) {}
163
164 void init();
165 void clear();
166 FxGridItem *createItem(int modelIndex);
167 void releaseItem(FxGridItem *item);
168 QDeclarativeItem *createComponentItem(QDeclarativeComponent *component);
169 void refill(qreal from, qreal to, bool doBuffer=false);
170
171 void updateGrid();
172 void scheduleLayout();
173 void layout();
174 void updateUnrequestedIndexes();
175 void updateUnrequestedPositions();
176 void updateTrackedItem();
177 void createHighlight();
178 void updateHighlight();
179 void updateCurrent(int modelIndex);
180 void updateHeader();
181 void updateFooter();
182 void fixupPosition();
183
visibleItem(int modelIndex) const184 FxGridItem *visibleItem(int modelIndex) const {
185 if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
186 for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
187 FxGridItem *item = visibleItems.at(i);
188 if (item->index == modelIndex)
189 return item;
190 }
191 }
192 return 0;
193 }
194
isRightToLeftTopToBottom() const195 bool isRightToLeftTopToBottom() const {
196 Q_Q(const QDeclarativeGridView);
197 return flow == QDeclarativeGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft;
198 }
199
regenerate()200 void regenerate() {
201 Q_Q(QDeclarativeGridView);
202 if (q->isComponentComplete()) {
203 clear();
204 updateGrid();
205 setPosition(0);
206 q->refill();
207 updateCurrent(currentIndex);
208 }
209 }
210
mirrorChange()211 void mirrorChange() {
212 regenerate();
213 }
214
position() const215 qreal position() const {
216 Q_Q(const QDeclarativeGridView);
217 return flow == QDeclarativeGridView::LeftToRight ? q->contentY() : q->contentX();
218 }
setPosition(qreal pos)219 void setPosition(qreal pos) {
220 Q_Q(QDeclarativeGridView);
221 if (flow == QDeclarativeGridView::LeftToRight) {
222 q->QDeclarativeFlickable::setContentY(pos);
223 q->QDeclarativeFlickable::setContentX(0);
224 } else {
225 if (q->effectiveLayoutDirection() == Qt::LeftToRight)
226 q->QDeclarativeFlickable::setContentX(pos);
227 else
228 q->QDeclarativeFlickable::setContentX(-pos-size());
229 q->QDeclarativeFlickable::setContentY(0);
230 }
231 }
size() const232 int size() const {
233 Q_Q(const QDeclarativeGridView);
234 return flow == QDeclarativeGridView::LeftToRight ? q->height() : q->width();
235 }
originPosition() const236 qreal originPosition() const {
237 qreal pos = 0;
238 if (!visibleItems.isEmpty())
239 pos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
240 return pos;
241 }
242
lastPosition() const243 qreal lastPosition() const {
244 qreal pos = 0;
245 if (model && model->count())
246 pos = rowPosAt(model->count() - 1) + rowSize();
247 return pos;
248 }
249
startPosition() const250 qreal startPosition() const {
251 return isRightToLeftTopToBottom() ? -lastPosition()+1 : originPosition();
252 }
253
endPosition() const254 qreal endPosition() const {
255 return isRightToLeftTopToBottom() ? -originPosition()+1 : lastPosition();
256
257 }
258
isValid() const259 bool isValid() const {
260 return model && model->count() && model->isValid();
261 }
262
rowSize() const263 int rowSize() const {
264 return flow == QDeclarativeGridView::LeftToRight ? cellHeight : cellWidth;
265 }
colSize() const266 int colSize() const {
267 return flow == QDeclarativeGridView::LeftToRight ? cellWidth : cellHeight;
268 }
269
colPosAt(int modelIndex) const270 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();
279 } else {
280 int count = columns - 1 - (modelIndex - visibleItems.last()->index - 1) % columns;
281 return visibleItems.last()->colPos() - count * colSize();
282 }
283 } else {
284 return (modelIndex % columns) * colSize();
285 }
286 return 0;
287 }
rowPosAt(int modelIndex) const288 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();
297 } else {
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();
302 }
303 } else {
304 qreal pos = (modelIndex / columns) * rowSize();
305 if (header)
306 pos += headerSize();
307 return pos;
308 }
309 return 0;
310 }
311
firstVisibleItem() const312 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)
317 return item;
318 }
319 return visibleItems.count() ? visibleItems.first() : 0;
320 }
321
lastVisibleIndex() const322 int lastVisibleIndex() const {
323 for (int i = 0; i < visibleItems.count(); ++i) {
324 FxGridItem *item = visibleItems.at(i);
325 if (item->index != -1)
326 return item->index;
327 }
328 return -1;
329 }
330
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
mapFromModel(int modelIndex) const334 int mapFromModel(int modelIndex) const {
335 if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
336 return -1;
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)
342 return -1;
343 }
344 return -1; // Not in visibleList
345 }
346
snapPosAt(qreal pos) const347 qreal snapPosAt(qreal pos) const {
348 Q_Q(const QDeclarativeGridView);
349 qreal snapPos = 0;
350 if (!visibleItems.isEmpty()) {
351 qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
352 pos += highlightStart;
353 pos += rowSize()/2;
354 snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
355 snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
356 snapPos -= highlightStart;
357 qreal maxExtent;
358 qreal minExtent;
359 if (isRightToLeftTopToBottom()) {
360 maxExtent = q->minXExtent();
361 minExtent = q->maxXExtent();
362 } else {
363 maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
364 minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
365 }
366 if (snapPos > maxExtent)
367 snapPos = maxExtent;
368 if (snapPos < minExtent)
369 snapPos = minExtent;
370 }
371 return snapPos;
372 }
373
snapItemAt(qreal pos)374 FxGridItem *snapItemAt(qreal pos) {
375 for (int i = 0; i < visibleItems.count(); ++i) {
376 FxGridItem *item = visibleItems[i];
377 if (item->index == -1)
378 continue;
379 qreal itemTop = item->rowPos();
380 if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
381 return item;
382 }
383 return 0;
384 }
385
snapIndex()386 int snapIndex() {
387 int index = currentIndex;
388 for (int i = 0; i < visibleItems.count(); ++i) {
389 FxGridItem *item = visibleItems[i];
390 if (item->index == -1)
391 continue;
392 qreal itemTop = item->rowPos();
393 if (itemTop >= highlight->rowPos()-rowSize()/2 && itemTop < highlight->rowPos()+rowSize()/2) {
394 index = item->index;
395 if (item->colPos() >= highlight->colPos()-colSize()/2 && item->colPos() < highlight->colPos()+colSize()/2)
396 return item->index;
397 }
398 }
399 return index;
400 }
401
headerSize() const402 qreal headerSize() const {
403 if (!header)
404 return 0.0;
405
406 return flow == QDeclarativeGridView::LeftToRight
407 ? header->item->height()
408 : header->item->width();
409 }
410
411
itemGeometryChanged(QDeclarativeItem * item,const QRectF & newGeometry,const QRectF & oldGeometry)412 virtual void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
413 Q_Q(const QDeclarativeGridView);
414 QDeclarativeFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
415 if (item == q) {
416 if (newGeometry.height() != oldGeometry.height()
417 || newGeometry.width() != oldGeometry.width()) {
418 if (q->isComponentComplete()) {
419 updateGrid();
420 scheduleLayout();
421 }
422 }
423 } else if ((header && header->item == item) || (footer && footer->item == item)) {
424 if (header)
425 updateHeader();
426 if (footer)
427 updateFooter();
428 }
429 }
430
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);
435
436 // for debugging only
checkVisible() const437 void checkVisible() const {
438 int skip = 0;
439 for (int i = 0; i < visibleItems.count(); ++i) {
440 FxGridItem *listItem = visibleItems.at(i);
441 if (listItem->index == -1) {
442 ++skip;
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);
447 }
448 }
449 }
450
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;
458 int visibleIndex;
459 int currentIndex;
460 int cellWidth;
461 int cellHeight;
462 int columns;
463 int requestedIndex;
464 int itemCount;
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;
475 int buffer;
476 QSmoothedAnimation *highlightXAnimator;
477 QSmoothedAnimation *highlightYAnimator;
478 int highlightMoveDuration;
479 QDeclarativeComponent *footerComponent;
480 FxGridItem *footer;
481 QDeclarativeComponent *headerComponent;
482 FxGridItem *header;
483 enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
484 int bufferMode;
485 QDeclarativeGridView::SnapMode snapMode;
486
487 bool ownModel : 1;
488 bool wrap : 1;
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;
496 };
497
init()498 void QDeclarativeGridViewPrivate::init()
499 {
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);
505 }
506
clear()507 void QDeclarativeGridViewPrivate::clear()
508 {
509 for (int i = 0; i < visibleItems.count(); ++i)
510 releaseItem(visibleItems.at(i));
511 visibleItems.clear();
512 visibleIndex = 0;
513 releaseItem(currentItem);
514 currentItem = 0;
515 createHighlight();
516 trackedItem = 0;
517 itemCount = 0;
518 }
519
createItem(int modelIndex)520 FxGridItem *QDeclarativeGridViewPrivate::createItem(int modelIndex)
521 {
522 Q_Q(QDeclarativeGridView);
523 // create object
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()) {
530 // complete
531 listItem->item->setZValue(1);
532 listItem->item->setParentItem(q->contentItem());
533 model->completeItem();
534 } else {
535 listItem->item->setParentItem(q->contentItem());
536 }
537 unrequestedItems.remove(listItem->item);
538 }
539 requestedIndex = -1;
540 return listItem;
541 }
542
543
releaseItem(FxGridItem * item)544 void QDeclarativeGridViewPrivate::releaseItem(FxGridItem *item)
545 {
546 Q_Q(QDeclarativeGridView);
547 if (!item || !model)
548 return;
549 if (trackedItem == item) {
550 QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
551 QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
552 trackedItem = 0;
553 }
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));
557 }
558 delete item;
559 }
560
createComponentItem(QDeclarativeComponent * component)561 QDeclarativeItem *QDeclarativeGridViewPrivate::createComponentItem(QDeclarativeComponent *component)
562 {
563 Q_Q(QDeclarativeGridView);
564 QDeclarativeItem *item = 0;
565 QDeclarativeContext *creationContext = component->creationContext();
566 QDeclarativeContext *context = new QDeclarativeContext(
567 creationContext ? creationContext : qmlContext(q));
568 QObject *nobj = component->create(context);
569 if (nobj) {
570 QDeclarative_setParent_noEvent(context, nobj);
571 item = qobject_cast<QDeclarativeItem *>(nobj);
572 if (!item)
573 delete nobj;
574 } else {
575 delete context;
576 }
577
578 return item;
579 }
580
refill(qreal from,qreal to,bool doBuffer)581 void QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer)
582 {
583 Q_Q(QDeclarativeGridView);
584 if (!isValid() || !q->isComponentComplete())
585 return;
586 itemCount = model->count();
587 qreal bufferFrom = from - buffer;
588 qreal bufferTo = to + buffer;
589 qreal fillFrom = from;
590 qreal fillTo = to;
591 if (doBuffer && (bufferMode & BufferAfter))
592 fillTo = bufferTo;
593 if (doBuffer && (bufferMode & BufferBefore))
594 fillFrom = bufferFrom;
595
596 bool changed = false;
597
598 int colPos = colPosAt(visibleIndex);
599 int rowPos = rowPosAt(visibleIndex);
600 int modelIndex = visibleIndex;
601 if (visibleItems.count()) {
602 rowPos = visibleItems.last()->rowPos();
603 colPos = visibleItems.last()->colPos() + colSize();
604 if (colPos > colSize() * (columns-1)) {
605 colPos = 0;
606 rowPos += rowSize();
607 }
608 int i = visibleItems.count() - 1;
609 while (i > 0 && visibleItems.at(i)->index == -1)
610 --i;
611 modelIndex = visibleItems.at(i)->index + 1;
612 }
613
614 if (visibleItems.count() && (fillFrom > rowPos + rowSize()*2
615 || fillTo < rowPosAt(visibleIndex) - rowSize())) {
616 // We've jumped more than a page. Estimate which items are now
617 // visible and fill from there.
618 int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
619 for (int i = 0; i < visibleItems.count(); ++i)
620 releaseItem(visibleItems.at(i));
621 visibleItems.clear();
622 modelIndex += count;
623 if (modelIndex >= model->count())
624 modelIndex = model->count() - 1;
625 else if (modelIndex < 0)
626 modelIndex = 0;
627 modelIndex = modelIndex / columns * columns;
628 visibleIndex = modelIndex;
629 colPos = colPosAt(visibleIndex);
630 rowPos = rowPosAt(visibleIndex);
631 }
632
633 int colNum = colPos / colSize();
634
635 FxGridItem *item = 0;
636
637 // Item creation and release is staggered in order to avoid
638 // creating/releasing multiple items in one frame
639 // while flicking (as much as possible).
640 while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
641 // qDebug() << "refill: append item" << modelIndex;
642 if (!(item = createItem(modelIndex)))
643 break;
644 item->setPosition(colPos, rowPos);
645 visibleItems.append(item);
646 colPos += colSize();
647 colNum++;
648 if (colPos > colSize() * (columns-1)) {
649 colPos = 0;
650 colNum = 0;
651 rowPos += rowSize();
652 }
653 ++modelIndex;
654 changed = true;
655 if (doBuffer) // never buffer more than one item per frame
656 break;
657 }
658
659 if (visibleItems.count()) {
660 rowPos = visibleItems.first()->rowPos();
661 colPos = visibleItems.first()->colPos() - colSize();
662 if (colPos < 0) {
663 colPos = colSize() * (columns - 1);
664 rowPos -= rowSize();
665 }
666 }
667 colNum = colPos / colSize();
668 while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
669 // qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
670 if (!(item = createItem(visibleIndex-1)))
671 break;
672 --visibleIndex;
673 item->setPosition(colPos, rowPos);
674 visibleItems.prepend(item);
675 colPos -= colSize();
676 colNum--;
677 if (colPos < 0) {
678 colPos = colSize() * (columns - 1);
679 colNum = columns-1;
680 rowPos -= rowSize();
681 }
682 changed = true;
683 if (doBuffer) // never buffer more than one item per frame
684 break;
685 }
686
687 if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
688 while (visibleItems.count() > 1
689 && (item = visibleItems.first())
690 && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
691 if (item->attached->delayRemove())
692 break;
693 // qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
694 if (item->index != -1)
695 visibleIndex++;
696 visibleItems.removeFirst();
697 releaseItem(item);
698 changed = true;
699 }
700 while (visibleItems.count() > 1
701 && (item = visibleItems.last())
702 && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
703 if (item->attached->delayRemove())
704 break;
705 // qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
706 visibleItems.removeLast();
707 releaseItem(item);
708 changed = true;
709 }
710 deferredRelease = false;
711 } else {
712 deferredRelease = true;
713 }
714 if (changed) {
715 if (header)
716 updateHeader();
717 if (footer)
718 updateFooter();
719 if (flow == QDeclarativeGridView::LeftToRight)
720 q->setContentHeight(endPosition() - startPosition());
721 else
722 q->setContentWidth(endPosition() - startPosition());
723 } else if (!doBuffer && buffer && bufferMode != NoBuffer) {
724 refill(from, to, true);
725 }
726 lazyRelease = false;
727 }
728
updateGrid()729 void QDeclarativeGridViewPrivate::updateGrid()
730 {
731 Q_Q(QDeclarativeGridView);
732
733 columns = (int)qMax((flow == QDeclarativeGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.));
734 if (isValid()) {
735 if (flow == QDeclarativeGridView::LeftToRight)
736 q->setContentHeight(endPosition() - startPosition());
737 else
738 q->setContentWidth(lastPosition() - originPosition());
739 }
740 }
741
scheduleLayout()742 void QDeclarativeGridViewPrivate::scheduleLayout()
743 {
744 Q_Q(QDeclarativeGridView);
745 if (!layoutScheduled) {
746 layoutScheduled = true;
747 QCoreApplication::postEvent(q, new QEvent(QEvent::User), Qt::HighEventPriority);
748 }
749 }
750
layout()751 void QDeclarativeGridViewPrivate::layout()
752 {
753 Q_Q(QDeclarativeGridView);
754 layoutScheduled = false;
755 if (!isValid() && !visibleItems.count()) {
756 clear();
757 return;
758 }
759 if (visibleItems.count()) {
760 qreal rowPos = visibleItems.first()->rowPos();
761 qreal colPos = visibleItems.first()->colPos();
762 int col = visibleIndex % columns;
763 if (colPos != col * colSize()) {
764 colPos = col * colSize();
765 visibleItems.first()->setPosition(colPos, rowPos);
766 }
767 for (int i = 1; i < visibleItems.count(); ++i) {
768 FxGridItem *item = visibleItems.at(i);
769 colPos += colSize();
770 if (colPos > colSize() * (columns-1)) {
771 colPos = 0;
772 rowPos += rowSize();
773 }
774 item->setPosition(colPos, rowPos);
775 }
776 }
777 if (header)
778 updateHeader();
779 if (footer)
780 updateFooter();
781 q->refill();
782 updateHighlight();
783 moveReason = Other;
784 if (flow == QDeclarativeGridView::LeftToRight) {
785 q->setContentHeight(endPosition() - startPosition());
786 fixupY();
787 } else {
788 q->setContentWidth(endPosition() - startPosition());
789 fixupX();
790 }
791 updateUnrequestedPositions();
792 }
793
updateUnrequestedIndexes()794 void QDeclarativeGridViewPrivate::updateUnrequestedIndexes()
795 {
796 Q_Q(QDeclarativeGridView);
797 QHash<QDeclarativeItem*,int>::iterator it;
798 for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
799 *it = model->indexOf(it.key(), q);
800 }
801
updateUnrequestedPositions()802 void QDeclarativeGridViewPrivate::updateUnrequestedPositions()
803 {
804 QHash<QDeclarativeItem*,int>::const_iterator it;
805 for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
806 QDeclarativeItem *item = it.key();
807 if (flow == QDeclarativeGridView::LeftToRight) {
808 item->setPos(QPointF(colPosAt(*it), rowPosAt(*it)));
809 } else {
810 if (isRightToLeftTopToBottom())
811 item->setPos(QPointF(-rowPosAt(*it)-item->width(), colPosAt(*it)));
812 else
813 item->setPos(QPointF(rowPosAt(*it), colPosAt(*it)));
814 }
815 }
816 }
817
updateTrackedItem()818 void QDeclarativeGridViewPrivate::updateTrackedItem()
819 {
820 Q_Q(QDeclarativeGridView);
821 FxGridItem *item = currentItem;
822 if (highlight)
823 item = highlight;
824
825 if (trackedItem && item != trackedItem) {
826 QObject::disconnect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
827 QObject::disconnect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
828 trackedItem = 0;
829 }
830
831 if (!trackedItem && item) {
832 trackedItem = item;
833 QObject::connect(trackedItem->item, SIGNAL(yChanged()), q, SLOT(trackedPositionChanged()));
834 QObject::connect(trackedItem->item, SIGNAL(xChanged()), q, SLOT(trackedPositionChanged()));
835 }
836 if (trackedItem)
837 q->trackedPositionChanged();
838 }
839
createHighlight()840 void QDeclarativeGridViewPrivate::createHighlight()
841 {
842 Q_Q(QDeclarativeGridView);
843 bool changed = false;
844 if (highlight) {
845 if (trackedItem == highlight)
846 trackedItem = 0;
847 if (highlight->item->scene())
848 highlight->item->scene()->removeItem(highlight->item);
849 highlight->item->deleteLater();
850 delete highlight;
851 highlight = 0;
852 delete highlightXAnimator;
853 delete highlightYAnimator;
854 highlightXAnimator = 0;
855 highlightYAnimator = 0;
856 changed = true;
857 }
858
859 if (currentItem) {
860 QDeclarativeItem *item = 0;
861 if (highlightComponent) {
862 item = createComponentItem(highlightComponent);
863 } else {
864 item = new QDeclarativeItem;
865 QDeclarative_setParent_noEvent(item, q->contentItem());
866 item->setParentItem(q->contentItem());
867 }
868 if (item) {
869 QDeclarative_setParent_noEvent(item, q->contentItem());
870 item->setParentItem(q->contentItem());
871 highlight = new FxGridItem(item, q);
872 if (currentItem && autoHighlight)
873 highlight->setPosition(currentItem->colPos(), currentItem->rowPos());
874 highlightXAnimator = new QSmoothedAnimation(q);
875 highlightXAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("x"));
876 highlightXAnimator->userDuration = highlightMoveDuration;
877 highlightYAnimator = new QSmoothedAnimation(q);
878 highlightYAnimator->target = QDeclarativeProperty(highlight->item, QLatin1String("y"));
879 highlightYAnimator->userDuration = highlightMoveDuration;
880 if (autoHighlight) {
881 highlightXAnimator->restart();
882 highlightYAnimator->restart();
883 }
884 changed = true;
885 }
886 }
887 if (changed)
888 emit q->highlightItemChanged();
889 }
890
updateHighlight()891 void QDeclarativeGridViewPrivate::updateHighlight()
892 {
893 if ((!currentItem && highlight) || (currentItem && !highlight))
894 createHighlight();
895 if (currentItem && autoHighlight && highlight && !hData.moving && !vData.moving) {
896 // auto-update highlight
897 highlightXAnimator->to = currentItem->item->x();
898 highlightYAnimator->to = currentItem->item->y();
899 highlight->item->setWidth(currentItem->item->width());
900 highlight->item->setHeight(currentItem->item->height());
901 highlightXAnimator->restart();
902 highlightYAnimator->restart();
903 }
904 updateTrackedItem();
905 }
906
updateCurrent(int modelIndex)907 void QDeclarativeGridViewPrivate::updateCurrent(int modelIndex)
908 {
909 Q_Q(QDeclarativeGridView);
910 if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
911 if (currentItem) {
912 currentItem->attached->setIsCurrentItem(false);
913 releaseItem(currentItem);
914 currentItem = 0;
915 currentIndex = modelIndex;
916 emit q->currentIndexChanged();
917 updateHighlight();
918 } else if (currentIndex != modelIndex) {
919 currentIndex = modelIndex;
920 emit q->currentIndexChanged();
921 }
922 return;
923 }
924
925 if (currentItem && currentIndex == modelIndex) {
926 updateHighlight();
927 return;
928 }
929
930 FxGridItem *oldCurrentItem = currentItem;
931 currentIndex = modelIndex;
932 currentItem = createItem(modelIndex);
933 fixCurrentVisibility = true;
934 if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
935 oldCurrentItem->attached->setIsCurrentItem(false);
936 if (currentItem) {
937 currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex));
938 currentItem->item->setFocus(true);
939 currentItem->attached->setIsCurrentItem(true);
940 }
941 updateHighlight();
942 emit q->currentIndexChanged();
943 releaseItem(oldCurrentItem);
944 }
945
updateFooter()946 void QDeclarativeGridViewPrivate::updateFooter()
947 {
948 Q_Q(QDeclarativeGridView);
949 if (!footer && footerComponent) {
950 QDeclarativeItem *item = createComponentItem(footerComponent);
951 if (item) {
952 QDeclarative_setParent_noEvent(item, q->contentItem());
953 item->setParentItem(q->contentItem());
954 item->setZValue(1);
955 QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
956 itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
957 footer = new FxGridItem(item, q);
958 }
959 }
960 if (footer) {
961 qreal colOffset = 0;
962 qreal rowOffset;
963 if (isRightToLeftTopToBottom()) {
964 rowOffset = footer->item->width()-cellWidth;
965 } else {
966 rowOffset = 0;
967 if (q->effectiveLayoutDirection() == Qt::RightToLeft)
968 colOffset = footer->item->width()-cellWidth;
969 }
970 if (visibleItems.count()) {
971 qreal endPos = lastPosition();
972 if (lastVisibleIndex() == model->count()-1) {
973 footer->setPosition(colOffset, endPos + rowOffset);
974 } else {
975 qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size();
976 if (endPos <= visiblePos || footer->endRowPos() < endPos + rowOffset)
977 footer->setPosition(colOffset, endPos + rowOffset);
978 }
979 } else {
980 qreal endPos = 0;
981 if (header) {
982 endPos += flow == QDeclarativeGridView::LeftToRight ? header->item->height() : header->item->width();
983 }
984 footer->setPosition(colOffset, endPos);
985 }
986 }
987 }
988
updateHeader()989 void QDeclarativeGridViewPrivate::updateHeader()
990 {
991 Q_Q(QDeclarativeGridView);
992 if (!header && headerComponent) {
993 QDeclarativeItem *item = createComponentItem(headerComponent);
994 if (item) {
995 QDeclarative_setParent_noEvent(item, q->contentItem());
996 item->setParentItem(q->contentItem());
997 item->setZValue(1);
998 QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
999 itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
1000 header = new FxGridItem(item, q);
1001 }
1002 }
1003 if (header) {
1004 qreal colOffset = 0;
1005 qreal rowOffset;
1006 if (isRightToLeftTopToBottom()) {
1007 rowOffset = -cellWidth;
1008 } else {
1009 rowOffset = -headerSize();
1010 if (q->effectiveLayoutDirection() == Qt::RightToLeft)
1011 colOffset = header->item->width()-cellWidth;
1012 }
1013 if (visibleItems.count()) {
1014 qreal startPos = originPosition();
1015 if (visibleIndex == 0) {
1016 header->setPosition(colOffset, startPos + rowOffset);
1017 } else {
1018 qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position();
1019 qreal headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
1020 if (tempPos <= startPos || headerPos > startPos + rowOffset)
1021 header->setPosition(colOffset, startPos + rowOffset);
1022 }
1023 } else {
1024 header->setPosition(colOffset, 0);
1025 }
1026 }
1027 }
1028
fixupPosition()1029 void QDeclarativeGridViewPrivate::fixupPosition()
1030 {
1031 moveReason = Other;
1032 if (flow == QDeclarativeGridView::LeftToRight)
1033 fixupY();
1034 else
1035 fixupX();
1036 }
1037
fixup(AxisData & data,qreal minExtent,qreal maxExtent)1038 void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
1039 {
1040 if ((flow == QDeclarativeGridView::TopToBottom && &data == &vData)
1041 || (flow == QDeclarativeGridView::LeftToRight && &data == &hData))
1042 return;
1043
1044 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1045
1046 qreal highlightStart;
1047 qreal highlightEnd;
1048 qreal viewPos;
1049 if (isRightToLeftTopToBottom()) {
1050 // Handle Right-To-Left exceptions
1051 viewPos = -position()-size();
1052 highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
1053 highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd;
1054 } else {
1055 viewPos = position();
1056 highlightStart = highlightRangeStart;
1057 highlightEnd = highlightRangeEnd;
1058 }
1059
1060 bool strictHighlightRange = haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange;
1061
1062 if (snapMode != QDeclarativeGridView::NoSnap) {
1063 qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
1064 if (snapMode == QDeclarativeGridView::SnapOneRow && moveReason == Mouse) {
1065 // if we've been dragged < rowSize()/2 then bias towards the next row
1066 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1067 qreal bias = 0;
1068 if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < rowSize()/2)
1069 bias = rowSize()/2;
1070 else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -rowSize()/2)
1071 bias = -rowSize()/2;
1072 if (isRightToLeftTopToBottom())
1073 bias = -bias;
1074 tempPosition -= bias;
1075 }
1076 FxGridItem *topItem = snapItemAt(tempPosition+highlightStart);
1077 if (!topItem && strictHighlightRange && currentItem) {
1078 // StrictlyEnforceRange always keeps an item in range
1079 updateHighlight();
1080 topItem = currentItem;
1081 }
1082 FxGridItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
1083 if (!bottomItem && strictHighlightRange && currentItem) {
1084 // StrictlyEnforceRange always keeps an item in range
1085 updateHighlight();
1086 bottomItem = currentItem;
1087 }
1088 qreal pos;
1089 bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1090 if (topItem && (isInBounds || strictHighlightRange)) {
1091 if (topItem->index == 0 && header && tempPosition+highlightStart < header->rowPos()+headerSize()/2 && !strictHighlightRange) {
1092 pos = isRightToLeftTopToBottom() ? - header->rowPos() + highlightStart - size() : header->rowPos() - highlightStart;
1093 } else {
1094 if (isRightToLeftTopToBottom())
1095 pos = qMax(qMin(-topItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
1096 else
1097 pos = qMax(qMin(topItem->rowPos() - highlightStart, -maxExtent), -minExtent);
1098 }
1099 } else if (bottomItem && isInBounds) {
1100 if (isRightToLeftTopToBottom())
1101 pos = qMax(qMin(-bottomItem->rowPos() + highlightEnd - size(), -maxExtent), -minExtent);
1102 else
1103 pos = qMax(qMin(bottomItem->rowPos() - highlightEnd, -maxExtent), -minExtent);
1104 } else {
1105 QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
1106 return;
1107 }
1108 qreal dist = qAbs(data.move + pos);
1109 if (dist > 0) {
1110 timeline.reset(data.move);
1111 if (fixupMode != Immediate) {
1112 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1113 data.fixingUp = true;
1114 } else {
1115 timeline.set(data.move, -pos);
1116 }
1117 vTime = timeline.time();
1118 }
1119 } else if (haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) {
1120 if (currentItem) {
1121 updateHighlight();
1122 qreal pos = currentItem->rowPos();
1123 if (viewPos < pos + rowSize() - highlightEnd)
1124 viewPos = pos + rowSize() - highlightEnd;
1125 if (viewPos > pos - highlightStart)
1126 viewPos = pos - highlightStart;
1127 if (isRightToLeftTopToBottom())
1128 viewPos = -viewPos-size();
1129 timeline.reset(data.move);
1130 if (viewPos != position()) {
1131 if (fixupMode != Immediate) {
1132 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1133 data.fixingUp = true;
1134 } else {
1135 timeline.set(data.move, -viewPos);
1136 }
1137 }
1138 vTime = timeline.time();
1139 }
1140 } else {
1141 QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
1142 }
1143 data.inOvershoot = false;
1144 fixupMode = Normal;
1145 }
1146
flick(AxisData & data,qreal minExtent,qreal maxExtent,qreal vSize,QDeclarativeTimeLineCallback::Callback fixupCallback,qreal velocity)1147 void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
1148 QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
1149 {
1150 Q_Q(QDeclarativeGridView);
1151 data.fixingUp = false;
1152 moveReason = Mouse;
1153 if ((!haveHighlightRange || highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1154 && snapMode == QDeclarativeGridView::NoSnap) {
1155 QDeclarativeFlickablePrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
1156 return;
1157 }
1158 qreal maxDistance = 0;
1159 qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value();
1160 // -ve velocity means list is moving up/left
1161 if (velocity > 0) {
1162 if (data.move.value() < minExtent) {
1163 if (snapMode == QDeclarativeGridView::SnapOneRow) {
1164 // if we've been dragged < averageSize/2 then bias towards the next item
1165 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1166 qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0;
1167 if (isRightToLeftTopToBottom())
1168 bias = -bias;
1169 data.flickTarget = -snapPosAt(-dataValue - bias);
1170 maxDistance = qAbs(data.flickTarget - data.move.value());
1171 velocity = maxVelocity;
1172 } else {
1173 maxDistance = qAbs(minExtent - data.move.value());
1174 }
1175 }
1176 if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1177 data.flickTarget = minExtent;
1178 } else {
1179 if (data.move.value() > maxExtent) {
1180 if (snapMode == QDeclarativeGridView::SnapOneRow) {
1181 // if we've been dragged < averageSize/2 then bias towards the next item
1182 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
1183 qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0;
1184 if (isRightToLeftTopToBottom())
1185 bias = -bias;
1186 data.flickTarget = -snapPosAt(-dataValue + bias);
1187 maxDistance = qAbs(data.flickTarget - data.move.value());
1188 velocity = -maxVelocity;
1189 } else {
1190 maxDistance = qAbs(maxExtent - data.move.value());
1191 }
1192 }
1193 if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
1194 data.flickTarget = maxExtent;
1195 }
1196
1197 bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds;
1198
1199 if (maxDistance > 0 || overShoot) {
1200 // This mode requires the grid to stop exactly on a row boundary.
1201 qreal v = velocity;
1202 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1203 if (v < 0)
1204 v = -maxVelocity;
1205 else
1206 v = maxVelocity;
1207 }
1208 qreal accel = deceleration;
1209 qreal v2 = v * v;
1210 qreal overshootDist = qreal(0.0);
1211 if ((maxDistance > qreal(0.0) && v2 / (2.0f * maxDistance) < accel) || snapMode == QDeclarativeGridView::SnapOneRow) {
1212 // + rowSize()/4 to encourage moving at least one item in the flick direction
1213 qreal dist = v2 / (accel * qreal(2.0)) + rowSize()/4;
1214 dist = qMin(dist, maxDistance);
1215 if (v > 0)
1216 dist = -dist;
1217 if (snapMode != QDeclarativeGridView::SnapOneRow) {
1218 qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
1219 data.flickTarget = -snapPosAt(-dataValue + distTemp);
1220 }
1221 data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
1222 if (overShoot) {
1223 if (data.flickTarget >= minExtent) {
1224 overshootDist = overShootDistance(vSize);
1225 data.flickTarget += overshootDist;
1226 } else if (data.flickTarget <= maxExtent) {
1227 overshootDist = overShootDistance(vSize);
1228 data.flickTarget -= overshootDist;
1229 }
1230 }
1231 qreal adjDist = -data.flickTarget + data.move.value();
1232 if (qAbs(adjDist) > qAbs(dist)) {
1233 // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
1234 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1235 if (adjv2 > v2) {
1236 v2 = adjv2;
1237 v = qSqrt(v2);
1238 if (dist > 0)
1239 v = -v;
1240 }
1241 }
1242 dist = adjDist;
1243 accel = v2 / (2.0f * qAbs(dist));
1244 } else {
1245 data.flickTarget = velocity > 0 ? minExtent : maxExtent;
1246 overshootDist = overShoot ? overShootDistance(vSize) : 0;
1247 }
1248 timeline.reset(data.move);
1249 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
1250 timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
1251 if (!hData.flicking && q->xflick()) {
1252 hData.flicking = true;
1253 emit q->flickingChanged();
1254 emit q->flickingHorizontallyChanged();
1255 emit q->flickStarted();
1256 }
1257 if (!vData.flicking && q->yflick()) {
1258 vData.flicking = true;
1259 emit q->flickingChanged();
1260 emit q->flickingVerticallyChanged();
1261 emit q->flickStarted();
1262 }
1263 } else {
1264 timeline.reset(data.move);
1265 fixup(data, minExtent, maxExtent);
1266 }
1267 }
1268
1269
1270 //----------------------------------------------------------------------------
1271
1272 /*!
1273 \qmlclass GridView QDeclarativeGridView
1274 \since 4.7
1275 \ingroup qml-view-elements
1276
1277 \inherits Flickable
1278 \brief The GridView item provides a grid view of items provided by a model.
1279
1280 A GridView displays data from models created from built-in QML elements like ListModel
1281 and XmlListModel, or custom model classes defined in C++ that inherit from
1282 QAbstractListModel.
1283
1284 A GridView has a \l model, which defines the data to be displayed, and
1285 a \l delegate, which defines how the data should be displayed. Items in a
1286 GridView are laid out horizontally or vertically. Grid views are inherently flickable
1287 as GridView inherits from \l Flickable.
1288
1289 \section1 Example Usage
1290
1291 The following example shows the definition of a simple list model defined
1292 in a file called \c ContactModel.qml:
1293
1294 \snippet doc/src/snippets/declarative/gridview/ContactModel.qml 0
1295
1296 \div {class="float-right"}
1297 \inlineimage gridview-simple.png
1298 \enddiv
1299
1300 This model can be referenced as \c ContactModel in other QML files. See \l{QML Modules}
1301 for more information about creating reusable components like this.
1302
1303 Another component can display this model data in a GridView, as in the following
1304 example, which creates a \c ContactModel component for its model, and a \l Column element
1305 (containing \l Image and \l Text elements) for its delegate.
1306
1307 \clearfloat
1308 \snippet doc/src/snippets/declarative/gridview/gridview.qml import
1309 \codeline
1310 \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs simple
1311
1312 \div {class="float-right"}
1313 \inlineimage gridview-highlight.png
1314 \enddiv
1315
1316 The view will create a new delegate for each item in the model. Note that the delegate
1317 is able to access the model's \c name and \c portrait data directly.
1318
1319 An improved grid view is shown below. The delegate is visually improved and is moved
1320 into a separate \c contactDelegate component.
1321
1322 \clearfloat
1323 \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs advanced
1324
1325 The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
1326 and \c focus is set to \c true to enable keyboard navigation for the grid view.
1327 The grid view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details).
1328
1329 Delegates are instantiated as needed and may be destroyed at any time.
1330 State should \e never be stored in a delegate.
1331
1332 GridView attaches a number of properties to the root item of the delegate, for example
1333 \c {GridView.isCurrentItem}. In the following example, the root delegate item can access
1334 this attached property directly as \c GridView.isCurrentItem, while the child
1335 \c contactInfo object must refer to this property as \c wrapper.GridView.isCurrentItem.
1336
1337 \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem
1338
1339 \note Views do not set the \l{Item::}{clip} property automatically.
1340 If the view is not clipped by another item or the screen, it will be necessary
1341 to set this property to true in order to clip the items that are partially or
1342 fully outside the view.
1343
1344 \sa {declarative/modelviews/gridview}{GridView example}
1345 */
QDeclarativeGridView(QDeclarativeItem * parent)1346 QDeclarativeGridView::QDeclarativeGridView(QDeclarativeItem *parent)
1347 : QDeclarativeFlickable(*(new QDeclarativeGridViewPrivate), parent)
1348 {
1349 Q_D(QDeclarativeGridView);
1350 d->init();
1351 }
1352
~QDeclarativeGridView()1353 QDeclarativeGridView::~QDeclarativeGridView()
1354 {
1355 Q_D(QDeclarativeGridView);
1356 d->clear();
1357 if (d->ownModel)
1358 delete d->model;
1359 delete d->header;
1360 delete d->footer;
1361 }
1362
1363 /*!
1364 \qmlattachedproperty bool GridView::isCurrentItem
1365 This attached property is true if this delegate is the current item; otherwise false.
1366
1367 It is attached to each instance of the delegate.
1368 */
1369
1370 /*!
1371 \qmlattachedproperty GridView GridView::view
1372 This attached property holds the view that manages this delegate instance.
1373
1374 It is attached to each instance of the delegate.
1375
1376 \snippet doc/src/snippets/declarative/gridview/gridview.qml isCurrentItem
1377 */
1378
1379 /*!
1380 \qmlattachedproperty bool GridView::delayRemove
1381 This attached property holds whether the delegate may be destroyed.
1382
1383 It is attached to each instance of the delegate.
1384
1385 It is sometimes necessary to delay the destruction of an item
1386 until an animation completes.
1387
1388 The example below ensures that the animation completes before
1389 the item is removed from the grid.
1390
1391 \snippet doc/src/snippets/declarative/gridview/gridview.qml delayRemove
1392 */
1393
1394 /*!
1395 \qmlattachedsignal GridView::onAdd()
1396 This attached handler is called immediately after an item is added to the view.
1397 */
1398
1399 /*!
1400 \qmlattachedsignal GridView::onRemove()
1401 This attached handler is called immediately before an item is removed from the view.
1402 */
1403
1404
1405 /*!
1406 \qmlproperty model GridView::model
1407 This property holds the model providing data for the grid.
1408
1409 The model provides the set of data that is used to create the items
1410 in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
1411 or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
1412 used, it must be a subclass of \l QAbstractItemModel or a simple list.
1413
1414 \sa {qmlmodels}{Data Models}
1415 */
model() const1416 QVariant QDeclarativeGridView::model() const
1417 {
1418 Q_D(const QDeclarativeGridView);
1419 return d->modelVariant;
1420 }
1421
1422 // For internal use
modelCount() const1423 int QDeclarativeGridView::modelCount() const
1424 {
1425 Q_D(const QDeclarativeGridView);
1426 return d->model->count();
1427 }
1428
setModel(const QVariant & model)1429 void QDeclarativeGridView::setModel(const QVariant &model)
1430 {
1431 Q_D(QDeclarativeGridView);
1432 if (d->modelVariant == model)
1433 return;
1434 if (d->model) {
1435 disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1436 disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1437 disconnect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1438 disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1439 disconnect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
1440 disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
1441 }
1442 d->clear();
1443 d->modelVariant = model;
1444 QObject *object = qvariant_cast<QObject*>(model);
1445 QDeclarativeVisualModel *vim = 0;
1446 if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
1447 if (d->ownModel) {
1448 delete d->model;
1449 d->ownModel = false;
1450 }
1451 d->model = vim;
1452 } else {
1453 if (!d->ownModel) {
1454 d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
1455 d->ownModel = true;
1456 }
1457 if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
1458 dataModel->setModel(model);
1459 }
1460 if (d->model) {
1461 d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore | QDeclarativeGridViewPrivate::BufferAfter;
1462 if (isComponentComplete()) {
1463 refill();
1464 if ((d->currentIndex >= d->model->count() || d->currentIndex < 0) && !d->currentIndexCleared) {
1465 setCurrentIndex(0);
1466 } else {
1467 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1468 d->updateCurrent(d->currentIndex);
1469 if (d->highlight && d->currentItem) {
1470 if (d->autoHighlight)
1471 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1472 d->updateTrackedItem();
1473 }
1474 d->moveReason = QDeclarativeGridViewPrivate::Other;
1475 }
1476 }
1477 connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
1478 connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
1479 connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
1480 connect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
1481 connect(d->model, SIGNAL(createdItem(int,QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
1482 connect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
1483 emit countChanged();
1484 }
1485 emit modelChanged();
1486 }
1487
1488 /*!
1489 \qmlproperty Component GridView::delegate
1490
1491 The delegate provides a template defining each item instantiated by the view.
1492 The index is exposed as an accessible \c index property. Properties of the
1493 model are also available depending upon the type of \l {qmlmodels}{Data Model}.
1494
1495 The number of elements in the delegate has a direct effect on the
1496 flicking performance of the view. If at all possible, place functionality
1497 that is not needed for the normal display of the delegate in a \l Loader which
1498 can load additional elements when needed.
1499
1500 The GridView will layout the items based on the size of the root item
1501 in the delegate.
1502
1503 \note Delegates are instantiated as needed and may be destroyed at any time.
1504 State should \e never be stored in a delegate.
1505 */
delegate() const1506 QDeclarativeComponent *QDeclarativeGridView::delegate() const
1507 {
1508 Q_D(const QDeclarativeGridView);
1509 if (d->model) {
1510 if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
1511 return dataModel->delegate();
1512 }
1513
1514 return 0;
1515 }
1516
setDelegate(QDeclarativeComponent * delegate)1517 void QDeclarativeGridView::setDelegate(QDeclarativeComponent *delegate)
1518 {
1519 Q_D(QDeclarativeGridView);
1520 if (delegate == this->delegate())
1521 return;
1522
1523 if (!d->ownModel) {
1524 d->model = new QDeclarativeVisualDataModel(qmlContext(this));
1525 d->ownModel = true;
1526 }
1527 if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model)) {
1528 int oldCount = dataModel->count();
1529 dataModel->setDelegate(delegate);
1530 if (isComponentComplete()) {
1531 for (int i = 0; i < d->visibleItems.count(); ++i)
1532 d->releaseItem(d->visibleItems.at(i));
1533 d->visibleItems.clear();
1534 d->releaseItem(d->currentItem);
1535 d->currentItem = 0;
1536 refill();
1537 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1538 d->updateCurrent(d->currentIndex);
1539 if (d->highlight && d->currentItem) {
1540 if (d->autoHighlight)
1541 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
1542 d->updateTrackedItem();
1543 }
1544 d->moveReason = QDeclarativeGridViewPrivate::Other;
1545 }
1546 if (oldCount != dataModel->count())
1547 emit countChanged();
1548 emit delegateChanged();
1549 }
1550 }
1551
1552 /*!
1553 \qmlproperty int GridView::currentIndex
1554 \qmlproperty Item GridView::currentItem
1555
1556 The \c currentIndex property holds the index of the current item, and
1557 \c currentItem holds the current item. Setting the currentIndex to -1
1558 will clear the highlight and set currentItem to null.
1559
1560 If highlightFollowsCurrentItem is \c true, setting either of these
1561 properties will smoothly scroll the GridView so that the current
1562 item becomes visible.
1563
1564 Note that the position of the current item
1565 may only be approximate until it becomes visible in the view.
1566 */
currentIndex() const1567 int QDeclarativeGridView::currentIndex() const
1568 {
1569 Q_D(const QDeclarativeGridView);
1570 return d->currentIndex;
1571 }
1572
setCurrentIndex(int index)1573 void QDeclarativeGridView::setCurrentIndex(int index)
1574 {
1575 Q_D(QDeclarativeGridView);
1576 if (d->requestedIndex >= 0) // currently creating item
1577 return;
1578 d->currentIndexCleared = (index == -1);
1579 if (index == d->currentIndex)
1580 return;
1581 if (isComponentComplete() && d->isValid()) {
1582 if (d->layoutScheduled)
1583 d->layout();
1584 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
1585 d->updateCurrent(index);
1586 } else {
1587 d->currentIndex = index;
1588 emit currentIndexChanged();
1589 }
1590 }
1591
currentItem()1592 QDeclarativeItem *QDeclarativeGridView::currentItem()
1593 {
1594 Q_D(QDeclarativeGridView);
1595 if (!d->currentItem)
1596 return 0;
1597 return d->currentItem->item;
1598 }
1599
1600 /*!
1601 \qmlproperty Item GridView::highlightItem
1602
1603 This holds the highlight item created from the \l highlight component.
1604
1605 The highlightItem is managed by the view unless
1606 \l highlightFollowsCurrentItem is set to false.
1607
1608 \sa highlight, highlightFollowsCurrentItem
1609 */
highlightItem()1610 QDeclarativeItem *QDeclarativeGridView::highlightItem()
1611 {
1612 Q_D(QDeclarativeGridView);
1613 if (!d->highlight)
1614 return 0;
1615 return d->highlight->item;
1616 }
1617
1618 /*!
1619 \qmlproperty int GridView::count
1620 This property holds the number of items in the view.
1621 */
count() const1622 int QDeclarativeGridView::count() const
1623 {
1624 Q_D(const QDeclarativeGridView);
1625 if (d->model)
1626 return d->model->count();
1627 return 0;
1628 }
1629
1630 /*!
1631 \qmlproperty Component GridView::highlight
1632 This property holds the component to use as the highlight.
1633
1634 An instance of the highlight component is created for each view.
1635 The geometry of the resulting component instance will be managed by the view
1636 so as to stay with the current item, unless the highlightFollowsCurrentItem property is false.
1637
1638 \sa highlightItem, highlightFollowsCurrentItem
1639 */
highlight() const1640 QDeclarativeComponent *QDeclarativeGridView::highlight() const
1641 {
1642 Q_D(const QDeclarativeGridView);
1643 return d->highlightComponent;
1644 }
1645
setHighlight(QDeclarativeComponent * highlight)1646 void QDeclarativeGridView::setHighlight(QDeclarativeComponent *highlight)
1647 {
1648 Q_D(QDeclarativeGridView);
1649 if (highlight != d->highlightComponent) {
1650 d->highlightComponent = highlight;
1651 d->updateCurrent(d->currentIndex);
1652 emit highlightChanged();
1653 }
1654 }
1655
1656 /*!
1657 \qmlproperty bool GridView::highlightFollowsCurrentItem
1658 This property sets whether the highlight is managed by the view.
1659
1660 If this property is true (the default value), the highlight is moved smoothly
1661 to follow the current item. Otherwise, the
1662 highlight is not moved by the view, and any movement must be implemented
1663 by the highlight.
1664
1665 Here is a highlight with its motion defined by a \l {SpringAnimation} item:
1666
1667 \snippet doc/src/snippets/declarative/gridview/gridview.qml highlightFollowsCurrentItem
1668 */
highlightFollowsCurrentItem() const1669 bool QDeclarativeGridView::highlightFollowsCurrentItem() const
1670 {
1671 Q_D(const QDeclarativeGridView);
1672 return d->autoHighlight;
1673 }
1674
setHighlightFollowsCurrentItem(bool autoHighlight)1675 void QDeclarativeGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
1676 {
1677 Q_D(QDeclarativeGridView);
1678 if (d->autoHighlight != autoHighlight) {
1679 d->autoHighlight = autoHighlight;
1680 if (autoHighlight) {
1681 d->updateHighlight();
1682 } else if (d->highlightXAnimator) {
1683 d->highlightXAnimator->stop();
1684 d->highlightYAnimator->stop();
1685 }
1686 }
1687 }
1688
1689 /*!
1690 \qmlproperty int GridView::highlightMoveDuration
1691 This property holds the move animation duration of the highlight delegate.
1692
1693 highlightFollowsCurrentItem must be true for this property
1694 to have effect.
1695
1696 The default value for the duration is 150ms.
1697
1698 \sa highlightFollowsCurrentItem
1699 */
highlightMoveDuration() const1700 int QDeclarativeGridView::highlightMoveDuration() const
1701 {
1702 Q_D(const QDeclarativeGridView);
1703 return d->highlightMoveDuration;
1704 }
1705
setHighlightMoveDuration(int duration)1706 void QDeclarativeGridView::setHighlightMoveDuration(int duration)
1707 {
1708 Q_D(QDeclarativeGridView);
1709 if (d->highlightMoveDuration != duration) {
1710 d->highlightMoveDuration = duration;
1711 if (d->highlightYAnimator) {
1712 d->highlightXAnimator->userDuration = d->highlightMoveDuration;
1713 d->highlightYAnimator->userDuration = d->highlightMoveDuration;
1714 }
1715 emit highlightMoveDurationChanged();
1716 }
1717 }
1718
1719
1720 /*!
1721 \qmlproperty real GridView::preferredHighlightBegin
1722 \qmlproperty real GridView::preferredHighlightEnd
1723 \qmlproperty enumeration GridView::highlightRangeMode
1724
1725 These properties define the preferred range of the highlight (for the current item)
1726 within the view. The \c preferredHighlightBegin value must be less than the
1727 \c preferredHighlightEnd value.
1728
1729 These properties affect the position of the current item when the view is scrolled.
1730 For example, if the currently selected item should stay in the middle of the
1731 view when it is scrolled, set the \c preferredHighlightBegin and
1732 \c preferredHighlightEnd values to the top and bottom coordinates of where the middle
1733 item would be. If the \c currentItem is changed programmatically, the view will
1734 automatically scroll so that the current item is in the middle of the view.
1735 Furthermore, the behavior of the current item index will occur whether or not a
1736 highlight exists.
1737
1738 Valid values for \c highlightRangeMode are:
1739
1740 \list
1741 \o GridView.ApplyRange - the view attempts to maintain the highlight within the range.
1742 However, the highlight can move outside of the range at the ends of the view or due
1743 to mouse interaction.
1744 \o GridView.StrictlyEnforceRange - the highlight never moves outside of the range.
1745 The current item changes if a keyboard or mouse action would cause the highlight to move
1746 outside of the range.
1747 \o GridView.NoHighlightRange - this is the default value.
1748 \endlist
1749 */
preferredHighlightBegin() const1750 qreal QDeclarativeGridView::preferredHighlightBegin() const
1751 {
1752 Q_D(const QDeclarativeGridView);
1753 return d->highlightRangeStart;
1754 }
1755
setPreferredHighlightBegin(qreal start)1756 void QDeclarativeGridView::setPreferredHighlightBegin(qreal start)
1757 {
1758 Q_D(QDeclarativeGridView);
1759 d->highlightRangeStartValid = true;
1760 if (d->highlightRangeStart == start)
1761 return;
1762 d->highlightRangeStart = start;
1763 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1764 emit preferredHighlightBeginChanged();
1765 }
1766
resetPreferredHighlightBegin()1767 void QDeclarativeGridView::resetPreferredHighlightBegin()
1768 {
1769 Q_D(QDeclarativeGridView);
1770 d->highlightRangeStartValid = false;
1771 if (d->highlightRangeStart == 0)
1772 return;
1773 d->highlightRangeStart = 0;
1774 emit preferredHighlightBeginChanged();
1775 }
1776
preferredHighlightEnd() const1777 qreal QDeclarativeGridView::preferredHighlightEnd() const
1778 {
1779 Q_D(const QDeclarativeGridView);
1780 return d->highlightRangeEnd;
1781 }
1782
setPreferredHighlightEnd(qreal end)1783 void QDeclarativeGridView::setPreferredHighlightEnd(qreal end)
1784 {
1785 Q_D(QDeclarativeGridView);
1786 d->highlightRangeEndValid = true;
1787 if (d->highlightRangeEnd == end)
1788 return;
1789 d->highlightRangeEnd = end;
1790 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1791 emit preferredHighlightEndChanged();
1792 }
1793
resetPreferredHighlightEnd()1794 void QDeclarativeGridView::resetPreferredHighlightEnd()
1795 {
1796 Q_D(QDeclarativeGridView);
1797 d->highlightRangeEndValid = false;
1798 if (d->highlightRangeEnd == 0)
1799 return;
1800 d->highlightRangeEnd = 0;
1801 emit preferredHighlightEndChanged();
1802 }
1803
highlightRangeMode() const1804 QDeclarativeGridView::HighlightRangeMode QDeclarativeGridView::highlightRangeMode() const
1805 {
1806 Q_D(const QDeclarativeGridView);
1807 return d->highlightRange;
1808 }
1809
setHighlightRangeMode(HighlightRangeMode mode)1810 void QDeclarativeGridView::setHighlightRangeMode(HighlightRangeMode mode)
1811 {
1812 Q_D(QDeclarativeGridView);
1813 if (d->highlightRange == mode)
1814 return;
1815 d->highlightRange = mode;
1816 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
1817 emit highlightRangeModeChanged();
1818 }
1819
1820 /*!
1821 \qmlproperty enumeration GridView::layoutDirection
1822 This property holds the layout direction of the grid.
1823
1824 Possible values:
1825
1826 \list
1827 \o Qt.LeftToRight (default) - Items will be laid out starting in the top, left corner. The flow is
1828 dependent on the \l GridView::flow property.
1829 \o Qt.RightToLeft - Items will be laid out starting in the top, right corner. The flow is dependent
1830 on the \l GridView::flow property.
1831 \endlist
1832
1833 When using the attached property \l {LayoutMirroring::enabled} for locale layouts,
1834 the layout direction of the grid view will be mirrored. However, the actual property
1835 \c layoutDirection will remain unchanged. You can use the property
1836 \l {LayoutMirroring::enabled} to determine whether the direction has been mirrored.
1837
1838 \sa {LayoutMirroring}{LayoutMirroring}
1839 */
1840
layoutDirection() const1841 Qt::LayoutDirection QDeclarativeGridView::layoutDirection() const
1842 {
1843 Q_D(const QDeclarativeGridView);
1844 return d->layoutDirection;
1845 }
1846
setLayoutDirection(Qt::LayoutDirection layoutDirection)1847 void QDeclarativeGridView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1848 {
1849 Q_D(QDeclarativeGridView);
1850 if (d->layoutDirection != layoutDirection) {
1851 d->layoutDirection = layoutDirection;
1852 d->regenerate();
1853 emit layoutDirectionChanged();
1854 }
1855 }
1856
effectiveLayoutDirection() const1857 Qt::LayoutDirection QDeclarativeGridView::effectiveLayoutDirection() const
1858 {
1859 Q_D(const QDeclarativeGridView);
1860 if (d->effectiveLayoutMirror)
1861 return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
1862 else
1863 return d->layoutDirection;
1864 }
1865
1866 /*!
1867 \qmlproperty enumeration GridView::flow
1868 This property holds the flow of the grid.
1869
1870 Possible values:
1871
1872 \list
1873 \o GridView.LeftToRight (default) - Items are laid out from left to right, and the view scrolls vertically
1874 \o GridView.TopToBottom - Items are laid out from top to bottom, and the view scrolls horizontally
1875 \endlist
1876 */
flow() const1877 QDeclarativeGridView::Flow QDeclarativeGridView::flow() const
1878 {
1879 Q_D(const QDeclarativeGridView);
1880 return d->flow;
1881 }
1882
setFlow(Flow flow)1883 void QDeclarativeGridView::setFlow(Flow flow)
1884 {
1885 Q_D(QDeclarativeGridView);
1886 if (d->flow != flow) {
1887 d->flow = flow;
1888 if (d->flow == LeftToRight) {
1889 setContentWidth(-1);
1890 setFlickableDirection(QDeclarativeFlickable::VerticalFlick);
1891 } else {
1892 setContentHeight(-1);
1893 setFlickableDirection(QDeclarativeFlickable::HorizontalFlick);
1894 }
1895 setContentX(0);
1896 setContentY(0);
1897 d->regenerate();
1898 emit flowChanged();
1899 }
1900 }
1901
1902 /*!
1903 \qmlproperty bool GridView::keyNavigationWraps
1904 This property holds whether the grid wraps key navigation
1905
1906 If this is true, key navigation that would move the current item selection
1907 past one end of the view instead wraps around and moves the selection to
1908 the other end of the view.
1909
1910 By default, key navigation is not wrapped.
1911 */
isWrapEnabled() const1912 bool QDeclarativeGridView::isWrapEnabled() const
1913 {
1914 Q_D(const QDeclarativeGridView);
1915 return d->wrap;
1916 }
1917
setWrapEnabled(bool wrap)1918 void QDeclarativeGridView::setWrapEnabled(bool wrap)
1919 {
1920 Q_D(QDeclarativeGridView);
1921 if (d->wrap == wrap)
1922 return;
1923 d->wrap = wrap;
1924 emit keyNavigationWrapsChanged();
1925 }
1926
1927 /*!
1928 \qmlproperty int GridView::cacheBuffer
1929 This property determines whether delegates are retained outside the
1930 visible area of the view.
1931
1932 If non-zero the view will keep as many delegates
1933 instantiated as will fit within the buffer specified. For example,
1934 if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
1935 set to 40, then up to 2 delegates above and 2 delegates below the visible
1936 area may be retained.
1937
1938 Note that cacheBuffer is not a pixel buffer - it only maintains additional
1939 instantiated delegates.
1940
1941 Setting this value can make scrolling the list smoother at the expense
1942 of additional memory usage. It is not a substitute for creating efficient
1943 delegates; the fewer elements in a delegate, the faster a view may be
1944 scrolled.
1945 */
cacheBuffer() const1946 int QDeclarativeGridView::cacheBuffer() const
1947 {
1948 Q_D(const QDeclarativeGridView);
1949 return d->buffer;
1950 }
1951
setCacheBuffer(int buffer)1952 void QDeclarativeGridView::setCacheBuffer(int buffer)
1953 {
1954 Q_D(QDeclarativeGridView);
1955 if (d->buffer != buffer) {
1956 d->buffer = buffer;
1957 if (isComponentComplete())
1958 refill();
1959 emit cacheBufferChanged();
1960 }
1961 }
1962
1963 /*!
1964 \qmlproperty int GridView::cellWidth
1965 \qmlproperty int GridView::cellHeight
1966
1967 These properties holds the width and height of each cell in the grid.
1968
1969 The default cell size is 100x100.
1970 */
cellWidth() const1971 int QDeclarativeGridView::cellWidth() const
1972 {
1973 Q_D(const QDeclarativeGridView);
1974 return d->cellWidth;
1975 }
1976
setCellWidth(int cellWidth)1977 void QDeclarativeGridView::setCellWidth(int cellWidth)
1978 {
1979 Q_D(QDeclarativeGridView);
1980 if (cellWidth != d->cellWidth && cellWidth > 0) {
1981 d->cellWidth = qMax(1, cellWidth);
1982 d->updateGrid();
1983 emit cellWidthChanged();
1984 d->layout();
1985 }
1986 }
1987
cellHeight() const1988 int QDeclarativeGridView::cellHeight() const
1989 {
1990 Q_D(const QDeclarativeGridView);
1991 return d->cellHeight;
1992 }
1993
setCellHeight(int cellHeight)1994 void QDeclarativeGridView::setCellHeight(int cellHeight)
1995 {
1996 Q_D(QDeclarativeGridView);
1997 if (cellHeight != d->cellHeight && cellHeight > 0) {
1998 d->cellHeight = qMax(1, cellHeight);
1999 d->updateGrid();
2000 emit cellHeightChanged();
2001 d->layout();
2002 }
2003 }
2004 /*!
2005 \qmlproperty enumeration GridView::snapMode
2006
2007 This property determines how the view scrolling will settle following a drag or flick.
2008 The possible values are:
2009
2010 \list
2011 \o GridView.NoSnap (default) - the view stops anywhere within the visible area.
2012 \o GridView.SnapToRow - the view settles with a row (or column for \c GridView.TopToBottom flow)
2013 aligned with the start of the view.
2014 \o GridView.SnapOneRow - the view will settle no more than one row (or column for \c GridView.TopToBottom flow)
2015 away from the first visible row at the time the mouse button is released.
2016 This mode is particularly useful for moving one page at a time.
2017 \endlist
2018
2019 */
snapMode() const2020 QDeclarativeGridView::SnapMode QDeclarativeGridView::snapMode() const
2021 {
2022 Q_D(const QDeclarativeGridView);
2023 return d->snapMode;
2024 }
2025
setSnapMode(SnapMode mode)2026 void QDeclarativeGridView::setSnapMode(SnapMode mode)
2027 {
2028 Q_D(QDeclarativeGridView);
2029 if (d->snapMode != mode) {
2030 d->snapMode = mode;
2031 emit snapModeChanged();
2032 }
2033 }
2034
2035 /*!
2036 \qmlproperty Component GridView::footer
2037 This property holds the component to use as the footer.
2038
2039 An instance of the footer component is created for each view. The
2040 footer is positioned at the end of the view, after any items.
2041
2042 \sa header
2043 */
footer() const2044 QDeclarativeComponent *QDeclarativeGridView::footer() const
2045 {
2046 Q_D(const QDeclarativeGridView);
2047 return d->footerComponent;
2048 }
2049
setFooter(QDeclarativeComponent * footer)2050 void QDeclarativeGridView::setFooter(QDeclarativeComponent *footer)
2051 {
2052 Q_D(QDeclarativeGridView);
2053 if (d->footerComponent != footer) {
2054 if (d->footer) {
2055 if (scene())
2056 scene()->removeItem(d->footer->item);
2057 d->footer->item->deleteLater();
2058 delete d->footer;
2059 d->footer = 0;
2060 }
2061 d->footerComponent = footer;
2062 if (isComponentComplete()) {
2063 d->updateFooter();
2064 d->updateGrid();
2065 d->fixupPosition();
2066 }
2067 emit footerChanged();
2068 }
2069 }
2070
2071 /*!
2072 \qmlproperty Component GridView::header
2073 This property holds the component to use as the header.
2074
2075 An instance of the header component is created for each view. The
2076 header is positioned at the beginning of the view, before any items.
2077
2078 \sa footer
2079 */
header() const2080 QDeclarativeComponent *QDeclarativeGridView::header() const
2081 {
2082 Q_D(const QDeclarativeGridView);
2083 return d->headerComponent;
2084 }
2085
setHeader(QDeclarativeComponent * header)2086 void QDeclarativeGridView::setHeader(QDeclarativeComponent *header)
2087 {
2088 Q_D(QDeclarativeGridView);
2089 if (d->headerComponent != header) {
2090 if (d->header) {
2091 if (scene())
2092 scene()->removeItem(d->header->item);
2093 d->header->item->deleteLater();
2094 delete d->header;
2095 d->header = 0;
2096 }
2097 d->headerComponent = header;
2098 if (isComponentComplete()) {
2099 d->updateHeader();
2100 d->updateFooter();
2101 d->updateGrid();
2102 d->fixupPosition();
2103 }
2104 emit headerChanged();
2105 }
2106 }
2107
setContentX(qreal pos)2108 void QDeclarativeGridView::setContentX(qreal pos)
2109 {
2110 Q_D(QDeclarativeGridView);
2111 // Positioning the view manually should override any current movement state
2112 d->moveReason = QDeclarativeGridViewPrivate::Other;
2113 QDeclarativeFlickable::setContentX(pos);
2114 }
2115
setContentY(qreal pos)2116 void QDeclarativeGridView::setContentY(qreal pos)
2117 {
2118 Q_D(QDeclarativeGridView);
2119 // Positioning the view manually should override any current movement state
2120 d->moveReason = QDeclarativeGridViewPrivate::Other;
2121 QDeclarativeFlickable::setContentY(pos);
2122 }
2123
event(QEvent * event)2124 bool QDeclarativeGridView::event(QEvent *event)
2125 {
2126 Q_D(QDeclarativeGridView);
2127 if (event->type() == QEvent::User) {
2128 if (d->layoutScheduled)
2129 d->layout();
2130 return true;
2131 }
2132
2133 return QDeclarativeFlickable::event(event);
2134 }
2135
viewportMoved()2136 void QDeclarativeGridView::viewportMoved()
2137 {
2138 Q_D(QDeclarativeGridView);
2139 QDeclarativeFlickable::viewportMoved();
2140 if (!d->itemCount)
2141 return;
2142 d->lazyRelease = true;
2143 if (d->hData.flicking || d->vData.flicking) {
2144 if (yflick()) {
2145 if (d->vData.velocity > 0)
2146 d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore;
2147 else if (d->vData.velocity < 0)
2148 d->bufferMode = QDeclarativeGridViewPrivate::BufferAfter;
2149 }
2150
2151 if (xflick()) {
2152 if (d->hData.velocity > 0)
2153 d->bufferMode = QDeclarativeGridViewPrivate::BufferBefore;
2154 else if (d->hData.velocity < 0)
2155 d->bufferMode = QDeclarativeGridViewPrivate::BufferAfter;
2156 }
2157 }
2158 refill();
2159 if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
2160 d->moveReason = QDeclarativeGridViewPrivate::Mouse;
2161 if (d->moveReason != QDeclarativeGridViewPrivate::SetIndex) {
2162 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
2163 // reposition highlight
2164 qreal pos = d->highlight->rowPos();
2165 qreal viewPos;
2166 qreal highlightStart;
2167 qreal highlightEnd;
2168 if (d->isRightToLeftTopToBottom()) {
2169 highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
2170 highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
2171 viewPos = -d->position()-d->size();
2172 } else {
2173 highlightStart = d->highlightRangeStart;
2174 highlightEnd = d->highlightRangeEnd;
2175 viewPos = d->position();
2176 }
2177 if (pos > viewPos + highlightEnd - d->rowSize())
2178 pos = viewPos + highlightEnd - d->rowSize();
2179 if (pos < viewPos + highlightStart)
2180 pos = viewPos + highlightStart;
2181
2182 d->highlight->setPosition(d->highlight->colPos(), qRound(pos));
2183
2184 // update current index
2185 int idx = d->snapIndex();
2186 if (idx >= 0 && idx != d->currentIndex) {
2187 d->updateCurrent(idx);
2188 if (d->currentItem && d->currentItem->colPos() != d->highlight->colPos() && d->autoHighlight) {
2189 if (d->flow == LeftToRight)
2190 d->highlightXAnimator->to = d->currentItem->item->x();
2191 else
2192 d->highlightYAnimator->to = d->currentItem->item->y();
2193 }
2194 }
2195 }
2196 }
2197 }
2198
minYExtent() const2199 qreal QDeclarativeGridView::minYExtent() const
2200 {
2201 Q_D(const QDeclarativeGridView);
2202 if (d->flow == QDeclarativeGridView::TopToBottom)
2203 return QDeclarativeFlickable::minYExtent();
2204 qreal extent = -d->startPosition();
2205 if (d->header && d->visibleItems.count())
2206 extent += d->header->item->height();
2207 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2208 extent += d->highlightRangeStart;
2209 extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd));
2210 }
2211 return extent;
2212 }
2213
maxYExtent() const2214 qreal QDeclarativeGridView::maxYExtent() const
2215 {
2216 Q_D(const QDeclarativeGridView);
2217 if (d->flow == QDeclarativeGridView::TopToBottom)
2218 return QDeclarativeFlickable::maxYExtent();
2219 qreal extent;
2220 if (!d->model || !d->model->count()) {
2221 extent = 0;
2222 } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2223 extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart);
2224 if (d->highlightRangeEnd != d->highlightRangeStart)
2225 extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1));
2226 } else {
2227 extent = -(d->endPosition() - height());
2228 }
2229 if (d->footer)
2230 extent -= d->footer->item->height();
2231 const qreal minY = minYExtent();
2232 if (extent > minY)
2233 extent = minY;
2234 return extent;
2235 }
2236
minXExtent() const2237 qreal QDeclarativeGridView::minXExtent() const
2238 {
2239 Q_D(const QDeclarativeGridView);
2240 if (d->flow == QDeclarativeGridView::LeftToRight)
2241 return QDeclarativeFlickable::minXExtent();
2242 qreal extent = -d->startPosition();
2243 qreal highlightStart;
2244 qreal highlightEnd;
2245 qreal endPositionFirstItem = 0;
2246 if (d->isRightToLeftTopToBottom()) {
2247 if (d->model && d->model->count())
2248 endPositionFirstItem = d->rowPosAt(d->model->count()-1);
2249 highlightStart = d->highlightRangeStartValid
2250 ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
2251 : d->size() - (d->lastPosition()-endPositionFirstItem);
2252 highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
2253 if (d->footer && d->visibleItems.count())
2254 extent += d->footer->item->width();
2255 } else {
2256 endPositionFirstItem = d->rowPosAt(0)+d->rowSize();
2257 highlightStart = d->highlightRangeStart;
2258 highlightEnd = d->highlightRangeEnd;
2259 if (d->header && d->visibleItems.count())
2260 extent += d->header->item->width();
2261 }
2262 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2263 extent += d->isRightToLeftTopToBottom() ? -highlightStart : highlightStart;
2264 extent = qMax(extent, -(endPositionFirstItem - highlightEnd));
2265 }
2266 return extent;
2267 }
2268
maxXExtent() const2269 qreal QDeclarativeGridView::maxXExtent() const
2270 {
2271 Q_D(const QDeclarativeGridView);
2272 if (d->flow == QDeclarativeGridView::LeftToRight)
2273 return QDeclarativeFlickable::maxXExtent();
2274 qreal extent;
2275 qreal highlightStart;
2276 qreal highlightEnd;
2277 qreal lastItemPosition = 0;
2278 if (d->isRightToLeftTopToBottom()){
2279 highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
2280 highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
2281 lastItemPosition = d->endPosition();
2282 } else {
2283 highlightStart = d->highlightRangeStart;
2284 highlightEnd = d->highlightRangeEnd;
2285 lastItemPosition = 0;
2286 if (d->model && d->model->count())
2287 lastItemPosition = d->rowPosAt(d->model->count()-1);
2288 }
2289 if (!d->model || !d->model->count()) {
2290 extent = 0;
2291 } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
2292 extent = -(lastItemPosition - highlightStart);
2293 if (highlightEnd != highlightStart)
2294 extent = d->isRightToLeftTopToBottom()
2295 ? qMax(extent, -(d->endPosition() - highlightEnd + 1))
2296 : qMin(extent, -(d->endPosition() - highlightEnd + 1));
2297 } else {
2298 extent = -(d->endPosition() - width());
2299 }
2300 if (d->isRightToLeftTopToBottom()) {
2301 if (d->header)
2302 extent -= d->header->item->width();
2303 } else {
2304 if (d->footer)
2305 extent -= d->footer->item->width();
2306 }
2307
2308 const qreal minX = minXExtent();
2309 if (extent > minX)
2310 extent = minX;
2311 return extent;
2312 }
2313
keyPressEvent(QKeyEvent * event)2314 void QDeclarativeGridView::keyPressEvent(QKeyEvent *event)
2315 {
2316 Q_D(QDeclarativeGridView);
2317 keyPressPreHandler(event);
2318 if (event->isAccepted())
2319 return;
2320 if (d->model && d->model->count() && d->interactive) {
2321 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
2322 int oldCurrent = currentIndex();
2323 switch (event->key()) {
2324 case Qt::Key_Up:
2325 moveCurrentIndexUp();
2326 break;
2327 case Qt::Key_Down:
2328 moveCurrentIndexDown();
2329 break;
2330 case Qt::Key_Left:
2331 moveCurrentIndexLeft();
2332 break;
2333 case Qt::Key_Right:
2334 moveCurrentIndexRight();
2335 break;
2336 default:
2337 break;
2338 }
2339 if (oldCurrent != currentIndex()) {
2340 event->accept();
2341 return;
2342 }
2343 }
2344 d->moveReason = QDeclarativeGridViewPrivate::Other;
2345 event->ignore();
2346 QDeclarativeFlickable::keyPressEvent(event);
2347 }
2348
2349 /*!
2350 \qmlmethod GridView::moveCurrentIndexUp()
2351
2352 Move the currentIndex up one item in the view.
2353 The current index will wrap if keyNavigationWraps is true and it
2354 is currently at the end. This method has no effect if the \l count is zero.
2355
2356 \bold Note: methods should only be called after the Component has completed.
2357 */
moveCurrentIndexUp()2358 void QDeclarativeGridView::moveCurrentIndexUp()
2359 {
2360 Q_D(QDeclarativeGridView);
2361 const int count = d->model ? d->model->count() : 0;
2362 if (!count)
2363 return;
2364 if (d->flow == QDeclarativeGridView::LeftToRight) {
2365 if (currentIndex() >= d->columns || d->wrap) {
2366 int index = currentIndex() - d->columns;
2367 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2368 }
2369 } else {
2370 if (currentIndex() > 0 || d->wrap) {
2371 int index = currentIndex() - 1;
2372 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2373 }
2374 }
2375 }
2376
2377 /*!
2378 \qmlmethod GridView::moveCurrentIndexDown()
2379
2380 Move the currentIndex down one item in the view.
2381 The current index will wrap if keyNavigationWraps is true and it
2382 is currently at the end. This method has no effect if the \l count is zero.
2383
2384 \bold Note: methods should only be called after the Component has completed.
2385 */
moveCurrentIndexDown()2386 void QDeclarativeGridView::moveCurrentIndexDown()
2387 {
2388 Q_D(QDeclarativeGridView);
2389 const int count = d->model ? d->model->count() : 0;
2390 if (!count)
2391 return;
2392 if (d->flow == QDeclarativeGridView::LeftToRight) {
2393 if (currentIndex() < count - d->columns || d->wrap) {
2394 int index = currentIndex()+d->columns;
2395 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2396 }
2397 } else {
2398 if (currentIndex() < count - 1 || d->wrap) {
2399 int index = currentIndex() + 1;
2400 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2401 }
2402 }
2403 }
2404
2405 /*!
2406 \qmlmethod GridView::moveCurrentIndexLeft()
2407
2408 Move the currentIndex left one item in the view.
2409 The current index will wrap if keyNavigationWraps is true and it
2410 is currently at the end. This method has no effect if the \l count is zero.
2411
2412 \bold Note: methods should only be called after the Component has completed.
2413 */
moveCurrentIndexLeft()2414 void QDeclarativeGridView::moveCurrentIndexLeft()
2415 {
2416 Q_D(QDeclarativeGridView);
2417 const int count = d->model ? d->model->count() : 0;
2418 if (!count)
2419 return;
2420
2421 if (effectiveLayoutDirection() == Qt::LeftToRight) {
2422 if (d->flow == QDeclarativeGridView::LeftToRight) {
2423 if (currentIndex() > 0 || d->wrap) {
2424 int index = currentIndex() - 1;
2425 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2426 }
2427 } else {
2428 if (currentIndex() >= d->columns || d->wrap) {
2429 int index = currentIndex() - d->columns;
2430 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2431 }
2432 }
2433 } else {
2434 if (d->flow == QDeclarativeGridView::LeftToRight) {
2435 if (currentIndex() < count - 1 || d->wrap) {
2436 int index = currentIndex() + 1;
2437 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2438 }
2439 } else {
2440 if (currentIndex() < count - d->columns || d->wrap) {
2441 int index = currentIndex() + d->columns;
2442 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2443 }
2444 }
2445 }
2446 }
2447
2448 /*!
2449 \qmlmethod GridView::moveCurrentIndexRight()
2450
2451 Move the currentIndex right one item in the view.
2452 The current index will wrap if keyNavigationWraps is true and it
2453 is currently at the end. This method has no effect if the \l count is zero.
2454
2455 \bold Note: methods should only be called after the Component has completed.
2456 */
moveCurrentIndexRight()2457 void QDeclarativeGridView::moveCurrentIndexRight()
2458 {
2459 Q_D(QDeclarativeGridView);
2460 const int count = d->model ? d->model->count() : 0;
2461 if (!count)
2462 return;
2463
2464 if (effectiveLayoutDirection() == Qt::LeftToRight) {
2465 if (d->flow == QDeclarativeGridView::LeftToRight) {
2466 if (currentIndex() < count - 1 || d->wrap) {
2467 int index = currentIndex() + 1;
2468 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2469 }
2470 } else {
2471 if (currentIndex() < count - d->columns || d->wrap) {
2472 int index = currentIndex()+d->columns;
2473 setCurrentIndex((index >= 0 && index < count) ? index : 0);
2474 }
2475 }
2476 } else {
2477 if (d->flow == QDeclarativeGridView::LeftToRight) {
2478 if (currentIndex() > 0 || d->wrap) {
2479 int index = currentIndex() - 1;
2480 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2481 }
2482 } else {
2483 if (currentIndex() >= d->columns || d->wrap) {
2484 int index = currentIndex() - d->columns;
2485 setCurrentIndex((index >= 0 && index < count) ? index : count-1);
2486 }
2487 }
2488 }
2489 }
2490
positionViewAtIndex(int index,int mode)2491 void QDeclarativeGridViewPrivate::positionViewAtIndex(int index, int mode)
2492 {
2493 Q_Q(QDeclarativeGridView);
2494 if (!isValid())
2495 return;
2496 if (mode < QDeclarativeGridView::Beginning || mode > QDeclarativeGridView::Contain)
2497 return;
2498
2499 int idx = qMax(qMin(index, model->count()-1), 0);
2500
2501 if (layoutScheduled)
2502 layout();
2503 qreal pos = isRightToLeftTopToBottom() ? -position() - size() : position();
2504 FxGridItem *item = visibleItem(idx);
2505 qreal maxExtent;
2506 if (flow == QDeclarativeGridView::LeftToRight)
2507 maxExtent = -q->maxYExtent();
2508 else
2509 maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2510
2511 if (!item) {
2512 int itemPos = rowPosAt(idx);
2513 // save the currently visible items in case any of them end up visible again
2514 QList<FxGridItem*> oldVisible = visibleItems;
2515 visibleItems.clear();
2516 visibleIndex = idx - idx % columns;
2517 if (flow == QDeclarativeGridView::LeftToRight)
2518 maxExtent = -q->maxYExtent();
2519 else
2520 maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
2521 setPosition(qMin(qreal(itemPos), maxExtent));
2522 // now release the reference to all the old visible items.
2523 for (int i = 0; i < oldVisible.count(); ++i)
2524 releaseItem(oldVisible.at(i));
2525 item = visibleItem(idx);
2526 }
2527 if (item) {
2528 qreal itemPos = item->rowPos();
2529 switch (mode) {
2530 case QDeclarativeGridView::Beginning:
2531 pos = itemPos;
2532 if (index < 0 && header) {
2533 pos -= flow == QDeclarativeGridView::LeftToRight
2534 ? header->item->height()
2535 : header->item->width();
2536 }
2537 break;
2538 case QDeclarativeGridView::Center:
2539 pos = itemPos - (size() - rowSize())/2;
2540 break;
2541 case QDeclarativeGridView::End:
2542 pos = itemPos - size() + rowSize();
2543 if (index >= model->count() && footer) {
2544 pos += flow == QDeclarativeGridView::LeftToRight
2545 ? footer->item->height()
2546 : footer->item->width();
2547 }
2548 break;
2549 case QDeclarativeGridView::Visible:
2550 if (itemPos > pos + size())
2551 pos = itemPos - size() + rowSize();
2552 else if (item->endRowPos() < pos)
2553 pos = itemPos;
2554 break;
2555 case QDeclarativeGridView::Contain:
2556 if (item->endRowPos() > pos + size())
2557 pos = itemPos - size() + rowSize();
2558 if (itemPos < pos)
2559 pos = itemPos;
2560 }
2561
2562 pos = qMin(pos, maxExtent);
2563 qreal minExtent;
2564 if (flow == QDeclarativeGridView::LeftToRight)
2565 minExtent = -q->minYExtent();
2566 else
2567 minExtent = isRightToLeftTopToBottom() ? q->maxXExtent()-size() : -q->minXExtent();
2568 pos = qMax(pos, minExtent);
2569 moveReason = QDeclarativeGridViewPrivate::Other;
2570 q->cancelFlick();
2571 setPosition(pos);
2572 }
2573 fixupPosition();
2574 }
2575
2576 /*!
2577 \qmlmethod GridView::positionViewAtIndex(int index, PositionMode mode)
2578
2579 Positions the view such that the \a index is at the position specified by
2580 \a mode:
2581
2582 \list
2583 \o GridView.Beginning - position item at the top (or left for \c GridView.TopToBottom flow) of the view.
2584 \o GridView.Center - position item in the center of the view.
2585 \o GridView.End - position item at bottom (or right for horizontal orientation) of the view.
2586 \o GridView.Visible - if any part of the item is visible then take no action, otherwise
2587 bring the item into view.
2588 \o GridView.Contain - ensure the entire item is visible. If the item is larger than
2589 the view the item is positioned at the top (or left for \c GridView.TopToBottom flow) of the view.
2590 \endlist
2591
2592 If positioning the view at the index would cause empty space to be displayed at
2593 the beginning or end of the view, the view will be positioned at the boundary.
2594
2595 It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2596 at a particular index. This is unreliable since removing items from the start
2597 of the view does not cause all other items to be repositioned.
2598 The correct way to bring an item into view is with \c positionViewAtIndex.
2599
2600 \bold Note: methods should only be called after the Component has completed. To position
2601 the view at startup, this method should be called by Component.onCompleted. For
2602 example, to position the view at the end:
2603
2604 \code
2605 Component.onCompleted: positionViewAtIndex(count - 1, GridView.Beginning)
2606 \endcode
2607 */
positionViewAtIndex(int index,int mode)2608 void QDeclarativeGridView::positionViewAtIndex(int index, int mode)
2609 {
2610 Q_D(QDeclarativeGridView);
2611 if (!d->isValid() || index < 0 || index >= d->model->count())
2612 return;
2613 d->positionViewAtIndex(index, mode);
2614 }
2615
2616 /*!
2617 \qmlmethod GridView::positionViewAtBeginning()
2618 \qmlmethod GridView::positionViewAtEnd()
2619 \since QtQuick 1.1
2620
2621 Positions the view at the beginning or end, taking into account any header or footer.
2622
2623 It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
2624 at a particular index. This is unreliable since removing items from the start
2625 of the list does not cause all other items to be repositioned, and because
2626 the actual start of the view can vary based on the size of the delegates.
2627
2628 \bold Note: methods should only be called after the Component has completed. To position
2629 the view at startup, this method should be called by Component.onCompleted. For
2630 example, to position the view at the end on startup:
2631
2632 \code
2633 Component.onCompleted: positionViewAtEnd()
2634 \endcode
2635 */
positionViewAtBeginning()2636 void QDeclarativeGridView::positionViewAtBeginning()
2637 {
2638 Q_D(QDeclarativeGridView);
2639 if (!d->isValid())
2640 return;
2641 d->positionViewAtIndex(-1, Beginning);
2642 }
2643
positionViewAtEnd()2644 void QDeclarativeGridView::positionViewAtEnd()
2645 {
2646 Q_D(QDeclarativeGridView);
2647 if (!d->isValid())
2648 return;
2649 d->positionViewAtIndex(d->model->count(), End);
2650 }
2651
2652 /*!
2653 \qmlmethod int GridView::indexAt(int x, int y)
2654
2655 Returns the index of the visible item containing the point \a x, \a y in content
2656 coordinates. If there is no item at the point specified, or the item is
2657 not visible -1 is returned.
2658
2659 If the item is outside the visible area, -1 is returned, regardless of
2660 whether an item will exist at that point when scrolled into view.
2661
2662 \bold Note: methods should only be called after the Component has completed.
2663 */
indexAt(qreal x,qreal y) const2664 int QDeclarativeGridView::indexAt(qreal x, qreal y) const
2665 {
2666 Q_D(const QDeclarativeGridView);
2667 for (int i = 0; i < d->visibleItems.count(); ++i) {
2668 const FxGridItem *listItem = d->visibleItems.at(i);
2669 if(listItem->contains(x, y))
2670 return listItem->index;
2671 }
2672
2673 return -1;
2674 }
2675
componentComplete()2676 void QDeclarativeGridView::componentComplete()
2677 {
2678 Q_D(QDeclarativeGridView);
2679 QDeclarativeFlickable::componentComplete();
2680 d->updateHeader();
2681 d->updateFooter();
2682 d->updateGrid();
2683 if (d->isValid()) {
2684 refill();
2685 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
2686 if (d->currentIndex < 0 && !d->currentIndexCleared)
2687 d->updateCurrent(0);
2688 else
2689 d->updateCurrent(d->currentIndex);
2690 if (d->highlight && d->currentItem) {
2691 if (d->autoHighlight)
2692 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
2693 d->updateTrackedItem();
2694 }
2695 d->moveReason = QDeclarativeGridViewPrivate::Other;
2696 d->fixupPosition();
2697 }
2698 }
2699
trackedPositionChanged()2700 void QDeclarativeGridView::trackedPositionChanged()
2701 {
2702 Q_D(QDeclarativeGridView);
2703 if (!d->trackedItem || !d->currentItem)
2704 return;
2705 if (d->moveReason == QDeclarativeGridViewPrivate::SetIndex) {
2706 const qreal trackedPos = d->trackedItem->rowPos();
2707 qreal viewPos;
2708 qreal highlightStart;
2709 qreal highlightEnd;
2710 if (d->isRightToLeftTopToBottom()) {
2711 viewPos = -d->position()-d->size();
2712 highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
2713 highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
2714 } else {
2715 viewPos = d->position();
2716 highlightStart = d->highlightRangeStart;
2717 highlightEnd = d->highlightRangeEnd;
2718 }
2719 qreal pos = viewPos;
2720 if (d->haveHighlightRange) {
2721 if (d->highlightRange == StrictlyEnforceRange) {
2722 if (trackedPos > pos + highlightEnd - d->rowSize())
2723 pos = trackedPos - highlightEnd + d->rowSize();
2724 if (trackedPos < pos + highlightStart)
2725 pos = trackedPos - highlightStart;
2726 } else {
2727 if (trackedPos < d->startPosition() + highlightStart) {
2728 pos = d->startPosition();
2729 } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + highlightEnd) {
2730 pos = d->endPosition() - d->size() + 1;
2731 if (pos < d->startPosition())
2732 pos = d->startPosition();
2733 } else {
2734 if (trackedPos < viewPos + highlightStart) {
2735 pos = trackedPos - highlightStart;
2736 } else if (trackedPos > viewPos + highlightEnd - d->rowSize()) {
2737 pos = trackedPos - highlightEnd + d->rowSize();
2738 }
2739 }
2740 }
2741 } else {
2742 if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) {
2743 pos = qMax(trackedPos, d->currentItem->rowPos());
2744 } else if (d->trackedItem->endRowPos() >= viewPos + d->size()
2745 && d->currentItem->endRowPos() >= viewPos + d->size()) {
2746 if (d->trackedItem->endRowPos() <= d->currentItem->endRowPos()) {
2747 pos = d->trackedItem->endRowPos() - d->size() + 1;
2748 if (d->rowSize() > d->size())
2749 pos = trackedPos;
2750 } else {
2751 pos = d->currentItem->endRowPos() - d->size() + 1;
2752 if (d->rowSize() > d->size())
2753 pos = d->currentItem->rowPos();
2754 }
2755 }
2756 }
2757 if (viewPos != pos) {
2758 cancelFlick();
2759 d->calcVelocity = true;
2760 d->setPosition(pos);
2761 d->calcVelocity = false;
2762 }
2763 }
2764 }
2765
itemsInserted(int modelIndex,int count)2766 void QDeclarativeGridView::itemsInserted(int modelIndex, int count)
2767 {
2768 Q_D(QDeclarativeGridView);
2769 if (!isComponentComplete())
2770 return;
2771
2772 int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
2773 if (index < 0) {
2774 int i = d->visibleItems.count() - 1;
2775 while (i > 0 && d->visibleItems.at(i)->index == -1)
2776 --i;
2777 if (d->visibleItems.at(i)->index + 1 == modelIndex) {
2778 // Special case of appending an item to the model.
2779 index = d->visibleIndex + d->visibleItems.count();
2780 } else {
2781 if (modelIndex <= d->visibleIndex) {
2782 // Insert before visible items
2783 d->visibleIndex += count;
2784 for (int i = 0; i < d->visibleItems.count(); ++i) {
2785 FxGridItem *listItem = d->visibleItems.at(i);
2786 if (listItem->index != -1 && listItem->index >= modelIndex)
2787 listItem->index += count;
2788 }
2789 }
2790 if (d->currentIndex >= modelIndex) {
2791 // adjust current item index
2792 d->currentIndex += count;
2793 if (d->currentItem)
2794 d->currentItem->index = d->currentIndex;
2795 emit currentIndexChanged();
2796 }
2797 d->scheduleLayout();
2798 d->itemCount += count;
2799 emit countChanged();
2800 return;
2801 }
2802 }
2803
2804 int insertCount = count;
2805 if (index < d->visibleIndex && d->visibleItems.count()) {
2806 insertCount -= d->visibleIndex - index;
2807 index = d->visibleIndex;
2808 modelIndex = d->visibleIndex;
2809 }
2810
2811 qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+d->width()+1 : d->position();
2812 int to = d->buffer+tempPos+d->size()-1;
2813 int colPos = 0;
2814 int rowPos = 0;
2815 if (d->visibleItems.count()) {
2816 index -= d->visibleIndex;
2817 if (index < d->visibleItems.count()) {
2818 colPos = d->visibleItems.at(index)->colPos();
2819 rowPos = d->visibleItems.at(index)->rowPos();
2820 } else {
2821 // appending items to visible list
2822 colPos = d->visibleItems.at(index-1)->colPos() + d->colSize();
2823 rowPos = d->visibleItems.at(index-1)->rowPos();
2824 if (colPos > d->colSize() * (d->columns-1)) {
2825 colPos = 0;
2826 rowPos += d->rowSize();
2827 }
2828 }
2829 } else if (d->itemCount == 0 && d->header) {
2830 rowPos = d->headerSize();
2831 }
2832
2833 // Update the indexes of the following visible items.
2834 for (int i = 0; i < d->visibleItems.count(); ++i) {
2835 FxGridItem *listItem = d->visibleItems.at(i);
2836 if (listItem->index != -1 && listItem->index >= modelIndex)
2837 listItem->index += count;
2838 }
2839
2840 bool addedVisible = false;
2841 QList<FxGridItem*> added;
2842 int i = 0;
2843 while (i < insertCount && rowPos <= to + d->rowSize()*(d->columns - (colPos/d->colSize()))/qreal(d->columns+1)) {
2844 if (!addedVisible) {
2845 d->scheduleLayout();
2846 addedVisible = true;
2847 }
2848 FxGridItem *item = d->createItem(modelIndex + i);
2849 if (!item) {
2850 // broken or no delegate
2851 d->clear();
2852 return;
2853 }
2854 d->visibleItems.insert(index, item);
2855 item->setPosition(colPos, rowPos);
2856 added.append(item);
2857 colPos += d->colSize();
2858 if (colPos > d->colSize() * (d->columns-1)) {
2859 colPos = 0;
2860 rowPos += d->rowSize();
2861 }
2862 ++index;
2863 ++i;
2864 }
2865 if (i < insertCount) {
2866 // We didn't insert all our new items, which means anything
2867 // beyond the current index is not visible - remove it.
2868 while (d->visibleItems.count() > index) {
2869 d->releaseItem(d->visibleItems.takeLast());
2870 }
2871 }
2872
2873 // update visibleIndex
2874 d->visibleIndex = 0;
2875 for (QList<FxGridItem*>::Iterator it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2876 if ((*it)->index != -1) {
2877 d->visibleIndex = (*it)->index;
2878 break;
2879 }
2880 }
2881
2882 if (d->itemCount && d->currentIndex >= modelIndex) {
2883 // adjust current item index
2884 d->currentIndex += count;
2885 if (d->currentItem) {
2886 d->currentItem->index = d->currentIndex;
2887 d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
2888 }
2889 emit currentIndexChanged();
2890 } else if (d->itemCount == 0 && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
2891 setCurrentIndex(0);
2892 }
2893
2894 // everything is in order now - emit add() signal
2895 for (int j = 0; j < added.count(); ++j)
2896 added.at(j)->attached->emitAdd();
2897
2898 d->itemCount += count;
2899 emit countChanged();
2900 }
2901
itemsRemoved(int modelIndex,int count)2902 void QDeclarativeGridView::itemsRemoved(int modelIndex, int count)
2903 {
2904 Q_D(QDeclarativeGridView);
2905 if (!isComponentComplete())
2906 return;
2907
2908 d->itemCount -= count;
2909 bool currentRemoved = d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count;
2910 bool removedVisible = false;
2911 // Remove the items from the visible list, skipping anything already marked for removal
2912 QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
2913 while (it != d->visibleItems.end()) {
2914 FxGridItem *item = *it;
2915 if (item->index == -1 || item->index < modelIndex) {
2916 // already removed, or before removed items
2917 if (item->index < modelIndex && !removedVisible) {
2918 d->scheduleLayout();
2919 removedVisible = true;
2920 }
2921 ++it;
2922 } else if (item->index >= modelIndex + count) {
2923 // after removed items
2924 item->index -= count;
2925 ++it;
2926 } else {
2927 // removed item
2928 if (!removedVisible) {
2929 d->scheduleLayout();
2930 removedVisible = true;
2931 }
2932 item->attached->emitRemove();
2933 if (item->attached->delayRemove()) {
2934 item->index = -1;
2935 connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
2936 ++it;
2937 } else {
2938 it = d->visibleItems.erase(it);
2939 d->releaseItem(item);
2940 }
2941 }
2942 }
2943
2944 // If we removed items before visible items a layout may be
2945 // required to ensure item 0 is in the first column.
2946 if (!removedVisible && modelIndex < d->visibleIndex)
2947 d->scheduleLayout();
2948
2949 // fix current
2950 if (d->currentIndex >= modelIndex + count) {
2951 d->currentIndex -= count;
2952 if (d->currentItem)
2953 d->currentItem->index -= count;
2954 emit currentIndexChanged();
2955 } else if (currentRemoved) {
2956 // current item has been removed.
2957 d->releaseItem(d->currentItem);
2958 d->currentItem = 0;
2959 d->currentIndex = -1;
2960 if (d->itemCount)
2961 d->updateCurrent(qMin(modelIndex, d->itemCount-1));
2962 else
2963 emit currentIndexChanged();
2964 }
2965
2966 // update visibleIndex
2967 d->visibleIndex = 0;
2968 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
2969 if ((*it)->index != -1) {
2970 d->visibleIndex = (*it)->index;
2971 break;
2972 }
2973 }
2974
2975 if (removedVisible && d->visibleItems.isEmpty()) {
2976 d->timeline.clear();
2977 if (d->itemCount == 0) {
2978 d->setPosition(0);
2979 d->updateHeader();
2980 d->updateFooter();
2981 update();
2982 }
2983 }
2984
2985 emit countChanged();
2986 }
2987
destroyRemoved()2988 void QDeclarativeGridView::destroyRemoved()
2989 {
2990 Q_D(QDeclarativeGridView);
2991 for (QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
2992 it != d->visibleItems.end();) {
2993 FxGridItem *listItem = *it;
2994 if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
2995 d->releaseItem(listItem);
2996 it = d->visibleItems.erase(it);
2997 } else {
2998 ++it;
2999 }
3000 }
3001
3002 // Correct the positioning of the items
3003 d->layout();
3004 }
3005
itemsMoved(int from,int to,int count)3006 void QDeclarativeGridView::itemsMoved(int from, int to, int count)
3007 {
3008 Q_D(QDeclarativeGridView);
3009 if (!isComponentComplete())
3010 return;
3011 QHash<int,FxGridItem*> moved;
3012
3013 FxGridItem *firstItem = d->firstVisibleItem();
3014
3015 QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
3016 while (it != d->visibleItems.end()) {
3017 FxGridItem *item = *it;
3018 if (item->index >= from && item->index < from + count) {
3019 // take the items that are moving
3020 item->index += (to-from);
3021 moved.insert(item->index, item);
3022 it = d->visibleItems.erase(it);
3023 } else {
3024 if (item->index > from && item->index != -1) {
3025 // move everything after the moved items.
3026 item->index -= count;
3027 if (item->index < d->visibleIndex)
3028 d->visibleIndex = item->index;
3029 }
3030 ++it;
3031 }
3032 }
3033
3034 int remaining = count;
3035 int endIndex = d->visibleIndex;
3036 it = d->visibleItems.begin();
3037 while (it != d->visibleItems.end()) {
3038 FxGridItem *item = *it;
3039 if (remaining && item->index >= to && item->index < to + count) {
3040 // place items in the target position, reusing any existing items
3041 FxGridItem *movedItem = moved.take(item->index);
3042 if (!movedItem)
3043 movedItem = d->createItem(item->index);
3044 if (!movedItem) {
3045 // broken or no delegate
3046 d->clear();
3047 return;
3048 }
3049 it = d->visibleItems.insert(it, movedItem);
3050 if (it == d->visibleItems.begin() && firstItem)
3051 movedItem->setPosition(firstItem->colPos(), firstItem->rowPos());
3052 ++it;
3053 --remaining;
3054 } else {
3055 if (item->index != -1) {
3056 if (item->index >= to) {
3057 // update everything after the moved items.
3058 item->index += count;
3059 }
3060 endIndex = item->index;
3061 }
3062 ++it;
3063 }
3064 }
3065
3066 // If we have moved items to the end of the visible items
3067 // then add any existing moved items that we have
3068 while (FxGridItem *item = moved.take(endIndex+1)) {
3069 d->visibleItems.append(item);
3070 ++endIndex;
3071 }
3072
3073 // update visibleIndex
3074 for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
3075 if ((*it)->index != -1) {
3076 d->visibleIndex = (*it)->index;
3077 break;
3078 }
3079 }
3080
3081 // Fix current index
3082 if (d->currentIndex >= 0 && d->currentItem) {
3083 int oldCurrent = d->currentIndex;
3084 d->currentIndex = d->model->indexOf(d->currentItem->item, this);
3085 if (oldCurrent != d->currentIndex) {
3086 d->currentItem->index = d->currentIndex;
3087 emit currentIndexChanged();
3088 }
3089 }
3090
3091 // Whatever moved items remain are no longer visible items.
3092 while (moved.count()) {
3093 int idx = moved.begin().key();
3094 FxGridItem *item = moved.take(idx);
3095 if (d->currentItem && item->item == d->currentItem->item)
3096 item->setPosition(d->colPosAt(idx), d->rowPosAt(idx));
3097 d->releaseItem(item);
3098 }
3099
3100 d->layout();
3101 }
3102
modelReset()3103 void QDeclarativeGridView::modelReset()
3104 {
3105 Q_D(QDeclarativeGridView);
3106 d->clear();
3107 refill();
3108 d->moveReason = QDeclarativeGridViewPrivate::SetIndex;
3109 d->updateCurrent(d->currentIndex);
3110 if (d->highlight && d->currentItem) {
3111 if (d->autoHighlight)
3112 d->highlight->setPosition(d->currentItem->colPos(), d->currentItem->rowPos());
3113 d->updateTrackedItem();
3114 }
3115 d->moveReason = QDeclarativeGridViewPrivate::Other;
3116
3117 emit countChanged();
3118 }
3119
createdItem(int index,QDeclarativeItem * item)3120 void QDeclarativeGridView::createdItem(int index, QDeclarativeItem *item)
3121 {
3122 Q_D(QDeclarativeGridView);
3123 if (d->requestedIndex != index) {
3124 item->setParentItem(this);
3125 d->unrequestedItems.insert(item, index);
3126 if (d->flow == QDeclarativeGridView::LeftToRight) {
3127 item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index)));
3128 } else {
3129 item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index)));
3130 }
3131 }
3132 }
3133
destroyingItem(QDeclarativeItem * item)3134 void QDeclarativeGridView::destroyingItem(QDeclarativeItem *item)
3135 {
3136 Q_D(QDeclarativeGridView);
3137 d->unrequestedItems.remove(item);
3138 }
3139
animStopped()3140 void QDeclarativeGridView::animStopped()
3141 {
3142 Q_D(QDeclarativeGridView);
3143 d->bufferMode = QDeclarativeGridViewPrivate::NoBuffer;
3144 if (d->haveHighlightRange && d->highlightRange == QDeclarativeGridView::StrictlyEnforceRange)
3145 d->updateHighlight();
3146 }
3147
refill()3148 void QDeclarativeGridView::refill()
3149 {
3150 Q_D(QDeclarativeGridView);
3151 if (d->isRightToLeftTopToBottom())
3152 d->refill(-d->position()-d->size()+1, -d->position());
3153 else
3154 d->refill(d->position(), d->position()+d->size()-1);
3155 }
3156
3157
qmlAttachedProperties(QObject * obj)3158 QDeclarativeGridViewAttached *QDeclarativeGridView::qmlAttachedProperties(QObject *obj)
3159 {
3160 return new QDeclarativeGridViewAttached(obj);
3161 }
3162
3163 QT_END_NAMESPACE
3164