~ubuntu-branches/ubuntu/saucy/qtdeclarative-opensource-src/saucy

« back to all changes in this revision

Viewing changes to .pc/qtquick_delegate_creation_range_itemviews.patch/src/quick/items/qquickgridview.cpp

  • Committer: Package Import Robot
  • Author(s): Michał Sawicz
  • Date: 2013-09-11 14:03:31 UTC
  • mfrom: (4.1.4 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130911140331-4lgbilnfzc06bdqd
Tags: 5.0.2-6ubuntu2
Add qtquick_delegate_creation_range_itemviews.patch to patchset.
(LP: #1217924)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the QtQml 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 Digia.  For licensing terms and
 
14
** conditions see http://qt.digia.com/licensing.  For further information
 
15
** use the contact form at http://qt.digia.com/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 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL included in the
 
21
** packaging of this file.  Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 2.1 requirements
 
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
24
**
 
25
** In addition, as a special exception, Digia gives you certain additional
 
26
** rights.  These rights are described in the Digia Qt LGPL Exception
 
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
28
**
 
29
** GNU General Public License Usage
 
30
** Alternatively, this file may be used under the terms of the GNU
 
31
** General Public License version 3.0 as published by the Free Software
 
32
** Foundation and appearing in the file LICENSE.GPL included in the
 
33
** packaging of this file.  Please review the following information to
 
34
** ensure the GNU General Public License version 3.0 requirements will be
 
35
** met: http://www.gnu.org/copyleft/gpl.html.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include "qquickgridview_p.h"
 
43
#include "qquickvisualitemmodel_p.h"
 
44
#include "qquickflickable_p_p.h"
 
45
#include "qquickitemview_p_p.h"
 
46
 
 
47
#include <private/qquicksmoothedanimation_p_p.h>
 
48
 
 
49
#include <QtGui/qevent.h>
 
50
#include <QtCore/qmath.h>
 
51
#include <QtCore/qcoreapplication.h>
 
52
#include <math.h>
 
53
#include "qplatformdefs.h"
 
54
 
 
55
QT_BEGIN_NAMESPACE
 
56
 
 
57
#ifndef QML_FLICK_SNAPONETHRESHOLD
 
58
#define QML_FLICK_SNAPONETHRESHOLD 30
 
59
#endif
 
60
 
 
61
//#define DEBUG_DELEGATE_LIFECYCLE
 
62
 
 
63
//----------------------------------------------------------------------------
 
64
 
 
65
class FxGridItemSG : public FxViewItem
 
66
{
 
67
public:
 
68
    FxGridItemSG(QQuickItem *i, QQuickGridView *v, bool own, bool trackGeometry) : FxViewItem(i, own, trackGeometry), view(v) {
 
69
        attached = static_cast<QQuickGridViewAttached*>(qmlAttachedPropertiesObject<QQuickGridView>(item));
 
70
        if (trackGeometry) {
 
71
            QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
 
72
            itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
 
73
        }
 
74
    }
 
75
 
 
76
    ~FxGridItemSG() {
 
77
        if (trackGeom) {
 
78
            QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
 
79
            itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
 
80
        }
 
81
    }
 
82
 
 
83
    qreal position() const {
 
84
        return rowPos();
 
85
    }
 
86
 
 
87
    qreal endPosition() const {
 
88
        return endRowPos();
 
89
    }
 
90
 
 
91
    qreal size() const {
 
92
        return view->flow() == QQuickGridView::FlowLeftToRight ? view->cellHeight() : view->cellWidth();
 
93
    }
 
94
 
 
95
    qreal sectionSize() const {
 
96
        return 0.0;
 
97
    }
 
98
 
 
99
    qreal rowPos() const {
 
100
        if (view->flow() == QQuickGridView::FlowLeftToRight)
 
101
            return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -view->cellHeight()-itemY() : itemY());
 
102
        else
 
103
            return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -view->cellWidth()-itemX() : itemX());
 
104
    }
 
105
 
 
106
    qreal colPos() const {
 
107
        if (view->flow() == QQuickGridView::FlowLeftToRight) {
 
108
            if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
 
109
                qreal colSize = view->cellWidth();
 
110
                int columns = view->width()/colSize;
 
111
                return colSize * (columns-1) - itemX();
 
112
            } else {
 
113
                return itemX();
 
114
            }
 
115
        } else {
 
116
            if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) {
 
117
                return -view->cellHeight() - itemY();
 
118
            } else {
 
119
                return itemY();
 
120
            }
 
121
        }
 
122
    }
 
123
    qreal endRowPos() const {
 
124
        if (view->flow() == QQuickGridView::FlowLeftToRight) {
 
125
            if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop)
 
126
                return -itemY();
 
127
            else
 
128
                return itemY() + view->cellHeight();
 
129
        } else {
 
130
            if (view->effectiveLayoutDirection() == Qt::RightToLeft)
 
131
                return -itemX();
 
132
            else
 
133
                return itemX() + view->cellWidth();
 
134
        }
 
135
    }
 
136
    void setPosition(qreal col, qreal row, bool immediate = false) {
 
137
        moveTo(pointForPosition(col, row), immediate);
 
138
    }
 
139
    bool contains(qreal x, qreal y) const {
 
140
        return (x >= itemX() && x < itemX() + view->cellWidth() &&
 
141
                y >= itemY() && y < itemY() + view->cellHeight());
 
142
    }
 
143
 
 
144
    QQuickGridView *view;
 
145
 
 
146
private:
 
147
    QPointF pointForPosition(qreal col, qreal row) const {
 
148
        qreal x;
 
149
        qreal y;
 
150
        if (view->flow() == QQuickGridView::FlowLeftToRight) {
 
151
            x = col;
 
152
            y = row;
 
153
            if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
 
154
                int columns = view->width()/view->cellWidth();
 
155
                x = view->cellWidth() * (columns-1) - col;
 
156
            }
 
157
        } else {
 
158
            x = row;
 
159
            y = col;
 
160
            if (view->effectiveLayoutDirection() == Qt::RightToLeft)
 
161
                x = -view->cellWidth() - row;
 
162
        }
 
163
        if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop)
 
164
            y = -view->cellHeight() - y;
 
165
        return QPointF(x, y);
 
166
    }
 
167
};
 
168
 
 
169
//----------------------------------------------------------------------------
 
170
 
 
171
class QQuickGridViewPrivate : public QQuickItemViewPrivate
 
172
{
 
173
    Q_DECLARE_PUBLIC(QQuickGridView)
 
174
 
 
175
public:
 
176
    virtual Qt::Orientation layoutOrientation() const;
 
177
    virtual bool isContentFlowReversed() const;
 
178
 
 
179
    virtual qreal positionAt(int index) const;
 
180
    virtual qreal endPositionAt(int index) const;
 
181
    virtual qreal originPosition() const;
 
182
    virtual qreal lastPosition() const;
 
183
 
 
184
    qreal rowSize() const;
 
185
    qreal colSize() const;
 
186
    qreal colPosAt(int modelIndex) const;
 
187
    qreal rowPosAt(int modelIndex) const;
 
188
    qreal snapPosAt(qreal pos) const;
 
189
    FxViewItem *snapItemAt(qreal pos) const;
 
190
    int snapIndex() const;
 
191
    qreal contentXForPosition(qreal pos) const;
 
192
    qreal contentYForPosition(qreal pos) const;
 
193
 
 
194
    void resetColumns();
 
195
 
 
196
    virtual bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer);
 
197
    virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
 
198
 
 
199
    virtual FxViewItem *newViewItem(int index, QQuickItem *item);
 
200
    virtual void initializeViewItem(FxViewItem *item);
 
201
    virtual void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer);
 
202
    virtual void repositionPackageItemAt(QQuickItem *item, int index);
 
203
    virtual void resetFirstItemPosition(qreal pos = 0.0);
 
204
    virtual void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible);
 
205
 
 
206
    virtual void createHighlight();
 
207
    virtual void updateHighlight();
 
208
    virtual void resetHighlightPosition();
 
209
 
 
210
    virtual void setPosition(qreal pos);
 
211
    virtual void layoutVisibleItems(int fromModelIndex = 0);
 
212
    virtual bool applyInsertionChange(const QQuickChangeSet::Insert &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView);
 
213
    virtual void translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult);
 
214
    virtual bool needsRefillForAddedOrRemovedIndex(int index) const;
 
215
 
 
216
    virtual qreal headerSize() const;
 
217
    virtual qreal footerSize() const;
 
218
    virtual bool showHeaderForIndex(int index) const;
 
219
    virtual bool showFooterForIndex(int index) const;
 
220
    virtual void updateHeader();
 
221
    virtual void updateFooter();
 
222
 
 
223
    virtual void changedVisibleIndex(int newIndex);
 
224
    virtual void initializeCurrentItem();
 
225
 
 
226
    virtual void updateViewport();
 
227
    virtual void fixupPosition();
 
228
    virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
 
229
    virtual bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
 
230
                        QQuickTimeLineCallback::Callback fixupCallback, qreal velocity);
 
231
 
 
232
    QQuickGridView::Flow flow;
 
233
    qreal cellWidth;
 
234
    qreal cellHeight;
 
235
    int columns;
 
236
    QQuickGridView::SnapMode snapMode;
 
237
 
 
238
    QSmoothedAnimation *highlightXAnimator;
 
239
    QSmoothedAnimation *highlightYAnimator;
 
240
 
 
241
    QQuickGridViewPrivate()
 
242
        : flow(QQuickGridView::FlowLeftToRight)
 
243
        , cellWidth(100), cellHeight(100), columns(1)
 
244
        , snapMode(QQuickGridView::NoSnap)
 
245
        , highlightXAnimator(0), highlightYAnimator(0)
 
246
    {}
 
247
    ~QQuickGridViewPrivate()
 
248
    {
 
249
        delete highlightXAnimator;
 
250
        delete highlightYAnimator;
 
251
    }
 
252
};
 
253
 
 
254
Qt::Orientation QQuickGridViewPrivate::layoutOrientation() const
 
255
{
 
256
    return flow == QQuickGridView::FlowLeftToRight ? Qt::Vertical : Qt::Horizontal;
 
257
}
 
258
 
 
259
bool QQuickGridViewPrivate::isContentFlowReversed() const
 
260
{
 
261
    Q_Q(const QQuickGridView);
 
262
 
 
263
    return (flow == QQuickGridView::FlowLeftToRight && verticalLayoutDirection == QQuickItemView::BottomToTop)
 
264
            || (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft);
 
265
}
 
266
 
 
267
void QQuickGridViewPrivate::changedVisibleIndex(int newIndex)
 
268
{
 
269
    visibleIndex = newIndex / columns * columns;
 
270
}
 
271
 
 
272
void QQuickGridViewPrivate::setPosition(qreal pos)
 
273
{
 
274
    Q_Q(QQuickGridView);
 
275
    q->QQuickFlickable::setContentX(contentXForPosition(pos));
 
276
    q->QQuickFlickable::setContentY(contentYForPosition(pos));
 
277
}
 
278
 
 
279
qreal QQuickGridViewPrivate::originPosition() const
 
280
{
 
281
    qreal pos = 0;
 
282
    if (!visibleItems.isEmpty())
 
283
        pos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
 
284
    return pos;
 
285
}
 
286
 
 
287
qreal QQuickGridViewPrivate::lastPosition() const
 
288
{
 
289
    qreal pos = 0;
 
290
    if (model && model->count()) {
 
291
        // get end position of last item
 
292
        pos = (rowPosAt(model->count() - 1) + rowSize());
 
293
    }
 
294
    return pos;
 
295
}
 
296
 
 
297
qreal QQuickGridViewPrivate::positionAt(int index) const
 
298
{
 
299
    return rowPosAt(index);
 
300
}
 
301
 
 
302
qreal QQuickGridViewPrivate::endPositionAt(int index) const
 
303
{
 
304
    return rowPosAt(index) + rowSize();
 
305
}
 
306
 
 
307
qreal QQuickGridViewPrivate::rowSize() const {
 
308
    return flow == QQuickGridView::FlowLeftToRight ? cellHeight : cellWidth;
 
309
}
 
310
qreal QQuickGridViewPrivate::colSize() const {
 
311
    return flow == QQuickGridView::FlowLeftToRight ? cellWidth : cellHeight;
 
312
}
 
313
 
 
314
qreal QQuickGridViewPrivate::colPosAt(int modelIndex) const
 
315
{
 
316
    if (FxViewItem *item = visibleItem(modelIndex))
 
317
        return static_cast<FxGridItemSG*>(item)->colPos();
 
318
    if (!visibleItems.isEmpty()) {
 
319
        if (modelIndex == visibleIndex) {
 
320
            FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
 
321
            return firstItem->colPos();
 
322
        } else if (modelIndex < visibleIndex) {
 
323
            int count = (visibleIndex - modelIndex) % columns;
 
324
            int col = static_cast<FxGridItemSG*>(visibleItems.first())->colPos() / colSize();
 
325
            col = (columns - count + col) % columns;
 
326
            return col * colSize();
 
327
        } else {
 
328
            FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
 
329
            int count = modelIndex - lastItem->index;
 
330
            int col = lastItem->colPos() / colSize();
 
331
            col = (col + count) % columns;
 
332
            return col * colSize();
 
333
        }
 
334
    }
 
335
    return (modelIndex % columns) * colSize();
 
336
}
 
337
 
 
338
qreal QQuickGridViewPrivate::rowPosAt(int modelIndex) const
 
339
{
 
340
    if (FxViewItem *item = visibleItem(modelIndex))
 
341
        return static_cast<FxGridItemSG*>(item)->rowPos();
 
342
    if (!visibleItems.isEmpty()) {
 
343
        if (modelIndex == visibleIndex) {
 
344
            FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
 
345
            return firstItem->rowPos();
 
346
        } else if (modelIndex < visibleIndex) {
 
347
            FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
 
348
            int firstCol = firstItem->colPos() / colSize();
 
349
            int col = visibleIndex - modelIndex + (columns - firstCol - 1);
 
350
            int rows = col / columns;
 
351
            return firstItem->rowPos() - rows * rowSize();
 
352
        } else {
 
353
            FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
 
354
            int count = modelIndex - lastItem->index;
 
355
            int col = lastItem->colPos() + count * colSize();
 
356
            int rows = col / (columns * colSize());
 
357
            return lastItem->rowPos() + rows * rowSize();
 
358
        }
 
359
    }
 
360
    return (modelIndex / columns) * rowSize();
 
361
}
 
362
 
 
363
 
 
364
qreal QQuickGridViewPrivate::snapPosAt(qreal pos) const
 
365
{
 
366
    Q_Q(const QQuickGridView);
 
367
    qreal snapPos = 0;
 
368
    if (!visibleItems.isEmpty()) {
 
369
        qreal highlightStart = highlightRangeStart;
 
370
        pos += highlightStart;
 
371
        pos += rowSize()/2;
 
372
        snapPos = static_cast<FxGridItemSG*>(visibleItems.first())->rowPos() - visibleIndex / columns * rowSize();
 
373
        snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
 
374
        snapPos -= highlightStart;
 
375
        qreal maxExtent;
 
376
        qreal minExtent;
 
377
        if (isContentFlowReversed()) {
 
378
            maxExtent = q->minXExtent()-size();
 
379
            minExtent = q->maxXExtent()-size();
 
380
        } else {
 
381
            maxExtent = flow == QQuickGridView::FlowLeftToRight ? -q->maxYExtent() : -q->maxXExtent();
 
382
            minExtent = flow == QQuickGridView::FlowLeftToRight ? -q->minYExtent() : -q->minXExtent();
 
383
        }
 
384
        if (snapPos > maxExtent)
 
385
            snapPos = maxExtent;
 
386
        if (snapPos < minExtent)
 
387
            snapPos = minExtent;
 
388
    }
 
389
    return snapPos;
 
390
}
 
391
 
 
392
FxViewItem *QQuickGridViewPrivate::snapItemAt(qreal pos) const
 
393
{
 
394
    for (int i = 0; i < visibleItems.count(); ++i) {
 
395
        FxViewItem *item = visibleItems.at(i);
 
396
        if (item->index == -1)
 
397
            continue;
 
398
        qreal itemTop = item->position();
 
399
        if (itemTop+rowSize()/2 >= pos && itemTop - rowSize()/2 <= pos)
 
400
            return item;
 
401
    }
 
402
    return 0;
 
403
}
 
404
 
 
405
int QQuickGridViewPrivate::snapIndex() const
 
406
{
 
407
    int index = currentIndex;
 
408
    for (int i = 0; i < visibleItems.count(); ++i) {
 
409
        FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.at(i));
 
410
        if (item->index == -1)
 
411
            continue;
 
412
        qreal itemTop = item->position();
 
413
        FxGridItemSG *hItem = static_cast<FxGridItemSG*>(highlight);
 
414
        if (itemTop >= hItem->rowPos()-rowSize()/2 && itemTop < hItem->rowPos()+rowSize()/2) {
 
415
            index = item->index;
 
416
            if (item->colPos() >= hItem->colPos()-colSize()/2 && item->colPos() < hItem->colPos()+colSize()/2)
 
417
                return item->index;
 
418
        }
 
419
    }
 
420
    return index;
 
421
}
 
422
 
 
423
qreal QQuickGridViewPrivate::contentXForPosition(qreal pos) const
 
424
{
 
425
    Q_Q(const QQuickGridView);
 
426
    if (flow == QQuickGridView::FlowLeftToRight) {
 
427
        // vertical scroll
 
428
        if (q->effectiveLayoutDirection() == Qt::LeftToRight) {
 
429
            return 0;
 
430
        } else {
 
431
            qreal colSize = cellWidth;
 
432
            int columns = q->width()/colSize;
 
433
            return -q->width() + (cellWidth * columns);
 
434
        }
 
435
    } else {
 
436
        // horizontal scroll
 
437
        if (q->effectiveLayoutDirection() == Qt::LeftToRight)
 
438
            return pos;
 
439
        else
 
440
            return -pos - q->width();
 
441
    }
 
442
}
 
443
 
 
444
qreal QQuickGridViewPrivate::contentYForPosition(qreal pos) const
 
445
{
 
446
    Q_Q(const QQuickGridView);
 
447
    if (flow == QQuickGridView::FlowLeftToRight) {
 
448
        // vertical scroll
 
449
        if (verticalLayoutDirection == QQuickItemView::TopToBottom)
 
450
            return pos;
 
451
        else
 
452
            return -pos - q->height();
 
453
    } else {
 
454
        // horizontal scroll
 
455
        if (verticalLayoutDirection == QQuickItemView::TopToBottom)
 
456
            return 0;
 
457
        else
 
458
            return -q->height();
 
459
    }
 
460
}
 
461
 
 
462
void QQuickGridViewPrivate::resetColumns()
 
463
{
 
464
    Q_Q(QQuickGridView);
 
465
    qreal length = flow == QQuickGridView::FlowLeftToRight ? q->width() : q->height();
 
466
    columns = (int)qMax((length + colSize()/2) / colSize(), qreal(1.));
 
467
}
 
468
 
 
469
FxViewItem *QQuickGridViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
 
470
{
 
471
    Q_Q(QQuickGridView);
 
472
    Q_UNUSED(modelIndex);
 
473
    return new FxGridItemSG(item, q, false, false);
 
474
}
 
475
 
 
476
void QQuickGridViewPrivate::initializeViewItem(FxViewItem *item)
 
477
{
 
478
    QQuickItemViewPrivate::initializeViewItem(item);
 
479
 
 
480
    // need to track current items that are animating
 
481
    QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item->item);
 
482
    itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
 
483
}
 
484
 
 
485
bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer)
 
486
{
 
487
    qreal colPos = colPosAt(visibleIndex);
 
488
    qreal rowPos = rowPosAt(visibleIndex);
 
489
    if (visibleItems.count()) {
 
490
        FxGridItemSG *lastItem = static_cast<FxGridItemSG*>(visibleItems.last());
 
491
        rowPos = lastItem->rowPos();
 
492
        int colNum = qFloor((lastItem->colPos()+colSize()/2) / colSize());
 
493
        if (++colNum >= columns) {
 
494
            colNum = 0;
 
495
            rowPos += rowSize();
 
496
        }
 
497
        colPos = colNum * colSize();
 
498
    }
 
499
 
 
500
    int modelIndex = findLastVisibleIndex();
 
501
    modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
 
502
 
 
503
    if (visibleItems.count() && (bufferFrom > rowPos + rowSize()*2
 
504
        || bufferTo < rowPosAt(visibleIndex) - rowSize())) {
 
505
        // We've jumped more than a page.  Estimate which items are now
 
506
        // visible and fill from there.
 
507
        int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns;
 
508
        for (int i = 0; i < visibleItems.count(); ++i)
 
509
            releaseItem(visibleItems.at(i));
 
510
        visibleItems.clear();
 
511
        modelIndex += count;
 
512
        if (modelIndex >= model->count())
 
513
            modelIndex = model->count() - 1;
 
514
        else if (modelIndex < 0)
 
515
            modelIndex = 0;
 
516
        modelIndex = modelIndex / columns * columns;
 
517
        visibleIndex = modelIndex;
 
518
        colPos = colPosAt(visibleIndex);
 
519
        rowPos = rowPosAt(visibleIndex);
 
520
    }
 
521
 
 
522
    int colNum = qFloor((colPos+colSize()/2) / colSize());
 
523
    FxGridItemSG *item = 0;
 
524
    bool changed = false;
 
525
 
 
526
    while (modelIndex < model->count() && rowPos <= fillTo + rowSize()*(columns - colNum)/(columns+1)) {
 
527
#ifdef DEBUG_DELEGATE_LIFECYCLE
 
528
        qDebug() << "refill: append item" << modelIndex << colPos << rowPos;
 
529
#endif
 
530
        if (!(item = static_cast<FxGridItemSG*>(createItem(modelIndex, doBuffer))))
 
531
            break;
 
532
        if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
 
533
            item->setPosition(colPos, rowPos, true);
 
534
        QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
 
535
        visibleItems.append(item);
 
536
        if (++colNum >= columns) {
 
537
            colNum = 0;
 
538
            rowPos += rowSize();
 
539
        }
 
540
        colPos = colNum * colSize();
 
541
        ++modelIndex;
 
542
        changed = true;
 
543
    }
 
544
 
 
545
    if (doBuffer && requestedIndex != -1) // already waiting for an item
 
546
        return changed;
 
547
 
 
548
    // Find first column
 
549
    if (visibleItems.count()) {
 
550
        FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
 
551
        rowPos = firstItem->rowPos();
 
552
        colNum = qFloor((firstItem->colPos()+colSize()/2) / colSize());
 
553
        if (--colNum < 0) {
 
554
            colNum = columns - 1;
 
555
            rowPos -= rowSize();
 
556
        }
 
557
    } else {
 
558
        colNum = qFloor((colPos+colSize()/2) / colSize());
 
559
    }
 
560
 
 
561
    // Prepend
 
562
    colPos = colNum * colSize();
 
563
    while (visibleIndex > 0 && rowPos + rowSize() - 1 >= fillFrom - rowSize()*(colNum+1)/(columns+1)){
 
564
#ifdef DEBUG_DELEGATE_LIFECYCLE
 
565
        qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
 
566
#endif
 
567
        if (!(item = static_cast<FxGridItemSG*>(createItem(visibleIndex-1, doBuffer))))
 
568
            break;
 
569
        --visibleIndex;
 
570
        if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
 
571
            item->setPosition(colPos, rowPos, true);
 
572
        QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
 
573
        visibleItems.prepend(item);
 
574
        if (--colNum < 0) {
 
575
            colNum = columns-1;
 
576
            rowPos -= rowSize();
 
577
        }
 
578
        colPos = colNum * colSize();
 
579
        changed = true;
 
580
    }
 
581
 
 
582
    return changed;
 
583
}
 
584
 
 
585
bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
 
586
{
 
587
    FxGridItemSG *item = 0;
 
588
    bool changed = false;
 
589
 
 
590
    while (visibleItems.count() > 1
 
591
           && (item = static_cast<FxGridItemSG*>(visibleItems.first()))
 
592
                && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
 
593
        if (item->attached->delayRemove())
 
594
            break;
 
595
#ifdef DEBUG_DELEGATE_LIFECYCLE
 
596
        qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
 
597
#endif
 
598
        if (item->index != -1)
 
599
            visibleIndex++;
 
600
        visibleItems.removeFirst();
 
601
        if (item->transitionScheduledOrRunning()) {
 
602
#ifdef DEBUG_DELEGATE_LIFECYCLE
 
603
            qDebug() << "\tnot releasing animating item:" << item->index << item->item->objectName();
 
604
#endif
 
605
            item->releaseAfterTransition = true;
 
606
            releasePendingTransition.append(item);
 
607
        } else {
 
608
            releaseItem(item);
 
609
        }
 
610
        changed = true;
 
611
    }
 
612
    while (visibleItems.count() > 1
 
613
           && (item = static_cast<FxGridItemSG*>(visibleItems.last()))
 
614
                && item->rowPos() > bufferTo + rowSize()*(columns - item->colPos()/colSize())/(columns+1)) {
 
615
        if (item->attached->delayRemove())
 
616
            break;
 
617
#ifdef DEBUG_DELEGATE_LIFECYCLE
 
618
        qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
 
619
#endif
 
620
        visibleItems.removeLast();
 
621
        if (item->transitionScheduledOrRunning()) {
 
622
#ifdef DEBUG_DELEGATE_LIFECYCLE
 
623
            qDebug() << "\tnot releasing animating item:" << item->index << item->item->objectName();
 
624
#endif
 
625
            item->releaseAfterTransition = true;
 
626
            releasePendingTransition.append(item);
 
627
        } else {
 
628
            releaseItem(item);
 
629
        }
 
630
        changed = true;
 
631
    }
 
632
 
 
633
    return changed;
 
634
}
 
635
 
 
636
void QQuickGridViewPrivate::updateViewport()
 
637
{
 
638
    resetColumns();
 
639
    QQuickItemViewPrivate::updateViewport();
 
640
}
 
641
 
 
642
void QQuickGridViewPrivate::layoutVisibleItems(int fromModelIndex)
 
643
{
 
644
    if (visibleItems.count()) {
 
645
        const qreal from = isContentFlowReversed() ? -position() - size() : position();
 
646
        const qreal to = isContentFlowReversed() ? -position() : position() + size();
 
647
 
 
648
        FxGridItemSG *firstItem = static_cast<FxGridItemSG*>(visibleItems.first());
 
649
        qreal rowPos = firstItem->rowPos();
 
650
        qreal colPos = firstItem->colPos();
 
651
        int col = visibleIndex % columns;
 
652
        if (colPos != col * colSize()) {
 
653
            colPos = col * colSize();
 
654
            firstItem->setPosition(colPos, rowPos);
 
655
            firstItem->setVisible(firstItem->rowPos() + rowSize() >= from && firstItem->rowPos() <= to);
 
656
        }
 
657
        for (int i = 1; i < visibleItems.count(); ++i) {
 
658
            FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.at(i));
 
659
            if (++col >= columns) {
 
660
                col = 0;
 
661
                rowPos += rowSize();
 
662
            }
 
663
            colPos = col * colSize();
 
664
            if (item->index >= fromModelIndex) {
 
665
                item->setPosition(colPos, rowPos);
 
666
                item->setVisible(item->rowPos() + rowSize() >= from && item->rowPos() <= to);
 
667
            }
 
668
        }
 
669
    }
 
670
}
 
671
 
 
672
void QQuickGridViewPrivate::repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer)
 
673
{
 
674
    int count = sizeBuffer / rowSize();
 
675
    static_cast<FxGridItemSG *>(item)->setPosition(colPosAt(index + count), rowPosAt(index + count));
 
676
}
 
677
 
 
678
void QQuickGridViewPrivate::repositionPackageItemAt(QQuickItem *item, int index)
 
679
{
 
680
    Q_Q(QQuickGridView);
 
681
    qreal pos = position();
 
682
    if (flow == QQuickGridView::FlowLeftToRight) {
 
683
        if (item->y() + item->height() > pos && item->y() < pos + q->height()) {
 
684
            qreal y = (verticalLayoutDirection == QQuickItemView::TopToBottom)
 
685
                    ? rowPosAt(index)
 
686
                    : -rowPosAt(index) - item->height();
 
687
            item->setPosition(QPointF(colPosAt(index), y));
 
688
        }
 
689
    } else {
 
690
        if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
 
691
            qreal y = (verticalLayoutDirection == QQuickItemView::TopToBottom)
 
692
                    ? colPosAt(index)
 
693
                    : -colPosAt(index) - item->height();
 
694
            if (flow == QQuickGridView::FlowTopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft)
 
695
                item->setPosition(QPointF(-rowPosAt(index)-item->width(), y));
 
696
            else
 
697
                item->setPosition(QPointF(rowPosAt(index), y));
 
698
        }
 
699
    }
 
700
}
 
701
 
 
702
void QQuickGridViewPrivate::resetFirstItemPosition(qreal pos)
 
703
{
 
704
    FxGridItemSG *item = static_cast<FxGridItemSG*>(visibleItems.first());
 
705
    item->setPosition(0, pos);
 
706
}
 
707
 
 
708
void QQuickGridViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible)
 
709
{
 
710
    if (!visibleItems.count())
 
711
        return;
 
712
 
 
713
    int moveCount = (forwards - backwards) / rowSize();
 
714
    if (moveCount == 0 && changeBeforeVisible != 0)
 
715
        moveCount += (changeBeforeVisible % columns) - (columns - 1);
 
716
 
 
717
    FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.first());
 
718
    gridItem->setPosition(gridItem->colPos(), gridItem->rowPos() + ((moveCount / columns) * rowSize()));
 
719
}
 
720
 
 
721
void QQuickGridViewPrivate::createHighlight()
 
722
{
 
723
    Q_Q(QQuickGridView);
 
724
    bool changed = false;
 
725
    if (highlight) {
 
726
        if (trackedItem == highlight)
 
727
            trackedItem = 0;
 
728
        delete highlight;
 
729
        highlight = 0;
 
730
 
 
731
        delete highlightXAnimator;
 
732
        delete highlightYAnimator;
 
733
        highlightXAnimator = 0;
 
734
        highlightYAnimator = 0;
 
735
 
 
736
        changed = true;
 
737
    }
 
738
 
 
739
    if (currentItem) {
 
740
        QQuickItem *item = createHighlightItem();
 
741
        if (item) {
 
742
            FxGridItemSG *newHighlight = new FxGridItemSG(item, q, true, true);
 
743
            if (autoHighlight)
 
744
                resetHighlightPosition();
 
745
            highlightXAnimator = new QSmoothedAnimation;
 
746
            highlightXAnimator->target = QQmlProperty(item, QLatin1String("x"));
 
747
            highlightXAnimator->userDuration = highlightMoveDuration;
 
748
            highlightYAnimator = new QSmoothedAnimation;
 
749
            highlightYAnimator->target = QQmlProperty(item, QLatin1String("y"));
 
750
            highlightYAnimator->userDuration = highlightMoveDuration;
 
751
 
 
752
            highlight = newHighlight;
 
753
            changed = true;
 
754
        }
 
755
    }
 
756
    if (changed)
 
757
        emit q->highlightItemChanged();
 
758
}
 
759
 
 
760
void QQuickGridViewPrivate::updateHighlight()
 
761
{
 
762
    applyPendingChanges();
 
763
 
 
764
    if ((!currentItem && highlight) || (currentItem && !highlight))
 
765
        createHighlight();
 
766
    bool strictHighlight = haveHighlightRange && highlightRange == QQuickGridView::StrictlyEnforceRange;
 
767
    if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
 
768
        // auto-update highlight
 
769
        highlightXAnimator->to = currentItem->itemX();
 
770
        highlightYAnimator->to = currentItem->itemY();
 
771
        highlight->item->setWidth(currentItem->item->width());
 
772
        highlight->item->setHeight(currentItem->item->height());
 
773
 
 
774
        highlightXAnimator->restart();
 
775
        highlightYAnimator->restart();
 
776
    }
 
777
    updateTrackedItem();
 
778
}
 
779
 
 
780
void QQuickGridViewPrivate::resetHighlightPosition()
 
781
{
 
782
    if (highlight && currentItem) {
 
783
        FxGridItemSG *cItem = static_cast<FxGridItemSG*>(currentItem);
 
784
        static_cast<FxGridItemSG*>(highlight)->setPosition(cItem->colPos(), cItem->rowPos());
 
785
    }
 
786
}
 
787
 
 
788
qreal QQuickGridViewPrivate::headerSize() const
 
789
{
 
790
    if (!header)
 
791
        return 0.0;
 
792
    return flow == QQuickGridView::FlowLeftToRight ? header->item->height() : header->item->width();
 
793
}
 
794
 
 
795
qreal QQuickGridViewPrivate::footerSize() const
 
796
{
 
797
    if (!footer)
 
798
        return 0.0;
 
799
    return flow == QQuickGridView::FlowLeftToRight? footer->item->height() : footer->item->width();
 
800
}
 
801
 
 
802
bool QQuickGridViewPrivate::showHeaderForIndex(int index) const
 
803
{
 
804
    return index / columns == 0;
 
805
}
 
806
 
 
807
bool QQuickGridViewPrivate::showFooterForIndex(int index) const
 
808
{
 
809
    return index / columns == (model->count()-1) / columns;
 
810
}
 
811
 
 
812
void QQuickGridViewPrivate::updateFooter()
 
813
{
 
814
    Q_Q(QQuickGridView);
 
815
    bool created = false;
 
816
    if (!footer) {
 
817
        QQuickItem *item = createComponentItem(footerComponent, 1.0);
 
818
        if (!item)
 
819
            return;
 
820
        footer = new FxGridItemSG(item, q, true, true);
 
821
        created = true;
 
822
    }
 
823
 
 
824
    FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(footer);
 
825
    qreal colOffset = 0;
 
826
    qreal rowOffset = 0;
 
827
    if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
 
828
        if (flow == QQuickGridView::FlowTopToBottom)
 
829
            rowOffset += gridItem->item->width() - cellWidth;
 
830
        else
 
831
            colOffset += gridItem->item->width() - cellWidth;
 
832
    }
 
833
    if (verticalLayoutDirection == QQuickItemView::BottomToTop) {
 
834
        if (flow == QQuickGridView::FlowTopToBottom)
 
835
            colOffset += gridItem->item->height() - cellHeight;
 
836
        else
 
837
            rowOffset += gridItem->item->height() - cellHeight;
 
838
    }
 
839
    if (visibleItems.count()) {
 
840
        qreal endPos = lastPosition();
 
841
        if (findLastVisibleIndex() == model->count()-1) {
 
842
            gridItem->setPosition(colOffset, endPos + rowOffset);
 
843
        } else {
 
844
            qreal visiblePos = isContentFlowReversed() ? -position() : position() + size();
 
845
            if (endPos <= visiblePos || gridItem->endPosition() <= endPos + rowOffset)
 
846
                gridItem->setPosition(colOffset, endPos + rowOffset);
 
847
        }
 
848
    } else {
 
849
        gridItem->setPosition(colOffset, rowOffset);
 
850
    }
 
851
 
 
852
    if (created)
 
853
        emit q->footerItemChanged();
 
854
}
 
855
 
 
856
void QQuickGridViewPrivate::updateHeader()
 
857
{
 
858
    Q_Q(QQuickGridView);
 
859
    bool created = false;
 
860
    if (!header) {
 
861
        QQuickItem *item = createComponentItem(headerComponent, 1.0);
 
862
        if (!item)
 
863
            return;
 
864
        header = new FxGridItemSG(item, q, true, true);
 
865
        created = true;
 
866
    }
 
867
 
 
868
    FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(header);
 
869
    qreal colOffset = 0;
 
870
    qreal rowOffset = -headerSize();
 
871
    if (q->effectiveLayoutDirection() == Qt::RightToLeft) {
 
872
        if (flow == QQuickGridView::FlowTopToBottom)
 
873
            rowOffset += gridItem->item->width() - cellWidth;
 
874
        else
 
875
            colOffset += gridItem->item->width() - cellWidth;
 
876
    }
 
877
    if (verticalLayoutDirection == QQuickItemView::BottomToTop) {
 
878
        if (flow == QQuickGridView::FlowTopToBottom)
 
879
            colOffset += gridItem->item->height() - cellHeight;
 
880
        else
 
881
            rowOffset += gridItem->item->height() - cellHeight;
 
882
    }
 
883
    if (visibleItems.count()) {
 
884
        qreal startPos = originPosition();
 
885
        if (visibleIndex == 0) {
 
886
            gridItem->setPosition(colOffset, startPos + rowOffset);
 
887
        } else {
 
888
            qreal tempPos = isContentFlowReversed() ? -position()-size() : position();
 
889
            qreal headerPos = isContentFlowReversed() ? gridItem->rowPos() + cellWidth - headerSize() : gridItem->rowPos();
 
890
            if (tempPos <= startPos || headerPos > startPos + rowOffset)
 
891
                gridItem->setPosition(colOffset, startPos + rowOffset);
 
892
        }
 
893
    } else {
 
894
        if (isContentFlowReversed())
 
895
            gridItem->setPosition(colOffset, rowOffset);
 
896
        else
 
897
            gridItem->setPosition(colOffset, -headerSize());
 
898
    }
 
899
 
 
900
    if (created)
 
901
        emit q->headerItemChanged();
 
902
}
 
903
 
 
904
void QQuickGridViewPrivate::initializeCurrentItem()
 
905
{
 
906
    if (currentItem && currentIndex >= 0) {
 
907
        FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(currentItem);
 
908
        FxViewItem *actualItem = visibleItem(currentIndex);
 
909
 
 
910
        // don't reposition the item if it's about to be transitioned to another position
 
911
        if ((!actualItem || !actualItem->transitionScheduledOrRunning()))
 
912
            gridItem->setPosition(colPosAt(currentIndex), rowPosAt(currentIndex));
 
913
    }
 
914
}
 
915
 
 
916
void QQuickGridViewPrivate::fixupPosition()
 
917
{
 
918
    moveReason = Other;
 
919
    if (flow == QQuickGridView::FlowLeftToRight)
 
920
        fixupY();
 
921
    else
 
922
        fixupX();
 
923
}
 
924
 
 
925
void QQuickGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
 
926
{
 
927
    if ((flow == QQuickGridView::FlowTopToBottom && &data == &vData)
 
928
        || (flow == QQuickGridView::FlowLeftToRight && &data == &hData))
 
929
        return;
 
930
 
 
931
    fixupMode = moveReason == Mouse ? fixupMode : Immediate;
 
932
 
 
933
    qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
 
934
 
 
935
    bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickGridView::StrictlyEnforceRange;
 
936
    if (snapMode != QQuickGridView::NoSnap) {
 
937
        qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
 
938
        if (snapMode == QQuickGridView::SnapOneRow && moveReason == Mouse) {
 
939
            // if we've been dragged < rowSize()/2 then bias towards the next row
 
940
            qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
 
941
            qreal bias = 0;
 
942
            if (data.velocity > 0 && dist > QML_FLICK_SNAPONETHRESHOLD && dist < rowSize()/2)
 
943
                bias = rowSize()/2;
 
944
            else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -rowSize()/2)
 
945
                bias = -rowSize()/2;
 
946
            if (isContentFlowReversed())
 
947
                bias = -bias;
 
948
            tempPosition -= bias;
 
949
        }
 
950
        FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
 
951
        if (!topItem && strictHighlightRange && currentItem) {
 
952
            // StrictlyEnforceRange always keeps an item in range
 
953
            updateHighlight();
 
954
            topItem = currentItem;
 
955
        }
 
956
        FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
 
957
        if (!bottomItem && strictHighlightRange && currentItem) {
 
958
            // StrictlyEnforceRange always keeps an item in range
 
959
            updateHighlight();
 
960
            bottomItem = currentItem;
 
961
        }
 
962
        qreal pos;
 
963
        bool isInBounds = -position() > maxExtent && -position() <= minExtent;
 
964
        if (topItem && (isInBounds || strictHighlightRange)) {
 
965
            qreal headerPos = header ? static_cast<FxGridItemSG*>(header)->rowPos() : 0;
 
966
            if (topItem->index == 0 && header && tempPosition+highlightRangeStart < headerPos+headerSize()/2 && !strictHighlightRange) {
 
967
                pos = isContentFlowReversed() ? - headerPos + highlightRangeStart - size() : headerPos - highlightRangeStart;
 
968
            } else {
 
969
                if (isContentFlowReversed())
 
970
                    pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
 
971
                else
 
972
                    pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
 
973
            }
 
974
        } else if (bottomItem && isInBounds) {
 
975
            if (isContentFlowReversed())
 
976
                pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
 
977
            else
 
978
                pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
 
979
        } else {
 
980
            QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
 
981
            return;
 
982
        }
 
983
 
 
984
        qreal dist = qAbs(data.move + pos);
 
985
        if (dist > 0) {
 
986
            timeline.reset(data.move);
 
987
            if (fixupMode != Immediate) {
 
988
                timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
 
989
                data.fixingUp = true;
 
990
            } else {
 
991
                timeline.set(data.move, -pos);
 
992
            }
 
993
            vTime = timeline.time();
 
994
        }
 
995
    } else if (haveHighlightRange && highlightRange == QQuickGridView::StrictlyEnforceRange) {
 
996
        if (currentItem) {
 
997
            updateHighlight();
 
998
            qreal pos = static_cast<FxGridItemSG*>(currentItem)->rowPos();
 
999
            if (viewPos < pos + rowSize() - highlightRangeEnd)
 
1000
                viewPos = pos + rowSize() - highlightRangeEnd;
 
1001
            if (viewPos > pos - highlightRangeStart)
 
1002
                viewPos = pos - highlightRangeStart;
 
1003
            if (isContentFlowReversed())
 
1004
                viewPos = -viewPos-size();
 
1005
            timeline.reset(data.move);
 
1006
            if (viewPos != position()) {
 
1007
                if (fixupMode != Immediate) {
 
1008
                    timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
 
1009
                    data.fixingUp = true;
 
1010
                } else {
 
1011
                    timeline.set(data.move, -viewPos);
 
1012
                }
 
1013
            }
 
1014
            vTime = timeline.time();
 
1015
        }
 
1016
    } else {
 
1017
        QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
 
1018
    }
 
1019
    data.inOvershoot = false;
 
1020
    fixupMode = Normal;
 
1021
}
 
1022
 
 
1023
bool QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
 
1024
                                        QQuickTimeLineCallback::Callback fixupCallback, qreal velocity)
 
1025
{
 
1026
    data.fixingUp = false;
 
1027
    moveReason = Mouse;
 
1028
    if ((!haveHighlightRange || highlightRange != QQuickGridView::StrictlyEnforceRange)
 
1029
        && snapMode == QQuickGridView::NoSnap) {
 
1030
        return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
 
1031
    }
 
1032
    qreal maxDistance = 0;
 
1033
    qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value();
 
1034
    // -ve velocity means list is moving up/left
 
1035
    if (velocity > 0) {
 
1036
        if (data.move.value() < minExtent) {
 
1037
            if (snapMode == QQuickGridView::SnapOneRow) {
 
1038
                // if we've been dragged < averageSize/2 then bias towards the next item
 
1039
                qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
 
1040
                qreal bias = dist < rowSize()/2 ? rowSize()/2 : 0;
 
1041
                if (isContentFlowReversed())
 
1042
                    bias = -bias;
 
1043
                data.flickTarget = -snapPosAt(-dataValue - bias);
 
1044
                maxDistance = qAbs(data.flickTarget - data.move.value());
 
1045
                velocity = maxVelocity;
 
1046
            } else {
 
1047
                maxDistance = qAbs(minExtent - data.move.value());
 
1048
            }
 
1049
        }
 
1050
        if (snapMode == QQuickGridView::NoSnap && highlightRange != QQuickGridView::StrictlyEnforceRange)
 
1051
            data.flickTarget = minExtent;
 
1052
    } else {
 
1053
        if (data.move.value() > maxExtent) {
 
1054
            if (snapMode == QQuickGridView::SnapOneRow) {
 
1055
                // if we've been dragged < averageSize/2 then bias towards the next item
 
1056
                qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
 
1057
                qreal bias = -dist < rowSize()/2 ? rowSize()/2 : 0;
 
1058
                if (isContentFlowReversed())
 
1059
                    bias = -bias;
 
1060
                data.flickTarget = -snapPosAt(-dataValue + bias);
 
1061
                maxDistance = qAbs(data.flickTarget - data.move.value());
 
1062
                velocity = -maxVelocity;
 
1063
            } else {
 
1064
                maxDistance = qAbs(maxExtent - data.move.value());
 
1065
            }
 
1066
        }
 
1067
        if (snapMode == QQuickGridView::NoSnap && highlightRange != QQuickGridView::StrictlyEnforceRange)
 
1068
            data.flickTarget = maxExtent;
 
1069
    }
 
1070
    bool overShoot = boundsBehavior == QQuickFlickable::DragAndOvershootBounds;
 
1071
    if (maxDistance > 0 || overShoot) {
 
1072
        // This mode requires the grid to stop exactly on a row boundary.
 
1073
        qreal v = velocity;
 
1074
        if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
 
1075
            if (v < 0)
 
1076
                v = -maxVelocity;
 
1077
            else
 
1078
                v = maxVelocity;
 
1079
        }
 
1080
        qreal accel = deceleration;
 
1081
        qreal v2 = v * v;
 
1082
        qreal overshootDist = 0.0;
 
1083
        if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickGridView::SnapOneRow) {
 
1084
            // + rowSize()/4 to encourage moving at least one item in the flick direction
 
1085
            qreal dist = v2 / (accel * 2.0) + rowSize()/4;
 
1086
            dist = qMin(dist, maxDistance);
 
1087
            if (v > 0)
 
1088
                dist = -dist;
 
1089
            if (snapMode != QQuickGridView::SnapOneRow) {
 
1090
                qreal distTemp = isContentFlowReversed() ? -dist : dist;
 
1091
                data.flickTarget = -snapPosAt(-dataValue + distTemp);
 
1092
            }
 
1093
            data.flickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
 
1094
            if (overShoot) {
 
1095
                if (data.flickTarget >= minExtent) {
 
1096
                    overshootDist = overShootDistance(vSize);
 
1097
                    data.flickTarget += overshootDist;
 
1098
                } else if (data.flickTarget <= maxExtent) {
 
1099
                    overshootDist = overShootDistance(vSize);
 
1100
                    data.flickTarget -= overshootDist;
 
1101
                }
 
1102
            }
 
1103
            qreal adjDist = -data.flickTarget + data.move.value();
 
1104
            if (qAbs(adjDist) > qAbs(dist)) {
 
1105
                // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
 
1106
                qreal adjv2 = accel * 2.0f * qAbs(adjDist);
 
1107
                if (adjv2 > v2) {
 
1108
                    v2 = adjv2;
 
1109
                    v = qSqrt(v2);
 
1110
                    if (dist > 0)
 
1111
                        v = -v;
 
1112
                }
 
1113
            }
 
1114
            dist = adjDist;
 
1115
            accel = v2 / (2.0f * qAbs(dist));
 
1116
        } else {
 
1117
            data.flickTarget = velocity > 0 ? minExtent : maxExtent;
 
1118
            overshootDist = overShoot ? overShootDistance(vSize) : 0;
 
1119
        }
 
1120
        timeline.reset(data.move);
 
1121
        timeline.accel(data.move, v, accel, maxDistance + overshootDist);
 
1122
        timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
 
1123
        return true;
 
1124
    } else {
 
1125
        timeline.reset(data.move);
 
1126
        fixup(data, minExtent, maxExtent);
 
1127
        return false;
 
1128
    }
 
1129
}
 
1130
 
 
1131
 
 
1132
//----------------------------------------------------------------------------
 
1133
/*!
 
1134
    \qmltype GridView
 
1135
    \instantiates QQuickGridView
 
1136
    \inqmlmodule QtQuick 2
 
1137
    \ingroup qtquick-views
 
1138
 
 
1139
    \inherits Flickable
 
1140
    \brief For specifying a grid view of items provided by a model
 
1141
 
 
1142
    A GridView displays data from models created from built-in QML types like ListModel
 
1143
    and XmlListModel, or custom model classes defined in C++ that inherit from
 
1144
    QAbstractListModel.
 
1145
 
 
1146
    A GridView has a \l model, which defines the data to be displayed, and
 
1147
    a \l delegate, which defines how the data should be displayed. Items in a
 
1148
    GridView are laid out horizontally or vertically. Grid views are inherently flickable
 
1149
    as GridView inherits from \l Flickable.
 
1150
 
 
1151
    \section1 Example Usage
 
1152
 
 
1153
    The following example shows the definition of a simple list model defined
 
1154
    in a file called \c ContactModel.qml:
 
1155
 
 
1156
    \snippet qml/gridview/ContactModel.qml 0
 
1157
 
 
1158
    \div {class="float-right"}
 
1159
    \inlineimage gridview-simple.png
 
1160
    \enddiv
 
1161
 
 
1162
    This model can be referenced as \c ContactModel in other QML files. See \l{QML Modules}
 
1163
    for more information about creating reusable components like this.
 
1164
 
 
1165
    Another component can display this model data in a GridView, as in the following
 
1166
    example, which creates a \c ContactModel component for its model, and a \l Column
 
1167
    (containing \l Image and \l Text items) for its delegate.
 
1168
 
 
1169
    \clearfloat
 
1170
    \snippet qml/gridview/gridview.qml import
 
1171
    \codeline
 
1172
    \snippet qml/gridview/gridview.qml classdocs simple
 
1173
 
 
1174
    \div {class="float-right"}
 
1175
    \inlineimage gridview-highlight.png
 
1176
    \enddiv
 
1177
 
 
1178
    The view will create a new delegate for each item in the model. Note that the delegate
 
1179
    is able to access the model's \c name and \c portrait data directly.
 
1180
 
 
1181
    An improved grid view is shown below. The delegate is visually improved and is moved
 
1182
    into a separate \c contactDelegate component.
 
1183
 
 
1184
    \clearfloat
 
1185
    \snippet qml/gridview/gridview.qml classdocs advanced
 
1186
 
 
1187
    The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
 
1188
    and \c focus is set to \c true to enable keyboard navigation for the grid view.
 
1189
    The grid view itself is a focus scope (see \l{Keyboard Focus in Qt Quick} for more details).
 
1190
 
 
1191
    Delegates are instantiated as needed and may be destroyed at any time.
 
1192
    State should \e never be stored in a delegate.
 
1193
 
 
1194
    GridView attaches a number of properties to the root item of the delegate, for example
 
1195
    \c {GridView.isCurrentItem}.  In the following example, the root delegate item can access
 
1196
    this attached property directly as \c GridView.isCurrentItem, while the child
 
1197
    \c contactInfo object must refer to this property as \c wrapper.GridView.isCurrentItem.
 
1198
 
 
1199
    \snippet qml/gridview/gridview.qml isCurrentItem
 
1200
 
 
1201
    \note Views do not set the \l{Item::}{clip} property automatically.
 
1202
    If the view is not clipped by another item or the screen, it will be necessary
 
1203
    to set this property to true in order to clip the items that are partially or
 
1204
    fully outside the view.
 
1205
 
 
1206
 
 
1207
    \section1 GridView layouts
 
1208
 
 
1209
    The layout of the items in a GridView can be controlled by these properties:
 
1210
 
 
1211
    \list
 
1212
    \li \l flow - controls whether items flow from left to right (as a series of rows)
 
1213
        or from top to bottom (as a series of columns). This value can be either
 
1214
        GridView.LeftToRight or GridView.TopToBottom.
 
1215
    \li \l layoutDirection - controls the horizontal layout direction: that is, whether items
 
1216
        are laid out from the left side of the view to the right, or vice-versa. This value can
 
1217
        be either Qt.LeftToRight or Qt.RightToLeft.
 
1218
    \li \l verticalLayoutDirection - controls the vertical layout direction: that is, whether items
 
1219
        are laid out from the top of the view down towards the bottom of the view, or vice-versa.
 
1220
        This value can be either GridView.TopToBottom or GridView.BottomToTop.
 
1221
    \endlist
 
1222
 
 
1223
    By default, a GridView flows from left to right, and items are laid out from left to right
 
1224
    horizontally, and from top to bottom vertically.
 
1225
 
 
1226
    These properties can be combined to produce a variety of layouts, as shown in the table below.
 
1227
    The GridViews in the first row all have a \l flow value of GridView.LeftToRight, but use
 
1228
    different combinations of horizontal and vertical layout directions (specified by \l layoutDirection
 
1229
    and \l verticalLayoutDirection respectively). Similarly, the GridViews in the second row below
 
1230
    all have a \l flow value of GridView.TopToBottom, but use different combinations of horizontal and
 
1231
    vertical layout directions to lay out their items in different ways.
 
1232
 
 
1233
    \table
 
1234
    \header
 
1235
        \li {4, 1}
 
1236
            \b GridViews with GridView.LeftToRight flow
 
1237
    \row
 
1238
        \li \b (H) Left to right \b (V) Top to bottom
 
1239
            \image gridview-layout-lefttoright-ltr-ttb.png
 
1240
        \li \b (H) Right to left \b (V) Top to bottom
 
1241
            \image gridview-layout-lefttoright-rtl-ttb.png
 
1242
        \li \b (H) Left to right \b (V) Bottom to top
 
1243
            \image gridview-layout-lefttoright-ltr-btt.png
 
1244
        \li \b (H) Right to left \b (V) Bottom to top
 
1245
            \image gridview-layout-lefttoright-rtl-btt.png
 
1246
    \header
 
1247
        \li {4, 1}
 
1248
            \b GridViews with GridView.TopToBottom flow
 
1249
    \row
 
1250
        \li \b (H) Left to right \b (V) Top to bottom
 
1251
            \image gridview-layout-toptobottom-ltr-ttb.png
 
1252
        \li \b (H) Right to left \b (V) Top to bottom
 
1253
            \image gridview-layout-toptobottom-rtl-ttb.png
 
1254
        \li \b (H) Left to right \b (V) Bottom to top
 
1255
            \image gridview-layout-toptobottom-ltr-btt.png
 
1256
        \li \b (H) Right to left \b (V) Bottom to top
 
1257
            \image gridview-layout-toptobottom-rtl-btt.png
 
1258
    \endtable
 
1259
 
 
1260
    \sa {quick/modelviews/gridview}{GridView example}
 
1261
*/
 
1262
 
 
1263
QQuickGridView::QQuickGridView(QQuickItem *parent)
 
1264
    : QQuickItemView(*(new QQuickGridViewPrivate), parent)
 
1265
{
 
1266
}
 
1267
 
 
1268
QQuickGridView::~QQuickGridView()
 
1269
{
 
1270
}
 
1271
 
 
1272
void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
 
1273
{
 
1274
    Q_D(QQuickGridView);
 
1275
    if (d->autoHighlight != autoHighlight) {
 
1276
        if (!autoHighlight && d->highlightXAnimator) {
 
1277
            d->highlightXAnimator->stop();
 
1278
            d->highlightYAnimator->stop();
 
1279
        }
 
1280
        QQuickItemView::setHighlightFollowsCurrentItem(autoHighlight);
 
1281
    }
 
1282
}
 
1283
 
 
1284
/*!
 
1285
    \qmlattachedproperty bool QtQuick2::GridView::isCurrentItem
 
1286
    This attached property is true if this delegate is the current item; otherwise false.
 
1287
 
 
1288
    It is attached to each instance of the delegate.
 
1289
*/
 
1290
 
 
1291
/*!
 
1292
    \qmlattachedproperty GridView QtQuick2::GridView::view
 
1293
    This attached property holds the view that manages this delegate instance.
 
1294
 
 
1295
    It is attached to each instance of the delegate.
 
1296
 
 
1297
    \snippet qml/gridview/gridview.qml isCurrentItem
 
1298
*/
 
1299
 
 
1300
/*!
 
1301
    \qmlattachedproperty bool QtQuick2::GridView::delayRemove
 
1302
    This attached property holds whether the delegate may be destroyed. It
 
1303
    is attached to each instance of the delegate. The default value is false.
 
1304
 
 
1305
    It is sometimes necessary to delay the destruction of an item
 
1306
    until an animation completes. The example delegate below ensures that the
 
1307
    animation completes before the item is removed from the list.
 
1308
 
 
1309
    \snippet qml/gridview/gridview.qml delayRemove
 
1310
 
 
1311
    If a \l remove transition has been specified, it will not be applied until
 
1312
    delayRemove is returned to \c false.
 
1313
*/
 
1314
 
 
1315
/*!
 
1316
    \qmlattachedsignal QtQuick2::GridView::onAdd()
 
1317
    This attached handler is called immediately after an item is added to the view.
 
1318
*/
 
1319
 
 
1320
/*!
 
1321
    \qmlattachedsignal QtQuick2::GridView::onRemove()
 
1322
    This attached handler is called immediately before an item is removed from the view.
 
1323
 
 
1324
    If a \l remove transition has been specified, it is applied after
 
1325
    this signal handler is called, providing that delayRemove is false.
 
1326
*/
 
1327
 
 
1328
 
 
1329
/*!
 
1330
  \qmlproperty model QtQuick2::GridView::model
 
1331
  This property holds the model providing data for the grid.
 
1332
 
 
1333
    The model provides the set of data that is used to create the items
 
1334
    in the view. Models can be created directly in QML using \l ListModel, \l XmlListModel
 
1335
    or \l VisualItemModel, or provided by C++ model classes. If a C++ model class is
 
1336
    used, it must be a subclass of \l QAbstractItemModel or a simple list.
 
1337
 
 
1338
  \sa {qml-data-models}{Data Models}
 
1339
*/
 
1340
 
 
1341
/*!
 
1342
    \qmlproperty Component QtQuick2::GridView::delegate
 
1343
 
 
1344
    The delegate provides a template defining each item instantiated by the view.
 
1345
    The index is exposed as an accessible \c index property.  Properties of the
 
1346
    model are also available depending upon the type of \l {qml-data-models}{Data Model}.
 
1347
 
 
1348
    The number of objects and bindings in the delegate has a direct effect on the
 
1349
    flicking performance of the view.  If at all possible, place functionality
 
1350
    that is not needed for the normal display of the delegate in a \l Loader which
 
1351
    can load additional components when needed.
 
1352
 
 
1353
    The item size of the GridView is determined by cellHeight and cellWidth. It will not resize the items
 
1354
    based on the size of the root item in the delegate.
 
1355
 
 
1356
    \note Delegates are instantiated as needed and may be destroyed at any time.
 
1357
    State should \e never be stored in a delegate.
 
1358
*/
 
1359
 
 
1360
/*!
 
1361
  \qmlproperty int QtQuick2::GridView::currentIndex
 
1362
  \qmlproperty Item QtQuick2::GridView::currentItem
 
1363
 
 
1364
    The \c currentIndex property holds the index of the current item, and
 
1365
    \c currentItem holds the current item.  Setting the currentIndex to -1
 
1366
    will clear the highlight and set currentItem to null.
 
1367
 
 
1368
    If highlightFollowsCurrentItem is \c true, setting either of these
 
1369
    properties will smoothly scroll the GridView so that the current
 
1370
    item becomes visible.
 
1371
 
 
1372
    Note that the position of the current item
 
1373
    may only be approximate until it becomes visible in the view.
 
1374
*/
 
1375
 
 
1376
 
 
1377
/*!
 
1378
  \qmlproperty Item QtQuick2::GridView::highlightItem
 
1379
 
 
1380
  This holds the highlight item created from the \l highlight component.
 
1381
 
 
1382
  The highlightItem is managed by the view unless
 
1383
  \l highlightFollowsCurrentItem is set to false.
 
1384
 
 
1385
  \sa highlight, highlightFollowsCurrentItem
 
1386
*/
 
1387
 
 
1388
 
 
1389
/*!
 
1390
  \qmlproperty int QtQuick2::GridView::count
 
1391
  This property holds the number of items in the view.
 
1392
*/
 
1393
 
 
1394
 
 
1395
/*!
 
1396
  \qmlproperty Component QtQuick2::GridView::highlight
 
1397
  This property holds the component to use as the highlight.
 
1398
 
 
1399
  An instance of the highlight component is created for each view.
 
1400
  The geometry of the resulting component instance will be managed by the view
 
1401
  so as to stay with the current item, unless the highlightFollowsCurrentItem property is false.
 
1402
 
 
1403
  \sa highlightItem, highlightFollowsCurrentItem
 
1404
*/
 
1405
 
 
1406
/*!
 
1407
  \qmlproperty bool QtQuick2::GridView::highlightFollowsCurrentItem
 
1408
  This property sets whether the highlight is managed by the view.
 
1409
 
 
1410
    If this property is true (the default value), the highlight is moved smoothly
 
1411
    to follow the current item.  Otherwise, the
 
1412
    highlight is not moved by the view, and any movement must be implemented
 
1413
    by the highlight.
 
1414
 
 
1415
    Here is a highlight with its motion defined by a \l {SpringAnimation} item:
 
1416
 
 
1417
    \snippet qml/gridview/gridview.qml highlightFollowsCurrentItem
 
1418
*/
 
1419
 
 
1420
 
 
1421
/*!
 
1422
    \qmlproperty int QtQuick2::GridView::highlightMoveDuration
 
1423
    This property holds the move animation duration of the highlight delegate.
 
1424
 
 
1425
    highlightFollowsCurrentItem must be true for this property
 
1426
    to have effect.
 
1427
 
 
1428
    The default value for the duration is 150ms.
 
1429
 
 
1430
    \sa highlightFollowsCurrentItem
 
1431
*/
 
1432
 
 
1433
/*!
 
1434
    \qmlproperty real QtQuick2::GridView::preferredHighlightBegin
 
1435
    \qmlproperty real QtQuick2::GridView::preferredHighlightEnd
 
1436
    \qmlproperty enumeration QtQuick2::GridView::highlightRangeMode
 
1437
 
 
1438
    These properties define the preferred range of the highlight (for the current item)
 
1439
    within the view. The \c preferredHighlightBegin value must be less than the
 
1440
    \c preferredHighlightEnd value.
 
1441
 
 
1442
    These properties affect the position of the current item when the view is scrolled.
 
1443
    For example, if the currently selected item should stay in the middle of the
 
1444
    view when it is scrolled, set the \c preferredHighlightBegin and
 
1445
    \c preferredHighlightEnd values to the top and bottom coordinates of where the middle
 
1446
    item would be. If the \c currentItem is changed programmatically, the view will
 
1447
    automatically scroll so that the current item is in the middle of the view.
 
1448
    Furthermore, the behavior of the current item index will occur whether or not a
 
1449
    highlight exists.
 
1450
 
 
1451
    Valid values for \c highlightRangeMode are:
 
1452
 
 
1453
    \list
 
1454
    \li GridView.ApplyRange - the view attempts to maintain the highlight within the range.
 
1455
       However, the highlight can move outside of the range at the ends of the view or due
 
1456
       to mouse interaction.
 
1457
    \li GridView.StrictlyEnforceRange - the highlight never moves outside of the range.
 
1458
       The current item changes if a keyboard or mouse action would cause the highlight to move
 
1459
       outside of the range.
 
1460
    \li GridView.NoHighlightRange - this is the default value.
 
1461
    \endlist
 
1462
*/
 
1463
 
 
1464
 
 
1465
/*!
 
1466
  \qmlproperty enumeration QtQuick2::GridView::layoutDirection
 
1467
  This property holds the layout direction of the grid.
 
1468
 
 
1469
    Possible values:
 
1470
 
 
1471
  \list
 
1472
  \li Qt.LeftToRight (default) - Items will be laid out starting in the top, left corner. The flow is
 
1473
  dependent on the \l GridView::flow property.
 
1474
  \li Qt.RightToLeft - Items will be laid out starting in the top, right corner. The flow is dependent
 
1475
  on the \l GridView::flow property.
 
1476
  \endlist
 
1477
 
 
1478
  \b Note: If GridView::flow is set to GridView.LeftToRight, this is not to be confused if
 
1479
  GridView::layoutDirection is set to Qt.RightToLeft. The GridView.LeftToRight flow value simply
 
1480
  indicates that the flow is horizontal.
 
1481
 
 
1482
  \sa GridView::effectiveLayoutDirection, GridView::verticalLayoutDirection
 
1483
*/
 
1484
 
 
1485
 
 
1486
/*!
 
1487
    \qmlproperty enumeration QtQuick2::GridView::effectiveLayoutDirection
 
1488
    This property holds the effective layout direction of the grid.
 
1489
 
 
1490
    When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
 
1491
    the visual layout direction of the grid will be mirrored. However, the
 
1492
    property \l {GridView::layoutDirection}{layoutDirection} will remain unchanged.
 
1493
 
 
1494
    \sa GridView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
 
1495
*/
 
1496
 
 
1497
/*!
 
1498
  \qmlproperty enumeration QtQuick2::GridView::verticalLayoutDirection
 
1499
  This property holds the vertical layout direction of the grid.
 
1500
 
 
1501
  Possible values:
 
1502
 
 
1503
  \list
 
1504
  \li GridView.TopToBottom (default) - Items are laid out from the top of the view down to the bottom of the view.
 
1505
  \li GridView.BottomToTop - Items are laid out from the bottom of the view up to the top of the view.
 
1506
  \endlist
 
1507
 
 
1508
  \sa GridView::layoutDirection
 
1509
*/
 
1510
 
 
1511
/*!
 
1512
  \qmlproperty bool QtQuick2::GridView::keyNavigationWraps
 
1513
  This property holds whether the grid wraps key navigation
 
1514
 
 
1515
    If this is true, key navigation that would move the current item selection
 
1516
    past one end of the view instead wraps around and moves the selection to
 
1517
    the other end of the view.
 
1518
 
 
1519
    By default, key navigation is not wrapped.
 
1520
*/
 
1521
/*!
 
1522
    \qmlproperty int QtQuick2::GridView::cacheBuffer
 
1523
    This property determines whether delegates are retained outside the
 
1524
    visible area of the view.
 
1525
 
 
1526
    If non-zero the view may keep as many delegates
 
1527
    instantiated as will fit within the buffer specified.  For example,
 
1528
    if in a vertical view the delegate is 20 pixels high, there are 3
 
1529
    columns and \c cacheBuffer is
 
1530
    set to 40, then up to 6 delegates above and 6 delegates below the visible
 
1531
    area may be created/retained.  The buffered delegates are created asynchronously,
 
1532
    allowing creation to occur across multiple frames and reducing the
 
1533
    likelihood of skipping frames.  In order to improve painting performance
 
1534
    delegates outside the visible area are not painted.
 
1535
 
 
1536
    The default value of this property is platform dependent, but will usually
 
1537
    be a non-zero value.
 
1538
 
 
1539
    Note that cacheBuffer is not a pixel buffer - it only maintains additional
 
1540
    instantiated delegates.
 
1541
 
 
1542
    Setting this value can make scrolling the list smoother at the expense
 
1543
    of additional memory usage.  It is not a substitute for creating efficient
 
1544
    delegates; the fewer objects and bindings in a delegate, the faster a view may be
 
1545
    scrolled.
 
1546
*/
 
1547
void QQuickGridView::setHighlightMoveDuration(int duration)
 
1548
{
 
1549
    Q_D(QQuickGridView);
 
1550
    if (d->highlightMoveDuration != duration) {
 
1551
        if (d->highlightYAnimator) {
 
1552
            d->highlightXAnimator->userDuration = duration;
 
1553
            d->highlightYAnimator->userDuration = duration;
 
1554
        }
 
1555
        QQuickItemView::setHighlightMoveDuration(duration);
 
1556
    }
 
1557
}
 
1558
 
 
1559
/*!
 
1560
  \qmlproperty enumeration QtQuick2::GridView::flow
 
1561
  This property holds the flow of the grid.
 
1562
 
 
1563
    Possible values:
 
1564
 
 
1565
    \list
 
1566
    \li GridView.LeftToRight (default) - Items are laid out from left to right, and the view scrolls vertically
 
1567
    \li GridView.TopToBottom - Items are laid out from top to bottom, and the view scrolls horizontally
 
1568
    \endlist
 
1569
*/
 
1570
QQuickGridView::Flow QQuickGridView::flow() const
 
1571
{
 
1572
    Q_D(const QQuickGridView);
 
1573
    return d->flow;
 
1574
}
 
1575
 
 
1576
void QQuickGridView::setFlow(Flow flow)
 
1577
{
 
1578
    Q_D(QQuickGridView);
 
1579
    if (d->flow != flow) {
 
1580
        d->flow = flow;
 
1581
        if (d->flow == FlowLeftToRight) {
 
1582
            setContentWidth(-1);
 
1583
            setFlickableDirection(VerticalFlick);
 
1584
        } else {
 
1585
            setContentHeight(-1);
 
1586
            setFlickableDirection(HorizontalFlick);
 
1587
        }
 
1588
        setContentX(0);
 
1589
        setContentY(0);
 
1590
        d->regenerate();
 
1591
        emit flowChanged();
 
1592
    }
 
1593
}
 
1594
 
 
1595
 
 
1596
/*!
 
1597
  \qmlproperty real QtQuick2::GridView::cellWidth
 
1598
  \qmlproperty real QtQuick2::GridView::cellHeight
 
1599
 
 
1600
  These properties holds the width and height of each cell in the grid.
 
1601
 
 
1602
  The default cell size is 100x100.
 
1603
*/
 
1604
qreal QQuickGridView::cellWidth() const
 
1605
{
 
1606
    Q_D(const QQuickGridView);
 
1607
    return d->cellWidth;
 
1608
}
 
1609
 
 
1610
void QQuickGridView::setCellWidth(qreal cellWidth)
 
1611
{
 
1612
    Q_D(QQuickGridView);
 
1613
    if (cellWidth != d->cellWidth && cellWidth > 0) {
 
1614
        d->cellWidth = qMax(qreal(1), cellWidth);
 
1615
        d->updateViewport();
 
1616
        emit cellWidthChanged();
 
1617
        d->forceLayoutPolish();
 
1618
    }
 
1619
}
 
1620
 
 
1621
qreal QQuickGridView::cellHeight() const
 
1622
{
 
1623
    Q_D(const QQuickGridView);
 
1624
    return d->cellHeight;
 
1625
}
 
1626
 
 
1627
void QQuickGridView::setCellHeight(qreal cellHeight)
 
1628
{
 
1629
    Q_D(QQuickGridView);
 
1630
    if (cellHeight != d->cellHeight && cellHeight > 0) {
 
1631
        d->cellHeight = qMax(qreal(1), cellHeight);
 
1632
        d->updateViewport();
 
1633
        emit cellHeightChanged();
 
1634
        d->forceLayoutPolish();
 
1635
    }
 
1636
}
 
1637
/*!
 
1638
    \qmlproperty enumeration QtQuick2::GridView::snapMode
 
1639
 
 
1640
    This property determines how the view scrolling will settle following a drag or flick.
 
1641
    The possible values are:
 
1642
 
 
1643
    \list
 
1644
    \li GridView.NoSnap (default) - the view stops anywhere within the visible area.
 
1645
    \li GridView.SnapToRow - the view settles with a row (or column for \c GridView.TopToBottom flow)
 
1646
    aligned with the start of the view.
 
1647
    \li GridView.SnapOneRow - the view will settle no more than one row (or column for \c GridView.TopToBottom flow)
 
1648
    away from the first visible row at the time the mouse button is released.
 
1649
    This mode is particularly useful for moving one page at a time.
 
1650
    \endlist
 
1651
 
 
1652
*/
 
1653
QQuickGridView::SnapMode QQuickGridView::snapMode() const
 
1654
{
 
1655
    Q_D(const QQuickGridView);
 
1656
    return d->snapMode;
 
1657
}
 
1658
 
 
1659
void QQuickGridView::setSnapMode(SnapMode mode)
 
1660
{
 
1661
    Q_D(QQuickGridView);
 
1662
    if (d->snapMode != mode) {
 
1663
        d->snapMode = mode;
 
1664
        emit snapModeChanged();
 
1665
    }
 
1666
}
 
1667
 
 
1668
 
 
1669
/*!
 
1670
    \qmlproperty Component QtQuick2::GridView::footer
 
1671
    This property holds the component to use as the footer.
 
1672
 
 
1673
    An instance of the footer component is created for each view.  The
 
1674
    footer is positioned at the end of the view, after any items.
 
1675
 
 
1676
    \sa header, footerItem
 
1677
*/
 
1678
/*!
 
1679
    \qmlproperty Component QtQuick2::GridView::header
 
1680
    This property holds the component to use as the header.
 
1681
 
 
1682
    An instance of the header component is created for each view.  The
 
1683
    header is positioned at the beginning of the view, before any items.
 
1684
 
 
1685
    \sa footer, headerItem
 
1686
*/
 
1687
 
 
1688
/*!
 
1689
    \qmlproperty Item QtQuick2::GridView::headerItem
 
1690
    This holds the header item created from the \l header component.
 
1691
 
 
1692
    An instance of the header component is created for each view.  The
 
1693
    header is positioned at the beginning of the view, before any items.
 
1694
 
 
1695
    \sa header, footerItem
 
1696
*/
 
1697
 
 
1698
/*!
 
1699
    \qmlproperty Item QtQuick2::GridView::footerItem
 
1700
    This holds the footer item created from the \l footer component.
 
1701
 
 
1702
    An instance of the footer component is created for each view.  The
 
1703
    footer is positioned at the end of the view, after any items.
 
1704
 
 
1705
    \sa footer, headerItem
 
1706
*/
 
1707
 
 
1708
/*!
 
1709
    \qmlproperty Transition QtQuick2::GridView::populate
 
1710
 
 
1711
    This property holds the transition to apply to the items that are initially created
 
1712
    for a view.
 
1713
 
 
1714
    It is applied to all items that are created when:
 
1715
 
 
1716
    \list
 
1717
    \li The view is first created
 
1718
    \li The view's \l model changes
 
1719
    \li The view's \l model is \l {QAbstractItemModel::reset()}{reset}, if the model is a QAbstractItemModel subclass
 
1720
    \endlist
 
1721
 
 
1722
    For example, here is a view that specifies such a transition:
 
1723
 
 
1724
    \code
 
1725
    GridView {
 
1726
        ...
 
1727
        populate: Transition {
 
1728
            NumberAnimation { properties: "x,y"; duration: 1000 }
 
1729
        }
 
1730
    }
 
1731
    \endcode
 
1732
 
 
1733
    When the view is initialized, the view will create all the necessary items for the view,
 
1734
    then animate them to their correct positions within the view over one second.
 
1735
 
 
1736
    For more details and examples on how to use view transitions, see the ViewTransition
 
1737
    documentation.
 
1738
 
 
1739
    \sa add, ViewTransition
 
1740
*/
 
1741
 
 
1742
/*!
 
1743
    \qmlproperty Transition QtQuick2::GridView::add
 
1744
 
 
1745
    This property holds the transition to apply to items that are added to the view.
 
1746
 
 
1747
    For example, here is a view that specifies such a transition:
 
1748
 
 
1749
    \code
 
1750
    GridView {
 
1751
        ...
 
1752
        add: Transition {
 
1753
            NumberAnimation { properties: "x,y"; from: 100; duration: 1000 }
 
1754
        }
 
1755
    }
 
1756
    \endcode
 
1757
 
 
1758
    Whenever an item is added to the above view, the item will be animated from the position (100,100)
 
1759
    to its final x,y position within the view, over one second. The transition only applies to
 
1760
    the new items that are added to the view; it does not apply to the items below that are
 
1761
    displaced by the addition of the new items. To animate the displaced items, set the \l displaced
 
1762
    or \l addDisplaced properties.
 
1763
 
 
1764
    For more details and examples on how to use view transitions, see the ViewTransition
 
1765
    documentation.
 
1766
 
 
1767
    \note This transition is not applied to the items that are created when the view is initially
 
1768
    populated, or when the view's \l model changes. (In those cases, the \l populate transition is
 
1769
    applied instead.) Additionally, this transition should \e not animate the height of the new item;
 
1770
    doing so will cause any items beneath the new item to be laid out at the wrong position. Instead,
 
1771
    the height can be animated within a \l {ListView::onAdd()}{ListView.onAdd} in the delegate.
 
1772
 
 
1773
    \sa addDisplaced, populate, ViewTransition
 
1774
*/
 
1775
 
 
1776
/*!
 
1777
    \qmlproperty Transition QtQuick2::GridView::addDisplaced
 
1778
 
 
1779
    This property holds the transition to apply to items within the view that are displaced by
 
1780
    the addition of other items to the view.
 
1781
 
 
1782
    For example, here is a view that specifies such a transition:
 
1783
 
 
1784
    \code
 
1785
    GridView {
 
1786
        ...
 
1787
        addDisplaced: Transition {
 
1788
            NumberAnimation { properties: "x,y"; duration: 1000 }
 
1789
        }
 
1790
    }
 
1791
    \endcode
 
1792
 
 
1793
    Whenever an item is added to the above view, all items beneath the new item are displaced, causing
 
1794
    them to move down (or sideways, if horizontally orientated) within the view. As this
 
1795
    displacement occurs, the items' movement to their new x,y positions within the view will be
 
1796
    animated by a NumberAnimation over one second, as specified. This transition is not applied to
 
1797
    the new item that has been added to the view; to animate the added items, set the \l add
 
1798
    property.
 
1799
 
 
1800
    If an item is displaced by multiple types of operations at the same time, it is not defined as to
 
1801
    whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
 
1802
    if it is not necessary to specify different transitions depending on whether an item is displaced
 
1803
    by an add, move or remove operation, consider setting the \l displaced property instead.
 
1804
 
 
1805
    For more details and examples on how to use view transitions, see the ViewTransition
 
1806
    documentation.
 
1807
 
 
1808
    \note This transition is not applied to the items that are created when the view is initially
 
1809
    populated, or when the view's \l model changes. In those cases, the \l populate transition is
 
1810
    applied instead.
 
1811
 
 
1812
    \sa displaced, add, populate, ViewTransition
 
1813
*/
 
1814
/*!
 
1815
    \qmlproperty Transition QtQuick2::GridView::move
 
1816
 
 
1817
    This property holds the transition to apply to items in the view that are being moved due
 
1818
    to a move operation in the view's \l model.
 
1819
 
 
1820
    For example, here is a view that specifies such a transition:
 
1821
 
 
1822
    \code
 
1823
    GridView {
 
1824
        ...
 
1825
        move: Transition {
 
1826
            NumberAnimation { properties: "x,y"; duration: 1000 }
 
1827
        }
 
1828
    }
 
1829
    \endcode
 
1830
 
 
1831
    Whenever the \l model performs a move operation to move a particular set of indexes, the
 
1832
    respective items in the view will be animated to their new positions in the view over one
 
1833
    second. The transition only applies to the items that are the subject of the move operation
 
1834
    in the model; it does not apply to items below them that are displaced by the move operation.
 
1835
    To animate the displaced items, set the \l displaced or \l moveDisplaced properties.
 
1836
 
 
1837
    For more details and examples on how to use view transitions, see the ViewTransition
 
1838
    documentation.
 
1839
 
 
1840
    \sa moveDisplaced, ViewTransition
 
1841
*/
 
1842
 
 
1843
/*!
 
1844
    \qmlproperty Transition QtQuick2::GridView::moveDisplaced
 
1845
 
 
1846
    This property holds the transition to apply to items that are displaced by a move operation in
 
1847
    the view's \l model.
 
1848
 
 
1849
    For example, here is a view that specifies such a transition:
 
1850
 
 
1851
    \code
 
1852
    GridView {
 
1853
        ...
 
1854
        moveDisplaced: Transition {
 
1855
            NumberAnimation { properties: "x,y"; duration: 1000 }
 
1856
        }
 
1857
    }
 
1858
    \endcode
 
1859
 
 
1860
    Whenever the \l model performs a move operation to move a particular set of indexes, the items
 
1861
    between the source and destination indexes of the move operation are displaced, causing them
 
1862
    to move upwards or downwards (or sideways, if horizontally orientated) within the view. As this
 
1863
    displacement occurs, the items' movement to their new x,y positions within the view will be
 
1864
    animated by a NumberAnimation over one second, as specified. This transition is not applied to
 
1865
    the items that are the actual subjects of the move operation; to animate the moved items, set
 
1866
    the \l move property.
 
1867
 
 
1868
    If an item is displaced by multiple types of operations at the same time, it is not defined as to
 
1869
    whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
 
1870
    if it is not necessary to specify different transitions depending on whether an item is displaced
 
1871
    by an add, move or remove operation, consider setting the \l displaced property instead.
 
1872
 
 
1873
    For more details and examples on how to use view transitions, see the ViewTransition
 
1874
    documentation.
 
1875
 
 
1876
    \sa displaced, move, ViewTransition
 
1877
*/
 
1878
 
 
1879
/*!
 
1880
    \qmlproperty Transition QtQuick2::GridView::remove
 
1881
 
 
1882
    This property holds the transition to apply to items that are removed from the view.
 
1883
 
 
1884
    For example, here is a view that specifies such a transition:
 
1885
 
 
1886
    \code
 
1887
    GridView {
 
1888
        ...
 
1889
        remove: Transition {
 
1890
            ParallelAnimation {
 
1891
                NumberAnimation { property: "opacity"; to: 0; duration: 1000 }
 
1892
                NumberAnimation { properties: "x,y"; to: 100; duration: 1000 }
 
1893
            }
 
1894
        }
 
1895
    }
 
1896
    \endcode
 
1897
 
 
1898
    Whenever an item is removed from the above view, the item will be animated to the position (100,100)
 
1899
    over one second, and in parallel will also change its opacity to 0. The transition
 
1900
    only applies to the items that are removed from the view; it does not apply to the items below
 
1901
    them that are displaced by the removal of the items. To animate the displaced items, set the
 
1902
    \l displaced or \l removeDisplaced properties.
 
1903
 
 
1904
    Note that by the time the transition is applied, the item has already been removed from the
 
1905
    model; any references to the model data for the removed index will not be valid.
 
1906
 
 
1907
    Additionally, if the \l delayRemove attached property has been set for a delegate item, the
 
1908
    remove transition will not be applied until \l delayRemove becomes false again.
 
1909
 
 
1910
    For more details and examples on how to use view transitions, see the ViewTransition
 
1911
    documentation.
 
1912
 
 
1913
    \sa removeDisplaced, ViewTransition
 
1914
*/
 
1915
 
 
1916
/*!
 
1917
    \qmlproperty Transition QtQuick2::GridView::removeDisplaced
 
1918
 
 
1919
    This property holds the transition to apply to items in the view that are displaced by the
 
1920
    removal of other items in the view.
 
1921
 
 
1922
    For example, here is a view that specifies such a transition:
 
1923
 
 
1924
    \code
 
1925
    GridView {
 
1926
        ...
 
1927
        removeDisplaced: Transition {
 
1928
            NumberAnimation { properties: "x,y"; duration: 1000 }
 
1929
        }
 
1930
    }
 
1931
    \endcode
 
1932
 
 
1933
    Whenever an item is removed from the above view, all items beneath it are displaced, causing
 
1934
    them to move upwards (or sideways, if horizontally orientated) within the view. As this
 
1935
    displacement occurs, the items' movement to their new x,y positions within the view will be
 
1936
    animated by a NumberAnimation over one second, as specified. This transition is not applied to
 
1937
    the item that has actually been removed from the view; to animate the removed items, set the
 
1938
    \l remove property.
 
1939
 
 
1940
    If an item is displaced by multiple types of operations at the same time, it is not defined as to
 
1941
    whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally,
 
1942
    if it is not necessary to specify different transitions depending on whether an item is displaced
 
1943
    by an add, move or remove operation, consider setting the \l displaced property instead.
 
1944
 
 
1945
    For more details and examples on how to use view transitions, see the ViewTransition
 
1946
    documentation.
 
1947
 
 
1948
    \sa displaced, remove, ViewTransition
 
1949
*/
 
1950
 
 
1951
/*!
 
1952
    \qmlproperty Transition QtQuick2::GridView::displaced
 
1953
    This property holds the generic transition to apply to items that have been displaced by
 
1954
    any model operation that affects the view.
 
1955
 
 
1956
    This is a convenience for specifying a generic transition for items that are displaced
 
1957
    by add, move or remove operations, without having to specify the individual addDisplaced,
 
1958
    moveDisplaced and removeDisplaced properties. For example, here is a view that specifies
 
1959
    a displaced transition:
 
1960
 
 
1961
    \code
 
1962
    GridView {
 
1963
        ...
 
1964
        displaced: Transition {
 
1965
            NumberAnimation { properties: "x,y"; duration: 1000 }
 
1966
        }
 
1967
    }
 
1968
    \endcode
 
1969
 
 
1970
    When any item is added, moved or removed within the above view, the items below it are
 
1971
    displaced, causing them to move down (or sideways, if horizontally orientated) within the
 
1972
    view. As this displacement occurs, the items' movement to their new x,y positions within
 
1973
    the view will be animated by a NumberAnimation over one second, as specified.
 
1974
 
 
1975
    If a view specifies this generic displaced transition as well as a specific addDisplaced,
 
1976
    moveDisplaced or removeDisplaced transition, the more specific transition will be used
 
1977
    instead of the generic displaced transition when the relevant operation occurs, providing that
 
1978
    the more specific transition has not been disabled (by setting \l {Transition::enabled}{enabled}
 
1979
    to false). If it has indeed been disabled, the generic displaced transition is applied instead.
 
1980
 
 
1981
    For more details and examples on how to use view transitions, see the ViewTransition
 
1982
    documentation.
 
1983
 
 
1984
    \sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition
 
1985
*/
 
1986
 
 
1987
void QQuickGridView::viewportMoved(Qt::Orientations orient)
 
1988
{
 
1989
    Q_D(QQuickGridView);
 
1990
    QQuickItemView::viewportMoved(orient);
 
1991
    if (!d->itemCount)
 
1992
        return;
 
1993
    if (d->inViewportMoved)
 
1994
        return;
 
1995
    d->inViewportMoved = true;
 
1996
 
 
1997
    if (yflick()) {
 
1998
        if (d->isContentFlowReversed())
 
1999
            d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore;
 
2000
        else
 
2001
            d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
 
2002
    } else {
 
2003
        if (d->isContentFlowReversed())
 
2004
            d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferAfter : QQuickItemViewPrivate::BufferBefore;
 
2005
        else
 
2006
            d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickItemViewPrivate::BufferBefore : QQuickItemViewPrivate::BufferAfter;
 
2007
    }
 
2008
 
 
2009
    d->refillOrLayout();
 
2010
 
 
2011
    // Set visibility of items to eliminate cost of items outside the visible area.
 
2012
    qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
 
2013
    qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
 
2014
    for (int i = 0; i < d->visibleItems.count(); ++i) {
 
2015
        FxGridItemSG *item = static_cast<FxGridItemSG*>(d->visibleItems.at(i));
 
2016
        QQuickItemPrivate::get(item->item)->setCulled(item->rowPos() + d->rowSize() < from || item->rowPos() > to);
 
2017
    }
 
2018
    if (d->currentItem) {
 
2019
        FxGridItemSG *item = static_cast<FxGridItemSG*>(d->currentItem);
 
2020
        QQuickItemPrivate::get(item->item)->setCulled(item->rowPos() + d->rowSize() < from || item->rowPos() > to);
 
2021
    }
 
2022
 
 
2023
    if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
 
2024
        d->moveReason = QQuickGridViewPrivate::Mouse;
 
2025
    if (d->moveReason != QQuickGridViewPrivate::SetIndex) {
 
2026
        if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
 
2027
            // reposition highlight
 
2028
            qreal pos = d->highlight->position();
 
2029
            qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
 
2030
            if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
 
2031
                pos = viewPos + d->highlightRangeEnd - d->highlight->size();
 
2032
            if (pos < viewPos + d->highlightRangeStart)
 
2033
                pos = viewPos + d->highlightRangeStart;
 
2034
 
 
2035
            if (pos != d->highlight->position()) {
 
2036
                d->highlightXAnimator->stop();
 
2037
                d->highlightYAnimator->stop();
 
2038
                static_cast<FxGridItemSG*>(d->highlight)->setPosition(static_cast<FxGridItemSG*>(d->highlight)->colPos(), pos);
 
2039
            } else {
 
2040
                d->updateHighlight();
 
2041
            }
 
2042
 
 
2043
            // update current index
 
2044
            int idx = d->snapIndex();
 
2045
            if (idx >= 0 && idx != d->currentIndex) {
 
2046
                d->updateCurrent(idx);
 
2047
                if (d->currentItem && static_cast<FxGridItemSG*>(d->currentItem)->colPos() != static_cast<FxGridItemSG*>(d->highlight)->colPos() && d->autoHighlight) {
 
2048
                    if (d->flow == FlowLeftToRight)
 
2049
                        d->highlightXAnimator->to = d->currentItem->itemX();
 
2050
                    else
 
2051
                        d->highlightYAnimator->to = d->currentItem->itemY();
 
2052
                }
 
2053
            }
 
2054
        }
 
2055
    }
 
2056
 
 
2057
    d->inViewportMoved = false;
 
2058
}
 
2059
 
 
2060
void QQuickGridView::keyPressEvent(QKeyEvent *event)
 
2061
{
 
2062
    Q_D(QQuickGridView);
 
2063
    if (d->model && d->model->count() && d->interactive) {
 
2064
        d->moveReason = QQuickGridViewPrivate::SetIndex;
 
2065
        int oldCurrent = currentIndex();
 
2066
        switch (event->key()) {
 
2067
        case Qt::Key_Up:
 
2068
            moveCurrentIndexUp();
 
2069
            break;
 
2070
        case Qt::Key_Down:
 
2071
            moveCurrentIndexDown();
 
2072
            break;
 
2073
        case Qt::Key_Left:
 
2074
            moveCurrentIndexLeft();
 
2075
            break;
 
2076
        case Qt::Key_Right:
 
2077
            moveCurrentIndexRight();
 
2078
            break;
 
2079
        default:
 
2080
            break;
 
2081
        }
 
2082
        if (oldCurrent != currentIndex() || d->wrap) {
 
2083
            event->accept();
 
2084
            return;
 
2085
        }
 
2086
    }
 
2087
    event->ignore();
 
2088
    QQuickItemView::keyPressEvent(event);
 
2089
}
 
2090
 
 
2091
void QQuickGridView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
 
2092
{
 
2093
    Q_D(QQuickGridView);
 
2094
    d->resetColumns();
 
2095
 
 
2096
    if (newGeometry.width() != oldGeometry.width()
 
2097
            && newGeometry.height() != oldGeometry.height()) {
 
2098
        d->setPosition(d->position());
 
2099
    } else if (newGeometry.width() != oldGeometry.width()) {
 
2100
        QQuickFlickable::setContentX(d->contentXForPosition(d->position()));
 
2101
    } else if (newGeometry.height() != oldGeometry.height()) {
 
2102
        QQuickFlickable::setContentY(d->contentYForPosition(d->position()));
 
2103
    }
 
2104
 
 
2105
    QQuickItemView::geometryChanged(newGeometry, oldGeometry);
 
2106
}
 
2107
 
 
2108
void QQuickGridView::initItem(int index, QQuickItem *item)
 
2109
{
 
2110
    QQuickItemView::initItem(index, item);
 
2111
    QQuickGridViewAttached *attached = static_cast<QQuickGridViewAttached *>(
 
2112
            qmlAttachedPropertiesObject<QQuickGridView>(item));
 
2113
    if (attached)
 
2114
        attached->setView(this);
 
2115
}
 
2116
 
 
2117
/*!
 
2118
    \qmlmethod QtQuick2::GridView::moveCurrentIndexUp()
 
2119
 
 
2120
    Move the currentIndex up one item in the view.
 
2121
    The current index will wrap if keyNavigationWraps is true and it
 
2122
    is currently at the end. This method has no effect if the \l count is zero.
 
2123
 
 
2124
    \b Note: methods should only be called after the Component has completed.
 
2125
*/
 
2126
 
 
2127
 
 
2128
void QQuickGridView::moveCurrentIndexUp()
 
2129
{
 
2130
    Q_D(QQuickGridView);
 
2131
    const int count = d->model ? d->model->count() : 0;
 
2132
    if (!count)
 
2133
        return;
 
2134
    if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) {
 
2135
        if (d->flow == QQuickGridView::FlowLeftToRight) {
 
2136
            if (currentIndex() >= d->columns || d->wrap) {
 
2137
                int index = currentIndex() - d->columns;
 
2138
                setCurrentIndex((index >= 0 && index < count) ? index : count-1);
 
2139
            }
 
2140
        } else {
 
2141
            if (currentIndex() > 0 || d->wrap) {
 
2142
                int index = currentIndex() - 1;
 
2143
                setCurrentIndex((index >= 0 && index < count) ? index : count-1);
 
2144
            }
 
2145
        }
 
2146
    } else {
 
2147
        if (d->flow == QQuickGridView::FlowLeftToRight) {
 
2148
            if (currentIndex() < count - d->columns || d->wrap) {
 
2149
                int index = currentIndex()+d->columns;
 
2150
                setCurrentIndex((index >= 0 && index < count) ? index : 0);
 
2151
            }
 
2152
        } else {
 
2153
            if (currentIndex() < count - 1 || d->wrap) {
 
2154
                int index = currentIndex() + 1;
 
2155
                setCurrentIndex((index >= 0 && index < count) ? index : 0);
 
2156
            }
 
2157
        }
 
2158
    }
 
2159
}
 
2160
 
 
2161
/*!
 
2162
    \qmlmethod QtQuick2::GridView::moveCurrentIndexDown()
 
2163
 
 
2164
    Move the currentIndex down one item in the view.
 
2165
    The current index will wrap if keyNavigationWraps is true and it
 
2166
    is currently at the end. This method has no effect if the \l count is zero.
 
2167
 
 
2168
    \b Note: methods should only be called after the Component has completed.
 
2169
*/
 
2170
void QQuickGridView::moveCurrentIndexDown()
 
2171
{
 
2172
    Q_D(QQuickGridView);
 
2173
    const int count = d->model ? d->model->count() : 0;
 
2174
    if (!count)
 
2175
        return;
 
2176
 
 
2177
    if (d->verticalLayoutDirection == QQuickItemView::TopToBottom) {
 
2178
        if (d->flow == QQuickGridView::FlowLeftToRight) {
 
2179
            if (currentIndex() < count - d->columns || d->wrap) {
 
2180
                int index = currentIndex()+d->columns;
 
2181
                setCurrentIndex((index >= 0 && index < count) ? index : 0);
 
2182
            }
 
2183
        } else {
 
2184
            if (currentIndex() < count - 1 || d->wrap) {
 
2185
                int index = currentIndex() + 1;
 
2186
                setCurrentIndex((index >= 0 && index < count) ? index : 0);
 
2187
            }
 
2188
        }
 
2189
    } else {
 
2190
        if (d->flow == QQuickGridView::FlowLeftToRight) {
 
2191
            if (currentIndex() >= d->columns || d->wrap) {
 
2192
                int index = currentIndex() - d->columns;
 
2193
                setCurrentIndex((index >= 0 && index < count) ? index : count-1);
 
2194
            }
 
2195
        } else {
 
2196
            if (currentIndex() > 0 || d->wrap) {
 
2197
                int index = currentIndex() - 1;
 
2198
                setCurrentIndex((index >= 0 && index < count) ? index : count-1);
 
2199
            }
 
2200
        }
 
2201
    }
 
2202
}
 
2203
 
 
2204
/*!
 
2205
    \qmlmethod QtQuick2::GridView::moveCurrentIndexLeft()
 
2206
 
 
2207
    Move the currentIndex left one item in the view.
 
2208
    The current index will wrap if keyNavigationWraps is true and it
 
2209
    is currently at the end. This method has no effect if the \l count is zero.
 
2210
 
 
2211
    \b Note: methods should only be called after the Component has completed.
 
2212
*/
 
2213
void QQuickGridView::moveCurrentIndexLeft()
 
2214
{
 
2215
    Q_D(QQuickGridView);
 
2216
    const int count = d->model ? d->model->count() : 0;
 
2217
    if (!count)
 
2218
        return;
 
2219
    if (effectiveLayoutDirection() == Qt::LeftToRight) {
 
2220
        if (d->flow == QQuickGridView::FlowLeftToRight) {
 
2221
            if (currentIndex() > 0 || d->wrap) {
 
2222
                int index = currentIndex() - 1;
 
2223
                setCurrentIndex((index >= 0 && index < count) ? index : count-1);
 
2224
            }
 
2225
        } else {
 
2226
            if (currentIndex() >= d->columns || d->wrap) {
 
2227
                int index = currentIndex() - d->columns;
 
2228
                setCurrentIndex((index >= 0 && index < count) ? index : count-1);
 
2229
            }
 
2230
        }
 
2231
    } else {
 
2232
        if (d->flow == QQuickGridView::FlowLeftToRight) {
 
2233
            if (currentIndex() < count - 1 || d->wrap) {
 
2234
                int index = currentIndex() + 1;
 
2235
                setCurrentIndex((index >= 0 && index < count) ? index : 0);
 
2236
            }
 
2237
        } else {
 
2238
            if (currentIndex() < count - d->columns || d->wrap) {
 
2239
                int index = currentIndex() + d->columns;
 
2240
                setCurrentIndex((index >= 0 && index < count) ? index : 0);
 
2241
            }
 
2242
        }
 
2243
    }
 
2244
}
 
2245
 
 
2246
 
 
2247
/*!
 
2248
    \qmlmethod QtQuick2::GridView::moveCurrentIndexRight()
 
2249
 
 
2250
    Move the currentIndex right one item in the view.
 
2251
    The current index will wrap if keyNavigationWraps is true and it
 
2252
    is currently at the end. This method has no effect if the \l count is zero.
 
2253
 
 
2254
    \b Note: methods should only be called after the Component has completed.
 
2255
*/
 
2256
void QQuickGridView::moveCurrentIndexRight()
 
2257
{
 
2258
    Q_D(QQuickGridView);
 
2259
    const int count = d->model ? d->model->count() : 0;
 
2260
    if (!count)
 
2261
        return;
 
2262
    if (effectiveLayoutDirection() == Qt::LeftToRight) {
 
2263
        if (d->flow == QQuickGridView::FlowLeftToRight) {
 
2264
            if (currentIndex() < count - 1 || d->wrap) {
 
2265
                int index = currentIndex() + 1;
 
2266
                setCurrentIndex((index >= 0 && index < count) ? index : 0);
 
2267
            }
 
2268
        } else {
 
2269
            if (currentIndex() < count - d->columns || d->wrap) {
 
2270
                int index = currentIndex()+d->columns;
 
2271
                setCurrentIndex((index >= 0 && index < count) ? index : 0);
 
2272
            }
 
2273
        }
 
2274
    } else {
 
2275
        if (d->flow == QQuickGridView::FlowLeftToRight) {
 
2276
            if (currentIndex() > 0 || d->wrap) {
 
2277
                int index = currentIndex() - 1;
 
2278
                setCurrentIndex((index >= 0 && index < count) ? index : count-1);
 
2279
            }
 
2280
        } else {
 
2281
            if (currentIndex() >= d->columns || d->wrap) {
 
2282
                int index = currentIndex() - d->columns;
 
2283
                setCurrentIndex((index >= 0 && index < count) ? index : count-1);
 
2284
            }
 
2285
        }
 
2286
    }
 
2287
}
 
2288
 
 
2289
bool QQuickGridViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert &change, ChangeResult *insertResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView)
 
2290
{
 
2291
    Q_Q(QQuickGridView);
 
2292
 
 
2293
    int modelIndex = change.index;
 
2294
    int count = change.count;
 
2295
 
 
2296
    int index = visibleItems.count() ? mapFromModel(modelIndex) : 0;
 
2297
 
 
2298
    if (index < 0) {
 
2299
        int i = visibleItems.count() - 1;
 
2300
        while (i > 0 && visibleItems.at(i)->index == -1)
 
2301
            --i;
 
2302
        if (visibleItems.at(i)->index + 1 == modelIndex) {
 
2303
            // Special case of appending an item to the model.
 
2304
            index = visibleItems.count();
 
2305
        } else {
 
2306
            if (modelIndex <= visibleIndex) {
 
2307
                // Insert before visible items
 
2308
                visibleIndex += count;
 
2309
                for (int i = 0; i < visibleItems.count(); ++i) {
 
2310
                    FxViewItem *item = visibleItems.at(i);
 
2311
                    if (item->index != -1 && item->index >= modelIndex)
 
2312
                        item->index += count;
 
2313
                }
 
2314
            }
 
2315
            return true;
 
2316
        }
 
2317
    }
 
2318
 
 
2319
    qreal tempPos = isContentFlowReversed() ? -position()-size()+q->width()+1 : position();
 
2320
    qreal colPos = 0;
 
2321
    qreal rowPos = 0;
 
2322
    int colNum = 0;
 
2323
    if (visibleItems.count()) {
 
2324
        if (index < visibleItems.count()) {
 
2325
            FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.at(index));
 
2326
            colPos = gridItem->colPos();
 
2327
            rowPos = gridItem->rowPos();
 
2328
            colNum = qFloor((colPos+colSize()/2) / colSize());
 
2329
        } else {
 
2330
            // appending items to visible list
 
2331
            FxGridItemSG *gridItem = static_cast<FxGridItemSG*>(visibleItems.at(index-1));
 
2332
            rowPos = gridItem->rowPos();
 
2333
            colNum = qFloor((gridItem->colPos()+colSize()/2) / colSize());
 
2334
            if (++colNum >= columns) {
 
2335
                colNum = 0;
 
2336
                rowPos += rowSize();
 
2337
            }
 
2338
            colPos = colNum * colSize();
 
2339
        }
 
2340
    }
 
2341
 
 
2342
    // Update the indexes of the following visible items.
 
2343
    for (int i = 0; i < visibleItems.count(); ++i) {
 
2344
        FxViewItem *item = visibleItems.at(i);
 
2345
        if (item->index != -1 && item->index >= modelIndex) {
 
2346
            item->index += count;
 
2347
            if (change.isMove())
 
2348
                item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false);
 
2349
            else
 
2350
                item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, false);
 
2351
        }
 
2352
    }
 
2353
 
 
2354
    int prevVisibleCount = visibleItems.count();
 
2355
    if (insertResult->visiblePos.isValid() && rowPos < insertResult->visiblePos) {
 
2356
        // Insert items before the visible item.
 
2357
        int insertionIdx = index;
 
2358
        int i = count - 1;
 
2359
        int from = tempPos - buffer;
 
2360
 
 
2361
        while (i >= 0) {
 
2362
            if (rowPos > from && insertionIdx < visibleIndex) {
 
2363
                // item won't be visible, just note the size for repositioning
 
2364
                insertResult->countChangeBeforeVisible++;
 
2365
            } else {
 
2366
                // item is before first visible e.g. in cache buffer
 
2367
                FxViewItem *item = 0;
 
2368
                if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
 
2369
                    item->index = modelIndex + i;
 
2370
                if (!item)
 
2371
                    item = createItem(modelIndex + i);
 
2372
                if (!item)
 
2373
                    return false;
 
2374
 
 
2375
                QQuickItemPrivate::get(item->item)->setCulled(false);
 
2376
                visibleItems.insert(insertionIdx, item);
 
2377
                if (insertionIdx == 0)
 
2378
                    insertResult->changedFirstItem = true;
 
2379
                if (!change.isMove()) {
 
2380
                    addedItems->append(item);
 
2381
                    item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
 
2382
                }
 
2383
                insertResult->sizeChangesBeforeVisiblePos += rowSize();
 
2384
            }
 
2385
 
 
2386
            if (--colNum < 0 ) {
 
2387
                colNum = columns - 1;
 
2388
                rowPos -= rowSize();
 
2389
            }
 
2390
            colPos = colNum * colSize();
 
2391
            index++;
 
2392
            i--;
 
2393
        }
 
2394
    } else {
 
2395
        int i = 0;
 
2396
        int to = buffer+tempPos+size()-1;
 
2397
        while (i < count && rowPos <= to + rowSize()*(columns - colNum)/qreal(columns+1)) {
 
2398
            FxViewItem *item = 0;
 
2399
            if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
 
2400
                item->index = modelIndex + i;
 
2401
            bool newItem = !item;
 
2402
            if (!item)
 
2403
                item = createItem(modelIndex + i);
 
2404
            if (!item)
 
2405
                return false;
 
2406
 
 
2407
            QQuickItemPrivate::get(item->item)->setCulled(false);
 
2408
            visibleItems.insert(index, item);
 
2409
            if (index == 0)
 
2410
                insertResult->changedFirstItem = true;
 
2411
            if (change.isMove()) {
 
2412
                // we know this is a move target, since move displaced items that are
 
2413
                // shuffled into view due to a move would be added in refill()
 
2414
                if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true))
 
2415
                    movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
 
2416
            } else {
 
2417
                addedItems->append(item);
 
2418
                item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
 
2419
            }
 
2420
            insertResult->sizeChangesAfterVisiblePos += rowSize();
 
2421
 
 
2422
            if (++colNum >= columns) {
 
2423
                colNum = 0;
 
2424
                rowPos += rowSize();
 
2425
            }
 
2426
            colPos = colNum * colSize();
 
2427
            ++index;
 
2428
            ++i;
 
2429
        }
 
2430
    }
 
2431
 
 
2432
    updateVisibleIndex();
 
2433
 
 
2434
    return visibleItems.count() > prevVisibleCount;
 
2435
}
 
2436
 
 
2437
void QQuickGridViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult)
 
2438
{
 
2439
    if (!transitioner)
 
2440
        return;
 
2441
 
 
2442
    int markerItemIndex = -1;
 
2443
    for (int i=0; i<visibleItems.count(); i++) {
 
2444
        if (visibleItems[i]->index == afterModelIndex) {
 
2445
            markerItemIndex = i;
 
2446
            break;
 
2447
        }
 
2448
    }
 
2449
    if (markerItemIndex < 0)
 
2450
        return;
 
2451
 
 
2452
    const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
 
2453
    int countItemsRemoved = -(removalResult.sizeChangesAfterVisiblePos / rowSize());
 
2454
 
 
2455
    // account for whether first item has changed if < 1 row was removed before visible
 
2456
    int changeBeforeVisible = insertionResult.countChangeBeforeVisible - removalResult.countChangeBeforeVisible;
 
2457
    if (changeBeforeVisible != 0)
 
2458
        countItemsRemoved += (changeBeforeVisible % columns) - (columns - 1);
 
2459
 
 
2460
    countItemsRemoved -= removalResult.countChangeAfterVisibleItems;
 
2461
 
 
2462
    for (int i=markerItemIndex+1; i<visibleItems.count() && visibleItems.at(i)->position() < viewEndPos; i++) {
 
2463
        FxGridItemSG *gridItem = static_cast<FxGridItemSG *>(visibleItems[i]);
 
2464
        if (!gridItem->transitionScheduledOrRunning()) {
 
2465
            qreal origRowPos = gridItem->colPos();
 
2466
            qreal origColPos = gridItem->rowPos();
 
2467
            int indexDiff = gridItem->index - countItemsRemoved;
 
2468
            gridItem->setPosition((indexDiff % columns) * colSize(), (indexDiff / columns) * rowSize());
 
2469
            gridItem->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
 
2470
            gridItem->setPosition(origRowPos, origColPos);
 
2471
        }
 
2472
    }
 
2473
}
 
2474
 
 
2475
bool QQuickGridViewPrivate::needsRefillForAddedOrRemovedIndex(int modelIndex) const
 
2476
{
 
2477
    // If we add or remove items before visible items, a layout may be
 
2478
    // required to ensure item 0 is in the first column.
 
2479
    return modelIndex < visibleIndex;
 
2480
}
 
2481
 
 
2482
/*!
 
2483
    \qmlmethod QtQuick2::GridView::positionViewAtIndex(int index, PositionMode mode)
 
2484
 
 
2485
    Positions the view such that the \a index is at the position specified by
 
2486
    \a mode:
 
2487
 
 
2488
    \list
 
2489
    \li GridView.Beginning - position item at the top (or left for \c GridView.TopToBottom flow) of the view.
 
2490
    \li GridView.Center - position item in the center of the view.
 
2491
    \li GridView.End - position item at bottom (or right for horizontal orientation) of the view.
 
2492
    \li GridView.Visible - if any part of the item is visible then take no action, otherwise
 
2493
    bring the item into view.
 
2494
    \li GridView.Contain - ensure the entire item is visible.  If the item is larger than
 
2495
    the view the item is positioned at the top (or left for \c GridView.TopToBottom flow) of the view.
 
2496
    \li GridView.SnapPosition - position the item at \l preferredHighlightBegin.  This mode
 
2497
    is only valid if \l highlightRangeMode is StrictlyEnforceRange or snapping is enabled
 
2498
    via \l snapMode.
 
2499
    \endlist
 
2500
 
 
2501
    If positioning the view at the index would cause empty space to be displayed at
 
2502
    the beginning or end of the view, the view will be positioned at the boundary.
 
2503
 
 
2504
    It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
 
2505
    at a particular index.  This is unreliable since removing items from the start
 
2506
    of the view does not cause all other items to be repositioned.
 
2507
    The correct way to bring an item into view is with \c positionViewAtIndex.
 
2508
 
 
2509
    \b Note: methods should only be called after the Component has completed.  To position
 
2510
    the view at startup, this method should be called by Component.onCompleted.  For
 
2511
    example, to position the view at the end:
 
2512
 
 
2513
    \code
 
2514
    Component.onCompleted: positionViewAtIndex(count - 1, GridView.Beginning)
 
2515
    \endcode
 
2516
*/
 
2517
 
 
2518
/*!
 
2519
    \qmlmethod QtQuick2::GridView::positionViewAtBeginning()
 
2520
    \qmlmethod QtQuick2::GridView::positionViewAtEnd()
 
2521
 
 
2522
    Positions the view at the beginning or end, taking into account any header or footer.
 
2523
 
 
2524
    It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
 
2525
    at a particular index.  This is unreliable since removing items from the start
 
2526
    of the list does not cause all other items to be repositioned, and because
 
2527
    the actual start of the view can vary based on the size of the delegates.
 
2528
 
 
2529
    \b Note: methods should only be called after the Component has completed.  To position
 
2530
    the view at startup, this method should be called by Component.onCompleted.  For
 
2531
    example, to position the view at the end on startup:
 
2532
 
 
2533
    \code
 
2534
    Component.onCompleted: positionViewAtEnd()
 
2535
    \endcode
 
2536
*/
 
2537
 
 
2538
/*!
 
2539
    \qmlmethod int QtQuick2::GridView::indexAt(int x, int y)
 
2540
 
 
2541
    Returns the index of the visible item containing the point \a x, \a y in content
 
2542
    coordinates.  If there is no item at the point specified, or the item is
 
2543
    not visible -1 is returned.
 
2544
 
 
2545
    If the item is outside the visible area, -1 is returned, regardless of
 
2546
    whether an item will exist at that point when scrolled into view.
 
2547
 
 
2548
    \b Note: methods should only be called after the Component has completed.
 
2549
*/
 
2550
 
 
2551
/*!
 
2552
    \qmlmethod Item QtQuick2::GridView::itemAt(int x, int y)
 
2553
 
 
2554
    Returns the visible item containing the point \a x, \a y in content
 
2555
    coordinates.  If there is no item at the point specified, or the item is
 
2556
    not visible null is returned.
 
2557
 
 
2558
    If the item is outside the visible area, null is returned, regardless of
 
2559
    whether an item will exist at that point when scrolled into view.
 
2560
 
 
2561
    \b Note: methods should only be called after the Component has completed.
 
2562
*/
 
2563
 
 
2564
 
 
2565
/*!
 
2566
    \qmlmethod QtQuick2::GridView::forceLayout()
 
2567
 
 
2568
    Responding to changes in the model is usually batched to happen only once
 
2569
    per frame. This means that inside script blocks it is possible for the
 
2570
    underlying model to have changed, but the GridView has not caught up yet.
 
2571
 
 
2572
    This method forces the GridView to immediately respond to any outstanding
 
2573
    changes in the model.
 
2574
 
 
2575
    \since 5.1
 
2576
 
 
2577
    \b Note: methods should only be called after the Component has completed.
 
2578
*/
 
2579
 
 
2580
QQuickGridViewAttached *QQuickGridView::qmlAttachedProperties(QObject *obj)
 
2581
{
 
2582
    return new QQuickGridViewAttached(obj);
 
2583
}
 
2584
 
 
2585
QT_END_NAMESPACE