1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <QtTest/QtTest> |
30 | #include <QtCore/qstringlistmodel.h> |
31 | #include <QtQuick/qquickview.h> |
32 | #include <QtQuickTest/QtQuickTest> |
33 | #include <QtQml/qqmlengine.h> |
34 | #include <QtQml/qqmlcomponent.h> |
35 | #include <QtQml/qqmlcontext.h> |
36 | #include <QtQml/qqmlexpression.h> |
37 | #include <QtQml/qqmlincubator.h> |
38 | #include <QtQml/qqmlcontext.h> |
39 | #include <QtQuick/private/qquickitem_p.h> |
40 | #include <QtQuick/private/qquickitemview_p_p.h> |
41 | #include <QtQuick/private/qquickgridview_p.h> |
42 | #include <QtQuick/private/qquicktext_p.h> |
43 | #include <QtQmlModels/private/qqmllistmodel_p.h> |
44 | #include "../../shared/util.h" |
45 | #include "../shared/viewtestutil.h" |
46 | #include "../shared/visualtestutil.h" |
47 | #include <QtGui/qguiapplication.h> |
48 | #include "qplatformdefs.h" |
49 | |
50 | #include <math.h> |
51 | |
52 | Q_DECLARE_METATYPE(QQuickGridView::Flow) |
53 | Q_DECLARE_METATYPE(Qt::LayoutDirection) |
54 | Q_DECLARE_METATYPE(QQuickItemView::VerticalLayoutDirection) |
55 | Q_DECLARE_METATYPE(QQuickItemView::PositionMode) |
56 | Q_DECLARE_METATYPE(Qt::Key) |
57 | |
58 | using namespace QQuickViewTestUtil; |
59 | using namespace QQuickVisualTestUtil; |
60 | |
61 | #define SHARE_VIEWS |
62 | |
63 | class tst_QQuickGridView : public QQmlDataTest |
64 | { |
65 | Q_OBJECT |
66 | public: |
67 | tst_QQuickGridView(); |
68 | |
69 | private slots: |
70 | void init(); |
71 | void cleanupTestCase(); |
72 | void items(); |
73 | void changed(); |
74 | void inserted_basic(); |
75 | void inserted_defaultLayout(QQuickGridView::Flow flow = QQuickGridView::FlowLeftToRight, Qt::LayoutDirection horizLayout = Qt::LeftToRight, QQuickItemView::VerticalLayoutDirection verticalLayout = QQuickItemView::TopToBottom); |
76 | void inserted_defaultLayout_data(); |
77 | void insertBeforeVisible(); |
78 | void insertBeforeVisible_data(); |
79 | void removed_basic(); |
80 | void removed_defaultLayout(QQuickGridView::Flow flow = QQuickGridView::FlowLeftToRight, Qt::LayoutDirection horizLayout = Qt::LeftToRight, QQuickItemView::VerticalLayoutDirection verticalLayout = QQuickItemView::TopToBottom); |
81 | void removed_defaultLayout_data(); |
82 | void addOrRemoveBeforeVisible(); |
83 | void addOrRemoveBeforeVisible_data(); |
84 | void clear(); |
85 | void moved_defaultLayout(QQuickGridView::Flow flow = QQuickGridView::FlowLeftToRight, Qt::LayoutDirection horizLayout = Qt::LeftToRight, QQuickItemView::VerticalLayoutDirection verticalLayout = QQuickItemView::TopToBottom); |
86 | void moved_defaultLayout_data(); |
87 | void multipleChanges_condensed() { multipleChanges(condensed: true); } |
88 | void multipleChanges_condensed_data() { multipleChanges_data(); } |
89 | void multipleChanges_uncondensed() { multipleChanges(condensed: false); } |
90 | void multipleChanges_uncondensed_data() { multipleChanges_data(); } |
91 | void swapWithFirstItem(); |
92 | void changeFlow(); |
93 | void currentIndex(); |
94 | void noCurrentIndex(); |
95 | void keyNavigation(); |
96 | void keyNavigation_data(); |
97 | void defaultValues(); |
98 | void properties(); |
99 | void propertyChanges(); |
100 | void componentChanges(); |
101 | void modelChanges(); |
102 | void positionViewAtBeginningEnd(); |
103 | void positionViewAtIndex(); |
104 | void positionViewAtIndex_data(); |
105 | void mirroring(); |
106 | void snapping(); |
107 | void resetModel(); |
108 | void enforceRange(); |
109 | void enforceRange_rightToLeft(); |
110 | void QTBUG_8456(); |
111 | void manualHighlight(); |
112 | void footer(); |
113 | void footer_data(); |
114 | void initialZValues(); |
115 | void initialZValues_data(); |
116 | void header(); |
117 | void header_data(); |
118 | void extents(); |
119 | void extents_data(); |
120 | void resetModel_headerFooter(); |
121 | void resizeViewAndRepaint(); |
122 | void resizeGrid(); |
123 | void resizeGrid_data(); |
124 | void changeColumnCount(); |
125 | void indexAt_itemAt_data(); |
126 | void indexAt_itemAt(); |
127 | void onAdd(); |
128 | void onAdd_data(); |
129 | void onRemove(); |
130 | void onRemove_data(); |
131 | void attachedProperties_QTBUG_32836(); |
132 | void columnCount(); |
133 | void margins(); |
134 | void creationContext(); |
135 | void snapToRow_data(); |
136 | void snapToRow(); |
137 | void snapOneRow_data(); |
138 | void snapOneRow(); |
139 | void unaligned(); |
140 | void cacheBuffer(); |
141 | void asynchronous(); |
142 | void unrequestedVisibility(); |
143 | |
144 | void populateTransitions(); |
145 | void populateTransitions_data(); |
146 | void addTransitions(); |
147 | void addTransitions_data(); |
148 | void moveTransitions(); |
149 | void moveTransitions_data(); |
150 | void removeTransitions(); |
151 | void removeTransitions_data(); |
152 | void displacedTransitions(); |
153 | void displacedTransitions_data(); |
154 | void multipleTransitions(); |
155 | void multipleTransitions_data(); |
156 | void multipleDisplaced(); |
157 | void regression_QTBUG_57225(); |
158 | void regression_QTBUG_57225_data(); |
159 | |
160 | void inserted_leftToRight_RtL_TtB(); |
161 | void inserted_leftToRight_RtL_TtB_data(); |
162 | void inserted_leftToRight_LtR_BtT(); |
163 | void inserted_leftToRight_LtR_BtT_data(); |
164 | void inserted_leftToRight_RtL_BtT(); |
165 | void inserted_leftToRight_RtL_BtT_data(); |
166 | void inserted_topToBottom_LtR_TtB(); |
167 | void inserted_topToBottom_LtR_TtB_data(); |
168 | void inserted_topToBottom_RtL_TtB(); |
169 | void inserted_topToBottom_RtL_TtB_data(); |
170 | void inserted_topToBottom_LtR_BtT(); |
171 | void inserted_topToBottom_LtR_BtT_data(); |
172 | void inserted_topToBottom_RtL_BtT(); |
173 | void inserted_topToBottom_RtL_BtT_data(); |
174 | |
175 | void removed_leftToRight_RtL_TtB(); |
176 | void removed_leftToRight_RtL_TtB_data(); |
177 | void removed_leftToRight_LtR_BtT(); |
178 | void removed_leftToRight_LtR_BtT_data(); |
179 | void removed_leftToRight_RtL_BtT(); |
180 | void removed_leftToRight_RtL_BtT_data(); |
181 | void removed_topToBottom_LtR_TtB(); |
182 | void removed_topToBottom_LtR_TtB_data(); |
183 | void removed_topToBottom_RtL_TtB(); |
184 | void removed_topToBottom_RtL_TtB_data(); |
185 | void removed_topToBottom_LtR_BtT(); |
186 | void removed_topToBottom_LtR_BtT_data(); |
187 | void removed_topToBottom_RtL_BtT(); |
188 | void removed_topToBottom_RtL_BtT_data(); |
189 | |
190 | void moved_leftToRight_RtL_TtB(); |
191 | void moved_leftToRight_RtL_TtB_data(); |
192 | void moved_leftToRight_LtR_BtT(); |
193 | void moved_leftToRight_LtR_BtT_data(); |
194 | void moved_leftToRight_RtL_BtT(); |
195 | void moved_leftToRight_RtL_BtT_data(); |
196 | void moved_topToBottom_LtR_TtB(); |
197 | void moved_topToBottom_LtR_TtB_data(); |
198 | void moved_topToBottom_RtL_TtB(); |
199 | void moved_topToBottom_RtL_TtB_data(); |
200 | void moved_topToBottom_LtR_BtT(); |
201 | void moved_topToBottom_LtR_BtT_data(); |
202 | void moved_topToBottom_RtL_BtT(); |
203 | void moved_topToBottom_RtL_BtT_data(); |
204 | |
205 | void displayMargin(); |
206 | void negativeDisplayMargin(); |
207 | |
208 | void jsArrayChange(); |
209 | |
210 | void contentHeightWithDelayRemove_data(); |
211 | void contentHeightWithDelayRemove(); |
212 | |
213 | void QTBUG_45640(); |
214 | void QTBUG_49218(); |
215 | void QTBUG_48870_fastModelUpdates(); |
216 | |
217 | void keyNavigationEnabled(); |
218 | void resizeDynamicCellWidthRtL(); |
219 | void releaseItems(); |
220 | |
221 | private: |
222 | QList<int> toIntList(const QVariantList &list); |
223 | void matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes); |
224 | void matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes); |
225 | void matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems); |
226 | |
227 | void multipleChanges(bool condensed); |
228 | void multipleChanges_data(); |
229 | |
230 | QPointF expectedItemPos(QQuickGridView *grid, int index, qreal rowOffset = 0) { |
231 | qreal x; |
232 | qreal y; |
233 | if (grid->flow() == QQuickGridView::FlowLeftToRight) { |
234 | int columns = grid->width() / grid->cellWidth(); |
235 | x = (index % columns) * grid->cellWidth(); |
236 | y = (index / columns) * grid->cellHeight(); |
237 | if (grid->effectiveLayoutDirection() == Qt::RightToLeft) { |
238 | int col = (index % columns) * grid->cellWidth(); |
239 | x = grid->cellWidth() * (columns - 1) - col; |
240 | } |
241 | |
242 | qreal offset = grid->cellHeight() * rowOffset; |
243 | if (grid->verticalLayoutDirection() == QQuickItemView::TopToBottom) |
244 | y += offset; |
245 | else |
246 | y = -grid->cellHeight() - y - offset; |
247 | } else { |
248 | int rows = grid->height() / grid->cellHeight(); |
249 | x = (index / rows) * grid->cellWidth(); |
250 | y = (index % rows) * grid->cellHeight(); |
251 | if (grid->effectiveLayoutDirection() == Qt::RightToLeft) |
252 | x = -x - grid->cellWidth(); |
253 | |
254 | qreal offset = grid->cellWidth() * rowOffset; |
255 | if (grid->effectiveLayoutDirection() == Qt::RightToLeft) |
256 | x -= offset; |
257 | else |
258 | x += offset; |
259 | if (grid->verticalLayoutDirection() == QQuickItemView::BottomToTop) |
260 | y = -grid->cellHeight() - y; |
261 | } |
262 | return QPointF(x, y); |
263 | } |
264 | |
265 | // Sets contentY (or contentX in TopToBottom flow) according to given row offset |
266 | // (in LeftToRight flow) or col offset (in TopToBottom). |
267 | bool setContentPos(QQuickGridView *gridview, qreal rowOrColOffset) { |
268 | bool contentPosChanged = (rowOrColOffset != 0); |
269 | qreal contentOffset = gridview->flow() == QQuickGridView::FlowLeftToRight |
270 | ? rowOrColOffset * gridview->cellHeight() |
271 | : rowOrColOffset * gridview->cellWidth(); |
272 | |
273 | if (gridview->flow() == QQuickGridView::FlowLeftToRight) { |
274 | if (gridview->verticalLayoutDirection() == QQuickItemView::BottomToTop) |
275 | contentOffset = -gridview->height() - contentOffset; |
276 | } else { |
277 | if (gridview->effectiveLayoutDirection() == Qt::RightToLeft) |
278 | contentOffset = -gridview->width() - contentOffset; |
279 | } |
280 | if (gridview->flow() == QQuickGridView::FlowLeftToRight) |
281 | gridview->setContentY(contentOffset); |
282 | else |
283 | gridview->setContentX(contentOffset); |
284 | return contentPosChanged; |
285 | } |
286 | |
287 | #ifdef SHARE_VIEWS |
288 | QQuickView *getView() { |
289 | if (m_view) { |
290 | if (QString(QTest::currentTestFunction()) != testForView) { |
291 | delete m_view; |
292 | m_view = nullptr; |
293 | } else { |
294 | m_view->setSource(QUrl()); |
295 | return m_view; |
296 | } |
297 | } |
298 | |
299 | testForView = QTest::currentTestFunction(); |
300 | m_view = createView(); |
301 | return m_view; |
302 | } |
303 | void releaseView(QQuickView *view) { |
304 | Q_ASSERT(view == m_view); |
305 | Q_UNUSED(view) |
306 | m_view->setSource(QUrl()); |
307 | } |
308 | #else |
309 | QQuickView *getView() { |
310 | return createView(); |
311 | } |
312 | void releaseView(QQuickView *view) { |
313 | delete view; |
314 | } |
315 | #endif |
316 | |
317 | QQuickView *m_view; |
318 | QString testForView; |
319 | }; |
320 | |
321 | tst_QQuickGridView::tst_QQuickGridView() : m_view(nullptr) |
322 | { |
323 | } |
324 | |
325 | void tst_QQuickGridView::init() |
326 | { |
327 | #ifdef SHARE_VIEWS |
328 | if (m_view && QString(QTest::currentTestFunction()) != testForView) { |
329 | testForView = QString(); |
330 | delete m_view; |
331 | m_view = nullptr; |
332 | } |
333 | #endif |
334 | } |
335 | |
336 | void tst_QQuickGridView::cleanupTestCase() |
337 | { |
338 | #ifdef SHARE_VIEWS |
339 | testForView = QString(); |
340 | delete m_view; |
341 | m_view = nullptr; |
342 | #endif |
343 | } |
344 | |
345 | void tst_QQuickGridView::items() |
346 | { |
347 | QQuickView *window = createView(); |
348 | |
349 | QaimModel model; |
350 | model.addItem(name: "Fred" , number: "12345" ); |
351 | model.addItem(name: "John" , number: "2345" ); |
352 | model.addItem(name: "Bob" , number: "54321" ); |
353 | model.addItem(name: "Billy" , number: "22345" ); |
354 | model.addItem(name: "Sam" , number: "2945" ); |
355 | model.addItem(name: "Ben" , number: "04321" ); |
356 | model.addItem(name: "Jim" , number: "0780" ); |
357 | |
358 | QQmlContext *ctxt = window->rootContext(); |
359 | ctxt->setContextProperty("testModel" , &model); |
360 | |
361 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
362 | qApp->processEvents(); |
363 | |
364 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
365 | QTRY_VERIFY(gridview != nullptr); |
366 | |
367 | QQuickItem *contentItem = gridview->contentItem(); |
368 | QTRY_VERIFY(contentItem != nullptr); |
369 | |
370 | QTRY_COMPARE(gridview->count(), model.count()); |
371 | QTRY_COMPARE(window->rootObject()->property("count" ).toInt(), model.count()); |
372 | QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item |
373 | |
374 | for (int i = 0; i < model.count(); ++i) { |
375 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
376 | QTRY_VERIFY(name != nullptr); |
377 | QTRY_COMPARE(name->text(), model.name(i)); |
378 | QQuickText *number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: i); |
379 | QTRY_VERIFY(number != nullptr); |
380 | QTRY_COMPARE(number->text(), model.number(i)); |
381 | } |
382 | |
383 | // set an empty model and confirm that items are destroyed |
384 | QaimModel model2; |
385 | ctxt->setContextProperty("testModel" , &model2); |
386 | |
387 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
388 | QTRY_COMPARE(itemCount, 0); |
389 | |
390 | delete window; |
391 | } |
392 | |
393 | void tst_QQuickGridView::changed() |
394 | { |
395 | QQuickView *window = createView(); |
396 | |
397 | QaimModel model; |
398 | model.addItem(name: "Fred" , number: "12345" ); |
399 | model.addItem(name: "John" , number: "2345" ); |
400 | model.addItem(name: "Bob" , number: "54321" ); |
401 | model.addItem(name: "Billy" , number: "22345" ); |
402 | model.addItem(name: "Sam" , number: "2945" ); |
403 | model.addItem(name: "Ben" , number: "04321" ); |
404 | model.addItem(name: "Jim" , number: "0780" ); |
405 | |
406 | QQmlContext *ctxt = window->rootContext(); |
407 | ctxt->setContextProperty("testModel" , &model); |
408 | |
409 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
410 | qApp->processEvents(); |
411 | |
412 | QQuickFlickable *gridview = findItem<QQuickFlickable>(parent: window->rootObject(), objectName: "grid" ); |
413 | QTRY_VERIFY(gridview != nullptr); |
414 | |
415 | QQuickItem *contentItem = gridview->contentItem(); |
416 | QTRY_VERIFY(contentItem != nullptr); |
417 | |
418 | model.modifyItem(idx: 1, name: "Will" , number: "9876" ); |
419 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: 1); |
420 | QTRY_VERIFY(name != nullptr); |
421 | QTRY_COMPARE(name->text(), model.name(1)); |
422 | QQuickText *number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: 1); |
423 | QTRY_VERIFY(number != nullptr); |
424 | QTRY_COMPARE(number->text(), model.number(1)); |
425 | |
426 | delete window; |
427 | } |
428 | |
429 | void tst_QQuickGridView::inserted_basic() |
430 | { |
431 | QQuickView *window = createView(); |
432 | window->show(); |
433 | |
434 | QaimModel model; |
435 | model.addItem(name: "Fred" , number: "12345" ); |
436 | model.addItem(name: "John" , number: "2345" ); |
437 | model.addItem(name: "Bob" , number: "54321" ); |
438 | |
439 | window->rootContext()->setContextProperty("testModel" , &model); |
440 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
441 | qApp->processEvents(); |
442 | |
443 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
444 | QTRY_VERIFY(gridview != nullptr); |
445 | |
446 | QQuickItem *contentItem = gridview->contentItem(); |
447 | QTRY_VERIFY(contentItem != nullptr); |
448 | |
449 | model.insertItem(index: 1, name: "Will" , number: "9876" ); |
450 | |
451 | QTRY_COMPARE(window->rootObject()->property("count" ).toInt(), model.count()); |
452 | QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item |
453 | |
454 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: 1); |
455 | QTRY_VERIFY(name != nullptr); |
456 | QTRY_COMPARE(name->text(), model.name(1)); |
457 | QQuickText *number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: 1); |
458 | QTRY_VERIFY(number != nullptr); |
459 | QTRY_COMPARE(number->text(), model.number(1)); |
460 | |
461 | // Checks that onAdd is called |
462 | int added = window->rootObject()->property(name: "added" ).toInt(); |
463 | QTRY_COMPARE(added, 1); |
464 | |
465 | // Confirm items positioned correctly |
466 | for (int i = 0; i < model.count(); ++i) { |
467 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
468 | QTRY_COMPARE(item->x(), (i%3)*80.0); |
469 | QTRY_COMPARE(item->y(), (i/3)*60.0); |
470 | } |
471 | |
472 | model.insertItem(index: 0, name: "Foo" , number: "1111" ); // zero index, and current item |
473 | |
474 | QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item |
475 | |
476 | name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: 0); |
477 | QTRY_VERIFY(name != nullptr); |
478 | QTRY_COMPARE(name->text(), model.name(0)); |
479 | number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: 0); |
480 | QTRY_VERIFY(number != nullptr); |
481 | QTRY_COMPARE(number->text(), model.number(0)); |
482 | |
483 | QTRY_COMPARE(gridview->currentIndex(), 1); |
484 | |
485 | // Confirm items positioned correctly |
486 | for (int i = 0; i < model.count(); ++i) { |
487 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
488 | QTRY_COMPARE(item->x(), qreal((i%3)*80)); |
489 | QTRY_COMPARE(item->y(), qreal((i/3)*60)); |
490 | } |
491 | |
492 | for (int i = model.count(); i < 30; ++i) |
493 | model.insertItem(index: i, name: "Hello" , number: QString::number(i)); |
494 | |
495 | gridview->setContentY(120); |
496 | |
497 | // Insert item outside visible area |
498 | model.insertItem(index: 1, name: "Hello" , number: "1324" ); |
499 | |
500 | QTRY_COMPARE(gridview->contentY(), qreal(120)); |
501 | |
502 | delete window; |
503 | } |
504 | |
505 | void tst_QQuickGridView::inserted_defaultLayout(QQuickGridView::Flow flow, |
506 | Qt::LayoutDirection horizLayout, |
507 | QQuickItemView::VerticalLayoutDirection verticalLayout) |
508 | { |
509 | QFETCH(qreal, contentYRowOffset); |
510 | QFETCH(int, insertIndex); |
511 | QFETCH(int, insertCount); |
512 | QFETCH(int, insertIndex_ttb); |
513 | QFETCH(int, insertCount_ttb); |
514 | QFETCH(qreal, rowOffsetAfterMove); |
515 | |
516 | QaimModel model; |
517 | for (int i = 0; i < 30; i++) |
518 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
519 | |
520 | QQuickView *window = getView(); |
521 | QQmlContext *ctxt = window->rootContext(); |
522 | ctxt->setContextProperty("testModel" , &model); |
523 | ctxt->setContextProperty("testTopToBottom" , flow == QQuickGridView::FlowTopToBottom); |
524 | ctxt->setContextProperty("testRightToLeft" , horizLayout == Qt::RightToLeft); |
525 | ctxt->setContextProperty("testBottomToTop" , verticalLayout == QQuickGridView::BottomToTop); |
526 | window->setSource(testFileUrl(fileName: "layouts.qml" )); |
527 | window->show(); |
528 | qApp->processEvents(); |
529 | |
530 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
531 | QTRY_VERIFY(gridview != nullptr); |
532 | QQuickItem *contentItem = gridview->contentItem(); |
533 | QTRY_VERIFY(contentItem != nullptr); |
534 | |
535 | if (flow == QQuickGridView::FlowTopToBottom) { |
536 | insertIndex = insertIndex_ttb; |
537 | insertCount = insertCount_ttb; |
538 | } |
539 | if (setContentPos(gridview, rowOrColOffset: contentYRowOffset)) |
540 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
541 | |
542 | QList<QPair<QString, QString> > newData; |
543 | for (int i=0; i<insertCount; i++) |
544 | newData << qMakePair(x: QString("value %1" ).arg(a: i), y: QString::number(i)); |
545 | model.insertItems(index: insertIndex, items: newData); |
546 | gridview->forceLayout(); |
547 | QTRY_COMPARE(gridview->property("count" ).toInt(), model.count()); |
548 | |
549 | // check visibleItems.first() is in correct position |
550 | QQuickItem *item0 = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: 0); |
551 | QVERIFY(item0); |
552 | QPointF firstPos(0, 0); |
553 | if (horizLayout == Qt::RightToLeft) |
554 | firstPos.rx() = flow == QQuickGridView::FlowLeftToRight ? gridview->width() - gridview->cellWidth() : -gridview->cellWidth(); |
555 | if (verticalLayout == QQuickItemView::BottomToTop) |
556 | firstPos.ry() -= gridview->cellHeight(); |
557 | QCOMPARE(item0->position(), firstPos); |
558 | |
559 | QList<QQuickItem*> items = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ); |
560 | int firstVisibleIndex = -1; |
561 | for (int i=0; i<items.count(); i++) { |
562 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
563 | if (item && delegateVisible(item)) { |
564 | firstVisibleIndex = i; |
565 | break; |
566 | } |
567 | } |
568 | QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); |
569 | |
570 | // Confirm items positioned correctly and indexes correct |
571 | for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) { |
572 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
573 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
574 | QCOMPARE(item->position(), expectedItemPos(gridview, i, rowOffsetAfterMove)); |
575 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
576 | QVERIFY(name != nullptr); |
577 | QCOMPARE(name->text(), model.name(i)); |
578 | } |
579 | |
580 | releaseView(view: window); |
581 | } |
582 | |
583 | void tst_QQuickGridView::inserted_defaultLayout_data() |
584 | { |
585 | QTest::addColumn<qreal>(name: "contentYRowOffset" ); |
586 | QTest::addColumn<int>(name: "insertIndex" ); |
587 | QTest::addColumn<int>(name: "insertCount" ); |
588 | QTest::addColumn<int>(name: "insertIndex_ttb" ); |
589 | QTest::addColumn<int>(name: "insertCount_ttb" ); |
590 | QTest::addColumn<qreal>(name: "rowOffsetAfterMove" ); |
591 | |
592 | QTest::newRow(dataTag: "add 1, before visible items" ) |
593 | << 2.0 // show 6-23 |
594 | << 5 << 1 |
595 | << 9 << 1 |
596 | << 0.0; // insert 1 above first visible, grid is rearranged; first visible moves forward within its row |
597 | // new 1st visible item is at 0 |
598 | |
599 | QTest::newRow(dataTag: "add 2, before visible items" ) |
600 | << 2.0 // show 6-23 |
601 | << 5 << 2 |
602 | << 9 << 2 |
603 | << 0.0; // insert 2 above first visible, grid is rearranged; first visible moves forward within its row |
604 | |
605 | QTest::newRow(dataTag: "add 3, before visible items" ) |
606 | << 2.0 // show 6-23 |
607 | << 5 << 3 |
608 | << 9 << 5 |
609 | << -1.0; // insert 3 (1 row) above first visible in negative pos, first visible does not move |
610 | |
611 | QTest::newRow(dataTag: "add 5, before visible items" ) |
612 | << 2.0 // show 6-23 |
613 | << 5 << 5 |
614 | << 9 << 7 |
615 | << -1.0; // insert 1 row + 2 items above first visible, 1 row added at negative pos, |
616 | // grid is rearranged and first visible moves forward within its row |
617 | |
618 | QTest::newRow(dataTag: "add 6, before visible items" ) |
619 | << 2.0 // show 6-23 |
620 | << 5 << 6 |
621 | << 9 << 10 |
622 | << -1.0 * 2; // insert 2 rows above first visible in negative pos, first visible does not move |
623 | |
624 | |
625 | |
626 | QTest::newRow(dataTag: "add 1, at start of visible, content at start" ) |
627 | << 0.0 |
628 | << 0 << 1 |
629 | << 0 << 1 |
630 | << 0.0; |
631 | |
632 | QTest::newRow(dataTag: "add multiple, at start of visible, content at start" ) |
633 | << 0.0 |
634 | << 0 << 3 |
635 | << 0 << 5 |
636 | << 0.0; |
637 | |
638 | QTest::newRow(dataTag: "add 1, at start of visible, content not at start" ) |
639 | << 2.0 // show 6-23 |
640 | << 6 << 1 |
641 | << 10 << 1 |
642 | << 0.0; |
643 | |
644 | QTest::newRow(dataTag: "add multiple, at start of visible, content not at start" ) |
645 | << 2.0 // show 6-23 |
646 | << 6 << 3 |
647 | << 10 << 5 |
648 | << 0.0; |
649 | |
650 | |
651 | QTest::newRow(dataTag: "add 1, at end of visible, content at start" ) |
652 | << 0.0 |
653 | << 17 << 1 |
654 | << 14 << 1 |
655 | << 0.0; |
656 | |
657 | QTest::newRow(dataTag: "add row, at end of visible, content at start" ) |
658 | << 0.0 |
659 | << 17 << 3 |
660 | << 14 << 5 |
661 | << 0.0; |
662 | |
663 | QTest::newRow(dataTag: "add 1, at end of visible, content not at start" ) |
664 | << 2.0 // show 6-23 |
665 | << 17+6 << 1 |
666 | << 14+10 << 1 |
667 | << 0.0; |
668 | |
669 | QTest::newRow(dataTag: "add multiple, at end of visible, content not at start" ) |
670 | << 2.0 // show 6-23 |
671 | << 17+6 << 3 |
672 | << 14+10 << 5 |
673 | << 0.0; |
674 | |
675 | |
676 | QTest::newRow(dataTag: "add 1, after visible, content at start" ) |
677 | << 0.0 |
678 | << 20 << 1 |
679 | << 18 << 1 |
680 | << 0.0; |
681 | |
682 | QTest::newRow(dataTag: "add row, after visible, content at start" ) |
683 | << 0.0 |
684 | << 20 << 3 |
685 | << 18 << 5 |
686 | << 0.0; |
687 | |
688 | QTest::newRow(dataTag: "add 1, after visible, content not at start" ) |
689 | << 2.0 // show 6-23 |
690 | << 20+6 << 1 |
691 | << 18+10 << 1 |
692 | << 0.0; |
693 | |
694 | QTest::newRow(dataTag: "add multiple, after visible, content not at start" ) |
695 | << 2.0 // show 6-23 |
696 | << 20+6 << 3 |
697 | << 18+10 << 3 |
698 | << 0.0; |
699 | } |
700 | |
701 | void tst_QQuickGridView::insertBeforeVisible() |
702 | { |
703 | QFETCH(int, insertIndex); |
704 | QFETCH(int, insertCount); |
705 | QFETCH(int, cacheBuffer); |
706 | |
707 | QQuickText *name; |
708 | QQuickView *window = getView(); |
709 | |
710 | QaimModel model; |
711 | for (int i = 0; i < 30; i++) |
712 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
713 | |
714 | QQmlContext *ctxt = window->rootContext(); |
715 | ctxt->setContextProperty("testModel" , &model); |
716 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
717 | window->show(); |
718 | qApp->processEvents(); |
719 | |
720 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
721 | QTRY_VERIFY(gridview != nullptr); |
722 | QQuickItem *contentItem = gridview->contentItem(); |
723 | QTRY_VERIFY(contentItem != nullptr); |
724 | |
725 | gridview->setCacheBuffer(cacheBuffer); |
726 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
727 | |
728 | // trigger a refill (not just setting contentY) so that the visibleItems grid is updated |
729 | int firstVisibleIndex = 12; // move to an index where the top item is not visible |
730 | gridview->setContentY(firstVisibleIndex/3 * 60.0); |
731 | gridview->setCurrentIndex(firstVisibleIndex); |
732 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
733 | |
734 | QTRY_COMPARE(gridview->currentIndex(), firstVisibleIndex); |
735 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: firstVisibleIndex); |
736 | QVERIFY(item); |
737 | QCOMPARE(item->y(), gridview->contentY()); |
738 | |
739 | QList<QPair<QString, QString> > newData; |
740 | for (int i=0; i<insertCount; i++) |
741 | newData << qMakePair(x: QString("value %1" ).arg(a: i), y: QString::number(i)); |
742 | model.insertItems(index: insertIndex, items: newData); |
743 | gridview->forceLayout(); |
744 | QTRY_COMPARE(gridview->property("count" ).toInt(), model.count()); |
745 | |
746 | // now, moving to the top of the view should position the inserted items correctly |
747 | int itemsOffsetAfterMove = (insertCount / 3) * -60.0; |
748 | gridview->setCurrentIndex(0); |
749 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
750 | QTRY_COMPARE(gridview->currentIndex(), 0); |
751 | QTRY_COMPARE(gridview->contentY(), 0.0 + itemsOffsetAfterMove); |
752 | |
753 | // Confirm items positioned correctly and indexes correct |
754 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
755 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
756 | item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
757 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
758 | QCOMPARE(item->x(), (i%3)*80.0); |
759 | QCOMPARE(item->y(), (i/3)*60.0 + itemsOffsetAfterMove); |
760 | name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
761 | QVERIFY(name != nullptr); |
762 | QTRY_COMPARE(name->text(), model.name(i)); |
763 | } |
764 | |
765 | releaseView(view: window); |
766 | } |
767 | |
768 | void tst_QQuickGridView::insertBeforeVisible_data() |
769 | { |
770 | QTest::addColumn<int>(name: "insertIndex" ); |
771 | QTest::addColumn<int>(name: "insertCount" ); |
772 | QTest::addColumn<int>(name: "cacheBuffer" ); |
773 | |
774 | QTest::newRow(dataTag: "insert 1 at 0, 0 buffer" ) << 0 << 1 << 0; |
775 | QTest::newRow(dataTag: "insert 1 at 0, 100 buffer" ) << 0 << 1 << 100; |
776 | QTest::newRow(dataTag: "insert 1 at 0, 500 buffer" ) << 0 << 1 << 500; |
777 | |
778 | QTest::newRow(dataTag: "insert 1 at 1, 0 buffer" ) << 1 << 1 << 0; |
779 | QTest::newRow(dataTag: "insert 1 at 1, 100 buffer" ) << 1 << 1 << 100; |
780 | QTest::newRow(dataTag: "insert 1 at 1, 500 buffer" ) << 1 << 1 << 500; |
781 | |
782 | QTest::newRow(dataTag: "insert multiple at 0, 0 buffer" ) << 0 << 6 << 0; |
783 | QTest::newRow(dataTag: "insert multiple at 0, 100 buffer" ) << 0 << 6 << 100; |
784 | QTest::newRow(dataTag: "insert multiple at 0, 500 buffer" ) << 0 << 6 << 500; |
785 | |
786 | QTest::newRow(dataTag: "insert multiple at 1, 0 buffer" ) << 1 << 6 << 0; |
787 | QTest::newRow(dataTag: "insert multiple at 1, 100 buffer" ) << 1 << 6 << 100; |
788 | QTest::newRow(dataTag: "insert multiple at 1, 500 buffer" ) << 1 << 6 << 500; |
789 | } |
790 | |
791 | void tst_QQuickGridView::removed_basic() |
792 | { |
793 | QQuickView *window = createView(); |
794 | window->show(); |
795 | |
796 | QaimModel model; |
797 | for (int i = 0; i < 40; i++) |
798 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
799 | |
800 | window->rootContext()->setContextProperty("testModel" , &model); |
801 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
802 | qApp->processEvents(); |
803 | |
804 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
805 | QTRY_VERIFY(gridview != nullptr); |
806 | QQuickItem *contentItem = gridview->contentItem(); |
807 | QTRY_VERIFY(contentItem != nullptr); |
808 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
809 | |
810 | model.removeItem(index: 1); |
811 | QTRY_COMPARE(window->rootObject()->property("count" ).toInt(), model.count()); |
812 | |
813 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: 1); |
814 | QTRY_VERIFY(name != nullptr); |
815 | QTRY_COMPARE(name->text(), model.name(1)); |
816 | QQuickText *number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: 1); |
817 | QTRY_VERIFY(number != nullptr); |
818 | QTRY_COMPARE(number->text(), model.number(1)); |
819 | |
820 | |
821 | // Checks that onRemove is called |
822 | QString removed = window->rootObject()->property(name: "removed" ).toString(); |
823 | QTRY_COMPARE(removed, QString("Item1" )); |
824 | |
825 | // Confirm items positioned correctly |
826 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
827 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
828 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
829 | if (!item) qWarning() << "Item" << i << "not found" ; |
830 | QTRY_COMPARE(item->x(), qreal((i%3)*80)); |
831 | QTRY_COMPARE(item->y(), qreal((i/3)*60)); |
832 | } |
833 | |
834 | // Remove first item (which is the current item); |
835 | model.removeItem(index: 0); |
836 | QTRY_COMPARE(window->rootObject()->property("count" ).toInt(), model.count()); |
837 | |
838 | name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: 0); |
839 | QTRY_VERIFY(name != nullptr); |
840 | QTRY_COMPARE(name->text(), model.name(0)); |
841 | number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: 0); |
842 | QTRY_VERIFY(number != nullptr); |
843 | QTRY_COMPARE(number->text(), model.number(0)); |
844 | |
845 | |
846 | // Confirm items positioned correctly |
847 | itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
848 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
849 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
850 | if (!item) qWarning() << "Item" << i << "not found" ; |
851 | QTRY_COMPARE(item->x(), qreal((i%3)*80)); |
852 | QTRY_COMPARE(item->y(), qreal((i/3)*60)); |
853 | } |
854 | |
855 | // Remove items not visible |
856 | model.removeItem(index: 25); |
857 | QTRY_COMPARE(window->rootObject()->property("count" ).toInt(), model.count()); |
858 | |
859 | // Confirm items positioned correctly |
860 | itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
861 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
862 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
863 | if (!item) qWarning() << "Item" << i << "not found" ; |
864 | QTRY_COMPARE(item->x(), qreal((i%3)*80)); |
865 | QTRY_COMPARE(item->y(), qreal((i/3)*60)); |
866 | } |
867 | |
868 | // Remove items before visible |
869 | gridview->setContentY(120); |
870 | gridview->setCurrentIndex(10); |
871 | |
872 | // Setting currentIndex above shouldn't cause view to scroll |
873 | QTRY_COMPARE(gridview->contentY(), 120.0); |
874 | |
875 | model.removeItem(index: 1); |
876 | QTRY_COMPARE(window->rootObject()->property("count" ).toInt(), model.count()); |
877 | |
878 | // Confirm items positioned correctly |
879 | for (int i = 6; i < 18; ++i) { |
880 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
881 | if (!item) qWarning() << "Item" << i << "not found" ; |
882 | QTRY_COMPARE(item->x(), qreal((i%3)*80)); |
883 | QTRY_COMPARE(item->y(), qreal((i/3)*60)); |
884 | } |
885 | |
886 | // Remove currentIndex |
887 | QQuickItem *oldCurrent = gridview->currentItem(); |
888 | model.removeItem(index: 9); |
889 | QTRY_COMPARE(window->rootObject()->property("count" ).toInt(), model.count()); |
890 | |
891 | QTRY_COMPARE(gridview->currentIndex(), 9); |
892 | QTRY_VERIFY(gridview->currentItem() != oldCurrent); |
893 | |
894 | gridview->setContentY(0); |
895 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
896 | |
897 | // Confirm items positioned correctly |
898 | itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
899 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
900 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
901 | QTRY_COMPARE(item->x(), qreal((i%3)*80)); |
902 | QTRY_COMPARE(item->y(), qreal((i/3)*60)); |
903 | } |
904 | |
905 | // remove item outside current view. |
906 | gridview->setCurrentIndex(32); |
907 | gridview->setContentY(240); |
908 | |
909 | model.removeItem(index: 30); |
910 | QTRY_COMPARE(gridview->currentIndex(), 31); |
911 | |
912 | // remove current item beyond visible items. |
913 | gridview->setCurrentIndex(20); |
914 | gridview->setContentY(0); |
915 | model.removeItem(index: 20); |
916 | |
917 | QTRY_COMPARE(gridview->currentIndex(), 20); |
918 | QTRY_VERIFY(gridview->currentItem() != nullptr); |
919 | |
920 | // remove item before current, but visible |
921 | gridview->setCurrentIndex(8); |
922 | gridview->setContentY(240); |
923 | oldCurrent = gridview->currentItem(); |
924 | model.removeItem(index: 6); |
925 | |
926 | QTRY_COMPARE(gridview->currentIndex(), 7); |
927 | QTRY_COMPARE(gridview->currentItem(), oldCurrent); |
928 | |
929 | delete window; |
930 | } |
931 | |
932 | void tst_QQuickGridView::removed_defaultLayout(QQuickGridView::Flow flow, |
933 | Qt::LayoutDirection horizLayout, |
934 | QQuickItemView::VerticalLayoutDirection verticalLayout) |
935 | { |
936 | QFETCH(qreal, contentYRowOffset); |
937 | QFETCH(int, removeIndex); |
938 | QFETCH(int, removeCount); |
939 | QFETCH(int, removeIndex_ttb); |
940 | QFETCH(int, removeCount_ttb); |
941 | QFETCH(qreal, rowOffsetAfterMove); |
942 | QFETCH(QString, firstVisible); |
943 | QFETCH(QString, firstVisible_ttb); |
944 | |
945 | QQuickView *window = getView(); |
946 | |
947 | QaimModel model; |
948 | for (int i = 0; i < 30; i++) |
949 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
950 | |
951 | QQmlContext *ctxt = window->rootContext(); |
952 | ctxt->setContextProperty("testModel" , &model); |
953 | ctxt->setContextProperty("testTopToBottom" , flow == QQuickGridView::FlowTopToBottom); |
954 | ctxt->setContextProperty("testRightToLeft" , horizLayout == Qt::RightToLeft); |
955 | ctxt->setContextProperty("testBottomToTop" , verticalLayout == QQuickGridView::BottomToTop); |
956 | window->setSource(testFileUrl(fileName: "layouts.qml" )); |
957 | window->show(); |
958 | qApp->processEvents(); |
959 | |
960 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
961 | QTRY_VERIFY(gridview != nullptr); |
962 | QQuickItem *contentItem = gridview->contentItem(); |
963 | QTRY_VERIFY(contentItem != nullptr); |
964 | |
965 | if (flow == QQuickGridView::FlowTopToBottom) { |
966 | removeIndex = removeIndex_ttb; |
967 | removeCount = removeCount_ttb; |
968 | firstVisible = firstVisible_ttb; |
969 | } |
970 | if (setContentPos(gridview, rowOrColOffset: contentYRowOffset)) |
971 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
972 | |
973 | model.removeItems(index: removeIndex, count: removeCount); |
974 | gridview->forceLayout(); |
975 | QTRY_COMPARE(gridview->property("count" ).toInt(), model.count()); |
976 | |
977 | QString firstName; |
978 | int firstVisibleIndex = -1; |
979 | QList<QQuickItem*> items = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ); |
980 | QRectF viewRect(gridview->contentX(), gridview->contentY(), gridview->width(), gridview->height()); |
981 | for (int i=0; i<items.count(); i++) { |
982 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
983 | if (item) { |
984 | QRectF itemRect(item->x(), item->y(), item->width(), item->height()); |
985 | if (delegateVisible(item) && viewRect.intersects(r: itemRect)) { |
986 | firstVisibleIndex = i; |
987 | QQmlExpression en(qmlContext(item), item, "name" ); |
988 | firstName = en.evaluate().toString(); |
989 | break; |
990 | } |
991 | } |
992 | } |
993 | QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); |
994 | QCOMPARE(firstName, firstVisible); |
995 | |
996 | // Confirm items positioned correctly and indexes correct |
997 | for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) { |
998 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
999 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
1000 | QCOMPARE(item->position(), expectedItemPos(gridview, i, rowOffsetAfterMove)); |
1001 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
1002 | QVERIFY(name != nullptr); |
1003 | QTRY_COMPARE(name->text(), model.name(i)); |
1004 | } |
1005 | |
1006 | releaseView(view: window); |
1007 | } |
1008 | |
1009 | void tst_QQuickGridView::removed_defaultLayout_data() |
1010 | { |
1011 | QTest::addColumn<qreal>(name: "contentYRowOffset" ); |
1012 | QTest::addColumn<int>(name: "removeIndex" ); |
1013 | QTest::addColumn<int>(name: "removeCount" ); |
1014 | QTest::addColumn<int>(name: "removeIndex_ttb" ); |
1015 | QTest::addColumn<int>(name: "removeCount_ttb" ); |
1016 | QTest::addColumn<qreal>(name: "rowOffsetAfterMove" ); |
1017 | QTest::addColumn<QString>(name: "firstVisible" ); |
1018 | QTest::addColumn<QString>(name: "firstVisible_ttb" ); |
1019 | |
1020 | QTest::newRow(dataTag: "remove 1, before visible items" ) |
1021 | << 2.0 // show 6-23 |
1022 | << 2 << 1 |
1023 | << 4 << 1 |
1024 | << 0.0 << "Item7" << "Item11" ; |
1025 | |
1026 | QTest::newRow(dataTag: "remove 1, before visible position" ) |
1027 | << 2.0 // show 6-23 |
1028 | << 3 << 1 |
1029 | << 5 << 1 |
1030 | << 0.0 << "Item7" << "Item11" ; |
1031 | |
1032 | QTest::newRow(dataTag: "remove multiple (1 row), all before visible items" ) |
1033 | << 2.0 |
1034 | << 1 << 3 |
1035 | << 1 << 5 |
1036 | << 1.0 << "Item6" << "Item10" ; // removed top row, slide down by 1 row |
1037 | |
1038 | QTest::newRow(dataTag: "remove multiple, all before visible items, remove item 0" ) |
1039 | << 2.0 |
1040 | << 0 << 4 |
1041 | << 0 << 6 |
1042 | << 1.0 << "Item7" << "Item11" ; // removed top row, slide down by 1 row |
1043 | |
1044 | QTest::newRow(dataTag: "remove multiple rows, all before visible items" ) |
1045 | << 4.0 // show 12-29 |
1046 | << 1 << 7 |
1047 | << 1 << 12 |
1048 | << 2.0 << "Item13" << "Item17" ; |
1049 | |
1050 | QTest::newRow(dataTag: "remove one row before visible, content y not on item border" ) |
1051 | << 1.5 |
1052 | << 0 << 3 |
1053 | << 0 << 5 |
1054 | << 1.0 << "Item3" << "Item5" ; // 1 row removed |
1055 | |
1056 | QTest::newRow(dataTag: "remove mix of visible/non-visible" ) |
1057 | << 2.0 // show 6-23 |
1058 | << 2 << 3 |
1059 | << 4 << 3 |
1060 | << 1.0 << "Item6" << "Item8" ; // 1 row removed |
1061 | |
1062 | |
1063 | // remove 3,4,5 before the visible pos, first row moves down to just before the visible pos, |
1064 | // items 6,7 are removed from view, item 8 slides up to original pos of item 6 (120px) |
1065 | QTest::newRow(dataTag: "remove multiple, mix of items from before and within visible items" ) |
1066 | << 2.0 |
1067 | << 3 << 5 |
1068 | << 5 << 7 |
1069 | << 1.0 << "Item8" << "Item12" ; // adjust for the 1 row removed before the visible |
1070 | |
1071 | QTest::newRow(dataTag: "remove multiple, mix of items from before and within visible items, remove item 0" ) |
1072 | << 2.0 |
1073 | << 0 << 8 |
1074 | << 0 << 12 |
1075 | << 1.0 * 2 << "Item8" << "Item12" ; // adjust for the 2 rows removed before the visible |
1076 | |
1077 | |
1078 | QTest::newRow(dataTag: "remove 1, from start of visible, content at start" ) |
1079 | << 0.0 |
1080 | << 0 << 1 |
1081 | << 0 << 1 |
1082 | << 0.0 << "Item1" << "Item1" ; |
1083 | |
1084 | QTest::newRow(dataTag: "remove multiple, from start of visible, content at start" ) |
1085 | << 0.0 |
1086 | << 0 << 3 |
1087 | << 0 << 5 |
1088 | << 0.0 << "Item3" << "Item5" ; |
1089 | |
1090 | QTest::newRow(dataTag: "remove 1, from start of visible, content not at start" ) |
1091 | << 2.0 // show 6-23 |
1092 | << 4 << 1 |
1093 | << 7 << 1 |
1094 | << 0.0 << "Item7" << "Item11" ; |
1095 | |
1096 | QTest::newRow(dataTag: "remove multiple, from start of visible, content not at start" ) |
1097 | << 2.0 // show 6-23 |
1098 | << 4 << 3 |
1099 | << 7 << 5 |
1100 | << 0.0 << "Item9" << "Item15" ; |
1101 | |
1102 | |
1103 | QTest::newRow(dataTag: "remove 1, from middle of visible, content at start" ) |
1104 | << 0.0 |
1105 | << 10 << 1 |
1106 | << 12 << 1 |
1107 | << 0.0 << "Item0" << "Item0" ; |
1108 | |
1109 | QTest::newRow(dataTag: "remove multiple, from middle of visible, content at start" ) |
1110 | << 0.0 |
1111 | << 10 << 5 |
1112 | << 12 << 5 |
1113 | << 0.0 << "Item0" << "Item0" ; |
1114 | |
1115 | QTest::newRow(dataTag: "remove 1, from middle of visible, content not at start" ) |
1116 | << 2.0 // show 6-23 |
1117 | << 10 << 1 |
1118 | << 12 << 1 |
1119 | << 0.0 << "Item6" << "Item10" ; |
1120 | |
1121 | QTest::newRow(dataTag: "remove multiple, from middle of visible, content not at start" ) |
1122 | << 2.0 // show 6-23 |
1123 | << 10 << 5 |
1124 | << 12 << 7 |
1125 | << 0.0 << "Item6" << "Item10" ; |
1126 | |
1127 | |
1128 | QTest::newRow(dataTag: "remove 1, after visible, content at start" ) |
1129 | << 0.0 |
1130 | << 16 << 1 |
1131 | << 15 << 1 |
1132 | << 0.0 << "Item0" << "Item0" ; |
1133 | |
1134 | QTest::newRow(dataTag: "remove multiple, after visible, content at start" ) |
1135 | << 0.0 |
1136 | << 16 << 5 |
1137 | << 15 << 7 |
1138 | << 0.0 << "Item0" << "Item0" ; |
1139 | |
1140 | QTest::newRow(dataTag: "remove 1, after visible, content not at start" ) |
1141 | << 2.0 // show 6-23 |
1142 | << 16+4 << 1 |
1143 | << 15+10 << 1 |
1144 | << 0.0 << "Item6" << "Item10" ; |
1145 | |
1146 | QTest::newRow(dataTag: "remove multiple, after visible, content not at start" ) |
1147 | << 2.0 // show 6-23 |
1148 | << 16+4 << 5 |
1149 | << 15 << 7 |
1150 | << 0.0 << "Item6" << "Item10" ; |
1151 | |
1152 | QTest::newRow(dataTag: "remove multiple, mix of items from within and after visible items" ) |
1153 | << 2.0 // show 6-23 |
1154 | << 20 << 5 |
1155 | << 22 << 7 |
1156 | << 0.0 << "Item6" << "Item10" ; |
1157 | } |
1158 | |
1159 | void tst_QQuickGridView::addOrRemoveBeforeVisible() |
1160 | { |
1161 | // QTBUG-21588: ensure re-layout is done on grid after adding or removing |
1162 | // items from before the visible area |
1163 | |
1164 | QFETCH(bool, doAdd); |
1165 | QFETCH(qreal, newTopContentY); |
1166 | |
1167 | QQuickView *window = getView(); |
1168 | window->show(); |
1169 | |
1170 | QaimModel model; |
1171 | for (int i = 0; i < 30; i++) |
1172 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
1173 | |
1174 | window->rootContext()->setContextProperty("testModel" , &model); |
1175 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
1176 | |
1177 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
1178 | QTRY_VERIFY(gridview != nullptr); |
1179 | QQuickItem *contentItem = gridview->contentItem(); |
1180 | QTRY_VERIFY(contentItem != nullptr); |
1181 | |
1182 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: 0); |
1183 | QTRY_COMPARE(name->text(), QString("Item0" )); |
1184 | |
1185 | gridview->setCurrentIndex(0); |
1186 | qApp->processEvents(); |
1187 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1188 | |
1189 | // scroll down until item 0 is no longer drawn |
1190 | // (bug not triggered if we just move using content y, since that doesn't |
1191 | // refill and change the visible items) |
1192 | gridview->setCurrentIndex(24); |
1193 | qApp->processEvents(); |
1194 | |
1195 | QTRY_COMPARE(gridview->currentIndex(), 24); |
1196 | QTRY_COMPARE(gridview->contentY(), 220.0); |
1197 | |
1198 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1199 | QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper" , 0)); // 0 shouldn't be visible |
1200 | |
1201 | if (doAdd) { |
1202 | model.insertItem(index: 0, name: "New Item" , number: "New Item number" ); |
1203 | QTRY_COMPARE(gridview->count(), 31); |
1204 | } else { |
1205 | model.removeItem(index: 0); |
1206 | QTRY_COMPARE(gridview->count(), 29); |
1207 | } |
1208 | |
1209 | // scroll back up and item 0 should be gone |
1210 | gridview->setCurrentIndex(0); |
1211 | qApp->processEvents(); |
1212 | QTRY_COMPARE(gridview->currentIndex(), 0); |
1213 | QTRY_COMPARE(gridview->contentY(), newTopContentY); |
1214 | |
1215 | name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: 0); |
1216 | if (doAdd) |
1217 | QCOMPARE(name->text(), QString("New Item" )); |
1218 | else |
1219 | QCOMPARE(name->text(), QString("Item1" )); |
1220 | |
1221 | // Confirm items positioned correctly |
1222 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
1223 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
1224 | QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper" , i)); |
1225 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
1226 | QTRY_COMPARE(item->x(), qreal((i%3)*80)); |
1227 | QTRY_VERIFY(item->y() == (i/3)*60 + newTopContentY); |
1228 | } |
1229 | |
1230 | releaseView(view: window); |
1231 | } |
1232 | |
1233 | void tst_QQuickGridView::addOrRemoveBeforeVisible_data() |
1234 | { |
1235 | QTest::addColumn<bool>(name: "doAdd" ); |
1236 | QTest::addColumn<qreal>(name: "newTopContentY" ); |
1237 | |
1238 | QTest::newRow(dataTag: "add" ) << true << -60.0; |
1239 | QTest::newRow(dataTag: "remove" ) << false << -60.0; |
1240 | } |
1241 | |
1242 | void tst_QQuickGridView::clear() |
1243 | { |
1244 | QQuickView *window = createView(); |
1245 | |
1246 | QaimModel model; |
1247 | for (int i = 0; i < 30; i++) |
1248 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
1249 | |
1250 | window->rootContext()->setContextProperty("testModel" , &model); |
1251 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
1252 | window->show(); |
1253 | qApp->processEvents(); |
1254 | |
1255 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
1256 | QVERIFY(gridview != nullptr); |
1257 | QQuickItem *contentItem = gridview->contentItem(); |
1258 | QVERIFY(contentItem != nullptr); |
1259 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1260 | |
1261 | model.clear(); |
1262 | gridview->forceLayout(); |
1263 | |
1264 | QCOMPARE(gridview->count(), 0); |
1265 | QVERIFY(!gridview->currentItem()); |
1266 | QCOMPARE(gridview->contentY(), qreal(0)); |
1267 | QCOMPARE(gridview->currentIndex(), -1); |
1268 | QCOMPARE(gridview->contentHeight(), 0.0); |
1269 | |
1270 | // confirm sanity when adding an item to cleared list |
1271 | model.addItem(name: "New" , number: "1" ); |
1272 | gridview->forceLayout(); |
1273 | QTRY_COMPARE(gridview->count(), 1); |
1274 | QVERIFY(gridview->currentItem() != nullptr); |
1275 | QCOMPARE(gridview->currentIndex(), 0); |
1276 | |
1277 | delete window; |
1278 | } |
1279 | |
1280 | void tst_QQuickGridView::moved_defaultLayout(QQuickGridView::Flow flow, |
1281 | Qt::LayoutDirection horizLayout, |
1282 | QQuickItemView::VerticalLayoutDirection verticalLayout) |
1283 | { |
1284 | QFETCH(qreal, contentYRowOffset); |
1285 | QFETCH(int, from); |
1286 | QFETCH(int, to); |
1287 | QFETCH(int, count); |
1288 | QFETCH(int, from_ttb); |
1289 | QFETCH(int, to_ttb); |
1290 | QFETCH(int, count_ttb); |
1291 | QFETCH(qreal, rowOffsetAfterMove); |
1292 | |
1293 | QQuickView *window = getView(); |
1294 | |
1295 | QaimModel model; |
1296 | for (int i = 0; i < 30; i++) |
1297 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
1298 | |
1299 | QQmlContext *ctxt = window->rootContext(); |
1300 | ctxt->setContextProperty("testModel" , &model); |
1301 | ctxt->setContextProperty("testTopToBottom" , flow == QQuickGridView::FlowTopToBottom); |
1302 | ctxt->setContextProperty("testRightToLeft" , horizLayout == Qt::RightToLeft); |
1303 | ctxt->setContextProperty("testBottomToTop" , verticalLayout == QQuickGridView::BottomToTop); |
1304 | window->setSource(testFileUrl(fileName: "layouts.qml" )); |
1305 | window->show(); |
1306 | qApp->processEvents(); |
1307 | |
1308 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
1309 | QTRY_VERIFY(gridview != nullptr); |
1310 | QQuickItem *contentItem = gridview->contentItem(); |
1311 | QTRY_VERIFY(contentItem != nullptr); |
1312 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1313 | |
1314 | QQuickItem *currentItem = gridview->currentItem(); |
1315 | QTRY_VERIFY(currentItem != nullptr); |
1316 | |
1317 | if (flow == QQuickGridView::FlowTopToBottom) { |
1318 | from = from_ttb; |
1319 | to = to_ttb; |
1320 | count = count_ttb; |
1321 | } |
1322 | if (setContentPos(gridview, rowOrColOffset: contentYRowOffset)) |
1323 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1324 | |
1325 | model.moveItems(from, to, count); |
1326 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1327 | |
1328 | // Confirm items positioned correctly and indexes correct |
1329 | QList<QQuickItem*> items = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ); |
1330 | int firstVisibleIndex = -1; |
1331 | for (int i=0; i<items.count(); i++) { |
1332 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
1333 | if (item && delegateVisible(item)) { |
1334 | firstVisibleIndex = i; |
1335 | break; |
1336 | } |
1337 | } |
1338 | QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); |
1339 | |
1340 | for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) { |
1341 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
1342 | if (!item && |
1343 | ( (flow == QQuickGridView::FlowLeftToRight && i >= firstVisibleIndex + (3*6)) |
1344 | || (flow == QQuickGridView::FlowTopToBottom && i >= firstVisibleIndex + (5*3)) ) ) { |
1345 | continue; // index has moved out of view |
1346 | } |
1347 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
1348 | QCOMPARE(item->position(), expectedItemPos(gridview, i, rowOffsetAfterMove)); |
1349 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
1350 | QVERIFY(name != nullptr); |
1351 | QTRY_COMPARE(name->text(), model.name(i)); |
1352 | |
1353 | // current index should have been updated |
1354 | if (item == currentItem) |
1355 | QTRY_COMPARE(gridview->currentIndex(), i); |
1356 | } |
1357 | |
1358 | releaseView(view: window); |
1359 | } |
1360 | |
1361 | void tst_QQuickGridView::moved_defaultLayout_data() |
1362 | { |
1363 | QTest::addColumn<qreal>(name: "contentYRowOffset" ); |
1364 | QTest::addColumn<int>(name: "from" ); |
1365 | QTest::addColumn<int>(name: "to" ); |
1366 | QTest::addColumn<int>(name: "count" ); |
1367 | QTest::addColumn<int>(name: "from_ttb" ); |
1368 | QTest::addColumn<int>(name: "to_ttb" ); |
1369 | QTest::addColumn<int>(name: "count_ttb" ); |
1370 | QTest::addColumn<qreal>(name: "rowOffsetAfterMove" ); |
1371 | |
1372 | // model starts with 30 items, each 80x60, in area 240x320 |
1373 | // 18 items should be visible at a time |
1374 | |
1375 | // The first visible item should not move upwards and out of the view |
1376 | // if items are moved/removed before it. |
1377 | |
1378 | |
1379 | QTest::newRow(dataTag: "move 1 forwards, within visible items" ) |
1380 | << 0.0 |
1381 | << 1 << 8 << 1 |
1382 | << 2 << 12 << 1 |
1383 | << 0.0; |
1384 | |
1385 | QTest::newRow(dataTag: "move 1 forwards, from non-visible -> visible" ) |
1386 | << 2.0 // show 6-23 |
1387 | << 1 << 8+6 << 1 |
1388 | << 2 << 12+10 << 1 |
1389 | << 0.0; |
1390 | |
1391 | QTest::newRow(dataTag: "move 1 forwards, from non-visible -> visible (move first item)" ) |
1392 | << 2.0 // // show 6-23 |
1393 | << 0 << 6 << 1 |
1394 | << 0 << 10 << 1 |
1395 | << 0.0; |
1396 | |
1397 | QTest::newRow(dataTag: "move 1 forwards, from visible -> non-visible" ) |
1398 | << 0.0 |
1399 | << 1 << 20 << 1 |
1400 | << 1 << 20 << 1 |
1401 | << 0.0; |
1402 | |
1403 | QTest::newRow(dataTag: "move 1 forwards, from visible -> non-visible (move first item)" ) |
1404 | << 0.0 |
1405 | << 0 << 20 << 1 |
1406 | << 0 << 20 << 1 |
1407 | << 0.0; |
1408 | |
1409 | |
1410 | QTest::newRow(dataTag: "move 1 backwards, within visible items" ) |
1411 | << 0.0 |
1412 | << 10 << 5 << 1 |
1413 | << 10 << 5 << 1 |
1414 | << 0.0; |
1415 | |
1416 | QTest::newRow(dataTag: "move 1 backwards, within visible items (to first index)" ) |
1417 | << 0.0 |
1418 | << 10 << 0 << 1 |
1419 | << 10 << 0 << 1 |
1420 | << 0.0; |
1421 | |
1422 | QTest::newRow(dataTag: "move 1 backwards, from non-visible -> visible" ) |
1423 | << 0.0 |
1424 | << 28 << 8 << 1 |
1425 | << 28 << 8 << 1 |
1426 | << 0.0; |
1427 | |
1428 | QTest::newRow(dataTag: "move 1 backwards, from non-visible -> visible (move last item)" ) |
1429 | << 0.0 |
1430 | << 29 << 14 << 1 |
1431 | << 29 << 14 << 1 |
1432 | << 0.0; |
1433 | |
1434 | QTest::newRow(dataTag: "move 1 backwards, from visible -> non-visible" ) |
1435 | << 2.0 // show 6-23 |
1436 | << 7 << 1 << 1 |
1437 | << 10 << 1 << 1 |
1438 | << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move |
1439 | |
1440 | QTest::newRow(dataTag: "move 1 backwards, from visible -> non-visible (move first item)" ) |
1441 | << 2.0 // show 6-23 |
1442 | << 7 << 0 << 1 |
1443 | << 10 << 0 << 1 |
1444 | << 0.0; // only 1 item moved back, so items shift accordingly and first row doesn't move |
1445 | |
1446 | |
1447 | QTest::newRow(dataTag: "move multiple forwards, within visible items" ) |
1448 | << 0.0 |
1449 | << 0 << 5 << 3 |
1450 | << 0 << 7 << 5 |
1451 | << 0.0; |
1452 | |
1453 | QTest::newRow(dataTag: "move multiple backwards, within visible items (move first item)" ) |
1454 | << 0.0 |
1455 | << 10 << 0 << 3 |
1456 | << 12 << 0 << 5 |
1457 | << 0.0; |
1458 | |
1459 | QTest::newRow(dataTag: "move multiple forwards, before visible items" ) |
1460 | << 2.0 // show 6-23 |
1461 | << 3 << 4 << 3 // 3, 4, 5 move to after 6 |
1462 | << 5 << 6 << 5 |
1463 | << 1.0; // row of 3,4,5 has moved down |
1464 | |
1465 | QTest::newRow(dataTag: "move multiple forwards, from non-visible -> visible" ) |
1466 | << 2.0 // show 6-23 |
1467 | << 1 << 6 << 3 |
1468 | << 1 << 10 << 5 |
1469 | << 1.0; // 1st row (it's above visible area) disappears, 0 drops down 1 row, first visible item (6) stays where it is |
1470 | |
1471 | QTest::newRow(dataTag: "move multiple forwards, from non-visible -> visible (move first item)" ) |
1472 | << 2.0 // show 6-23 |
1473 | << 0 << 6 << 3 |
1474 | << 0 << 10 << 5 |
1475 | << 1.0; // top row moved and shifted to below 3rd row, all items should shift down by 1 row |
1476 | |
1477 | QTest::newRow(dataTag: "move multiple forwards, mix of non-visible/visible" ) |
1478 | << 2.0 |
1479 | << 3 << 16 << 6 |
1480 | << 5 << 18 << 10 |
1481 | << 1.0; // top two rows removed, third row is now the first visible |
1482 | |
1483 | QTest::newRow(dataTag: "move multiple forwards, to bottom of view" ) |
1484 | << 0.0 |
1485 | << 5 << 13 << 5 |
1486 | << 1 << 8 << 6 |
1487 | << 0.0; |
1488 | |
1489 | QTest::newRow(dataTag: "move multiple forwards, to bottom of view, first row -> last" ) |
1490 | << 0.0 |
1491 | << 0 << 15 << 3 |
1492 | << 0 << 10 << 5 |
1493 | << 0.0; |
1494 | |
1495 | QTest::newRow(dataTag: "move multiple forwards, to bottom of view, content y not 0" ) |
1496 | << 2.0 |
1497 | << 5+4 << 13+4 << 5 |
1498 | << 11 << 19 << 6 |
1499 | << 0.0; |
1500 | |
1501 | QTest::newRow(dataTag: "move multiple forwards, from visible -> non-visible" ) |
1502 | << 0.0 |
1503 | << 1 << 16 << 3 |
1504 | << 1 << 18 << 5 |
1505 | << 0.0; |
1506 | |
1507 | QTest::newRow(dataTag: "move multiple forwards, from visible -> non-visible (move first item)" ) |
1508 | << 0.0 |
1509 | << 0 << 16 << 3 |
1510 | << 1 << 18 << 5 |
1511 | << 0.0; |
1512 | |
1513 | |
1514 | QTest::newRow(dataTag: "move multiple backwards, within visible items" ) |
1515 | << 0.0 |
1516 | << 4 << 1 << 3 |
1517 | << 7 << 1 << 5 |
1518 | << 0.0; |
1519 | |
1520 | QTest::newRow(dataTag: "move multiple backwards, from non-visible -> visible" ) |
1521 | << 0.0 |
1522 | << 20 << 4 << 3 |
1523 | << 20 << 4 << 5 |
1524 | << 0.0; |
1525 | |
1526 | QTest::newRow(dataTag: "move multiple backwards, from non-visible -> visible (move last item)" ) |
1527 | << 0.0 |
1528 | << 27 << 10 << 3 |
1529 | << 25 << 8 << 5 |
1530 | << 0.0; |
1531 | |
1532 | QTest::newRow(dataTag: "move multiple backwards, from visible -> non-visible" ) |
1533 | << 2.0 // show 6-23 |
1534 | << 16 << 1 << 3 |
1535 | << 17 << 1 << 5 |
1536 | << -1.0; // to minimize movement, items are added above visible area, all items move up by 1 row |
1537 | |
1538 | QTest::newRow(dataTag: "move multiple backwards, from visible -> non-visible (move first item)" ) |
1539 | << 2.0 // show 6-23 |
1540 | << 16 << 0 << 3 |
1541 | << 17 << 0 << 5 |
1542 | << -1.0; // 16,17,18 move to above item 0, all items move up by 1 row |
1543 | } |
1544 | |
1545 | void tst_QQuickGridView::multipleChanges(bool condensed) |
1546 | { |
1547 | QFETCH(int, startCount); |
1548 | QFETCH(QList<ListChange>, changes); |
1549 | QFETCH(int, newCount); |
1550 | QFETCH(int, newCurrentIndex); |
1551 | |
1552 | QQuickView *window = getView(); |
1553 | |
1554 | QaimModel model; |
1555 | for (int i = 0; i < startCount; i++) |
1556 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
1557 | |
1558 | window->rootContext()->setContextProperty("testModel" , &model); |
1559 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
1560 | window->show(); |
1561 | qApp->processEvents(); |
1562 | |
1563 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
1564 | QTRY_VERIFY(gridview != nullptr); |
1565 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1566 | |
1567 | for (int i=0; i<changes.count(); i++) { |
1568 | switch (changes[i].type) { |
1569 | case ListChange::Inserted: |
1570 | { |
1571 | QList<QPair<QString, QString> > items; |
1572 | for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j) |
1573 | items << qMakePair(x: QString("new item %1" ).arg(a: j), y: QString::number(j)); |
1574 | model.insertItems(index: changes[i].index, items); |
1575 | break; |
1576 | } |
1577 | case ListChange::Removed: |
1578 | model.removeItems(index: changes[i].index, count: changes[i].count); |
1579 | break; |
1580 | case ListChange::Moved: |
1581 | model.moveItems(from: changes[i].index, to: changes[i].to, count: changes[i].count); |
1582 | break; |
1583 | case ListChange::SetCurrent: |
1584 | gridview->setCurrentIndex(changes[i].index); |
1585 | break; |
1586 | case ListChange::SetContentY: |
1587 | gridview->setContentY(changes[i].pos); |
1588 | break; |
1589 | case ListChange::Polish: |
1590 | break; |
1591 | } |
1592 | if (condensed) { |
1593 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1594 | } |
1595 | } |
1596 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1597 | |
1598 | QCOMPARE(gridview->count(), newCount); |
1599 | QCOMPARE(gridview->count(), model.count()); |
1600 | QCOMPARE(gridview->currentIndex(), newCurrentIndex); |
1601 | |
1602 | QQuickText *name; |
1603 | QQuickText *number; |
1604 | QQuickItem *contentItem = gridview->contentItem(); |
1605 | QTRY_VERIFY(contentItem != nullptr); |
1606 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
1607 | for (int i=0; i < model.count() && i < itemCount; ++i) { |
1608 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
1609 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
1610 | name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
1611 | QVERIFY(name != nullptr); |
1612 | QTRY_COMPARE(name->text(), model.name(i)); |
1613 | number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: i); |
1614 | QVERIFY(number != nullptr); |
1615 | QTRY_COMPARE(number->text(), model.number(i)); |
1616 | } |
1617 | |
1618 | releaseView(view: window); |
1619 | } |
1620 | |
1621 | void tst_QQuickGridView::multipleChanges_data() |
1622 | { |
1623 | QTest::addColumn<int>(name: "startCount" ); |
1624 | QTest::addColumn<QList<ListChange> >(name: "changes" ); |
1625 | QTest::addColumn<int>(name: "newCount" ); |
1626 | QTest::addColumn<int>(name: "newCurrentIndex" ); |
1627 | |
1628 | QList<ListChange> changes; |
1629 | |
1630 | for (int i=1; i<30; i++) |
1631 | changes << ListChange::remove(index: 0); |
1632 | QTest::newRow(dataTag: "remove all but 1, first->last" ) << 30 << changes << 1 << 0; |
1633 | |
1634 | changes << ListChange::remove(index: 0); |
1635 | QTest::newRow(dataTag: "remove all" ) << 30 << changes << 0 << -1; |
1636 | |
1637 | changes.clear(); |
1638 | changes << ListChange::setCurrent(29); |
1639 | for (int i=29; i>0; i--) |
1640 | changes << ListChange::remove(index: i); |
1641 | QTest::newRow(dataTag: "remove last (current) -> first" ) << 30 << changes << 1 << 0; |
1642 | |
1643 | QTest::newRow(dataTag: "remove then insert at 0" ) << 10 << (QList<ListChange>() |
1644 | << ListChange::remove(index: 0, count: 1) |
1645 | << ListChange::insert(index: 0, count: 1) |
1646 | ) << 10 << 1; |
1647 | |
1648 | QTest::newRow(dataTag: "remove then insert at non-zero index" ) << 10 << (QList<ListChange>() |
1649 | << ListChange::setCurrent(2) |
1650 | << ListChange::remove(index: 2, count: 1) |
1651 | << ListChange::insert(index: 2, count: 1) |
1652 | ) << 10 << 3; |
1653 | |
1654 | QTest::newRow(dataTag: "remove current then insert below it" ) << 10 << (QList<ListChange>() |
1655 | << ListChange::setCurrent(1) |
1656 | << ListChange::remove(index: 1, count: 3) |
1657 | << ListChange::insert(index: 2, count: 2) |
1658 | ) << 9 << 1; |
1659 | |
1660 | QTest::newRow(dataTag: "remove current index then move it down" ) << 10 << (QList<ListChange>() |
1661 | << ListChange::setCurrent(2) |
1662 | << ListChange::remove(index: 1, count: 3) |
1663 | << ListChange::move(index: 1, to: 5, count: 1) |
1664 | ) << 7 << 5; |
1665 | |
1666 | QTest::newRow(dataTag: "remove current index then move it up" ) << 10 << (QList<ListChange>() |
1667 | << ListChange::setCurrent(5) |
1668 | << ListChange::remove(index: 4, count: 3) |
1669 | << ListChange::move(index: 4, to: 1, count: 1) |
1670 | ) << 7 << 1; |
1671 | |
1672 | |
1673 | QTest::newRow(dataTag: "insert multiple times" ) << 0 << (QList<ListChange>() |
1674 | << ListChange::insert(index: 0, count: 2) |
1675 | << ListChange::insert(index: 0, count: 4) |
1676 | << ListChange::insert(index: 0, count: 6) |
1677 | ) << 12 << 10; |
1678 | |
1679 | QTest::newRow(dataTag: "insert multiple times with current index changes" ) << 0 << (QList<ListChange>() |
1680 | << ListChange::insert(index: 0, count: 2) |
1681 | << ListChange::insert(index: 0, count: 4) |
1682 | << ListChange::insert(index: 0, count: 6) |
1683 | << ListChange::setCurrent(3) |
1684 | << ListChange::insert(index: 3, count: 2) |
1685 | ) << 14 << 5; |
1686 | |
1687 | QTest::newRow(dataTag: "insert and remove all" ) << 0 << (QList<ListChange>() |
1688 | << ListChange::insert(index: 0, count: 30) |
1689 | << ListChange::remove(index: 0, count: 30) |
1690 | ) << 0 << -1; |
1691 | |
1692 | QTest::newRow(dataTag: "insert and remove current" ) << 30 << (QList<ListChange>() |
1693 | << ListChange::insert(index: 1) |
1694 | << ListChange::setCurrent(1) |
1695 | << ListChange::remove(index: 1) |
1696 | ) << 30 << 1; |
1697 | |
1698 | QTest::newRow(dataTag: "insert before 0, then remove cross section of new and old items" ) << 10 << (QList<ListChange>() |
1699 | << ListChange::insert(index: 0, count: 10) |
1700 | << ListChange::remove(index: 5, count: 10) |
1701 | ) << 10 << 5; |
1702 | |
1703 | QTest::newRow(dataTag: "insert multiple, then move new items to end" ) << 10 << (QList<ListChange>() |
1704 | << ListChange::insert(index: 0, count: 3) |
1705 | << ListChange::move(index: 0, to: 10, count: 3) |
1706 | ) << 13 << 0; |
1707 | |
1708 | QTest::newRow(dataTag: "insert multiple, then move new and some old items to end" ) << 10 << (QList<ListChange>() |
1709 | << ListChange::insert(index: 0, count: 3) |
1710 | << ListChange::move(index: 0, to: 8, count: 5) |
1711 | ) << 13 << 11; |
1712 | |
1713 | QTest::newRow(dataTag: "insert multiple at end, then move new and some old items to start" ) << 10 << (QList<ListChange>() |
1714 | << ListChange::setCurrent(9) |
1715 | << ListChange::insert(index: 10, count: 3) |
1716 | << ListChange::move(index: 8, to: 0, count: 5) |
1717 | ) << 13 << 1; |
1718 | |
1719 | |
1720 | QTest::newRow(dataTag: "move back and forth to same index" ) << 10 << (QList<ListChange>() |
1721 | << ListChange::setCurrent(1) |
1722 | << ListChange::move(index: 1, to: 2, count: 2) |
1723 | << ListChange::move(index: 2, to: 1, count: 2) |
1724 | ) << 10 << 1; |
1725 | |
1726 | QTest::newRow(dataTag: "move forwards then back" ) << 10 << (QList<ListChange>() |
1727 | << ListChange::setCurrent(2) |
1728 | << ListChange::move(index: 1, to: 2, count: 3) |
1729 | << ListChange::move(index: 3, to: 0, count: 5) |
1730 | ) << 10 << 0; |
1731 | |
1732 | QTest::newRow(dataTag: "move current, then remove it" ) << 10 << (QList<ListChange>() |
1733 | << ListChange::setCurrent(5) |
1734 | << ListChange::move(index: 5, to: 0, count: 1) |
1735 | << ListChange::remove(index: 0) |
1736 | ) << 9 << 0; |
1737 | |
1738 | QTest::newRow(dataTag: "move current, then insert before it" ) << 10 << (QList<ListChange>() |
1739 | << ListChange::setCurrent(5) |
1740 | << ListChange::move(index: 5, to: 0, count: 1) |
1741 | << ListChange::insert(index: 0) |
1742 | ) << 11 << 1; |
1743 | |
1744 | QTest::newRow(dataTag: "move multiple, then remove them" ) << 10 << (QList<ListChange>() |
1745 | << ListChange::setCurrent(1) |
1746 | << ListChange::move(index: 5, to: 1, count: 3) |
1747 | << ListChange::remove(index: 1, count: 3) |
1748 | ) << 7 << 1; |
1749 | |
1750 | QTest::newRow(dataTag: "move multiple, then insert before them" ) << 10 << (QList<ListChange>() |
1751 | << ListChange::setCurrent(5) |
1752 | << ListChange::move(index: 5, to: 1, count: 3) |
1753 | << ListChange::insert(index: 1, count: 5) |
1754 | ) << 15 << 6; |
1755 | |
1756 | QTest::newRow(dataTag: "move multiple, then insert after them" ) << 10 << (QList<ListChange>() |
1757 | << ListChange::setCurrent(3) |
1758 | << ListChange::move(index: 0, to: 1, count: 2) |
1759 | << ListChange::insert(index: 3, count: 5) |
1760 | ) << 15 << 8; |
1761 | |
1762 | |
1763 | QTest::newRow(dataTag: "clear current" ) << 0 << (QList<ListChange>() |
1764 | << ListChange::insert(index: 0, count: 5) |
1765 | << ListChange::setCurrent(-1) |
1766 | << ListChange::remove(index: 0, count: 5) |
1767 | << ListChange::insert(index: 0, count: 5) |
1768 | ) << 5 << -1; |
1769 | |
1770 | QTest::newRow(dataTag: "remove, scroll" ) << 30 << (QList<ListChange>() |
1771 | << ListChange::remove(index: 20, count: 5) |
1772 | << ListChange::setContentY(20) |
1773 | ) << 25 << 0; |
1774 | |
1775 | QTest::newRow(dataTag: "insert, scroll" ) << 10 << (QList<ListChange>() |
1776 | << ListChange::insert(index: 9, count: 5) |
1777 | << ListChange::setContentY(20) |
1778 | ) << 15 << 0; |
1779 | |
1780 | QTest::newRow(dataTag: "move, scroll" ) << 20 << (QList<ListChange>() |
1781 | << ListChange::move(index: 15, to: 8, count: 3) |
1782 | << ListChange::setContentY(0) |
1783 | ) << 20 << 0; |
1784 | |
1785 | QTest::newRow(dataTag: "clear, insert, scroll" ) << 30 << (QList<ListChange>() |
1786 | << ListChange::setContentY(20) |
1787 | << ListChange::remove(index: 0, count: 30) |
1788 | << ListChange::insert(index: 0, count: 2) |
1789 | << ListChange::setContentY(0) |
1790 | ) << 2 << 0; |
1791 | } |
1792 | |
1793 | |
1794 | void tst_QQuickGridView::swapWithFirstItem() |
1795 | { |
1796 | // QTBUG_9697 |
1797 | QQuickView *window = createView(); |
1798 | |
1799 | QaimModel model; |
1800 | for (int i = 0; i < 30; i++) |
1801 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
1802 | |
1803 | window->rootContext()->setContextProperty("testModel" , &model); |
1804 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
1805 | window->show(); |
1806 | qApp->processEvents(); |
1807 | |
1808 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
1809 | QTRY_VERIFY(gridview != nullptr); |
1810 | |
1811 | // ensure content position is stable |
1812 | gridview->setContentY(0); |
1813 | model.moveItem(from: 10, to: 0); |
1814 | QTRY_COMPARE(gridview->contentY(), qreal(0)); |
1815 | |
1816 | delete window; |
1817 | } |
1818 | |
1819 | void tst_QQuickGridView::currentIndex() |
1820 | { |
1821 | QaimModel initModel; |
1822 | for (int i = 0; i < 60; i++) |
1823 | initModel.addItem(name: "Item" + QString::number(i), number: QString::number(i)); |
1824 | |
1825 | QQuickView *window = new QQuickView(nullptr); |
1826 | window->setGeometry(posx: 0,posy: 0,w: 240,h: 320); |
1827 | window->show(); |
1828 | |
1829 | QQmlContext *ctxt = window->rootContext(); |
1830 | ctxt->setContextProperty("testModel" , &initModel); |
1831 | |
1832 | QString filename(testFile(fileName: "gridview-initCurrent.qml" )); |
1833 | window->setSource(QUrl::fromLocalFile(localfile: filename)); |
1834 | |
1835 | qApp->processEvents(); |
1836 | |
1837 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
1838 | QVERIFY(gridview != nullptr); |
1839 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1840 | |
1841 | QQuickItem *contentItem = gridview->contentItem(); |
1842 | QVERIFY(contentItem != nullptr); |
1843 | |
1844 | // currentIndex is initialized to 35 |
1845 | // currentItem should be in view |
1846 | QCOMPARE(gridview->currentIndex(), 35); |
1847 | QCOMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper" , 35)); |
1848 | // Wait for possible animation to finish |
1849 | QTRY_COMPARE(gridview->currentItem()->y(), gridview->highlightItem()->y()); |
1850 | QCOMPARE(gridview->contentY(), 400.0); |
1851 | |
1852 | // changing model should reset currentIndex to 0 |
1853 | QaimModel model; |
1854 | for (int i = 0; i < 60; i++) |
1855 | model.addItem(name: "Item" + QString::number(i), number: QString::number(i)); |
1856 | ctxt->setContextProperty("testModel" , &model); |
1857 | |
1858 | QCOMPARE(gridview->currentIndex(), 0); |
1859 | QCOMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper" , 0)); |
1860 | |
1861 | // confirm that the velocity is updated |
1862 | gridview->setCurrentIndex(35); |
1863 | QTRY_VERIFY(gridview->verticalVelocity() != 0.0); |
1864 | gridview->setCurrentIndex(0); |
1865 | QTRY_COMPARE(gridview->verticalVelocity(), 0.0); |
1866 | |
1867 | // footer should become visible if it is out of view, and then current index moves to the first row |
1868 | window->rootObject()->setProperty(name: "showFooter" , value: true); |
1869 | QTRY_VERIFY(gridview->footerItem()); |
1870 | gridview->setCurrentIndex(model.count()-3); |
1871 | QTRY_VERIFY(gridview->footerItem()->y() > gridview->contentY() + gridview->height()); |
1872 | gridview->setCurrentIndex(model.count()-2); |
1873 | QTRY_COMPARE(gridview->contentY() + gridview->height(), (60.0 * model.count()/3) + gridview->footerItem()->height()); |
1874 | window->rootObject()->setProperty(name: "showFooter" , value: false); |
1875 | |
1876 | // header should become visible if it is out of view, and then current index moves to the last row |
1877 | window->rootObject()->setProperty(name: "showHeader" , value: true); |
1878 | QTRY_VERIFY(gridview->headerItem()); |
1879 | gridview->setCurrentIndex(3); |
1880 | QTRY_VERIFY(gridview->headerItem()->y() + gridview->headerItem()->height() < gridview->contentY()); |
1881 | gridview->setCurrentIndex(1); |
1882 | QTRY_COMPARE(gridview->contentY(), -gridview->headerItem()->height()); |
1883 | window->rootObject()->setProperty(name: "showHeader" , value: false); |
1884 | |
1885 | // turn off auto highlight |
1886 | gridview->setHighlightFollowsCurrentItem(false); |
1887 | QVERIFY(!gridview->highlightFollowsCurrentItem()); |
1888 | QVERIFY(gridview->highlightItem()); |
1889 | qreal hlPosX = gridview->highlightItem()->x(); |
1890 | qreal hlPosY = gridview->highlightItem()->y(); |
1891 | |
1892 | gridview->setCurrentIndex(5); |
1893 | QTRY_COMPARE(gridview->highlightItem()->x(), hlPosX); |
1894 | QTRY_COMPARE(gridview->highlightItem()->y(), hlPosY); |
1895 | |
1896 | // insert item before currentIndex |
1897 | window->rootObject()->setProperty(name: "currentItemChangedCount" , value: QVariant(0)); |
1898 | gridview->setCurrentIndex(28); |
1899 | QTRY_COMPARE(window->rootObject()->property("currentItemChangedCount" ).toInt(), 1); |
1900 | model.insertItem(index: 0, name: "Foo" , number: "1111" ); |
1901 | QTRY_COMPARE(window->rootObject()->property("current" ).toInt(), 29); |
1902 | QCOMPARE(window->rootObject()->property("currentItemChangedCount" ).toInt(), 1); |
1903 | |
1904 | // check removing highlight by setting currentIndex to -1; |
1905 | gridview->setCurrentIndex(-1); |
1906 | |
1907 | QCOMPARE(gridview->currentIndex(), -1); |
1908 | QVERIFY(!gridview->highlightItem()); |
1909 | QVERIFY(!gridview->currentItem()); |
1910 | |
1911 | // moving currentItem out of view should make it invisible |
1912 | gridview->setCurrentIndex(0); |
1913 | QTRY_VERIFY(delegateVisible(gridview->currentItem())); |
1914 | gridview->setContentY(200); |
1915 | QTRY_VERIFY(!delegateVisible(gridview->currentItem())); |
1916 | |
1917 | delete window; |
1918 | } |
1919 | |
1920 | void tst_QQuickGridView::noCurrentIndex() |
1921 | { |
1922 | QaimModel model; |
1923 | for (int i = 0; i < 60; i++) |
1924 | model.addItem(name: "Item" + QString::number(i), number: QString::number(i)); |
1925 | |
1926 | QQuickView *window = new QQuickView(nullptr); |
1927 | window->setGeometry(posx: 0,posy: 0,w: 240,h: 320); |
1928 | |
1929 | QQmlContext *ctxt = window->rootContext(); |
1930 | ctxt->setContextProperty("testModel" , &model); |
1931 | |
1932 | QString filename(testFile(fileName: "gridview-noCurrent.qml" )); |
1933 | window->setSource(QUrl::fromLocalFile(localfile: filename)); |
1934 | window->show(); |
1935 | qApp->processEvents(); |
1936 | |
1937 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
1938 | QVERIFY(gridview != nullptr); |
1939 | QQuickItem *contentItem = gridview->contentItem(); |
1940 | QVERIFY(contentItem != nullptr); |
1941 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1942 | |
1943 | // current index should be -1 |
1944 | QCOMPARE(gridview->currentIndex(), -1); |
1945 | QVERIFY(!gridview->currentItem()); |
1946 | QVERIFY(!gridview->highlightItem()); |
1947 | QCOMPARE(gridview->contentY(), 0.0); |
1948 | |
1949 | gridview->setCurrentIndex(5); |
1950 | QCOMPARE(gridview->currentIndex(), 5); |
1951 | QVERIFY(gridview->currentItem()); |
1952 | QVERIFY(gridview->highlightItem()); |
1953 | |
1954 | delete window; |
1955 | } |
1956 | |
1957 | void tst_QQuickGridView::keyNavigation() |
1958 | { |
1959 | QFETCH(QQuickGridView::Flow, flow); |
1960 | QFETCH(Qt::LayoutDirection, layoutDirection); |
1961 | QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); |
1962 | QFETCH(Qt::Key, forwardsKey); |
1963 | QFETCH(Qt::Key, backwardsKey); |
1964 | QFETCH(QPointF, contentPosAtFirstItem); |
1965 | QFETCH(QPointF, contentPosAtLastItem); |
1966 | QFETCH(int, indexRightOf7); |
1967 | QFETCH(int, indexLeftOf7); |
1968 | QFETCH(int, indexUpFrom7); |
1969 | QFETCH(int, indexDownFrom7); |
1970 | |
1971 | QaimModel model; |
1972 | for (int i = 0; i < 18; i++) |
1973 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
1974 | |
1975 | QQuickView *window = getView(); |
1976 | window->rootContext()->setContextProperty("testModel" , &model); |
1977 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
1978 | window->show(); |
1979 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1980 | |
1981 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
1982 | QTRY_VERIFY(gridview != nullptr); |
1983 | gridview->setFlow(flow); |
1984 | gridview->setLayoutDirection(layoutDirection); |
1985 | gridview->setVerticalLayoutDirection(verticalLayoutDirection); |
1986 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
1987 | |
1988 | window->requestActivate(); |
1989 | QVERIFY(QTest::qWaitForWindowActive(window)); |
1990 | QTRY_COMPARE(qGuiApp->focusWindow(), window); |
1991 | QCOMPARE(gridview->currentIndex(), 0); |
1992 | |
1993 | QTest::keyClick(window, key: forwardsKey); |
1994 | QCOMPARE(gridview->currentIndex(), 1); |
1995 | |
1996 | QTest::keyClick(window, key: backwardsKey); |
1997 | QCOMPARE(gridview->currentIndex(), 0); |
1998 | |
1999 | gridview->setCurrentIndex(7); |
2000 | gridview->moveCurrentIndexRight(); |
2001 | QCOMPARE(gridview->currentIndex(), indexRightOf7); |
2002 | gridview->moveCurrentIndexLeft(); |
2003 | QCOMPARE(gridview->currentIndex(), 7); |
2004 | gridview->moveCurrentIndexLeft(); |
2005 | QCOMPARE(gridview->currentIndex(), indexLeftOf7); |
2006 | gridview->moveCurrentIndexRight(); |
2007 | QCOMPARE(gridview->currentIndex(), 7); |
2008 | gridview->moveCurrentIndexUp(); |
2009 | QCOMPARE(gridview->currentIndex(), indexUpFrom7); |
2010 | gridview->moveCurrentIndexDown(); |
2011 | QCOMPARE(gridview->currentIndex(), 7); |
2012 | gridview->moveCurrentIndexDown(); |
2013 | QCOMPARE(gridview->currentIndex(), indexDownFrom7); |
2014 | |
2015 | gridview->setCurrentIndex(7); |
2016 | QTest::keyClick(window, key: Qt::Key_Right); |
2017 | QCOMPARE(gridview->currentIndex(), indexRightOf7); |
2018 | QTest::keyClick(window, key: Qt::Key_Left); |
2019 | QCOMPARE(gridview->currentIndex(), 7); |
2020 | QTest::keyClick(window, key: Qt::Key_Left); |
2021 | QCOMPARE(gridview->currentIndex(), indexLeftOf7); |
2022 | QTest::keyClick(window, key: Qt::Key_Right); |
2023 | QCOMPARE(gridview->currentIndex(), 7); |
2024 | QTest::keyClick(window, key: Qt::Key_Up); |
2025 | QCOMPARE(gridview->currentIndex(), indexUpFrom7); |
2026 | QTest::keyClick(window, key: Qt::Key_Down); |
2027 | QCOMPARE(gridview->currentIndex(), 7); |
2028 | QTest::keyClick(window, key: Qt::Key_Down); |
2029 | QCOMPARE(gridview->currentIndex(), indexDownFrom7); |
2030 | |
2031 | // hold down a key to go forwards |
2032 | gridview->setCurrentIndex(0); |
2033 | for (int i=0; i<model.count()-1; i++) { |
2034 | // QTest::qWait(500); |
2035 | QTest::simulateEvent(window, press: true, code: forwardsKey, modifier: Qt::NoModifier, text: "" , repeat: true); |
2036 | QTRY_COMPARE(gridview->currentIndex(), i+1); |
2037 | } |
2038 | QTest::keyRelease(window, key: forwardsKey); |
2039 | QTRY_COMPARE(gridview->currentIndex(), model.count()-1); |
2040 | QTRY_COMPARE(gridview->contentX(), contentPosAtLastItem.x()); |
2041 | QTRY_COMPARE(gridview->contentY(), contentPosAtLastItem.y()); |
2042 | |
2043 | // hold down a key to go backwards |
2044 | for (int i=model.count()-1; i > 0; i--) { |
2045 | QTest::simulateEvent(window, press: true, code: backwardsKey, modifier: Qt::NoModifier, text: "" , repeat: true); |
2046 | QTRY_COMPARE(gridview->currentIndex(), i-1); |
2047 | } |
2048 | QTest::keyRelease(window, key: backwardsKey); |
2049 | QTRY_COMPARE(gridview->currentIndex(), 0); |
2050 | QTRY_COMPARE(gridview->contentX(), contentPosAtFirstItem.x()); |
2051 | QTRY_COMPARE(gridview->contentY(), contentPosAtFirstItem.y()); |
2052 | |
2053 | // no wrap |
2054 | QVERIFY(!gridview->isWrapEnabled()); |
2055 | QTest::keyClick(window, key: forwardsKey); |
2056 | QCOMPARE(gridview->currentIndex(), 1); |
2057 | QTest::keyClick(window, key: backwardsKey); |
2058 | QCOMPARE(gridview->currentIndex(), 0); |
2059 | |
2060 | QTest::keyClick(window, key: backwardsKey); |
2061 | QCOMPARE(gridview->currentIndex(), 0); |
2062 | |
2063 | // with wrap |
2064 | gridview->setWrapEnabled(true); |
2065 | QVERIFY(gridview->isWrapEnabled()); |
2066 | |
2067 | QTest::keyClick(window, key: backwardsKey); |
2068 | QCOMPARE(gridview->currentIndex(), model.count()-1); |
2069 | QTRY_COMPARE(gridview->contentX(), contentPosAtLastItem.x()); |
2070 | QTRY_COMPARE(gridview->contentY(), contentPosAtLastItem.y()); |
2071 | |
2072 | QTest::keyClick(window, key: forwardsKey); |
2073 | QCOMPARE(gridview->currentIndex(), 0); |
2074 | QTRY_COMPARE(gridview->contentX(), contentPosAtFirstItem.x()); |
2075 | QTRY_COMPARE(gridview->contentY(), contentPosAtFirstItem.y()); |
2076 | |
2077 | // Test key press still accepted when position wraps to same index. |
2078 | window->rootObject()->setProperty(name: "lastKey" , value: 0); |
2079 | model.removeItems(index: 1, count: model.count() - 1); |
2080 | |
2081 | QTest::keyClick(window, key: backwardsKey); |
2082 | QCOMPARE(window->rootObject()->property("lastKey" ).toInt(), 0); |
2083 | |
2084 | QTest::keyClick(window, key: forwardsKey); |
2085 | QCOMPARE(window->rootObject()->property("lastKey" ).toInt(), 0); |
2086 | |
2087 | // Test key press not accepted at limits when wrap is disabled. |
2088 | gridview->setWrapEnabled(false); |
2089 | |
2090 | QTest::keyClick(window, key: backwardsKey); |
2091 | QCOMPARE(window->rootObject()->property("lastKey" ).toInt(), int(backwardsKey)); |
2092 | |
2093 | QTest::keyClick(window, key: forwardsKey); |
2094 | QCOMPARE(window->rootObject()->property("lastKey" ).toInt(), int(forwardsKey)); |
2095 | |
2096 | releaseView(view: window); |
2097 | } |
2098 | |
2099 | void tst_QQuickGridView::keyNavigation_data() |
2100 | { |
2101 | QTest::addColumn<QQuickGridView::Flow>(name: "flow" ); |
2102 | QTest::addColumn<Qt::LayoutDirection>(name: "layoutDirection" ); |
2103 | QTest::addColumn<QQuickItemView::VerticalLayoutDirection>(name: "verticalLayoutDirection" ); |
2104 | QTest::addColumn<Qt::Key>(name: "forwardsKey" ); |
2105 | QTest::addColumn<Qt::Key>(name: "backwardsKey" ); |
2106 | QTest::addColumn<QPointF>(name: "contentPosAtFirstItem" ); |
2107 | QTest::addColumn<QPointF>(name: "contentPosAtLastItem" ); |
2108 | QTest::addColumn<int>(name: "indexRightOf7" ); |
2109 | QTest::addColumn<int>(name: "indexLeftOf7" ); |
2110 | QTest::addColumn<int>(name: "indexUpFrom7" ); |
2111 | QTest::addColumn<int>(name: "indexDownFrom7" ); |
2112 | |
2113 | QTest::newRow(dataTag: "LeftToRight, LtR, TtB" ) |
2114 | << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom |
2115 | << Qt::Key_Right << Qt::Key_Left |
2116 | << QPointF(0, 0) |
2117 | << QPointF(0, 40) |
2118 | << 8 << 6 << 4 << 10; |
2119 | |
2120 | QTest::newRow(dataTag: "LeftToRight, RtL, TtB" ) |
2121 | << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom |
2122 | << Qt::Key_Left << Qt::Key_Right |
2123 | << QPointF(0, 0) |
2124 | << QPointF(0, 40) |
2125 | << 6 << 8 << 4 << 10; |
2126 | |
2127 | QTest::newRow(dataTag: "LeftToRight, LtR, BtT" ) |
2128 | << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop |
2129 | << Qt::Key_Right << Qt::Key_Left |
2130 | << QPointF(0, -320) |
2131 | << QPointF(0, -360) |
2132 | << 8 << 6 << 10 << 4; |
2133 | |
2134 | QTest::newRow(dataTag: "LeftToRight, RtL, BtT" ) |
2135 | << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop |
2136 | << Qt::Key_Left << Qt::Key_Right |
2137 | << QPointF(0, -320) |
2138 | << QPointF(0, -360) |
2139 | << 6 << 8 << 10 << 4; |
2140 | |
2141 | QTest::newRow(dataTag: "TopToBottom, LtR, TtB" ) |
2142 | << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom |
2143 | << Qt::Key_Down << Qt::Key_Up |
2144 | << QPointF(0, 0) |
2145 | << QPointF(80, 0) |
2146 | << 12 << 2 << 6 << 8; |
2147 | |
2148 | QTest::newRow(dataTag: "TopToBottom, RtL, TtB" ) |
2149 | << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom |
2150 | << Qt::Key_Down << Qt::Key_Up |
2151 | << QPointF(-240, 0) |
2152 | << QPointF(-320, 0) |
2153 | << 2 << 12 << 6 << 8; |
2154 | |
2155 | QTest::newRow(dataTag: "TopToBottom, LtR, BtT" ) |
2156 | << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop |
2157 | << Qt::Key_Up << Qt::Key_Down |
2158 | << QPointF(0, -320) |
2159 | << QPointF(80, -320) |
2160 | << 12 << 2 << 8 << 6; |
2161 | |
2162 | QTest::newRow(dataTag: "TopToBottom, RtL, BtT" ) |
2163 | << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop |
2164 | << Qt::Key_Up << Qt::Key_Down |
2165 | << QPointF(-240, -320) |
2166 | << QPointF(-320, -320) |
2167 | << 2 << 12 << 8 << 6; |
2168 | } |
2169 | |
2170 | void tst_QQuickGridView::changeFlow() |
2171 | { |
2172 | QQuickView *window = createView(); |
2173 | |
2174 | QaimModel model; |
2175 | for (int i = 0; i < 30; i++) |
2176 | model.addItem(name: "Item" + QString::number(i), number: QString::number(i)); |
2177 | |
2178 | QQmlContext *ctxt = window->rootContext(); |
2179 | ctxt->setContextProperty("testModel" , &model); |
2180 | ctxt->setContextProperty("testRightToLeft" , QVariant(false)); |
2181 | ctxt->setContextProperty("testTopToBottom" , QVariant(false)); |
2182 | ctxt->setContextProperty("testBottomToTop" , QVariant(false)); |
2183 | |
2184 | window->setSource(testFileUrl(fileName: "layouts.qml" )); |
2185 | qApp->processEvents(); |
2186 | |
2187 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
2188 | QTRY_VERIFY(gridview != nullptr); |
2189 | |
2190 | QQuickItem *contentItem = gridview->contentItem(); |
2191 | QTRY_VERIFY(contentItem != nullptr); |
2192 | |
2193 | // Confirm items positioned correctly and indexes correct |
2194 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
2195 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
2196 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
2197 | if (!item) qWarning() << "Item" << i << "not found" ; |
2198 | QTRY_VERIFY(item); |
2199 | QTRY_COMPARE(item->x(), qreal((i%3)*80)); |
2200 | QTRY_COMPARE(item->y(), qreal((i/3)*60)); |
2201 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
2202 | QTRY_VERIFY(name != nullptr); |
2203 | QTRY_COMPARE(name->text(), model.name(i)); |
2204 | QQuickText *number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: i); |
2205 | QTRY_VERIFY(number != nullptr); |
2206 | QTRY_COMPARE(number->text(), model.number(i)); |
2207 | } |
2208 | |
2209 | ctxt->setContextProperty("testTopToBottom" , QVariant(true)); |
2210 | |
2211 | // Confirm items positioned correctly and indexes correct |
2212 | itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
2213 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
2214 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
2215 | if (!item) qWarning() << "Item" << i << "not found" ; |
2216 | QTRY_VERIFY(item); |
2217 | QTRY_COMPARE(item->x(), qreal((i/5)*80)); |
2218 | QTRY_COMPARE(item->y(), qreal((i%5)*60)); |
2219 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
2220 | QTRY_VERIFY(name != nullptr); |
2221 | QTRY_COMPARE(name->text(), model.name(i)); |
2222 | QQuickText *number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: i); |
2223 | QTRY_VERIFY(number != nullptr); |
2224 | QTRY_COMPARE(number->text(), model.number(i)); |
2225 | } |
2226 | |
2227 | ctxt->setContextProperty("testRightToLeft" , QVariant(true)); |
2228 | |
2229 | // Confirm items positioned correctly and indexes correct |
2230 | itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
2231 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
2232 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
2233 | if (!item) qWarning() << "Item" << i << "not found" ; |
2234 | QTRY_VERIFY(item); |
2235 | QTRY_COMPARE(item->x(), qreal(-(i/5)*80 - item->width())); |
2236 | QTRY_COMPARE(item->y(), qreal((i%5)*60)); |
2237 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
2238 | QTRY_VERIFY(name != nullptr); |
2239 | QTRY_COMPARE(name->text(), model.name(i)); |
2240 | QQuickText *number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: i); |
2241 | QTRY_VERIFY(number != nullptr); |
2242 | QTRY_COMPARE(number->text(), model.number(i)); |
2243 | } |
2244 | gridview->setContentX(100); |
2245 | QTRY_COMPARE(gridview->contentX(), 100.); |
2246 | ctxt->setContextProperty("testTopToBottom" , QVariant(false)); |
2247 | QTRY_COMPARE(gridview->contentX(), 0.); |
2248 | |
2249 | // Confirm items positioned correctly and indexes correct |
2250 | itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
2251 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
2252 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
2253 | if (!item) qWarning() << "Item" << i << "not found" ; |
2254 | QTRY_VERIFY(item); |
2255 | QTRY_COMPARE(item->x(), qreal(240 - (i%3+1)*80)); |
2256 | QTRY_COMPARE(item->y(), qreal((i/3)*60)); |
2257 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
2258 | QTRY_VERIFY(name != nullptr); |
2259 | QTRY_COMPARE(name->text(), model.name(i)); |
2260 | QQuickText *number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: i); |
2261 | QTRY_VERIFY(number != nullptr); |
2262 | QTRY_COMPARE(number->text(), model.number(i)); |
2263 | } |
2264 | |
2265 | delete window; |
2266 | } |
2267 | |
2268 | void tst_QQuickGridView::defaultValues() |
2269 | { |
2270 | QQmlEngine engine; |
2271 | QQmlComponent c(&engine, testFileUrl(fileName: "gridview3.qml" )); |
2272 | QQuickGridView *obj = qobject_cast<QQuickGridView*>(object: c.create()); |
2273 | |
2274 | QTRY_VERIFY(obj != nullptr); |
2275 | QTRY_COMPARE(obj->model(), QVariant()); |
2276 | QTRY_VERIFY(!obj->delegate()); |
2277 | QTRY_COMPARE(obj->currentIndex(), -1); |
2278 | QTRY_VERIFY(!obj->currentItem()); |
2279 | QTRY_COMPARE(obj->count(), 0); |
2280 | QTRY_VERIFY(!obj->highlight()); |
2281 | QTRY_VERIFY(!obj->highlightItem()); |
2282 | QTRY_COMPARE(obj->highlightFollowsCurrentItem(), true); |
2283 | QTRY_COMPARE(obj->flow(), QQuickGridView::FlowLeftToRight); |
2284 | QTRY_COMPARE(obj->isWrapEnabled(), false); |
2285 | #ifdef QML_VIEW_DEFAULTCACHEBUFFER |
2286 | QTRY_COMPARE(obj->cacheBuffer(), QML_VIEW_DEFAULTCACHEBUFFER); |
2287 | #else |
2288 | QTRY_COMPARE(obj->cacheBuffer(), 320); |
2289 | #endif |
2290 | QTRY_COMPARE(obj->cellWidth(), qreal(100)); //### Should 100 be the default? |
2291 | QTRY_COMPARE(obj->cellHeight(), qreal(100)); |
2292 | delete obj; |
2293 | } |
2294 | |
2295 | void tst_QQuickGridView::properties() |
2296 | { |
2297 | QQmlEngine engine; |
2298 | QQmlComponent c(&engine, testFileUrl(fileName: "gridview2.qml" )); |
2299 | QQuickGridView *obj = qobject_cast<QQuickGridView*>(object: c.create()); |
2300 | |
2301 | QTRY_VERIFY(obj != nullptr); |
2302 | QTRY_VERIFY(obj->model() != QVariant()); |
2303 | QTRY_VERIFY(obj->delegate() != nullptr); |
2304 | QTRY_COMPARE(obj->currentIndex(), 0); |
2305 | QTRY_VERIFY(obj->currentItem() != nullptr); |
2306 | QTRY_COMPARE(obj->count(), 4); |
2307 | QTRY_VERIFY(obj->highlight() != nullptr); |
2308 | QTRY_VERIFY(obj->highlightItem() != nullptr); |
2309 | QTRY_COMPARE(obj->highlightFollowsCurrentItem(), false); |
2310 | QTRY_COMPARE(obj->flow(), QQuickGridView::FlowLeftToRight); |
2311 | QTRY_COMPARE(obj->isWrapEnabled(), true); |
2312 | QTRY_COMPARE(obj->cacheBuffer(), 200); |
2313 | QTRY_COMPARE(obj->cellWidth(), qreal(100)); |
2314 | QTRY_COMPARE(obj->cellHeight(), qreal(100)); |
2315 | delete obj; |
2316 | } |
2317 | |
2318 | void tst_QQuickGridView::propertyChanges() |
2319 | { |
2320 | QQuickView *window = createView(); |
2321 | QTRY_VERIFY(window); |
2322 | window->setSource(testFileUrl(fileName: "propertychangestest.qml" )); |
2323 | |
2324 | QQuickGridView *gridView = window->rootObject()->findChild<QQuickGridView*>(aName: "gridView" ); |
2325 | QTRY_VERIFY(gridView); |
2326 | |
2327 | QSignalSpy keyNavigationWrapsSpy(gridView, SIGNAL(keyNavigationWrapsChanged())); |
2328 | QSignalSpy cacheBufferSpy(gridView, SIGNAL(cacheBufferChanged())); |
2329 | QSignalSpy layoutSpy(gridView, SIGNAL(layoutDirectionChanged())); |
2330 | QSignalSpy flowSpy(gridView, SIGNAL(flowChanged())); |
2331 | |
2332 | QTRY_COMPARE(gridView->isWrapEnabled(), true); |
2333 | QTRY_COMPARE(gridView->cacheBuffer(), 10); |
2334 | QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowLeftToRight); |
2335 | |
2336 | gridView->setWrapEnabled(false); |
2337 | gridView->setCacheBuffer(3); |
2338 | gridView->setFlow(QQuickGridView::FlowTopToBottom); |
2339 | |
2340 | QTRY_COMPARE(gridView->isWrapEnabled(), false); |
2341 | QTRY_COMPARE(gridView->cacheBuffer(), 3); |
2342 | QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowTopToBottom); |
2343 | |
2344 | QTRY_COMPARE(keyNavigationWrapsSpy.count(),1); |
2345 | QTRY_COMPARE(cacheBufferSpy.count(),1); |
2346 | QTRY_COMPARE(flowSpy.count(),1); |
2347 | |
2348 | gridView->setWrapEnabled(false); |
2349 | gridView->setCacheBuffer(3); |
2350 | gridView->setFlow(QQuickGridView::FlowTopToBottom); |
2351 | |
2352 | QTRY_COMPARE(keyNavigationWrapsSpy.count(),1); |
2353 | QTRY_COMPARE(cacheBufferSpy.count(),1); |
2354 | QTRY_COMPARE(flowSpy.count(),1); |
2355 | |
2356 | gridView->setFlow(QQuickGridView::FlowLeftToRight); |
2357 | QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowLeftToRight); |
2358 | |
2359 | gridView->setWrapEnabled(true); |
2360 | gridView->setCacheBuffer(5); |
2361 | gridView->setLayoutDirection(Qt::RightToLeft); |
2362 | |
2363 | QTRY_COMPARE(gridView->isWrapEnabled(), true); |
2364 | QTRY_COMPARE(gridView->cacheBuffer(), 5); |
2365 | QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft); |
2366 | |
2367 | QTRY_COMPARE(keyNavigationWrapsSpy.count(),2); |
2368 | QTRY_COMPARE(cacheBufferSpy.count(),2); |
2369 | QTRY_COMPARE(layoutSpy.count(),1); |
2370 | QTRY_COMPARE(flowSpy.count(),2); |
2371 | |
2372 | gridView->setWrapEnabled(true); |
2373 | gridView->setCacheBuffer(5); |
2374 | gridView->setLayoutDirection(Qt::RightToLeft); |
2375 | |
2376 | QTRY_COMPARE(keyNavigationWrapsSpy.count(),2); |
2377 | QTRY_COMPARE(cacheBufferSpy.count(),2); |
2378 | QTRY_COMPARE(layoutSpy.count(),1); |
2379 | QTRY_COMPARE(flowSpy.count(),2); |
2380 | |
2381 | gridView->setFlow(QQuickGridView::FlowTopToBottom); |
2382 | QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowTopToBottom); |
2383 | QTRY_COMPARE(flowSpy.count(),3); |
2384 | |
2385 | gridView->setFlow(QQuickGridView::FlowTopToBottom); |
2386 | QTRY_COMPARE(flowSpy.count(),3); |
2387 | |
2388 | delete window; |
2389 | } |
2390 | |
2391 | void tst_QQuickGridView::componentChanges() |
2392 | { |
2393 | QQuickView *window = createView(); |
2394 | QTRY_VERIFY(window); |
2395 | window->setSource(testFileUrl(fileName: "propertychangestest.qml" )); |
2396 | |
2397 | QQuickGridView *gridView = window->rootObject()->findChild<QQuickGridView*>(aName: "gridView" ); |
2398 | QTRY_VERIFY(gridView); |
2399 | |
2400 | QQmlComponent component(window->engine()); |
2401 | component.setData("import QtQuick 2.0; Rectangle { color: \"blue\"; }" , baseUrl: QUrl::fromLocalFile(localfile: "" )); |
2402 | |
2403 | QQmlComponent delegateComponent(window->engine()); |
2404 | delegateComponent.setData("import QtQuick 2.0; Text { text: '<b>Name:</b> ' + name }" , baseUrl: QUrl::fromLocalFile(localfile: "" )); |
2405 | |
2406 | QSignalSpy highlightSpy(gridView, SIGNAL(highlightChanged())); |
2407 | QSignalSpy delegateSpy(gridView, SIGNAL(delegateChanged())); |
2408 | QSignalSpy (gridView, SIGNAL(headerChanged())); |
2409 | QSignalSpy (gridView, SIGNAL(footerChanged())); |
2410 | QSignalSpy (gridView, SIGNAL(headerItemChanged())); |
2411 | QSignalSpy (gridView, SIGNAL(footerItemChanged())); |
2412 | |
2413 | gridView->setHighlight(&component); |
2414 | gridView->setDelegate(&delegateComponent); |
2415 | gridView->setHeader(&component); |
2416 | gridView->setFooter(&component); |
2417 | |
2418 | QTRY_COMPARE(gridView->highlight(), &component); |
2419 | QTRY_COMPARE(gridView->delegate(), &delegateComponent); |
2420 | QTRY_COMPARE(gridView->header(), &component); |
2421 | QTRY_COMPARE(gridView->footer(), &component); |
2422 | |
2423 | QVERIFY(gridView->headerItem()); |
2424 | QVERIFY(gridView->footerItem()); |
2425 | |
2426 | QTRY_COMPARE(highlightSpy.count(),1); |
2427 | QTRY_COMPARE(delegateSpy.count(),1); |
2428 | QTRY_COMPARE(headerSpy.count(),1); |
2429 | QTRY_COMPARE(footerSpy.count(),1); |
2430 | QTRY_COMPARE(headerItemSpy.count(),1); |
2431 | QTRY_COMPARE(footerItemSpy.count(),1); |
2432 | |
2433 | gridView->setHighlight(&component); |
2434 | gridView->setDelegate(&delegateComponent); |
2435 | gridView->setHeader(&component); |
2436 | gridView->setFooter(&component); |
2437 | |
2438 | QTRY_COMPARE(highlightSpy.count(),1); |
2439 | QTRY_COMPARE(delegateSpy.count(),1); |
2440 | QTRY_COMPARE(headerSpy.count(),1); |
2441 | QTRY_COMPARE(footerSpy.count(),1); |
2442 | QTRY_COMPARE(headerItemSpy.count(),1); |
2443 | QTRY_COMPARE(footerItemSpy.count(),1); |
2444 | |
2445 | delete window; |
2446 | } |
2447 | |
2448 | void tst_QQuickGridView::modelChanges() |
2449 | { |
2450 | QQuickView *window = createView(); |
2451 | QTRY_VERIFY(window); |
2452 | window->setSource(testFileUrl(fileName: "propertychangestest.qml" )); |
2453 | |
2454 | QQuickGridView *gridView = window->rootObject()->findChild<QQuickGridView*>(aName: "gridView" ); |
2455 | QTRY_VERIFY(gridView); |
2456 | |
2457 | QQmlListModel *alternateModel = window->rootObject()->findChild<QQmlListModel*>(aName: "alternateModel" ); |
2458 | QTRY_VERIFY(alternateModel); |
2459 | QVariant modelVariant = QVariant::fromValue<QObject *>(value: alternateModel); |
2460 | QSignalSpy modelSpy(gridView, SIGNAL(modelChanged())); |
2461 | |
2462 | gridView->setModel(modelVariant); |
2463 | QTRY_COMPARE(gridView->model(), modelVariant); |
2464 | QTRY_COMPARE(modelSpy.count(),1); |
2465 | |
2466 | gridView->setModel(modelVariant); |
2467 | QTRY_COMPARE(modelSpy.count(),1); |
2468 | |
2469 | gridView->setModel(QVariant()); |
2470 | QTRY_COMPARE(modelSpy.count(),2); |
2471 | delete window; |
2472 | } |
2473 | |
2474 | void tst_QQuickGridView::positionViewAtBeginningEnd() |
2475 | { |
2476 | QQuickView *window = createView(); |
2477 | |
2478 | QaimModel model; |
2479 | for (int i = 0; i < 40; i++) |
2480 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
2481 | |
2482 | QQmlContext *ctxt = window->rootContext(); |
2483 | ctxt->setContextProperty("testModel" , &model); |
2484 | ctxt->setContextProperty("testRightToLeft" , QVariant(false)); |
2485 | ctxt->setContextProperty("testTopToBottom" , QVariant(false)); |
2486 | ctxt->setContextProperty("testBottomToTop" , QVariant(false)); |
2487 | |
2488 | window->setSource(testFileUrl(fileName: "layouts.qml" )); |
2489 | window->show(); |
2490 | qApp->processEvents(); |
2491 | |
2492 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
2493 | QTRY_VERIFY(gridview != nullptr); |
2494 | QQuickItem *contentItem = gridview->contentItem(); |
2495 | QTRY_VERIFY(contentItem != nullptr); |
2496 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
2497 | |
2498 | // positionViewAtBeginning |
2499 | gridview->setContentY(150); |
2500 | gridview->positionViewAtBeginning(); |
2501 | QTRY_COMPARE(gridview->contentY(), 0.); |
2502 | |
2503 | gridview->setContentY(80); |
2504 | window->rootObject()->setProperty(name: "showHeader" , value: true); |
2505 | gridview->positionViewAtBeginning(); |
2506 | QTRY_COMPARE(gridview->contentY(), -30.); |
2507 | |
2508 | // positionViewAtEnd |
2509 | gridview->setContentY(150); |
2510 | gridview->positionViewAtEnd(); |
2511 | QTRY_COMPARE(gridview->contentY(), 520.); // 14*60 - 320 (14 rows) |
2512 | |
2513 | gridview->setContentY(80); |
2514 | window->rootObject()->setProperty(name: "showFooter" , value: true); |
2515 | gridview->positionViewAtEnd(); |
2516 | QTRY_COMPARE(gridview->contentY(), 550.); |
2517 | |
2518 | // Test for Top To Bottom layout |
2519 | ctxt->setContextProperty("testTopToBottom" , QVariant(true)); |
2520 | window->rootObject()->setProperty(name: "showHeader" , value: false); |
2521 | window->rootObject()->setProperty(name: "showFooter" , value: false); |
2522 | |
2523 | // positionViewAtBeginning |
2524 | gridview->setContentX(150); |
2525 | gridview->positionViewAtBeginning(); |
2526 | QTRY_COMPARE(gridview->contentX(), 0.); |
2527 | |
2528 | gridview->setContentX(80); |
2529 | window->rootObject()->setProperty(name: "showHeader" , value: true); |
2530 | gridview->positionViewAtBeginning(); |
2531 | QTRY_COMPARE(gridview->contentX(), -30.); |
2532 | |
2533 | // positionViewAtEnd |
2534 | gridview->positionViewAtEnd(); |
2535 | QTRY_COMPARE(gridview->contentX(), 400.); // 8*80 - 240 (8 columns) |
2536 | |
2537 | gridview->setContentX(80); |
2538 | window->rootObject()->setProperty(name: "showFooter" , value: true); |
2539 | gridview->positionViewAtEnd(); |
2540 | QTRY_COMPARE(gridview->contentX(), 430.); |
2541 | |
2542 | // set current item to outside visible view, position at beginning |
2543 | // and ensure highlight moves to current item |
2544 | gridview->setCurrentIndex(6); |
2545 | gridview->positionViewAtBeginning(); |
2546 | QTRY_COMPARE(gridview->contentX(), -30.); |
2547 | QVERIFY(gridview->highlightItem()); |
2548 | QCOMPARE(gridview->highlightItem()->x(), 80.); |
2549 | |
2550 | delete window; |
2551 | } |
2552 | |
2553 | void tst_QQuickGridView::positionViewAtIndex() |
2554 | { |
2555 | QFETCH(bool, enforceRange); |
2556 | QFETCH(bool, topToBottom); |
2557 | QFETCH(bool, rightToLeft); |
2558 | QFETCH(qreal, initContentPos); |
2559 | QFETCH(int, index); |
2560 | QFETCH(QQuickGridView::PositionMode, mode); |
2561 | QFETCH(qreal, contentPos); |
2562 | |
2563 | QQuickView *window = getView(); |
2564 | |
2565 | QaimModel model; |
2566 | for (int i = 0; i < 40; i++) |
2567 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
2568 | |
2569 | QQmlContext *ctxt = window->rootContext(); |
2570 | ctxt->setContextProperty("testModel" , &model); |
2571 | ctxt->setContextProperty("testRightToLeft" , QVariant(rightToLeft)); |
2572 | ctxt->setContextProperty("testTopToBottom" , QVariant(topToBottom)); |
2573 | ctxt->setContextProperty("testBottomToTop" , QVariant(false)); |
2574 | |
2575 | window->setSource(testFileUrl(fileName: "layouts.qml" )); |
2576 | window->show(); |
2577 | qApp->processEvents(); |
2578 | |
2579 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
2580 | QTRY_VERIFY(gridview != nullptr); |
2581 | QQuickItem *contentItem = gridview->contentItem(); |
2582 | QTRY_VERIFY(contentItem != nullptr); |
2583 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
2584 | |
2585 | window->rootObject()->setProperty(name: "enforceRange" , value: enforceRange); |
2586 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
2587 | |
2588 | if (topToBottom) |
2589 | gridview->setContentX(initContentPos); |
2590 | else |
2591 | gridview->setContentY(initContentPos); |
2592 | |
2593 | gridview->positionViewAtIndex(index, mode); |
2594 | if (topToBottom) |
2595 | QTRY_COMPARE(gridview->contentX(), contentPos); |
2596 | else |
2597 | QTRY_COMPARE(gridview->contentY(), contentPos); |
2598 | |
2599 | // Confirm items positioned correctly |
2600 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
2601 | for (int i = index; i < model.count() && i < itemCount-index-1; ++i) { |
2602 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
2603 | if (!item) qWarning() << "Item" << i << "not found" ; |
2604 | QTRY_VERIFY(item); |
2605 | if (topToBottom) { |
2606 | if (rightToLeft) { |
2607 | QTRY_COMPARE(item->x(), qreal(-(i/5)*80-item->width())); |
2608 | QTRY_COMPARE(item->y(), qreal((i%5)*60)); |
2609 | } else { |
2610 | QTRY_COMPARE(item->x(), (i/5)*80.); |
2611 | QTRY_COMPARE(item->y(), (i%5)*60.); |
2612 | } |
2613 | } else { |
2614 | QTRY_COMPARE(item->x(), (i%3)*80.); |
2615 | QTRY_COMPARE(item->y(), (i/3)*60.); |
2616 | } |
2617 | } |
2618 | |
2619 | releaseView(view: window); |
2620 | } |
2621 | |
2622 | void tst_QQuickGridView::positionViewAtIndex_data() |
2623 | { |
2624 | QTest::addColumn<bool>(name: "enforceRange" ); |
2625 | QTest::addColumn<bool>(name: "topToBottom" ); |
2626 | QTest::addColumn<bool>(name: "rightToLeft" ); |
2627 | QTest::addColumn<qreal>(name: "initContentPos" ); |
2628 | QTest::addColumn<int>(name: "index" ); |
2629 | QTest::addColumn<QQuickGridView::PositionMode>(name: "mode" ); |
2630 | QTest::addColumn<qreal>(name: "contentPos" ); |
2631 | |
2632 | QTest::newRow(dataTag: "no range, 4 at Beginning" ) << false << false << false << 0. << 4 << QQuickGridView::Beginning << 60.; |
2633 | QTest::newRow(dataTag: "no range, 4 at End" ) << false << false << false << 0. << 4 << QQuickGridView::End << 0.; |
2634 | QTest::newRow(dataTag: "no range, 21 at Beginning" ) << false << false << false << 0. << 21 << QQuickGridView::Beginning << 420.; |
2635 | // Position on an item that would leave empty space if positioned at the top |
2636 | QTest::newRow(dataTag: "no range, 31 at Beginning" ) << false << false << false << 0. << 31 << QQuickGridView::Beginning << 520.; |
2637 | QTest::newRow(dataTag: "no range, 30 at End" ) << false << false << false << 0. << 30 << QQuickGridView::End << 340.; |
2638 | QTest::newRow(dataTag: "no range, 15 at Center" ) << false << false << false << 0. << 15 << QQuickGridView::Center << 170.; |
2639 | // Ensure at least partially visible |
2640 | QTest::newRow(dataTag: "no range, 15 visible => Visible" ) << false << false << false << 302. << 15 << QQuickGridView::Visible << 302.; |
2641 | QTest::newRow(dataTag: "no range, 15 after visible => Visible" ) << false << false << false << 360. << 15 << QQuickGridView::Visible << 300.; |
2642 | QTest::newRow(dataTag: "no range, 20 visible => Visible" ) << false << false << false << 60. << 20 << QQuickGridView::Visible << 60.; |
2643 | QTest::newRow(dataTag: "no range, 20 before visible => Visible" ) << false << false << false << 20. << 20 << QQuickGridView::Visible << 100.; |
2644 | // Ensure completely visible |
2645 | QTest::newRow(dataTag: "no range, 20 visible => Contain" ) << false << false << false << 120. << 20 << QQuickGridView::Contain << 120.; |
2646 | QTest::newRow(dataTag: "no range, 15 partially visible => Contain" ) << false << false << false << 302. << 15 << QQuickGridView::Contain << 300.; |
2647 | QTest::newRow(dataTag: "no range, 20 partially visible => Contain" ) << false << false << false << 60. << 20 << QQuickGridView::Contain << 100.; |
2648 | |
2649 | QTest::newRow(dataTag: "strict range, 4 at End" ) << true << false << false << 0. << 4 << QQuickGridView::End << -120.; |
2650 | QTest::newRow(dataTag: "strict range, 38 at Beginning" ) << true << false << false << 0. << 38 << QQuickGridView::Beginning << 660.; |
2651 | QTest::newRow(dataTag: "strict range, 15 at Center" ) << true << false << false << 0. << 15 << QQuickGridView::Center << 180.; |
2652 | QTest::newRow(dataTag: "strict range, 4 at SnapPosition" ) << true << false << false << 0. << 4 << QQuickGridView::SnapPosition << -60.; |
2653 | QTest::newRow(dataTag: "strict range, 10 at SnapPosition" ) << true << false << false << 0. << 10 << QQuickGridView::SnapPosition << 60.; |
2654 | QTest::newRow(dataTag: "strict range, 38 at SnapPosition" ) << true << false << false << 0. << 38 << QQuickGridView::SnapPosition << 600.; |
2655 | |
2656 | // TopToBottom |
2657 | QTest::newRow(dataTag: "no range, ttb, 30 at End" ) << false << true << false << 0. << 30 << QQuickGridView::End << 320.; |
2658 | QTest::newRow(dataTag: "no range, ttb, 15 at Center" ) << false << true << false << 0. << 15 << QQuickGridView::Center << 160.; |
2659 | QTest::newRow(dataTag: "no range, ttb, 15 visible => Visible" ) << false << true << false << 160. << 15 << QQuickGridView::Visible << 160.; |
2660 | QTest::newRow(dataTag: "no range, ttb, 25 partially visible => Visible" ) << false << true << false << 170. << 25 << QQuickGridView::Visible << 170.; |
2661 | QTest::newRow(dataTag: "no range, ttb, 30 before visible => Visible" ) << false << true << false << 170. << 30 << QQuickGridView::Visible << 320.; |
2662 | QTest::newRow(dataTag: "no range, ttb, 25 partially visible => Contain" ) << false << true << false << 170. << 25 << QQuickGridView::Contain << 240.; |
2663 | |
2664 | // RightToLeft |
2665 | QTest::newRow(dataTag: "no range, rtl, ttb, 6 at Beginning" ) << false << true << true << 0. << 6 << QQuickGridView::Beginning << -320.; |
2666 | QTest::newRow(dataTag: "no range, rtl, ttb, 21 at Beginning" ) << false << true << true << 0. << 21 << QQuickGridView::Beginning << -560.; |
2667 | // Position on an item that would leave empty space if positioned at the top |
2668 | QTest::newRow(dataTag: "no range, rtl, ttb, 31 at Beginning" ) << false << true << true << 0. << 31 << QQuickGridView::Beginning << -640.; |
2669 | QTest::newRow(dataTag: "no range, rtl, ttb, 0 at Beginning" ) << false << true << true << -400. << 0 << QQuickGridView::Beginning << -240.; |
2670 | QTest::newRow(dataTag: "no range, rtl, ttb, 30 at End" ) << false << true << true << 0. << 30 << QQuickGridView::End << -560.; |
2671 | QTest::newRow(dataTag: "no range, rtl, ttb, 15 at Center" ) << false << true << true << 0. << 15 << QQuickGridView::Center << -400.; |
2672 | QTest::newRow(dataTag: "no range, rtl, ttb, 15 visible => Visible" ) << false << true << true << -555. << 15 << QQuickGridView::Visible << -555.; |
2673 | QTest::newRow(dataTag: "no range, rtl, ttb, 15 not visible => Visible" ) << false << true << true << -239. << 15 << QQuickGridView::Visible << -320.; |
2674 | QTest::newRow(dataTag: "no range, rtl, ttb, 15 partially visible => Visible" ) << false << true << true << -300. << 15 << QQuickGridView::Visible << -300.; |
2675 | QTest::newRow(dataTag: "no range, rtl, ttb, 20 visible => Contain" ) << false << true << true << -400. << 20 << QQuickGridView::Contain << -400.; |
2676 | QTest::newRow(dataTag: "no range, rtl, ttb, 15 partially visible => Contain" ) << false << true << true << -315. << 15 << QQuickGridView::Contain << -320.; |
2677 | } |
2678 | |
2679 | void tst_QQuickGridView::snapping() |
2680 | { |
2681 | QQuickView *window = createView(); |
2682 | |
2683 | QaimModel model; |
2684 | for (int i = 0; i < 40; i++) |
2685 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
2686 | |
2687 | window->rootContext()->setContextProperty("testModel" , &model); |
2688 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
2689 | qApp->processEvents(); |
2690 | |
2691 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
2692 | QTRY_VERIFY(gridview != nullptr); |
2693 | |
2694 | gridview->setHeight(220); |
2695 | QCOMPARE(gridview->height(), 220.); |
2696 | |
2697 | gridview->positionViewAtIndex(index: 12, mode: QQuickGridView::Visible); |
2698 | QCOMPARE(gridview->contentY(), 80.); |
2699 | |
2700 | gridview->setContentY(0); |
2701 | QCOMPARE(gridview->contentY(), 0.); |
2702 | |
2703 | gridview->setSnapMode(QQuickGridView::SnapToRow); |
2704 | QCOMPARE(gridview->snapMode(), QQuickGridView::SnapToRow); |
2705 | |
2706 | gridview->positionViewAtIndex(index: 12, mode: QQuickGridView::Visible); |
2707 | QCOMPARE(gridview->contentY(), 60.); |
2708 | |
2709 | gridview->positionViewAtIndex(index: 15, mode: QQuickGridView::End); |
2710 | QCOMPARE(gridview->contentY(), 120.); |
2711 | |
2712 | delete window; |
2713 | |
2714 | } |
2715 | |
2716 | void tst_QQuickGridView::mirroring() |
2717 | { |
2718 | QQuickView *windowA = createView(); |
2719 | windowA->setSource(testFileUrl(fileName: "mirroring.qml" )); |
2720 | QQuickGridView *gridviewA = findItem<QQuickGridView>(parent: windowA->rootObject(), objectName: "view" ); |
2721 | QTRY_VERIFY(gridviewA != nullptr); |
2722 | |
2723 | QQuickView *windowB = createView(); |
2724 | windowB->setSource(testFileUrl(fileName: "mirroring.qml" )); |
2725 | QQuickGridView *gridviewB = findItem<QQuickGridView>(parent: windowB->rootObject(), objectName: "view" ); |
2726 | QTRY_VERIFY(gridviewA != nullptr); |
2727 | qApp->processEvents(); |
2728 | |
2729 | QList<QString> objectNames; |
2730 | objectNames << "item1" << "item2" ; // << "item3" |
2731 | |
2732 | gridviewA->setProperty(name: "layoutDirection" , value: Qt::LeftToRight); |
2733 | gridviewB->setProperty(name: "layoutDirection" , value: Qt::RightToLeft); |
2734 | QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection()); |
2735 | |
2736 | // LTR != RTL |
2737 | foreach (const QString objectName, objectNames) |
2738 | QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x()); |
2739 | |
2740 | gridviewA->setProperty(name: "layoutDirection" , value: Qt::LeftToRight); |
2741 | gridviewB->setProperty(name: "layoutDirection" , value: Qt::LeftToRight); |
2742 | |
2743 | // LTR == LTR |
2744 | foreach (const QString objectName, objectNames) |
2745 | QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x()); |
2746 | |
2747 | QCOMPARE(gridviewB->layoutDirection(), gridviewB->effectiveLayoutDirection()); |
2748 | QQuickItemPrivate::get(item: gridviewB)->setLayoutMirror(true); |
2749 | QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection()); |
2750 | |
2751 | // LTR != LTR+mirror |
2752 | foreach (const QString objectName, objectNames) |
2753 | QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x()); |
2754 | |
2755 | gridviewA->setProperty(name: "layoutDirection" , value: Qt::RightToLeft); |
2756 | |
2757 | // RTL == LTR+mirror |
2758 | foreach (const QString objectName, objectNames) |
2759 | QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x()); |
2760 | |
2761 | gridviewB->setProperty(name: "layoutDirection" , value: Qt::RightToLeft); |
2762 | |
2763 | // RTL != RTL+mirror |
2764 | foreach (const QString objectName, objectNames) |
2765 | QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x()); |
2766 | |
2767 | gridviewA->setProperty(name: "layoutDirection" , value: Qt::LeftToRight); |
2768 | |
2769 | // LTR == RTL+mirror |
2770 | foreach (const QString objectName, objectNames) |
2771 | QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x()); |
2772 | |
2773 | delete windowA; |
2774 | delete windowB; |
2775 | } |
2776 | |
2777 | void tst_QQuickGridView::resetModel() |
2778 | { |
2779 | QQuickView *window = createView(); |
2780 | |
2781 | QStringList strings; |
2782 | strings << "one" << "two" << "three" ; |
2783 | QStringListModel model(strings); |
2784 | |
2785 | QQmlContext *ctxt = window->rootContext(); |
2786 | ctxt->setContextProperty("testModel" , &model); |
2787 | |
2788 | window->setSource(testFileUrl(fileName: "displaygrid.qml" )); |
2789 | window->show(); |
2790 | qApp->processEvents(); |
2791 | |
2792 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
2793 | QTRY_VERIFY(gridview != nullptr); |
2794 | QQuickItem *contentItem = gridview->contentItem(); |
2795 | QTRY_VERIFY(contentItem != nullptr); |
2796 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
2797 | |
2798 | QTRY_COMPARE(gridview->count(), model.rowCount()); |
2799 | |
2800 | for (int i = 0; i < model.rowCount(); ++i) { |
2801 | QQuickText *display = findItem<QQuickText>(parent: contentItem, objectName: "displayText" , index: i); |
2802 | QTRY_VERIFY(display != nullptr); |
2803 | QTRY_COMPARE(display->text(), strings.at(i)); |
2804 | } |
2805 | |
2806 | strings.clear(); |
2807 | strings << "four" << "five" << "six" << "seven" ; |
2808 | model.setStringList(strings); |
2809 | |
2810 | QTRY_COMPARE(gridview->count(), model.rowCount()); |
2811 | |
2812 | for (int i = 0; i < model.rowCount(); ++i) { |
2813 | QQuickText *display = findItem<QQuickText>(parent: contentItem, objectName: "displayText" , index: i); |
2814 | QTRY_VERIFY(display != nullptr); |
2815 | QTRY_COMPARE(display->text(), strings.at(i)); |
2816 | } |
2817 | |
2818 | delete window; |
2819 | } |
2820 | |
2821 | void tst_QQuickGridView::enforceRange() |
2822 | { |
2823 | QQuickView *window = createView(); |
2824 | |
2825 | QaimModel model; |
2826 | for (int i = 0; i < 30; i++) |
2827 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
2828 | |
2829 | QQmlContext *ctxt = window->rootContext(); |
2830 | ctxt->setContextProperty("testModel" , &model); |
2831 | ctxt->setContextProperty("testRightToLeft" , QVariant(false)); |
2832 | ctxt->setContextProperty("testTopToBottom" , QVariant(false)); |
2833 | |
2834 | window->setSource(testFileUrl(fileName: "gridview-enforcerange.qml" )); |
2835 | window->show(); |
2836 | qApp->processEvents(); |
2837 | QVERIFY(window->rootObject() != nullptr); |
2838 | |
2839 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
2840 | QTRY_VERIFY(gridview != nullptr); |
2841 | |
2842 | QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0); |
2843 | QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0); |
2844 | QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange); |
2845 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
2846 | |
2847 | QQuickItem *contentItem = gridview->contentItem(); |
2848 | QTRY_VERIFY(contentItem != nullptr); |
2849 | |
2850 | // view should be positioned at the top of the range. |
2851 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: 0); |
2852 | QTRY_VERIFY(item); |
2853 | QTRY_COMPARE(gridview->contentY(), -100.0); |
2854 | |
2855 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: 0); |
2856 | QTRY_VERIFY(name != nullptr); |
2857 | QTRY_COMPARE(name->text(), model.name(0)); |
2858 | QQuickText *number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: 0); |
2859 | QTRY_VERIFY(number != nullptr); |
2860 | QTRY_COMPARE(number->text(), model.number(0)); |
2861 | |
2862 | // Check currentIndex is updated when contentItem moves |
2863 | gridview->setContentY(0); |
2864 | QTRY_COMPARE(gridview->currentIndex(), 2); |
2865 | |
2866 | gridview->setCurrentIndex(5); |
2867 | QTRY_COMPARE(gridview->contentY(), 100.); |
2868 | |
2869 | QaimModel model2; |
2870 | for (int i = 0; i < 5; i++) |
2871 | model2.addItem(name: "Item" + QString::number(i), number: "" ); |
2872 | |
2873 | ctxt->setContextProperty("testModel" , &model2); |
2874 | QCOMPARE(gridview->count(), 5); |
2875 | |
2876 | delete window; |
2877 | } |
2878 | |
2879 | void tst_QQuickGridView::enforceRange_rightToLeft() |
2880 | { |
2881 | QQuickView *window = createView(); |
2882 | |
2883 | QaimModel model; |
2884 | for (int i = 0; i < 30; i++) |
2885 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
2886 | |
2887 | QQmlContext *ctxt = window->rootContext(); |
2888 | ctxt->setContextProperty("testModel" , &model); |
2889 | ctxt->setContextProperty("testRightToLeft" , QVariant(true)); |
2890 | ctxt->setContextProperty("testTopToBottom" , QVariant(true)); |
2891 | |
2892 | window->setSource(testFileUrl(fileName: "gridview-enforcerange.qml" )); |
2893 | window->show(); |
2894 | QTRY_VERIFY(window->isExposed()); |
2895 | QVERIFY(window->rootObject() != nullptr); |
2896 | |
2897 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
2898 | QTRY_VERIFY(gridview != nullptr); |
2899 | |
2900 | QCOMPARE(gridview->preferredHighlightBegin(), 100.0); |
2901 | QCOMPARE(gridview->preferredHighlightEnd(), 100.0); |
2902 | QCOMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange); |
2903 | |
2904 | QQuickItem *contentItem = gridview->contentItem(); |
2905 | QVERIFY(contentItem != nullptr); |
2906 | |
2907 | // view should be positioned at the top of the range. |
2908 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: 0); |
2909 | QVERIFY(item); |
2910 | QTRY_COMPARE(gridview->contentX(), -140.); |
2911 | QTRY_COMPARE(gridview->contentY(), 0.0); |
2912 | |
2913 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: 0); |
2914 | QTRY_VERIFY(name != nullptr); |
2915 | QTRY_COMPARE(name->text(), model.name(0)); |
2916 | QQuickText *number = findItem<QQuickText>(parent: contentItem, objectName: "textNumber" , index: 0); |
2917 | QTRY_VERIFY(number != nullptr); |
2918 | QTRY_COMPARE(number->text(), model.number(0)); |
2919 | |
2920 | // Check currentIndex is updated when contentItem moves |
2921 | gridview->setContentX(-240); |
2922 | QTRY_COMPARE(gridview->currentIndex(), 3); |
2923 | |
2924 | gridview->setCurrentIndex(7); |
2925 | QTRY_COMPARE(gridview->contentX(), -340.); |
2926 | QTRY_COMPARE(gridview->contentY(), 0.0); |
2927 | |
2928 | QaimModel model2; |
2929 | for (int i = 0; i < 5; i++) |
2930 | model2.addItem(name: "Item" + QString::number(i), number: "" ); |
2931 | |
2932 | ctxt->setContextProperty("testModel" , &model2); |
2933 | QCOMPARE(gridview->count(), 5); |
2934 | |
2935 | delete window; |
2936 | } |
2937 | |
2938 | void tst_QQuickGridView::QTBUG_8456() |
2939 | { |
2940 | QQuickView *window = createView(); |
2941 | |
2942 | window->setSource(testFileUrl(fileName: "setindex.qml" )); |
2943 | qApp->processEvents(); |
2944 | |
2945 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
2946 | QTRY_VERIFY(gridview != nullptr); |
2947 | |
2948 | QTRY_COMPARE(gridview->currentIndex(), 0); |
2949 | |
2950 | delete window; |
2951 | } |
2952 | |
2953 | void tst_QQuickGridView::manualHighlight() |
2954 | { |
2955 | QQuickView *window = createView(); |
2956 | |
2957 | QString filename(testFile(fileName: "manual-highlight.qml" )); |
2958 | window->setSource(QUrl::fromLocalFile(localfile: filename)); |
2959 | |
2960 | qApp->processEvents(); |
2961 | |
2962 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
2963 | QTRY_VERIFY(gridview != nullptr); |
2964 | |
2965 | QQuickItem *contentItem = gridview->contentItem(); |
2966 | QTRY_VERIFY(contentItem != nullptr); |
2967 | |
2968 | QTRY_COMPARE(gridview->currentIndex(), 0); |
2969 | QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper" , 0)); |
2970 | QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y()); |
2971 | QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x()); |
2972 | |
2973 | gridview->setCurrentIndex(2); |
2974 | |
2975 | QTRY_COMPARE(gridview->currentIndex(), 2); |
2976 | QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper" , 2)); |
2977 | QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y()); |
2978 | QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x()); |
2979 | |
2980 | gridview->positionViewAtIndex(index: 8, mode: QQuickGridView::Contain); |
2981 | |
2982 | QTRY_COMPARE(gridview->currentIndex(), 2); |
2983 | QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper" , 2)); |
2984 | QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y()); |
2985 | QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x()); |
2986 | |
2987 | gridview->setFlow(QQuickGridView::FlowTopToBottom); |
2988 | QTRY_COMPARE(gridview->flow(), QQuickGridView::FlowTopToBottom); |
2989 | |
2990 | gridview->setCurrentIndex(0); |
2991 | QTRY_COMPARE(gridview->currentIndex(), 0); |
2992 | QTRY_COMPARE(gridview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper" , 0)); |
2993 | QTRY_COMPARE(gridview->highlightItem()->y() - 5, gridview->currentItem()->y()); |
2994 | QTRY_COMPARE(gridview->highlightItem()->x() - 5, gridview->currentItem()->x()); |
2995 | |
2996 | delete window; |
2997 | } |
2998 | |
2999 | |
3000 | void tst_QQuickGridView::() |
3001 | { |
3002 | QFETCH(QQuickGridView::Flow, flow); |
3003 | QFETCH(Qt::LayoutDirection, layoutDirection); |
3004 | QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); |
3005 | QFETCH(QPointF, ); |
3006 | QFETCH(QPointF, ); |
3007 | QFETCH(QPointF, initialContentPos); |
3008 | QFETCH(QPointF, firstDelegatePos); |
3009 | QFETCH(QPointF, resizeContentPos); |
3010 | |
3011 | QQuickView *window = getView(); |
3012 | window->show(); |
3013 | |
3014 | QaimModel model; |
3015 | for (int i = 0; i < 7; i++) |
3016 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
3017 | |
3018 | QQmlContext *ctxt = window->rootContext(); |
3019 | ctxt->setContextProperty("testModel" , &model); |
3020 | window->setSource(testFileUrl(fileName: "footer.qml" )); |
3021 | qApp->processEvents(); |
3022 | |
3023 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
3024 | QTRY_VERIFY(gridview != nullptr); |
3025 | gridview->setFlow(flow); |
3026 | gridview->setLayoutDirection(layoutDirection); |
3027 | gridview->setVerticalLayoutDirection(verticalLayoutDirection); |
3028 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
3029 | |
3030 | QQuickItem *contentItem = gridview->contentItem(); |
3031 | QTRY_VERIFY(contentItem != nullptr); |
3032 | |
3033 | QQuickText * = findItem<QQuickText>(parent: contentItem, objectName: "footer" ); |
3034 | QVERIFY(footer); |
3035 | QCOMPARE(footer, gridview->footerItem()); |
3036 | |
3037 | QCOMPARE(footer->position(), initialFooterPos); |
3038 | QCOMPARE(footer->width(), 100.); |
3039 | QCOMPARE(footer->height(), 30.); |
3040 | QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos); |
3041 | |
3042 | if (flow == QQuickGridView::FlowLeftToRight) |
3043 | QCOMPARE(gridview->contentHeight(), (model.count()+2) / 3 * 60. + footer->height()); |
3044 | else |
3045 | QCOMPARE(gridview->contentWidth(), (model.count()+3) / 5 * 80. + footer->width()); |
3046 | |
3047 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: 0); |
3048 | QVERIFY(item); |
3049 | QCOMPARE(item->position(), firstDelegatePos); |
3050 | |
3051 | if (flow == QQuickGridView::FlowLeftToRight) { |
3052 | // shrink by one row |
3053 | model.removeItem(index: 2); |
3054 | if (verticalLayoutDirection == QQuickItemView::TopToBottom) |
3055 | QTRY_COMPARE(footer->y(), initialFooterPos.y() - gridview->cellHeight()); |
3056 | else |
3057 | QTRY_COMPARE(footer->y(), initialFooterPos.y() + gridview->cellHeight()); |
3058 | } else { |
3059 | // shrink by one column |
3060 | model.removeItem(index: 2); |
3061 | model.removeItem(index: 3); |
3062 | if (layoutDirection == Qt::LeftToRight) |
3063 | QTRY_COMPARE(footer->x(), initialFooterPos.x() - gridview->cellWidth()); |
3064 | else |
3065 | QTRY_COMPARE(footer->x(), initialFooterPos.x() + gridview->cellWidth()); |
3066 | } |
3067 | |
3068 | // remove all items |
3069 | model.clear(); |
3070 | if (flow == QQuickGridView::FlowLeftToRight) |
3071 | QTRY_COMPARE(gridview->contentHeight(), footer->height()); |
3072 | else |
3073 | QTRY_COMPARE(gridview->contentWidth(), footer->width()); |
3074 | |
3075 | QPointF posWhenNoItems(0, 0); |
3076 | if (layoutDirection == Qt::RightToLeft) |
3077 | posWhenNoItems.setX(flow == QQuickGridView::FlowLeftToRight ? gridview->width() - footer->width() : -footer->width()); |
3078 | if (verticalLayoutDirection == QQuickItemView::BottomToTop) |
3079 | posWhenNoItems.setY(-footer->height()); |
3080 | QTRY_COMPARE(footer->position(), posWhenNoItems); |
3081 | |
3082 | // if header is toggled, it shouldn't affect the footer position |
3083 | window->rootObject()->setProperty(name: "showHeader" , value: true); |
3084 | QVERIFY(findItem<QQuickItem>(contentItem, "header" ) != nullptr); |
3085 | QTRY_COMPARE(footer->position(), posWhenNoItems); |
3086 | window->rootObject()->setProperty(name: "showHeader" , value: false); |
3087 | |
3088 | // add 30 items |
3089 | for (int i = 0; i < 30; i++) |
3090 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
3091 | |
3092 | QSignalSpy (gridview, SIGNAL(footerItemChanged())); |
3093 | QMetaObject::invokeMethod(obj: window->rootObject(), member: "changeFooter" ); |
3094 | |
3095 | QCOMPARE(footerItemSpy.count(), 1); |
3096 | |
3097 | footer = findItem<QQuickText>(parent: contentItem, objectName: "footer" ); |
3098 | QVERIFY(!footer); |
3099 | footer = findItem<QQuickText>(parent: contentItem, objectName: "footer2" ); |
3100 | QVERIFY(footer); |
3101 | QCOMPARE(footer, gridview->footerItem()); |
3102 | |
3103 | QCOMPARE(footer->position(), changedFooterPos); |
3104 | QCOMPARE(footer->width(), 50.); |
3105 | QCOMPARE(footer->height(), 20.); |
3106 | |
3107 | // changing the footer shouldn't change the content pos |
3108 | QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos); |
3109 | |
3110 | item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: 0); |
3111 | QVERIFY(item); |
3112 | QCOMPARE(item->position(), firstDelegatePos); |
3113 | |
3114 | gridview->positionViewAtEnd(); |
3115 | footer->setHeight(10); |
3116 | footer->setWidth(40); |
3117 | QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos); |
3118 | |
3119 | releaseView(view: window); |
3120 | } |
3121 | |
3122 | void tst_QQuickGridView::() |
3123 | { |
3124 | QTest::addColumn<QQuickGridView::Flow>(name: "flow" ); |
3125 | QTest::addColumn<Qt::LayoutDirection>(name: "layoutDirection" ); |
3126 | QTest::addColumn<QQuickItemView::VerticalLayoutDirection>(name: "verticalLayoutDirection" ); |
3127 | QTest::addColumn<QPointF>(name: "initialFooterPos" ); |
3128 | QTest::addColumn<QPointF>(name: "changedFooterPos" ); |
3129 | QTest::addColumn<QPointF>(name: "initialContentPos" ); |
3130 | QTest::addColumn<QPointF>(name: "firstDelegatePos" ); |
3131 | QTest::addColumn<QPointF>(name: "resizeContentPos" ); |
3132 | |
3133 | // footer1 = 100 x 30 |
3134 | // footer2 = 50 x 20 |
3135 | // cells = 80 * 60 |
3136 | // view width = 240 |
3137 | // view height = 320 |
3138 | |
3139 | // footer below items, bottom left |
3140 | QTest::newRow(dataTag: "LeftToRight, LtR, TtB" ) |
3141 | << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom |
3142 | << QPointF(0, 3 * 60) // 180 = height of 3 rows (cell height is 60) |
3143 | << QPointF(0, 10 * 60) // 30 items = 10 rows |
3144 | << QPointF(0, 0) |
3145 | << QPointF(0, 0) |
3146 | << QPointF(0, (10 * 60) - 320 + 10); |
3147 | |
3148 | // footer below items, bottom right |
3149 | QTest::newRow(dataTag: "LeftToRight, RtL, TtB" ) |
3150 | << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom |
3151 | << QPointF(240 - 100, 3 * 60) |
3152 | << QPointF((240 - 100) + 50, 10 * 60) // 50 = width diff between old and new footers |
3153 | << QPointF(0, 0) |
3154 | << QPointF(240 - 80, 0) |
3155 | << QPointF(0, (10 * 60) - 320 + 10); |
3156 | |
3157 | // footer above items, top left |
3158 | QTest::newRow(dataTag: "LeftToRight, LtR, BtT" ) |
3159 | << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop |
3160 | << QPointF(0, -(3 * 60) - 30) |
3161 | << QPointF(0, -(10 * 60) - 20) |
3162 | << QPointF(0, -320) |
3163 | << QPointF(0, -60) |
3164 | << QPointF(0, -(10 * 60) - 10); |
3165 | |
3166 | // footer above items, top right |
3167 | QTest::newRow(dataTag: "LeftToRight, RtL, BtT" ) |
3168 | << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop |
3169 | << QPointF(240 - 100, -(3 * 60) - 30) |
3170 | << QPointF((240 - 100) + 50, -(10 * 60) - 20) |
3171 | << QPointF(0, -320) |
3172 | << QPointF(240 - 80, -60) |
3173 | << QPointF(0, -(10 * 60) - 10); |
3174 | |
3175 | |
3176 | // footer to right of items, bottom right |
3177 | QTest::newRow(dataTag: "TopToBottom, LtR, TtB" ) |
3178 | << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom |
3179 | << QPointF(2 * 80, 0) // 2 columns, cell width 80 |
3180 | << QPointF(6 * 80, 0) // 30 items = 6 columns |
3181 | << QPointF(0, 0) |
3182 | << QPointF(0, 0) |
3183 | << QPointF((6 * 80) - 240 + 40, 0); |
3184 | |
3185 | // footer to left of items, bottom right |
3186 | QTest::newRow(dataTag: "TopToBottom, RtL, TtB" ) |
3187 | << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom |
3188 | << QPointF(-(2 * 80) - 100, 0) |
3189 | << QPointF(-(6 * 80) - 50, 0) // 50 = new footer width |
3190 | << QPointF(-240, 0) |
3191 | << QPointF(-80, 0) |
3192 | << QPointF(-(6 * 80) - 40, 0); |
3193 | |
3194 | // footer to right of items, top right |
3195 | QTest::newRow(dataTag: "TopToBottom, LtR, BtT" ) |
3196 | << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop |
3197 | << QPointF(2 * 80, -30) |
3198 | << QPointF(6 * 80, -20) |
3199 | << QPointF(0, -320) |
3200 | << QPointF(0, -60) |
3201 | << QPointF((6 * 80) - 240 + 40, -320); |
3202 | |
3203 | // footer to left of items, top left |
3204 | QTest::newRow(dataTag: "TopToBottom, RtL, BtT" ) |
3205 | << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop |
3206 | << QPointF(-(2 * 80) - 100, -30) |
3207 | << QPointF(-(6 * 80) - 50, -20) |
3208 | << QPointF(-240, -320) |
3209 | << QPointF(-80, -60) |
3210 | << QPointF(-(6 * 80) - 40, -320); |
3211 | } |
3212 | |
3213 | void tst_QQuickGridView::initialZValues() |
3214 | { |
3215 | QFETCH(QString, fileName); |
3216 | QQuickView *window = createView(); |
3217 | window->setSource(testFileUrl(fileName)); |
3218 | qApp->processEvents(); |
3219 | |
3220 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
3221 | QTRY_VERIFY(gridview != nullptr); |
3222 | QQuickItem *contentItem = gridview->contentItem(); |
3223 | QTRY_VERIFY(contentItem != nullptr); |
3224 | |
3225 | QVERIFY(gridview->currentItem()); |
3226 | QTRY_COMPARE(gridview->currentItem()->z(), gridview->property("itemZ" ).toReal()); |
3227 | |
3228 | QVERIFY(gridview->headerItem()); |
3229 | QTRY_COMPARE(gridview->headerItem()->z(), gridview->property("headerZ" ).toReal()); |
3230 | |
3231 | QVERIFY(gridview->footerItem()); |
3232 | QTRY_COMPARE(gridview->footerItem()->z(), gridview->property("footerZ" ).toReal()); |
3233 | |
3234 | QVERIFY(gridview->highlightItem()); |
3235 | QTRY_COMPARE(gridview->highlightItem()->z(), gridview->property("highlightZ" ).toReal()); |
3236 | |
3237 | delete window; |
3238 | } |
3239 | |
3240 | void tst_QQuickGridView::initialZValues_data() |
3241 | { |
3242 | QTest::addColumn<QString>(name: "fileName" ); |
3243 | QTest::newRow(dataTag: "defaults" ) << "defaultZValues.qml" ; |
3244 | QTest::newRow(dataTag: "constants" ) << "constantZValues.qml" ; |
3245 | QTest::newRow(dataTag: "bindings" ) << "boundZValues.qml" ; |
3246 | } |
3247 | |
3248 | void tst_QQuickGridView::() |
3249 | { |
3250 | QFETCH(QQuickGridView::Flow, flow); |
3251 | QFETCH(Qt::LayoutDirection, layoutDirection); |
3252 | QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); |
3253 | QFETCH(QPointF, ); |
3254 | QFETCH(QPointF, ); |
3255 | QFETCH(QPointF, initialContentPos); |
3256 | QFETCH(QPointF, changedContentPos); |
3257 | QFETCH(QPointF, firstDelegatePos); |
3258 | QFETCH(QPointF, resizeContentPos); |
3259 | |
3260 | QaimModel model; |
3261 | for (int i = 0; i < 30; i++) |
3262 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
3263 | |
3264 | QQuickView *window = getView(); |
3265 | window->rootContext()->setContextProperty("testModel" , &model); |
3266 | window->rootContext()->setContextProperty("initialViewWidth" , 240); |
3267 | window->rootContext()->setContextProperty("initialViewHeight" , 320); |
3268 | window->setSource(testFileUrl(fileName: "header.qml" )); |
3269 | window->show(); |
3270 | qApp->processEvents(); |
3271 | |
3272 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
3273 | QTRY_VERIFY(gridview != nullptr); |
3274 | gridview->setFlow(flow); |
3275 | gridview->setLayoutDirection(layoutDirection); |
3276 | gridview->setVerticalLayoutDirection(verticalLayoutDirection); |
3277 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
3278 | |
3279 | QQuickItem *contentItem = gridview->contentItem(); |
3280 | QTRY_VERIFY(contentItem != nullptr); |
3281 | |
3282 | QQuickText * = findItem<QQuickText>(parent: contentItem, objectName: "header" ); |
3283 | QVERIFY(header); |
3284 | QCOMPARE(header, gridview->headerItem()); |
3285 | |
3286 | QCOMPARE(header->position(), initialHeaderPos); |
3287 | QCOMPARE(header->width(), 100.); |
3288 | QCOMPARE(header->height(), 30.); |
3289 | QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos); |
3290 | |
3291 | if (flow == QQuickGridView::FlowLeftToRight) |
3292 | QCOMPARE(gridview->contentHeight(), (model.count()+2) / 3 * 60. + header->height()); |
3293 | else |
3294 | QCOMPARE(gridview->contentWidth(), (model.count()+3) / 5 * 80. + header->width()); |
3295 | |
3296 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: 0); |
3297 | QVERIFY(item); |
3298 | QCOMPARE(item->position(), firstDelegatePos); |
3299 | |
3300 | model.clear(); |
3301 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
3302 | QCOMPARE(header->position(), initialHeaderPos); // header should stay where it is |
3303 | if (flow == QQuickGridView::FlowLeftToRight) |
3304 | QCOMPARE(gridview->contentHeight(), header->height()); |
3305 | else |
3306 | QCOMPARE(gridview->contentWidth(), header->width()); |
3307 | |
3308 | for (int i = 0; i < 30; i++) |
3309 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
3310 | |
3311 | QSignalSpy (gridview, SIGNAL(headerItemChanged())); |
3312 | QMetaObject::invokeMethod(obj: window->rootObject(), member: "changeHeader" ); |
3313 | |
3314 | QCOMPARE(headerItemSpy.count(), 1); |
3315 | |
3316 | header = findItem<QQuickText>(parent: contentItem, objectName: "header" ); |
3317 | QVERIFY(!header); |
3318 | header = findItem<QQuickText>(parent: contentItem, objectName: "header2" ); |
3319 | QVERIFY(header); |
3320 | |
3321 | QCOMPARE(header, gridview->headerItem()); |
3322 | |
3323 | QCOMPARE(header->position(), changedHeaderPos); |
3324 | QCOMPARE(header->width(), 50.); |
3325 | QCOMPARE(header->height(), 20.); |
3326 | QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), changedContentPos); |
3327 | |
3328 | item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: 0); |
3329 | QVERIFY(item); |
3330 | QCOMPARE(item->position(), firstDelegatePos); |
3331 | |
3332 | header->setHeight(10); |
3333 | header->setWidth(40); |
3334 | QTRY_COMPARE(QPointF(gridview->contentX(), gridview->contentY()), resizeContentPos); |
3335 | |
3336 | releaseView(view: window); |
3337 | |
3338 | |
3339 | // QTBUG-21207 header should become visible if view resizes from initial empty size |
3340 | |
3341 | window = getView(); |
3342 | window->rootContext()->setContextProperty("testModel" , &model); |
3343 | window->rootContext()->setContextProperty("initialViewWidth" , 240); |
3344 | window->rootContext()->setContextProperty("initialViewHeight" , 320); |
3345 | window->setSource(testFileUrl(fileName: "header.qml" )); |
3346 | window->show(); |
3347 | qApp->processEvents(); |
3348 | |
3349 | gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
3350 | QTRY_VERIFY(gridview != nullptr); |
3351 | gridview->setFlow(flow); |
3352 | gridview->setLayoutDirection(layoutDirection); |
3353 | gridview->setVerticalLayoutDirection(verticalLayoutDirection); |
3354 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
3355 | |
3356 | gridview->setWidth(240); |
3357 | gridview->setHeight(320); |
3358 | QTRY_COMPARE(gridview->headerItem()->position(), initialHeaderPos); |
3359 | QCOMPARE(QPointF(gridview->contentX(), gridview->contentY()), initialContentPos); |
3360 | |
3361 | releaseView(view: window); |
3362 | } |
3363 | |
3364 | void tst_QQuickGridView::() |
3365 | { |
3366 | QTest::addColumn<QQuickGridView::Flow>(name: "flow" ); |
3367 | QTest::addColumn<Qt::LayoutDirection>(name: "layoutDirection" ); |
3368 | QTest::addColumn<QQuickItemView::VerticalLayoutDirection>(name: "verticalLayoutDirection" ); |
3369 | QTest::addColumn<QPointF>(name: "initialHeaderPos" ); |
3370 | QTest::addColumn<QPointF>(name: "changedHeaderPos" ); |
3371 | QTest::addColumn<QPointF>(name: "initialContentPos" ); |
3372 | QTest::addColumn<QPointF>(name: "changedContentPos" ); |
3373 | QTest::addColumn<QPointF>(name: "firstDelegatePos" ); |
3374 | QTest::addColumn<QPointF>(name: "resizeContentPos" ); |
3375 | |
3376 | // header1 = 100 x 30 |
3377 | // header2 = 50 x 20 |
3378 | // cells = 80 x 60 |
3379 | // view width = 240 |
3380 | |
3381 | // header above items, top left |
3382 | QTest::newRow(dataTag: "LeftToRight, LtR, TtB" ) |
3383 | << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom |
3384 | << QPointF(0, -30) |
3385 | << QPointF(0, -20) |
3386 | << QPointF(0, -30) |
3387 | << QPointF(0, -20) |
3388 | << QPointF(0, 0) |
3389 | << QPointF(0, -10); |
3390 | |
3391 | // header above items, top right |
3392 | QTest::newRow(dataTag: "LeftToRight, RtL, TtB" ) |
3393 | << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom |
3394 | << QPointF(240 - 100, -30) |
3395 | << QPointF((240 - 100) + 50, -20) // 50 = width diff between old and new headers |
3396 | << QPointF(0, -30) |
3397 | << QPointF(0, -20) |
3398 | << QPointF(160, 0) |
3399 | << QPointF(0, -10); |
3400 | |
3401 | // header below items, bottom left |
3402 | QTest::newRow(dataTag: "LeftToRight, LtR, BtT" ) |
3403 | << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop |
3404 | << QPointF(0, 0) |
3405 | << QPointF(0, 0) |
3406 | << QPointF(0, -320 + 30) |
3407 | << QPointF(0, -320 + 20) |
3408 | << QPointF(0, -60) |
3409 | << QPointF(0, -320 + 10); |
3410 | |
3411 | // header above items, top right |
3412 | QTest::newRow(dataTag: "LeftToRight, RtL, BtT" ) |
3413 | << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop |
3414 | << QPointF(240 - 100, 0) |
3415 | << QPointF((240 - 100) + 50, 0) |
3416 | << QPointF(0, -320 + 30) |
3417 | << QPointF(0, -320 + 20) |
3418 | << QPointF(160, -60) |
3419 | << QPointF(0, -320 + 10); |
3420 | |
3421 | |
3422 | // header to left of items, bottom left |
3423 | QTest::newRow(dataTag: "TopToBottom, LtR, TtB" ) |
3424 | << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom |
3425 | << QPointF(-100, 0) |
3426 | << QPointF(-50, 0) |
3427 | << QPointF(-100, 0) |
3428 | << QPointF(-50, 0) |
3429 | << QPointF(0, 0) |
3430 | << QPointF(-40, 0); |
3431 | |
3432 | // header to right of items, bottom right |
3433 | QTest::newRow(dataTag: "TopToBottom, RtL, TtB" ) |
3434 | << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom |
3435 | << QPointF(0, 0) |
3436 | << QPointF(0, 0) |
3437 | << QPointF(-(240 - 100), 0) |
3438 | << QPointF(-(240 - 50), 0) |
3439 | << QPointF(-80, 0) |
3440 | << QPointF(-(240 - 40), 0); |
3441 | |
3442 | // header to left of items, top left |
3443 | QTest::newRow(dataTag: "TopToBottom, LtR, BtT" ) |
3444 | << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop |
3445 | << QPointF(-100, -30) |
3446 | << QPointF(-50, -20) |
3447 | << QPointF(-100, -320) |
3448 | << QPointF(-50, -320) |
3449 | << QPointF(0, -60) |
3450 | << QPointF(-40, -320); |
3451 | |
3452 | // header to right of items, top right |
3453 | QTest::newRow(dataTag: "TopToBottom, RtL, BtT" ) |
3454 | << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop |
3455 | << QPointF(0, -30) |
3456 | << QPointF(0, -20) |
3457 | << QPointF(-(240 - 100), -320) |
3458 | << QPointF(-(240 - 50), -320) |
3459 | << QPointF(-80, -60) |
3460 | << QPointF(-(240 - 40), -320); |
3461 | } |
3462 | |
3463 | class GVAccessor : public QQuickGridView |
3464 | { |
3465 | public: |
3466 | qreal minY() const { return minYExtent(); } |
3467 | qreal maxY() const { return maxYExtent(); } |
3468 | qreal minX() const { return minXExtent(); } |
3469 | qreal maxX() const { return maxXExtent(); } |
3470 | }; |
3471 | |
3472 | void tst_QQuickGridView::extents() |
3473 | { |
3474 | QFETCH(QQuickGridView::Flow, flow); |
3475 | QFETCH(Qt::LayoutDirection, layoutDirection); |
3476 | QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); |
3477 | QFETCH(QPointF, ); |
3478 | QFETCH(QPointF, ); |
3479 | QFETCH(QPointF, minPos); |
3480 | QFETCH(QPointF, maxPos); |
3481 | QFETCH(QPointF, origin_empty); |
3482 | QFETCH(QPointF, origin_nonEmpty); |
3483 | |
3484 | QQuickView *window = getView(); |
3485 | |
3486 | QaimModel model; |
3487 | QQmlContext *ctxt = window->rootContext(); |
3488 | |
3489 | ctxt->setContextProperty("testModel" , &model); |
3490 | window->setSource(testFileUrl(fileName: "headerfooter.qml" )); |
3491 | window->show(); |
3492 | qApp->processEvents(); |
3493 | |
3494 | QQuickGridView *gridview = qobject_cast<QQuickGridView*>(object: window->rootObject()); |
3495 | QTRY_VERIFY(gridview != nullptr); |
3496 | gridview->setFlow(flow); |
3497 | gridview->setLayoutDirection(layoutDirection); |
3498 | gridview->setVerticalLayoutDirection(verticalLayoutDirection); |
3499 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
3500 | |
3501 | QQuickItem *contentItem = gridview->contentItem(); |
3502 | QTRY_VERIFY(contentItem != nullptr); |
3503 | |
3504 | QQuickItem * = findItem<QQuickItem>(parent: contentItem, objectName: "header" ); |
3505 | QVERIFY(header); |
3506 | QCOMPARE(header->position(), headerPos); |
3507 | |
3508 | QQuickItem * = findItem<QQuickItem>(parent: contentItem, objectName: "footer" ); |
3509 | QVERIFY(footer); |
3510 | QCOMPARE(footer->position(), footerPos); |
3511 | |
3512 | QCOMPARE(static_cast<GVAccessor*>(gridview)->minX(), minPos.x()); |
3513 | QCOMPARE(static_cast<GVAccessor*>(gridview)->minY(), minPos.y()); |
3514 | QCOMPARE(static_cast<GVAccessor*>(gridview)->maxX(), maxPos.x()); |
3515 | QCOMPARE(static_cast<GVAccessor*>(gridview)->maxY(), maxPos.y()); |
3516 | |
3517 | QCOMPARE(gridview->originX(), origin_empty.x()); |
3518 | QCOMPARE(gridview->originY(), origin_empty.y()); |
3519 | for (int i=0; i<30; i++) |
3520 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
3521 | gridview->forceLayout(); |
3522 | QTRY_COMPARE(gridview->count(), model.count()); |
3523 | QCOMPARE(gridview->originX(), origin_nonEmpty.x()); |
3524 | QCOMPARE(gridview->originY(), origin_nonEmpty.y()); |
3525 | |
3526 | releaseView(view: window); |
3527 | } |
3528 | |
3529 | void tst_QQuickGridView::extents_data() |
3530 | { |
3531 | QTest::addColumn<QQuickGridView::Flow>(name: "flow" ); |
3532 | QTest::addColumn<Qt::LayoutDirection>(name: "layoutDirection" ); |
3533 | QTest::addColumn<QQuickItemView::VerticalLayoutDirection>(name: "verticalLayoutDirection" ); |
3534 | QTest::addColumn<QPointF>(name: "headerPos" ); |
3535 | QTest::addColumn<QPointF>(name: "footerPos" ); |
3536 | QTest::addColumn<QPointF>(name: "minPos" ); |
3537 | QTest::addColumn<QPointF>(name: "maxPos" ); |
3538 | QTest::addColumn<QPointF>(name: "origin_empty" ); |
3539 | QTest::addColumn<QPointF>(name: "origin_nonEmpty" ); |
3540 | |
3541 | // header is 240x20 (or 20x320 in TopToBottom) |
3542 | // footer is 240x30 (or 30x320 in TopToBottom) |
3543 | // grid has 10 rows in LeftToRight mode and 6 columns in TopToBottom |
3544 | |
3545 | QTest::newRow(dataTag: "LeftToRight, LtR, TtB" ) |
3546 | << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom |
3547 | << QPointF(0, -20) << QPointF(0, 0) |
3548 | << QPointF(0, 20) << QPointF(240, 20) |
3549 | << QPointF(0, -20) << QPointF(0, -20); |
3550 | |
3551 | QTest::newRow(dataTag: "LeftToRight, RtL, TtB" ) |
3552 | << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom |
3553 | << QPointF(0, -20) << QPointF(0, 0) |
3554 | << QPointF(0, 20) << QPointF(240, 20) |
3555 | << QPointF(0, -20) << QPointF(0, -20); |
3556 | |
3557 | QTest::newRow(dataTag: "LeftToRight, LtR, BtT" ) |
3558 | << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop |
3559 | << QPointF(0, 0) << QPointF(0, -30) |
3560 | << QPointF(0, 320 - 20) << QPointF(240, 320 - 20) // content flow is reversed |
3561 | << QPointF(0, -30) << QPointF(0, (-60.0 * 10) - 30); |
3562 | |
3563 | QTest::newRow(dataTag: "LeftToRight, RtL, BtT" ) |
3564 | << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop |
3565 | << QPointF(0, 0) << QPointF(0, -30) |
3566 | << QPointF(0, 320 - 20) << QPointF(240, 320 - 20) // content flow is reversed |
3567 | << QPointF(0, -30) << QPointF(0, (-60.0 * 10) - 30); |
3568 | |
3569 | |
3570 | QTest::newRow(dataTag: "TopToBottom, LtR, TtB" ) |
3571 | << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom |
3572 | << QPointF(-20, 0) << QPointF(0, 0) |
3573 | << QPointF(20, 0) << QPointF(20, 320) |
3574 | << QPointF(-20, 0) << QPointF(-20, 0); |
3575 | |
3576 | QTest::newRow(dataTag: "TopToBottom, RtL, TtB" ) |
3577 | << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom |
3578 | << QPointF(0, 0) << QPointF(-30, 0) |
3579 | << QPointF(240 - 20, 0) << QPointF(240 - 20, 320) // content flow is reversed |
3580 | << QPointF(-30, 0) << QPointF((-80.0 * 6) - 30, 0); |
3581 | |
3582 | QTest::newRow(dataTag: "TopToBottom, LtR, BtT" ) |
3583 | << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop |
3584 | << QPointF(-20, -320) << QPointF(0, -320) |
3585 | << QPointF(20, 0) << QPointF(20, 320) |
3586 | << QPointF(-20, 0) << QPointF(-20, 0); |
3587 | |
3588 | QTest::newRow(dataTag: "TopToBottom, RtL, BtT" ) |
3589 | << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop |
3590 | << QPointF(0, -320) << QPointF(-30, -320) |
3591 | << QPointF(240 - 20, 0) << QPointF(240 - 20, 320) // content flow is reversed |
3592 | << QPointF(-30, 0) << QPointF((-80.0 * 6) - 30, 0); |
3593 | } |
3594 | |
3595 | void tst_QQuickGridView::() |
3596 | { |
3597 | // Resetting a model shouldn't crash in views with header/footer |
3598 | |
3599 | QQuickView *window = createView(); |
3600 | |
3601 | QaimModel model; |
3602 | for (int i = 0; i < 6; i++) |
3603 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
3604 | QQmlContext *ctxt = window->rootContext(); |
3605 | ctxt->setContextProperty("testModel" , &model); |
3606 | |
3607 | window->setSource(testFileUrl(fileName: "headerfooter.qml" )); |
3608 | qApp->processEvents(); |
3609 | |
3610 | QQuickGridView *gridview = qobject_cast<QQuickGridView*>(object: window->rootObject()); |
3611 | QTRY_VERIFY(gridview != nullptr); |
3612 | |
3613 | QQuickItem *contentItem = gridview->contentItem(); |
3614 | QTRY_VERIFY(contentItem != nullptr); |
3615 | |
3616 | QQuickItem * = findItem<QQuickItem>(parent: contentItem, objectName: "header" ); |
3617 | QVERIFY(header); |
3618 | QCOMPARE(header->y(), -header->height()); |
3619 | |
3620 | QQuickItem * = findItem<QQuickItem>(parent: contentItem, objectName: "footer" ); |
3621 | QVERIFY(footer); |
3622 | QCOMPARE(footer->y(), 60.*2); |
3623 | |
3624 | model.reset(); |
3625 | |
3626 | // A reset should not force a new header or footer to be created. |
3627 | QQuickItem * = findItem<QQuickItem>(parent: contentItem, objectName: "header" ); |
3628 | QCOMPARE(newHeader, header); |
3629 | QCOMPARE(header->y(), -header->height()); |
3630 | |
3631 | QQuickItem * = findItem<QQuickItem>(parent: contentItem, objectName: "footer" ); |
3632 | QCOMPARE(newFooter, footer); |
3633 | QCOMPARE(footer->y(), 60.*2); |
3634 | |
3635 | delete window; |
3636 | } |
3637 | |
3638 | void tst_QQuickGridView::resizeViewAndRepaint() |
3639 | { |
3640 | QQuickView *window = createView(); |
3641 | window->show(); |
3642 | |
3643 | QaimModel model; |
3644 | for (int i = 0; i < 40; i++) |
3645 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
3646 | |
3647 | QQmlContext *ctxt = window->rootContext(); |
3648 | ctxt->setContextProperty("testModel" , &model); |
3649 | ctxt->setContextProperty("initialWidth" , 240); |
3650 | ctxt->setContextProperty("initialHeight" , 100); |
3651 | |
3652 | window->setSource(testFileUrl(fileName: "resizeview.qml" )); |
3653 | window->show(); |
3654 | qApp->processEvents(); |
3655 | |
3656 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
3657 | QTRY_VERIFY(gridview != nullptr); |
3658 | QQuickItem *contentItem = gridview->contentItem(); |
3659 | QTRY_VERIFY(contentItem != nullptr); |
3660 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
3661 | |
3662 | // item at index 10 should not be currently visible |
3663 | QVERIFY(!findItem<QQuickItem>(contentItem, "wrapper" , 10)); |
3664 | |
3665 | gridview->setHeight(320); |
3666 | QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper" , 10)); |
3667 | |
3668 | gridview->setHeight(100); |
3669 | QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper" , 10)); |
3670 | |
3671 | // Ensure we handle -ve sizes |
3672 | gridview->setHeight(-100); |
3673 | QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper" , false).count(), 3); |
3674 | |
3675 | gridview->setCacheBuffer(120); |
3676 | QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper" , false).count(), 9); |
3677 | |
3678 | // ensure items in cache become visible |
3679 | gridview->setHeight(120); |
3680 | QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper" , false).count(), 15); |
3681 | |
3682 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
3683 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
3684 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
3685 | if (!item) qWarning() << "Item" << i << "not found" ; |
3686 | QTRY_VERIFY(item); |
3687 | QTRY_COMPARE(item->x(), qreal((i%3)*80)); |
3688 | QTRY_COMPARE(item->y(), qreal((i/3)*60)); |
3689 | QCOMPARE(delegateVisible(item), i < 9); // inside view visible, outside not visible |
3690 | } |
3691 | |
3692 | // ensure items outside view become invisible |
3693 | gridview->setHeight(60); |
3694 | QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper" , false).count(), 12); |
3695 | |
3696 | itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" , visibleOnly: false).count(); |
3697 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
3698 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
3699 | if (!item) qWarning() << "Item" << i << "not found" ; |
3700 | QTRY_VERIFY(item); |
3701 | QTRY_COMPARE(item->x(), qreal((i%3)*80)); |
3702 | QTRY_COMPARE(item->y(), qreal((i/3)*60)); |
3703 | QCOMPARE(delegateVisible(item), i < 6); // inside view visible, outside not visible |
3704 | } |
3705 | |
3706 | delete window; |
3707 | } |
3708 | |
3709 | void tst_QQuickGridView::resizeGrid() |
3710 | { |
3711 | QFETCH(QQuickGridView::Flow, flow); |
3712 | QFETCH(Qt::LayoutDirection, layoutDirection); |
3713 | QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection); |
3714 | QFETCH(QPointF, initialContentPos); |
3715 | QFETCH(QPointF, firstItemPos); |
3716 | |
3717 | QaimModel model; |
3718 | for (int i = 0; i < 30; i++) |
3719 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
3720 | |
3721 | QQuickView *window = getView(); |
3722 | QQmlContext *ctxt = window->rootContext(); |
3723 | ctxt->setContextProperty("testModel" , &model); |
3724 | ctxt->setContextProperty("testTopToBottom" , flow == QQuickGridView::FlowTopToBottom); |
3725 | ctxt->setContextProperty("testRightToLeft" , layoutDirection == Qt::RightToLeft); |
3726 | ctxt->setContextProperty("testBottomToTop" , verticalLayoutDirection == QQuickGridView::BottomToTop); |
3727 | window->setSource(testFileUrl(fileName: "resizegrid.qml" )); |
3728 | QQuickViewTestUtil::centerOnScreen(window, size: window->size()); |
3729 | window->show(); |
3730 | qApp->processEvents(); |
3731 | |
3732 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
3733 | QTRY_VERIFY(gridview != nullptr); |
3734 | QQuickItem *contentItem = gridview->contentItem(); |
3735 | QTRY_VERIFY(contentItem != nullptr); |
3736 | |
3737 | // set the width to slightly larger than 3 items across, to test |
3738 | // items are aligned correctly in right-to-left |
3739 | window->rootObject()->setWidth(260); |
3740 | window->rootObject()->setHeight(320); |
3741 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
3742 | |
3743 | QCOMPARE(gridview->contentX(), initialContentPos.x()); |
3744 | QCOMPARE(gridview->contentY(), initialContentPos.y()); |
3745 | |
3746 | QQuickItem *item0 = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: 0); |
3747 | QVERIFY(item0); |
3748 | QCOMPARE(item0->position(), firstItemPos); |
3749 | |
3750 | // Confirm items positioned correctly and indexes correct |
3751 | QList<QQuickItem*> items = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ); |
3752 | QVERIFY(items.count() >= 18 && items.count() <= 21); |
3753 | for (int i = 0; i < model.count() && i < items.count(); ++i) { |
3754 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
3755 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
3756 | QCOMPARE(item->position(), expectedItemPos(gridview, i, 0)); |
3757 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
3758 | QVERIFY(name != nullptr); |
3759 | QCOMPARE(name->text(), model.name(i)); |
3760 | } |
3761 | |
3762 | // change from 3x5 grid to 4x7 |
3763 | window->rootObject()->setWidth(window->rootObject()->width() + 80); |
3764 | window->rootObject()->setHeight(window->rootObject()->height() + 60*2); |
3765 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
3766 | |
3767 | // other than in LeftToRight+RightToLeft layout, the first item should not move |
3768 | // if view is resized |
3769 | QCOMPARE(findItem<QQuickItem>(contentItem, "wrapper" , 0), item0); |
3770 | if (flow == QQuickGridView::FlowLeftToRight && layoutDirection == Qt::RightToLeft) |
3771 | firstItemPos.rx() += 80; |
3772 | QCOMPARE(item0->position(), firstItemPos); |
3773 | |
3774 | QPointF newContentPos = initialContentPos; |
3775 | if (flow == QQuickGridView::FlowTopToBottom && layoutDirection == Qt::RightToLeft) |
3776 | newContentPos.rx() -= 80.0; |
3777 | if (verticalLayoutDirection == QQuickItemView::BottomToTop) |
3778 | newContentPos.ry() -= 60.0 * 2; |
3779 | QCOMPARE(gridview->contentX(), newContentPos.x()); |
3780 | QCOMPARE(gridview->contentY(), newContentPos.y()); |
3781 | |
3782 | // Confirm items positioned correctly and indexes correct |
3783 | items = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ); |
3784 | QVERIFY(items.count() >= 28); |
3785 | for (int i = 0; i < model.count() && i < items.count(); ++i) { |
3786 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
3787 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
3788 | QCOMPARE(item->position(), expectedItemPos(gridview, i, 0)); |
3789 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
3790 | QVERIFY(name != nullptr); |
3791 | QCOMPARE(name->text(), model.name(i)); |
3792 | } |
3793 | |
3794 | releaseView(view: window); |
3795 | } |
3796 | |
3797 | void tst_QQuickGridView::resizeGrid_data() |
3798 | { |
3799 | QTest::addColumn<QQuickGridView::Flow>(name: "flow" ); |
3800 | QTest::addColumn<Qt::LayoutDirection>(name: "layoutDirection" ); |
3801 | QTest::addColumn<QQuickItemView::VerticalLayoutDirection>(name: "verticalLayoutDirection" ); |
3802 | QTest::addColumn<QPointF>(name: "initialContentPos" ); |
3803 | QTest::addColumn<QPointF>(name: "firstItemPos" ); |
3804 | |
3805 | // Initial view width is 260, so in LeftToRight + right-to-left mode the |
3806 | // content x should be -20 |
3807 | |
3808 | QTest::newRow(dataTag: "LeftToRight, LtR, TtB" ) |
3809 | << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom |
3810 | << QPointF(0, 0) |
3811 | << QPointF(0, 0); |
3812 | |
3813 | QTest::newRow(dataTag: "LeftToRight, RtL, TtB" ) |
3814 | << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom |
3815 | << QPointF(-20.0, 0) |
3816 | << QPointF(80.0 * 2, 0); |
3817 | |
3818 | QTest::newRow(dataTag: "LeftToRight, LtR, BtT" ) |
3819 | << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop |
3820 | << QPointF(0, -320) |
3821 | << QPointF(0, -60.0); |
3822 | |
3823 | QTest::newRow(dataTag: "LeftToRight, RtL, BtT" ) |
3824 | << QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop |
3825 | << QPointF(-20.0, -320) |
3826 | << QPointF(80.0 * 2, -60.0); |
3827 | |
3828 | |
3829 | QTest::newRow(dataTag: "TopToBottom, LtR, TtB" ) |
3830 | << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom |
3831 | << QPointF(0, 0) |
3832 | << QPointF(0, 0); |
3833 | |
3834 | QTest::newRow(dataTag: "TopToBottom, RtL, TtB" ) |
3835 | << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom |
3836 | << QPointF(-260, 0) |
3837 | << QPointF(-80.0, 0); |
3838 | |
3839 | QTest::newRow(dataTag: "TopToBottom, LtR, BtT" ) |
3840 | << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop |
3841 | << QPointF(0, -320) |
3842 | << QPointF(0, -60.0); |
3843 | |
3844 | QTest::newRow(dataTag: "TopToBottom, RtL, BtT" ) |
3845 | << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop |
3846 | << QPointF(-260, -320) |
3847 | << QPointF(-80.0, -60.0); |
3848 | } |
3849 | |
3850 | |
3851 | void tst_QQuickGridView::changeColumnCount() |
3852 | { |
3853 | QaimModel model; |
3854 | for (int i = 0; i < 40; i++) |
3855 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
3856 | |
3857 | QQuickView *window = createView(); |
3858 | QQmlContext *ctxt = window->rootContext(); |
3859 | ctxt->setContextProperty("testModel" , &model); |
3860 | ctxt->setContextProperty("initialWidth" , 100); |
3861 | ctxt->setContextProperty("initialHeight" , 320); |
3862 | window->setSource(testFileUrl(fileName: "resizeview.qml" )); |
3863 | window->show(); |
3864 | qApp->processEvents(); |
3865 | |
3866 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
3867 | QTRY_VERIFY(gridview != nullptr); |
3868 | QQuickItem *contentItem = gridview->contentItem(); |
3869 | QTRY_VERIFY(contentItem != nullptr); |
3870 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
3871 | |
3872 | // a single column of 6 items are visible |
3873 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
3874 | QCOMPARE(itemCount, 6); |
3875 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
3876 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
3877 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
3878 | QCOMPARE(item->x(), 0.0); |
3879 | QCOMPARE(item->y(), qreal(i*60)); |
3880 | } |
3881 | |
3882 | // now 6x3 grid is visible, plus 1 extra below for refill |
3883 | gridview->setWidth(240); |
3884 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
3885 | itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
3886 | QCOMPARE(itemCount, 6*3 + 1); |
3887 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
3888 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
3889 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
3890 | QCOMPARE(item->x(), qreal((i%3)*80)); |
3891 | QCOMPARE(item->y(), qreal((i/3)*60)); |
3892 | } |
3893 | |
3894 | // back to single column |
3895 | gridview->setWidth(100); |
3896 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
3897 | itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
3898 | QCOMPARE(itemCount, 6); |
3899 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
3900 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
3901 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
3902 | QCOMPARE(item->x(), 0.0); |
3903 | QCOMPARE(item->y(), qreal(i*60)); |
3904 | } |
3905 | |
3906 | delete window; |
3907 | } |
3908 | |
3909 | void tst_QQuickGridView::indexAt_itemAt_data() |
3910 | { |
3911 | QTest::addColumn<qreal>(name: "x" ); |
3912 | QTest::addColumn<qreal>(name: "y" ); |
3913 | QTest::addColumn<int>(name: "index" ); |
3914 | |
3915 | QTest::newRow(dataTag: "Item 0 - 0, 0" ) << 0. << 0. << 0; |
3916 | QTest::newRow(dataTag: "Item 0 - 79, 59" ) << 79. << 59. << 0; |
3917 | QTest::newRow(dataTag: "Item 1 - 80, 0" ) << 80. << 0. << 1; |
3918 | QTest::newRow(dataTag: "Item 3 - 0, 60" ) << 0. << 60. << 3; |
3919 | QTest::newRow(dataTag: "No Item - 240, 0" ) << 240. << 0. << -1; |
3920 | } |
3921 | |
3922 | void tst_QQuickGridView::indexAt_itemAt() |
3923 | { |
3924 | QFETCH(qreal, x); |
3925 | QFETCH(qreal, y); |
3926 | QFETCH(int, index); |
3927 | |
3928 | QQuickView *window = getView(); |
3929 | |
3930 | QaimModel model; |
3931 | model.addItem(name: "Fred" , number: "12345" ); |
3932 | model.addItem(name: "John" , number: "2345" ); |
3933 | model.addItem(name: "Bob" , number: "54321" ); |
3934 | model.addItem(name: "Billy" , number: "22345" ); |
3935 | model.addItem(name: "Sam" , number: "2945" ); |
3936 | model.addItem(name: "Ben" , number: "04321" ); |
3937 | model.addItem(name: "Jim" , number: "0780" ); |
3938 | |
3939 | window->rootContext()->setContextProperty("testModel" , &model); |
3940 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
3941 | qApp->processEvents(); |
3942 | |
3943 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
3944 | QTRY_VERIFY(gridview != nullptr); |
3945 | |
3946 | QQuickItem *contentItem = gridview->contentItem(); |
3947 | QTRY_VERIFY(contentItem != nullptr); |
3948 | |
3949 | QTRY_COMPARE(gridview->count(), model.count()); |
3950 | |
3951 | QQuickItem *item = nullptr; |
3952 | if (index >= 0) { |
3953 | item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index); |
3954 | QVERIFY(item); |
3955 | } |
3956 | QCOMPARE(gridview->indexAt(x, y), index); |
3957 | QVERIFY(gridview->itemAt(x, y) == item); |
3958 | |
3959 | releaseView(view: window); |
3960 | } |
3961 | |
3962 | void tst_QQuickGridView::onAdd() |
3963 | { |
3964 | QFETCH(int, initialItemCount); |
3965 | QFETCH(int, itemsToAdd); |
3966 | |
3967 | const int delegateWidth = 50; |
3968 | const int delegateHeight = 100; |
3969 | QaimModel model; |
3970 | QQuickView *window = getView(); |
3971 | window->setGeometry(posx: 0,posy: 0,w: 5 * delegateWidth, h: 5 * delegateHeight); // just ensure all items fit |
3972 | |
3973 | // these initial items should not trigger GridView.onAdd |
3974 | for (int i=0; i<initialItemCount; i++) |
3975 | model.addItem(name: "dummy value" , number: "dummy value" ); |
3976 | |
3977 | QQmlContext *ctxt = window->rootContext(); |
3978 | ctxt->setContextProperty("testModel" , &model); |
3979 | ctxt->setContextProperty("delegateWidth" , delegateWidth); |
3980 | ctxt->setContextProperty("delegateHeight" , delegateHeight); |
3981 | window->setSource(testFileUrl(fileName: "attachedSignals.qml" )); |
3982 | |
3983 | QQuickGridView *gridview = qobject_cast<QQuickGridView*>(object: window->rootObject()); |
3984 | gridview->setProperty(name: "width" , value: window->width()); |
3985 | gridview->setProperty(name: "height" , value: window->height()); |
3986 | qApp->processEvents(); |
3987 | |
3988 | QList<QPair<QString, QString> > items; |
3989 | for (int i=0; i<itemsToAdd; i++) |
3990 | items << qMakePair(x: QString("value %1" ).arg(a: i), y: QString::number(i)); |
3991 | model.addItems(items); |
3992 | |
3993 | gridview->forceLayout(); |
3994 | QTRY_COMPARE(model.count(), gridview->count()); |
3995 | qApp->processEvents(); |
3996 | |
3997 | QVariantList result = gridview->property(name: "addedDelegates" ).toList(); |
3998 | QTRY_COMPARE(result.count(), items.count()); |
3999 | for (int i=0; i<items.count(); i++) |
4000 | QCOMPARE(result[i].toString(), items[i].first); |
4001 | |
4002 | releaseView(view: window); |
4003 | } |
4004 | |
4005 | void tst_QQuickGridView::onAdd_data() |
4006 | { |
4007 | QTest::addColumn<int>(name: "initialItemCount" ); |
4008 | QTest::addColumn<int>(name: "itemsToAdd" ); |
4009 | |
4010 | QTest::newRow(dataTag: "0, add 1" ) << 0 << 1; |
4011 | QTest::newRow(dataTag: "0, add 2" ) << 0 << 2; |
4012 | QTest::newRow(dataTag: "0, add 10" ) << 0 << 10; |
4013 | |
4014 | QTest::newRow(dataTag: "1, add 1" ) << 1 << 1; |
4015 | QTest::newRow(dataTag: "1, add 2" ) << 1 << 2; |
4016 | QTest::newRow(dataTag: "1, add 10" ) << 1 << 10; |
4017 | |
4018 | QTest::newRow(dataTag: "5, add 1" ) << 5 << 1; |
4019 | QTest::newRow(dataTag: "5, add 2" ) << 5 << 2; |
4020 | QTest::newRow(dataTag: "5, add 10" ) << 5 << 10; |
4021 | } |
4022 | |
4023 | void tst_QQuickGridView::onRemove() |
4024 | { |
4025 | QFETCH(int, initialItemCount); |
4026 | QFETCH(int, indexToRemove); |
4027 | QFETCH(int, removeCount); |
4028 | |
4029 | const int delegateWidth = 50; |
4030 | const int delegateHeight = 100; |
4031 | QaimModel model; |
4032 | for (int i=0; i<initialItemCount; i++) |
4033 | model.addItem(name: QString("value %1" ).arg(a: i), number: "dummy value" ); |
4034 | |
4035 | QQuickView *window = getView(); |
4036 | QQmlContext *ctxt = window->rootContext(); |
4037 | ctxt->setContextProperty("testModel" , &model); |
4038 | ctxt->setContextProperty("delegateWidth" , delegateWidth); |
4039 | ctxt->setContextProperty("delegateHeight" , delegateHeight); |
4040 | window->setSource(testFileUrl(fileName: "attachedSignals.qml" )); |
4041 | QQuickGridView *gridview = qobject_cast<QQuickGridView*>(object: window->rootObject()); |
4042 | |
4043 | model.removeItems(index: indexToRemove, count: removeCount); |
4044 | gridview->forceLayout(); |
4045 | QTRY_COMPARE(model.count(), gridview->count()); |
4046 | QCOMPARE(gridview->property("removedDelegateCount" ), QVariant(removeCount)); |
4047 | |
4048 | releaseView(view: window); |
4049 | } |
4050 | |
4051 | void tst_QQuickGridView::onRemove_data() |
4052 | { |
4053 | QTest::addColumn<int>(name: "initialItemCount" ); |
4054 | QTest::addColumn<int>(name: "indexToRemove" ); |
4055 | QTest::addColumn<int>(name: "removeCount" ); |
4056 | |
4057 | QTest::newRow(dataTag: "remove first" ) << 1 << 0 << 1; |
4058 | QTest::newRow(dataTag: "two items, remove first" ) << 2 << 0 << 1; |
4059 | QTest::newRow(dataTag: "two items, remove last" ) << 2 << 1 << 1; |
4060 | QTest::newRow(dataTag: "two items, remove all" ) << 2 << 0 << 2; |
4061 | |
4062 | QTest::newRow(dataTag: "four items, remove first" ) << 4 << 0 << 1; |
4063 | QTest::newRow(dataTag: "four items, remove 0-2" ) << 4 << 0 << 2; |
4064 | QTest::newRow(dataTag: "four items, remove 1-3" ) << 4 << 1 << 2; |
4065 | QTest::newRow(dataTag: "four items, remove 2-4" ) << 4 << 2 << 2; |
4066 | QTest::newRow(dataTag: "four items, remove last" ) << 4 << 3 << 1; |
4067 | QTest::newRow(dataTag: "four items, remove all" ) << 4 << 0 << 4; |
4068 | |
4069 | QTest::newRow(dataTag: "ten items, remove 1-8" ) << 10 << 0 << 8; |
4070 | QTest::newRow(dataTag: "ten items, remove 2-7" ) << 10 << 2 << 5; |
4071 | QTest::newRow(dataTag: "ten items, remove 4-10" ) << 10 << 4 << 6; |
4072 | } |
4073 | |
4074 | void tst_QQuickGridView::attachedProperties_QTBUG_32836() |
4075 | { |
4076 | QQuickView *window = createView(); |
4077 | |
4078 | window->setSource(testFileUrl(fileName: "attachedProperties.qml" )); |
4079 | window->show(); |
4080 | qApp->processEvents(); |
4081 | |
4082 | QQuickGridView *gridview = qobject_cast<QQuickGridView*>(object: window->rootObject()); |
4083 | QVERIFY(gridview != nullptr); |
4084 | |
4085 | QQuickItem * = gridview->headerItem(); |
4086 | QVERIFY(header); |
4087 | QCOMPARE(header->width(), gridview->width()); |
4088 | |
4089 | QQuickItem * = gridview->footerItem(); |
4090 | QVERIFY(footer); |
4091 | QCOMPARE(footer->width(), gridview->width()); |
4092 | |
4093 | QQuickItem *highlight = gridview->highlightItem(); |
4094 | QVERIFY(highlight); |
4095 | QCOMPARE(highlight->width(), gridview->width()); |
4096 | |
4097 | QQuickItem *currentItem = gridview->currentItem(); |
4098 | QVERIFY(currentItem); |
4099 | QCOMPARE(currentItem->width(), gridview->width()); |
4100 | |
4101 | delete window; |
4102 | } |
4103 | |
4104 | void tst_QQuickGridView::columnCount() |
4105 | { |
4106 | QQuickView window; |
4107 | window.setSource(testFileUrl(fileName: "gridview4.qml" )); |
4108 | window.show(); |
4109 | window.requestActivate(); |
4110 | QVERIFY(QTest::qWaitForWindowActive(&window)); |
4111 | |
4112 | QQuickGridView *view = qobject_cast<QQuickGridView*>(object: window.rootObject()); |
4113 | |
4114 | QCOMPARE(view->cellWidth(), qreal(405)/qreal(9)); |
4115 | QCOMPARE(view->cellHeight(), qreal(100)); |
4116 | |
4117 | QList<QQuickItem*> items = findItems<QQuickItem>(parent: view, objectName: "delegate" ); |
4118 | QCOMPARE(items.size(), 18); |
4119 | QCOMPARE(items.at(8)->y(), qreal(0)); |
4120 | QCOMPARE(items.at(9)->y(), qreal(100)); |
4121 | } |
4122 | |
4123 | void tst_QQuickGridView::margins() |
4124 | { |
4125 | { |
4126 | QQuickView *window = createView(); |
4127 | |
4128 | QaimModel model; |
4129 | for (int i = 0; i < 40; i++) |
4130 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
4131 | |
4132 | QQmlContext *ctxt = window->rootContext(); |
4133 | ctxt->setContextProperty("testModel" , &model); |
4134 | ctxt->setContextProperty("testRightToLeft" , QVariant(false)); |
4135 | |
4136 | window->setSource(testFileUrl(fileName: "margins.qml" )); |
4137 | window->show(); |
4138 | qApp->processEvents(); |
4139 | |
4140 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
4141 | QTRY_VERIFY(gridview != nullptr); |
4142 | QQuickItem *contentItem = gridview->contentItem(); |
4143 | QTRY_VERIFY(contentItem != nullptr); |
4144 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
4145 | |
4146 | QCOMPARE(gridview->contentX(), -30.); |
4147 | QCOMPARE(gridview->originX(), 0.); |
4148 | |
4149 | // check end bound |
4150 | gridview->positionViewAtEnd(); |
4151 | qreal pos = gridview->contentX(); |
4152 | gridview->setContentX(pos + 80); |
4153 | gridview->returnToBounds(); |
4154 | QTRY_COMPARE(gridview->contentX(), pos + 50); |
4155 | |
4156 | // remove item before visible and check that left margin is maintained |
4157 | // and originX is updated |
4158 | gridview->setContentX(200); |
4159 | model.removeItems(index: 0, count: 4); |
4160 | QTest::qWait(ms: 100); |
4161 | gridview->setContentX(-50); |
4162 | gridview->returnToBounds(); |
4163 | QCOMPARE(gridview->originX(), 100.); |
4164 | QTRY_COMPARE(gridview->contentX(), 70.); |
4165 | |
4166 | // reduce left margin |
4167 | gridview->setLeftMargin(20); |
4168 | QCOMPARE(gridview->originX(), 100.); |
4169 | QTRY_COMPARE(gridview->contentX(), 80.); |
4170 | |
4171 | // check end bound |
4172 | gridview->positionViewAtEnd(); |
4173 | QCOMPARE(gridview->originX(), 0.); // positionViewAtEnd() resets origin |
4174 | pos = gridview->contentX(); |
4175 | gridview->setContentX(pos + 80); |
4176 | gridview->returnToBounds(); |
4177 | QTRY_COMPARE(gridview->contentX(), pos + 50); |
4178 | |
4179 | // reduce right margin |
4180 | pos = gridview->contentX(); |
4181 | gridview->setRightMargin(40); |
4182 | QCOMPARE(gridview->originX(), 0.); |
4183 | QTRY_COMPARE(gridview->contentX(), pos-10); |
4184 | |
4185 | delete window; |
4186 | } |
4187 | { |
4188 | //RTL |
4189 | QQuickView *window = createView(); |
4190 | window->show(); |
4191 | |
4192 | QaimModel model; |
4193 | for (int i = 0; i < 40; i++) |
4194 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
4195 | |
4196 | QQmlContext *ctxt = window->rootContext(); |
4197 | ctxt->setContextProperty("testModel" , &model); |
4198 | ctxt->setContextProperty("testRightToLeft" , QVariant(true)); |
4199 | |
4200 | window->setSource(testFileUrl(fileName: "margins.qml" )); |
4201 | qApp->processEvents(); |
4202 | |
4203 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
4204 | QTRY_VERIFY(gridview != nullptr); |
4205 | |
4206 | QQuickItem *contentItem = gridview->contentItem(); |
4207 | QTRY_VERIFY(contentItem != nullptr); |
4208 | |
4209 | QTRY_COMPARE(gridview->contentX(), -240+50.); |
4210 | QTRY_COMPARE(gridview->originX(), -100. * 10); |
4211 | |
4212 | // check end bound |
4213 | gridview->positionViewAtEnd(); |
4214 | qreal pos = gridview->contentX(); |
4215 | gridview->setContentX(pos - 80); |
4216 | gridview->returnToBounds(); |
4217 | QTRY_COMPARE(gridview->contentX(), pos - 30); |
4218 | |
4219 | // remove item before visible and check that left margin is maintained |
4220 | // and originX is updated |
4221 | gridview->setContentX(-400); |
4222 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
4223 | model.removeItems(index: 0, count: 4); |
4224 | gridview->forceLayout(); |
4225 | QTRY_COMPARE(model.count(), gridview->count()); |
4226 | gridview->setContentX(-240+50); |
4227 | gridview->returnToBounds(); |
4228 | QCOMPARE(gridview->originX(), -1000.); |
4229 | QTRY_COMPARE(gridview->contentX(), -240-50.); |
4230 | |
4231 | // reduce right margin |
4232 | pos = gridview->contentX(); |
4233 | gridview->setRightMargin(40); |
4234 | QCOMPARE(gridview->originX(), -1000.); |
4235 | QTRY_COMPARE(gridview->contentX(), -240-100 + 40.); |
4236 | |
4237 | // check end bound |
4238 | gridview->positionViewAtEnd(); |
4239 | QCOMPARE(gridview->originX(), -900.); // positionViewAtEnd() resets origin |
4240 | pos = gridview->contentX(); |
4241 | gridview->setContentX(pos - 80); |
4242 | gridview->returnToBounds(); |
4243 | QTRY_COMPARE(gridview->contentX(), pos - 30); |
4244 | |
4245 | // reduce left margin |
4246 | pos = gridview->contentX(); |
4247 | gridview->setLeftMargin(20); |
4248 | QCOMPARE(gridview->originX(), -900.); |
4249 | QTRY_COMPARE(gridview->contentX(), pos+10); |
4250 | |
4251 | delete window; |
4252 | } |
4253 | { |
4254 | QQuickView *window = createView(); |
4255 | |
4256 | window->setSource(testFileUrl(fileName: "margins2.qml" )); |
4257 | window->show(); |
4258 | qApp->processEvents(); |
4259 | |
4260 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
4261 | QVERIFY(gridview != nullptr); |
4262 | QQuickItem *contentItem = gridview->contentItem(); |
4263 | QVERIFY(contentItem != nullptr); |
4264 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
4265 | QCOMPARE(contentItem->x(), 200); |
4266 | QCOMPARE(contentItem->y(), 20); |
4267 | |
4268 | delete window; |
4269 | } |
4270 | } |
4271 | |
4272 | void tst_QQuickGridView::creationContext() |
4273 | { |
4274 | QQuickView window; |
4275 | window.setGeometry(posx: 0,posy: 0,w: 240,h: 320); |
4276 | window.setSource(testFileUrl(fileName: "creationContext.qml" )); |
4277 | qApp->processEvents(); |
4278 | |
4279 | QQuickItem *rootItem = qobject_cast<QQuickItem *>(object: window.rootObject()); |
4280 | QVERIFY(rootItem); |
4281 | QVERIFY(rootItem->property("count" ).toInt() > 0); |
4282 | |
4283 | QQuickItem *item; |
4284 | QVERIFY(item = findItem<QQuickItem>(rootItem, "listItem" )); |
4285 | QCOMPARE(item->property("text" ).toString(), QString("Hello!" )); |
4286 | QVERIFY(item = rootItem->findChild<QQuickItem *>("header" )); |
4287 | QCOMPARE(item->property("text" ).toString(), QString("Hello!" )); |
4288 | QVERIFY(item = rootItem->findChild<QQuickItem *>("footer" )); |
4289 | QCOMPARE(item->property("text" ).toString(), QString("Hello!" )); |
4290 | } |
4291 | |
4292 | void tst_QQuickGridView::snapToRow_data() |
4293 | { |
4294 | QTest::addColumn<QQuickGridView::Flow>(name: "flow" ); |
4295 | QTest::addColumn<Qt::LayoutDirection>(name: "layoutDirection" ); |
4296 | QTest::addColumn<int>(name: "highlightRangeMode" ); |
4297 | QTest::addColumn<QPoint>(name: "flickStart" ); |
4298 | QTest::addColumn<QPoint>(name: "flickEnd" ); |
4299 | QTest::addColumn<qreal>(name: "snapAlignment" ); |
4300 | QTest::addColumn<qreal>(name: "endExtent" ); |
4301 | QTest::addColumn<qreal>(name: "startExtent" ); |
4302 | |
4303 | QTest::newRow(dataTag: "vertical, left to right" ) << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) |
4304 | << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 800.0 << 0.0; |
4305 | |
4306 | QTest::newRow(dataTag: "horizontal, left to right" ) << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) |
4307 | << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 800.0 << 0.0; |
4308 | |
4309 | QTest::newRow(dataTag: "horizontal, right to left" ) << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange) |
4310 | << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -800.0 - 240.0 << -240.0; |
4311 | |
4312 | QTest::newRow(dataTag: "vertical, left to right, enforce range" ) << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) |
4313 | << QPoint(20, 200) << QPoint(20, 20) << 60.0 << 940.0 << -20.0; |
4314 | |
4315 | QTest::newRow(dataTag: "horizontal, left to right, enforce range" ) << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) |
4316 | << QPoint(200, 20) << QPoint(20, 20) << 60.0 << 940.0 << -20.0; |
4317 | |
4318 | QTest::newRow(dataTag: "horizontal, right to left, enforce range" ) << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange) |
4319 | << QPoint(20, 20) << QPoint(200, 20) << -60.0 << -800.0 - 240.0 - 140.0 << -220.0; |
4320 | } |
4321 | |
4322 | void tst_QQuickGridView::snapToRow() |
4323 | { |
4324 | QFETCH(QQuickGridView::Flow, flow); |
4325 | QFETCH(Qt::LayoutDirection, layoutDirection); |
4326 | QFETCH(int, highlightRangeMode); |
4327 | QFETCH(QPoint, flickStart); |
4328 | QFETCH(QPoint, flickEnd); |
4329 | QFETCH(qreal, snapAlignment); |
4330 | QFETCH(qreal, endExtent); |
4331 | QFETCH(qreal, startExtent); |
4332 | |
4333 | QQuickView *window = getView(); |
4334 | |
4335 | QQuickViewTestUtil::moveMouseAway(window); |
4336 | window->setSource(testFileUrl(fileName: "snapToRow.qml" )); |
4337 | window->show(); |
4338 | qApp->processEvents(); |
4339 | |
4340 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
4341 | QTRY_VERIFY(gridview != nullptr); |
4342 | |
4343 | gridview->setFlow(flow); |
4344 | gridview->setLayoutDirection(layoutDirection); |
4345 | gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode)); |
4346 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
4347 | |
4348 | QQuickItem *contentItem = gridview->contentItem(); |
4349 | QTRY_VERIFY(contentItem != nullptr); |
4350 | |
4351 | qreal origContentY = gridview->contentY(); |
4352 | qreal origContentX = gridview->contentX(); |
4353 | // confirm that a flick hits an item boundary |
4354 | flick(window, from: flickStart, to: flickEnd, duration: 180); |
4355 | |
4356 | // wait until it's at least one cell further |
4357 | QTRY_VERIFY(qAbs(gridview->contentX() - origContentX) > 80 || |
4358 | qAbs(gridview->contentY() - origContentY) > 80); |
4359 | |
4360 | // click to stop it. Otherwise we wouldn't know how much further it will go. We don't want to it |
4361 | // to hit the endExtent, yet. |
4362 | QTest::mouseClick(window, button: Qt::LeftButton, stateKey: Qt::NoModifier, pos: flickEnd); |
4363 | |
4364 | QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops |
4365 | if (flow == QQuickGridView::FlowLeftToRight) |
4366 | QCOMPARE(qreal(fmod(gridview->contentY(),80.0)), snapAlignment); |
4367 | else |
4368 | QCOMPARE(qreal(fmod(gridview->contentX(),80.0)), snapAlignment); |
4369 | |
4370 | // flick to end |
4371 | do { |
4372 | flick(window, from: flickStart, to: flickEnd, duration: 180); |
4373 | QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops |
4374 | } while (flow == QQuickGridView::FlowLeftToRight |
4375 | ? !gridview->isAtYEnd() |
4376 | : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning()); |
4377 | |
4378 | if (flow == QQuickGridView::FlowLeftToRight) |
4379 | QCOMPARE(gridview->contentY(), endExtent); |
4380 | else |
4381 | QCOMPARE(gridview->contentX(), endExtent); |
4382 | |
4383 | // flick to start |
4384 | do { |
4385 | flick(window, from: flickEnd, to: flickStart, duration: 180); |
4386 | QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops |
4387 | } while (flow == QQuickGridView::FlowLeftToRight |
4388 | ? !gridview->isAtYBeginning() |
4389 | : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd()); |
4390 | |
4391 | if (flow == QQuickGridView::FlowLeftToRight) |
4392 | QCOMPARE(gridview->contentY(), startExtent); |
4393 | else |
4394 | QCOMPARE(gridview->contentX(), startExtent); |
4395 | |
4396 | releaseView(view: window); |
4397 | } |
4398 | |
4399 | void tst_QQuickGridView::snapOneRow_data() |
4400 | { |
4401 | QTest::addColumn<QQuickGridView::Flow>(name: "flow" ); |
4402 | QTest::addColumn<Qt::LayoutDirection>(name: "layoutDirection" ); |
4403 | QTest::addColumn<int>(name: "highlightRangeMode" ); |
4404 | QTest::addColumn<QPoint>(name: "flickStart" ); |
4405 | QTest::addColumn<QPoint>(name: "flickEnd" ); |
4406 | QTest::addColumn<qreal>(name: "snapAlignment" ); |
4407 | QTest::addColumn<qreal>(name: "endExtent" ); |
4408 | QTest::addColumn<qreal>(name: "startExtent" ); |
4409 | QTest::addColumn<qreal>(name: "flickSlowdown" ); |
4410 | |
4411 | QTest::newRow(dataTag: "vertical, left to right" ) << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) |
4412 | << QPoint(20, 160) << QPoint(20, 20) << 100.0 << 240.0 << 0.0 << 1.0; |
4413 | |
4414 | QTest::newRow(dataTag: "horizontal, left to right" ) << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) |
4415 | << QPoint(160, 20) << QPoint(20, 20) << 100.0 << 240.0 << 0.0 << 1.0; |
4416 | |
4417 | QTest::newRow(dataTag: "horizontal, right to left" ) << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::NoHighlightRange) |
4418 | << QPoint(20, 20) << QPoint(160, 20) << -340.0 << -240.0 - 240.0 << -240.0 << 1.0; |
4419 | |
4420 | QTest::newRow(dataTag: "vertical, left to right, enforce range" ) << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) |
4421 | << QPoint(20, 160) << QPoint(20, 20) << 100.0 << 340.0 << -20.0 << 1.0; |
4422 | |
4423 | QTest::newRow(dataTag: "horizontal, left to right, enforce range" ) << QQuickGridView::FlowTopToBottom << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) |
4424 | << QPoint(160, 20) << QPoint(20, 20) << 100.0 << 340.0 << -20.0 << 1.0; |
4425 | |
4426 | QTest::newRow(dataTag: "horizontal, right to left, enforce range" ) << QQuickGridView::FlowTopToBottom << Qt::RightToLeft << int(QQuickItemView::StrictlyEnforceRange) |
4427 | << QPoint(20, 20) << QPoint(160, 20) << -340.0 << -240.0 - 240.0 - 100.0 << -220.0 << 1.0; |
4428 | |
4429 | // Using e.g. 120 rather than 95 always went to the next row. |
4430 | // Ensure this further movement has the same behavior |
4431 | QTest::newRow(dataTag: "vertical, left to right, no more blindspot" ) << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::NoHighlightRange) |
4432 | << QPoint(20, 160) << QPoint(20, 95) << 100.0 << 240.0 << 0.0 << 4.0; |
4433 | |
4434 | // StrictlyEnforceRange should not override valid SnapOneItem decisions |
4435 | QTest::newRow(dataTag: "vertical, left to right, no more blindspot, enforce range" ) << QQuickGridView::FlowLeftToRight << Qt::LeftToRight << int(QQuickItemView::StrictlyEnforceRange) |
4436 | << QPoint(20, 160) << QPoint(20, 95) << 100.0 << 340.0 << -20.0 << 4.0; |
4437 | } |
4438 | |
4439 | void tst_QQuickGridView::snapOneRow() |
4440 | { |
4441 | QFETCH(QQuickGridView::Flow, flow); |
4442 | QFETCH(Qt::LayoutDirection, layoutDirection); |
4443 | QFETCH(int, highlightRangeMode); |
4444 | QFETCH(QPoint, flickStart); |
4445 | QFETCH(QPoint, flickEnd); |
4446 | QFETCH(qreal, snapAlignment); |
4447 | QFETCH(qreal, endExtent); |
4448 | QFETCH(qreal, startExtent); |
4449 | QFETCH(qreal, flickSlowdown); |
4450 | |
4451 | qreal flickDuration = 180 * flickSlowdown; |
4452 | |
4453 | QQuickView *window = getView(); |
4454 | QQuickViewTestUtil::moveMouseAway(window); |
4455 | |
4456 | window->setSource(testFileUrl(fileName: "snapOneRow.qml" )); |
4457 | window->show(); |
4458 | qApp->processEvents(); |
4459 | |
4460 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
4461 | QTRY_VERIFY(gridview != nullptr); |
4462 | |
4463 | gridview->setFlow(flow); |
4464 | gridview->setLayoutDirection(layoutDirection); |
4465 | gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode)); |
4466 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
4467 | |
4468 | QQuickItem *contentItem = gridview->contentItem(); |
4469 | QTRY_VERIFY(contentItem != nullptr); |
4470 | |
4471 | QSignalSpy currentIndexSpy(gridview, SIGNAL(currentIndexChanged())); |
4472 | |
4473 | // confirm that a flick hits next row boundary |
4474 | flick(window, from: flickStart, to: flickEnd, duration: flickDuration); |
4475 | QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops |
4476 | if (flow == QQuickGridView::FlowLeftToRight) |
4477 | QCOMPARE(gridview->contentY(), snapAlignment); |
4478 | else |
4479 | QCOMPARE(gridview->contentX(), snapAlignment); |
4480 | |
4481 | if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) { |
4482 | QCOMPARE(gridview->currentIndex(), 2); |
4483 | QCOMPARE(currentIndexSpy.count(), 1); |
4484 | } |
4485 | |
4486 | // flick to end |
4487 | do { |
4488 | flick(window, from: flickStart, to: flickEnd, duration: flickDuration); |
4489 | QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops |
4490 | } while (flow == QQuickGridView::FlowLeftToRight |
4491 | ? !gridview->isAtYEnd() |
4492 | : layoutDirection == Qt::LeftToRight ? !gridview->isAtXEnd() : !gridview->isAtXBeginning()); |
4493 | |
4494 | if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) { |
4495 | QCOMPARE(gridview->currentIndex(), 6); |
4496 | QCOMPARE(currentIndexSpy.count(), 3); |
4497 | } |
4498 | |
4499 | if (flow == QQuickGridView::FlowLeftToRight) |
4500 | QCOMPARE(gridview->contentY(), endExtent); |
4501 | else |
4502 | QCOMPARE(gridview->contentX(), endExtent); |
4503 | |
4504 | // flick to start |
4505 | do { |
4506 | flick(window, from: flickEnd, to: flickStart, duration: flickDuration); |
4507 | QTRY_VERIFY(gridview->isMoving() == false); // wait until it stops |
4508 | } while (flow == QQuickGridView::FlowLeftToRight |
4509 | ? !gridview->isAtYBeginning() |
4510 | : layoutDirection == Qt::LeftToRight ? !gridview->isAtXBeginning() : !gridview->isAtXEnd()); |
4511 | |
4512 | if (flow == QQuickGridView::FlowLeftToRight) |
4513 | QCOMPARE(gridview->contentY(), startExtent); |
4514 | else |
4515 | QCOMPARE(gridview->contentX(), startExtent); |
4516 | |
4517 | if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) { |
4518 | QCOMPARE(gridview->currentIndex(), 0); |
4519 | QCOMPARE(currentIndexSpy.count(), 6); |
4520 | } |
4521 | |
4522 | releaseView(view: window); |
4523 | } |
4524 | |
4525 | |
4526 | void tst_QQuickGridView::unaligned() |
4527 | { |
4528 | QQuickView *window = createView(); |
4529 | window->show(); |
4530 | |
4531 | QaimModel model; |
4532 | for (int i = 0; i < 10; i++) |
4533 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
4534 | |
4535 | QQmlContext *ctxt = window->rootContext(); |
4536 | ctxt->setContextProperty("testModel" , &model); |
4537 | |
4538 | window->setSource(testFileUrl(fileName: "unaligned.qml" )); |
4539 | qApp->processEvents(); |
4540 | |
4541 | QQuickGridView *gridview = qobject_cast<QQuickGridView*>(object: window->rootObject()); |
4542 | QVERIFY(gridview != nullptr); |
4543 | |
4544 | QQuickItem *contentItem = gridview->contentItem(); |
4545 | QVERIFY(contentItem != nullptr); |
4546 | |
4547 | for (int i = 0; i < 10; ++i) { |
4548 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
4549 | if (!item) qWarning() << "Item" << i << "not found" ; |
4550 | QVERIFY(item); |
4551 | QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth())); |
4552 | QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight())); |
4553 | } |
4554 | |
4555 | // appending |
4556 | for (int i = 10; i < 18; ++i) { |
4557 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
4558 | QQuickItem *item = nullptr; |
4559 | QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper" , i)); |
4560 | QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth())); |
4561 | QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight())); |
4562 | } |
4563 | |
4564 | // inserting |
4565 | for (int i = 0; i < 10; ++i) { |
4566 | model.insertItem(index: i, name: "Item" + QString::number(i), number: "" ); |
4567 | QQuickItem *item = nullptr; |
4568 | QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper" , i)); |
4569 | QCOMPARE(item->x(), qreal((i%9)*gridview->cellWidth())); |
4570 | QCOMPARE(item->y(), qreal((i/9)*gridview->cellHeight())); |
4571 | } |
4572 | |
4573 | // removing |
4574 | model.removeItems(index: 7, count: 10); |
4575 | gridview->forceLayout(); |
4576 | QTRY_COMPARE(model.count(), gridview->count()); |
4577 | for (int i = 0; i < 18; ++i) { |
4578 | QQuickItem *item = nullptr; |
4579 | QTRY_VERIFY(item = findItem<QQuickItem>(contentItem, "wrapper" , i)); |
4580 | QCOMPARE(item->x(), qreal(i%9)*gridview->cellWidth()); |
4581 | QCOMPARE(item->y(), qreal(i/9)*gridview->cellHeight()); |
4582 | } |
4583 | |
4584 | delete window; |
4585 | } |
4586 | |
4587 | void tst_QQuickGridView::populateTransitions() |
4588 | { |
4589 | QFETCH(bool, staticallyPopulate); |
4590 | QFETCH(bool, dynamicallyPopulate); |
4591 | QFETCH(bool, usePopulateTransition); |
4592 | |
4593 | QPointF transitionFrom(-50, -50); |
4594 | QPointF transitionVia(100, 100); |
4595 | QaimModel model_transitionFrom; |
4596 | QaimModel model_transitionVia; |
4597 | |
4598 | QaimModel model; |
4599 | if (staticallyPopulate) { |
4600 | for (int i = 0; i < 30; i++) |
4601 | model.addItem(name: "item" + QString::number(i), number: "" ); |
4602 | } |
4603 | |
4604 | QQuickView *window = getView(); |
4605 | window->rootContext()->setContextProperty("testModel" , &model); |
4606 | window->rootContext()->setContextProperty("usePopulateTransition" , usePopulateTransition); |
4607 | window->rootContext()->setContextProperty("dynamicallyPopulate" , dynamicallyPopulate); |
4608 | window->rootContext()->setContextProperty("transitionFrom" , transitionFrom); |
4609 | window->rootContext()->setContextProperty("transitionVia" , transitionVia); |
4610 | window->rootContext()->setContextProperty("model_transitionFrom" , &model_transitionFrom); |
4611 | window->rootContext()->setContextProperty("model_transitionVia" , &model_transitionVia); |
4612 | window->setSource(testFileUrl(fileName: "populateTransitions.qml" )); |
4613 | window->show(); |
4614 | |
4615 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
4616 | QVERIFY(gridview); |
4617 | QQuickItem *contentItem = gridview->contentItem(); |
4618 | QVERIFY(contentItem); |
4619 | |
4620 | // check the populate transition is run |
4621 | if (staticallyPopulate && usePopulateTransition) { |
4622 | QTRY_COMPARE(gridview->property("countPopulateTransitions" ).toInt(), 18); |
4623 | QTRY_COMPARE(gridview->property("countAddTransitions" ).toInt(), 0); |
4624 | } else if (dynamicallyPopulate) { |
4625 | QTRY_COMPARE(gridview->property("countPopulateTransitions" ).toInt(), 0); |
4626 | QTRY_COMPARE(gridview->property("countAddTransitions" ).toInt(), 18); |
4627 | } else { |
4628 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
4629 | QCOMPARE(gridview->property("countPopulateTransitions" ).toInt(), 0); |
4630 | QCOMPARE(gridview->property("countAddTransitions" ).toInt(), 0); |
4631 | } |
4632 | |
4633 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
4634 | for (int i=0; i < model.count() && i < itemCount; ++i) { |
4635 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
4636 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
4637 | QTRY_COMPARE(item->x(), (i%3)*80.0); |
4638 | QTRY_COMPARE(item->y(), (i/3)*60.0); |
4639 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
4640 | QVERIFY(name != nullptr); |
4641 | QTRY_COMPARE(name->text(), model.name(i)); |
4642 | } |
4643 | |
4644 | gridview->setProperty(name: "countPopulateTransitions" , value: 0); |
4645 | gridview->setProperty(name: "countAddTransitions" , value: 0); |
4646 | |
4647 | // add an item and check this is done with add transition, not populate |
4648 | model.insertItem(index: 0, name: "another item" , number: "" ); |
4649 | QTRY_COMPARE(gridview->property("countAddTransitions" ).toInt(), 1); |
4650 | QTRY_COMPARE(gridview->property("countPopulateTransitions" ).toInt(), 0); |
4651 | |
4652 | // clear the model |
4653 | window->rootContext()->setContextProperty("testModel" , QVariant()); |
4654 | QTRY_COMPARE(gridview->count(), 0); |
4655 | QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper" ).count(), 0); |
4656 | gridview->setProperty(name: "countPopulateTransitions" , value: 0); |
4657 | gridview->setProperty(name: "countAddTransitions" , value: 0); |
4658 | |
4659 | // set to a valid model and check populate transition is run a second time |
4660 | model.clear(); |
4661 | for (int i = 0; i < 30; i++) |
4662 | model.addItem(name: "item" + QString::number(i), number: "" ); |
4663 | window->rootContext()->setContextProperty("testModel" , &model); |
4664 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
4665 | |
4666 | QTRY_COMPARE(gridview->property("countPopulateTransitions" ).toInt(), usePopulateTransition ? 18 : 0); |
4667 | QTRY_COMPARE(gridview->property("countAddTransitions" ).toInt(), 0); |
4668 | |
4669 | itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
4670 | for (int i=0; i < model.count() && i < itemCount; ++i) { |
4671 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
4672 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
4673 | QTRY_COMPARE(item->x(), (i%3)*80.0); |
4674 | QTRY_COMPARE(item->y(), (i/3)*60.0); |
4675 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
4676 | QVERIFY(name != nullptr); |
4677 | QTRY_COMPARE(name->text(), model.name(i)); |
4678 | } |
4679 | |
4680 | // reset model and check populate transition is run again |
4681 | gridview->setProperty(name: "countPopulateTransitions" , value: 0); |
4682 | gridview->setProperty(name: "countAddTransitions" , value: 0); |
4683 | model.reset(); |
4684 | QTRY_COMPARE(gridview->property("countPopulateTransitions" ).toInt(), usePopulateTransition ? 18 : 0); |
4685 | QTRY_COMPARE(gridview->property("countAddTransitions" ).toInt(), 0); |
4686 | |
4687 | itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
4688 | for (int i=0; i < model.count() && i < itemCount; ++i) { |
4689 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
4690 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
4691 | QTRY_COMPARE(item->x(), (i%3)*80.0); |
4692 | QTRY_COMPARE(item->y(), (i/3)*60.0); |
4693 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
4694 | QVERIFY(name != nullptr); |
4695 | QTRY_COMPARE(name->text(), model.name(i)); |
4696 | } |
4697 | |
4698 | releaseView(view: window); |
4699 | } |
4700 | |
4701 | void tst_QQuickGridView::populateTransitions_data() |
4702 | { |
4703 | QTest::addColumn<bool>(name: "staticallyPopulate" ); |
4704 | QTest::addColumn<bool>(name: "dynamicallyPopulate" ); |
4705 | QTest::addColumn<bool>(name: "usePopulateTransition" ); |
4706 | |
4707 | QTest::newRow(dataTag: "static" ) << true << false << true; |
4708 | QTest::newRow(dataTag: "static, no populate" ) << true << false << false; |
4709 | |
4710 | QTest::newRow(dataTag: "dynamic" ) << false << true << true; |
4711 | QTest::newRow(dataTag: "dynamic, no populate" ) << false << true << false; |
4712 | |
4713 | QTest::newRow(dataTag: "empty to start with" ) << false << false << true; |
4714 | QTest::newRow(dataTag: "empty to start with, no populate" ) << false << false << false; |
4715 | } |
4716 | |
4717 | void tst_QQuickGridView::addTransitions() |
4718 | { |
4719 | QFETCH(int, initialItemCount); |
4720 | QFETCH(bool, shouldAnimateTargets); |
4721 | QFETCH(qreal, contentYRowOffset); |
4722 | QFETCH(int, insertionIndex); |
4723 | QFETCH(int, insertionCount); |
4724 | QFETCH(ListRange, expectedDisplacedIndexes); |
4725 | |
4726 | // added items should start here |
4727 | QPointF targetItems_transitionFrom(-50, -50); |
4728 | |
4729 | // displaced items should pass through this point |
4730 | QPointF displacedItems_transitionVia(100, 100); |
4731 | |
4732 | QaimModel model; |
4733 | for (int i = 0; i < initialItemCount; i++) |
4734 | model.addItem(name: "Original item" + QString::number(i), number: "" ); |
4735 | QaimModel model_targetItems_transitionFrom; |
4736 | QaimModel model_displacedItems_transitionVia; |
4737 | |
4738 | QQuickView *window = getView(); |
4739 | QQmlContext *ctxt = window->rootContext(); |
4740 | ctxt->setContextProperty("testModel" , &model); |
4741 | ctxt->setContextProperty("model_targetItems_transitionFrom" , &model_targetItems_transitionFrom); |
4742 | ctxt->setContextProperty("model_displacedItems_transitionVia" , &model_displacedItems_transitionVia); |
4743 | ctxt->setContextProperty("targetItems_transitionFrom" , targetItems_transitionFrom); |
4744 | ctxt->setContextProperty("displacedItems_transitionVia" , displacedItems_transitionVia); |
4745 | window->setSource(testFileUrl(fileName: "addTransitions.qml" )); |
4746 | window->show(); |
4747 | |
4748 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
4749 | QTRY_VERIFY(gridview != nullptr); |
4750 | QQuickItem *contentItem = gridview->contentItem(); |
4751 | QVERIFY(contentItem != nullptr); |
4752 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
4753 | |
4754 | if (contentYRowOffset != 0) { |
4755 | gridview->setContentY(contentYRowOffset * 60.0); |
4756 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
4757 | } |
4758 | |
4759 | QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); |
4760 | |
4761 | // only target items that will become visible should be animated |
4762 | QList<QPair<QString, QString> > newData; |
4763 | QList<QPair<QString, QString> > expectedTargetData; |
4764 | QList<int> targetIndexes; |
4765 | if (shouldAnimateTargets) { |
4766 | for (int i=insertionIndex; i<insertionIndex+insertionCount; i++) { |
4767 | newData << qMakePair(x: QString("New item %1" ).arg(a: i), y: QString("" )); |
4768 | |
4769 | // last visible item is the first item of the row beneath the view |
4770 | if (i >= (gridview->contentY() / 60)*3 && i < qCeil(v: (gridview->contentY() + gridview->height()) / 60.0)*3) { |
4771 | expectedTargetData << newData.last(); |
4772 | targetIndexes << i; |
4773 | } |
4774 | } |
4775 | QVERIFY(expectedTargetData.count() > 0); |
4776 | } |
4777 | |
4778 | // start animation |
4779 | if (!newData.isEmpty()) { |
4780 | model.insertItems(index: insertionIndex, items: newData); |
4781 | gridview->forceLayout(); |
4782 | QTRY_COMPARE(model.count(), gridview->count()); |
4783 | } |
4784 | |
4785 | QList<QQuickItem *> targetItems = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" , indexes: targetIndexes); |
4786 | |
4787 | if (shouldAnimateTargets) { |
4788 | QTRY_COMPARE(gridview->property("targetTransitionsDone" ).toInt(), expectedTargetData.count()); |
4789 | QTRY_COMPARE(gridview->property("displaceTransitionsDone" ).toInt(), |
4790 | expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0); |
4791 | |
4792 | // check the target and displaced items were animated |
4793 | model_targetItems_transitionFrom.matchAgainst(other: expectedTargetData, error1: "wasn't animated from target 'from' pos" , error2: "shouldn't have been animated from target 'from' pos" ); |
4794 | model_displacedItems_transitionVia.matchAgainst(other: expectedDisplacedValues, error1: "wasn't animated with displaced anim" , error2: "shouldn't have been animated with displaced anim" ); |
4795 | |
4796 | // check attached properties |
4797 | matchItemsAndIndexes(items: gridview->property(name: "targetTrans_items" ).toMap(), model, expectedIndexes: targetIndexes); |
4798 | matchIndexLists(indexLists: gridview->property(name: "targetTrans_targetIndexes" ).toList(), expectedIndexes: targetIndexes); |
4799 | matchItemLists(itemLists: gridview->property(name: "targetTrans_targetItems" ).toList(), expectedItems: targetItems); |
4800 | if (expectedDisplacedIndexes.isValid()) { |
4801 | // adjust expectedDisplacedIndexes to their final values after the move |
4802 | QList<int> displacedIndexes = adjustIndexesForAddDisplaced(indexes: expectedDisplacedIndexes.indexes, index: insertionIndex, count: insertionCount); |
4803 | matchItemsAndIndexes(items: gridview->property(name: "displacedTrans_items" ).toMap(), model, expectedIndexes: displacedIndexes); |
4804 | matchIndexLists(indexLists: gridview->property(name: "displacedTrans_targetIndexes" ).toList(), expectedIndexes: targetIndexes); |
4805 | matchItemLists(itemLists: gridview->property(name: "displacedTrans_targetItems" ).toList(), expectedItems: targetItems); |
4806 | } |
4807 | } else { |
4808 | QTRY_COMPARE(model_targetItems_transitionFrom.count(), 0); |
4809 | QTRY_COMPARE(model_displacedItems_transitionVia.count(), 0); |
4810 | } |
4811 | |
4812 | QList<QQuickItem*> items = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ); |
4813 | int firstVisibleIndex = -1; |
4814 | for (int i=0; i<items.count(); i++) { |
4815 | if (items[i]->y() >= gridview->contentY()) { |
4816 | QQmlExpression e(qmlContext(items[i]), items[i], "index" ); |
4817 | firstVisibleIndex = e.evaluate().toInt(); |
4818 | break; |
4819 | } |
4820 | } |
4821 | QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); |
4822 | |
4823 | // verify all items moved to the correct final positions |
4824 | for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) { |
4825 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
4826 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
4827 | QCOMPARE(item->x(), (i%3)*80.0); |
4828 | QCOMPARE(item->y(), (i/3)*60.0); |
4829 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
4830 | QVERIFY(name != nullptr); |
4831 | QCOMPARE(name->text(), model.name(i)); |
4832 | } |
4833 | |
4834 | releaseView(view: window); |
4835 | } |
4836 | |
4837 | void tst_QQuickGridView::addTransitions_data() |
4838 | { |
4839 | QTest::addColumn<int>(name: "initialItemCount" ); |
4840 | QTest::addColumn<qreal>(name: "contentYRowOffset" ); |
4841 | QTest::addColumn<bool>(name: "shouldAnimateTargets" ); |
4842 | QTest::addColumn<int>(name: "insertionIndex" ); |
4843 | QTest::addColumn<int>(name: "insertionCount" ); |
4844 | QTest::addColumn<ListRange>(name: "expectedDisplacedIndexes" ); |
4845 | |
4846 | // if inserting a full row before visible index, items don't appear or animate in, even if there are > 1 new items |
4847 | QTest::newRow(dataTag: "insert 1, just before start" ) |
4848 | << 30 << 1.0 << false |
4849 | << 0 << 1 << ListRange(); |
4850 | QTest::newRow(dataTag: "insert 1, way before start" ) |
4851 | << 30 << 1.0 << false |
4852 | << 0 << 1 << ListRange(); |
4853 | QTest::newRow(dataTag: "insert multiple, just before start" ) |
4854 | << 30 << 1.0 << false |
4855 | << 0 << 3 << ListRange(); |
4856 | QTest::newRow(dataTag: "insert multiple (< 1 row), just before start" ) |
4857 | << 30 << 1.0 << false |
4858 | << 0 << 2 << ListRange(); |
4859 | QTest::newRow(dataTag: "insert multiple, way before start" ) |
4860 | << 30 << 3.0 << false |
4861 | << 0 << 3 << ListRange(); |
4862 | |
4863 | QTest::newRow(dataTag: "insert 1 at start" ) |
4864 | << 30 << 0.0 << true |
4865 | << 0 << 1 << ListRange(0, 17); |
4866 | QTest::newRow(dataTag: "insert multiple at start" ) |
4867 | << 30 << 0.0 << true |
4868 | << 0 << 3 << ListRange(0, 17); |
4869 | QTest::newRow(dataTag: "insert multiple (> 1 row) at start" ) |
4870 | << 30 << 0.0 << true |
4871 | << 0 << 5 << ListRange(0, 17); |
4872 | QTest::newRow(dataTag: "insert 1 at start, content y not 0" ) |
4873 | << 30 << 1.0 << true // first visible is index 3 |
4874 | << 3 << 1 << ListRange(0 + 3, 17 + 3); |
4875 | QTest::newRow(dataTag: "insert multiple at start, content y not 0" ) |
4876 | << 30 << 1.0 << true // first visible is index 3 |
4877 | << 3 << 3 << ListRange(0 + 3, 17 + 3); |
4878 | QTest::newRow(dataTag: "insert multiple (> 1 row) at start, content y not 0" ) |
4879 | << 30 << 1.0 << true // first visible is index 3 |
4880 | << 3 << 5 << ListRange(0 + 3, 17 + 3); |
4881 | |
4882 | QTest::newRow(dataTag: "insert 1 at start, to empty grid" ) |
4883 | << 0 << 0.0 << true |
4884 | << 0 << 1 << ListRange(); |
4885 | QTest::newRow(dataTag: "insert multiple at start, to empty grid" ) |
4886 | << 0 << 0.0 << true |
4887 | << 0 << 3 << ListRange(); |
4888 | |
4889 | QTest::newRow(dataTag: "insert 1 at middle" ) |
4890 | << 30 << 0.0 << true |
4891 | << 7 << 1 << ListRange(7, 17); |
4892 | QTest::newRow(dataTag: "insert multiple at middle" ) |
4893 | << 30 << 0.0 << true |
4894 | << 7 << 3 << ListRange(7, 17); |
4895 | QTest::newRow(dataTag: "insert multiple (> 1 row) at middle" ) |
4896 | << 30 << 0.0 << true |
4897 | << 7 << 5 << ListRange(7, 17); |
4898 | |
4899 | QTest::newRow(dataTag: "insert 1 at bottom" ) |
4900 | << 30 << 0.0 << true |
4901 | << 17 << 1 << ListRange(17, 17); |
4902 | QTest::newRow(dataTag: "insert multiple at bottom" ) |
4903 | << 30 << 0.0 << true |
4904 | << 17 << 3 << ListRange(17, 17); |
4905 | QTest::newRow(dataTag: "insert 1 at bottom, content y not 0" ) |
4906 | << 30 << 1.0 << true |
4907 | << 17 + 3 << 1 << ListRange(17 + 3, 17 + 3); |
4908 | QTest::newRow(dataTag: "insert multiple at bottom, content y not 0" ) |
4909 | << 30 << 1.0 << true |
4910 | << 17 + 3 << 3 << ListRange(17 + 3, 17 + 3); |
4911 | |
4912 | |
4913 | // items added after the last visible will not be animated in, since they |
4914 | // do not appear in the final view |
4915 | QTest::newRow(dataTag: "insert 1 after end" ) |
4916 | << 30 << 0.0 << false |
4917 | << 18 << 1 << ListRange(); |
4918 | QTest::newRow(dataTag: "insert multiple after end" ) |
4919 | << 30 << 0.0 << false |
4920 | << 18 << 3 << ListRange(); |
4921 | } |
4922 | |
4923 | void tst_QQuickGridView::moveTransitions() |
4924 | { |
4925 | QFETCH(int, initialItemCount); |
4926 | QFETCH(qreal, contentYRowOffset); |
4927 | QFETCH(qreal, rowOffsetAfterMove); |
4928 | QFETCH(int, moveFrom); |
4929 | QFETCH(int, moveTo); |
4930 | QFETCH(int, moveCount); |
4931 | QFETCH(ListRange, expectedDisplacedIndexes); |
4932 | |
4933 | // target and displaced items should pass through these points |
4934 | QPointF targetItems_transitionVia(-50, 50); |
4935 | QPointF displacedItems_transitionVia(100, 100); |
4936 | |
4937 | QaimModel model; |
4938 | for (int i = 0; i < initialItemCount; i++) |
4939 | model.addItem(name: "Original item" + QString::number(i), number: "" ); |
4940 | QaimModel model_targetItems_transitionVia; |
4941 | QaimModel model_displacedItems_transitionVia; |
4942 | |
4943 | QQuickView *window = getView(); |
4944 | QQmlContext *ctxt = window->rootContext(); |
4945 | ctxt->setContextProperty("testModel" , &model); |
4946 | ctxt->setContextProperty("model_targetItems_transitionVia" , &model_targetItems_transitionVia); |
4947 | ctxt->setContextProperty("model_displacedItems_transitionVia" , &model_displacedItems_transitionVia); |
4948 | ctxt->setContextProperty("targetItems_transitionVia" , targetItems_transitionVia); |
4949 | ctxt->setContextProperty("displacedItems_transitionVia" , displacedItems_transitionVia); |
4950 | window->setSource(testFileUrl(fileName: "moveTransitions.qml" )); |
4951 | window->show(); |
4952 | |
4953 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
4954 | QTRY_VERIFY(gridview != nullptr); |
4955 | QQuickItem *contentItem = gridview->contentItem(); |
4956 | QVERIFY(contentItem != nullptr); |
4957 | QQuickText *name; |
4958 | |
4959 | if (contentYRowOffset != 0) { |
4960 | gridview->setContentY(contentYRowOffset * 60.0); |
4961 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
4962 | } |
4963 | |
4964 | QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); |
4965 | |
4966 | // Items moving to *or* from visible positions should be animated. |
4967 | // Otherwise, they should not be animated. |
4968 | QList<QPair<QString, QString> > expectedTargetData; |
4969 | QList<int> targetIndexes; |
4970 | for (int i=moveFrom; i<moveFrom+moveCount; i++) { |
4971 | int toIndex = moveTo + (i - moveFrom); |
4972 | int firstVisibleIndex = (gridview->contentY() / 60) * 3; |
4973 | int lastVisibleIndex = (qCeil(v: (gridview->contentY() + gridview->height()) / 60.0)*3) - 1; |
4974 | if ((i >= firstVisibleIndex && i <= lastVisibleIndex) |
4975 | || (toIndex >= firstVisibleIndex && toIndex <= lastVisibleIndex)) { |
4976 | expectedTargetData << qMakePair(x: model.name(index: i), y: model.number(index: i)); |
4977 | targetIndexes << i; |
4978 | } |
4979 | } |
4980 | // ViewTransition.index provides the indices that items are moving to, not from |
4981 | targetIndexes = adjustIndexesForMove(indexes: targetIndexes, from: moveFrom, to: moveTo, count: moveCount); |
4982 | |
4983 | // start animation |
4984 | model.moveItems(from: moveFrom, to: moveTo, count: moveCount); |
4985 | gridview->forceLayout(); |
4986 | |
4987 | QTRY_COMPARE(gridview->property("targetTransitionsDone" ).toInt(), expectedTargetData.count()); |
4988 | QTRY_COMPARE(gridview->property("displaceTransitionsDone" ).toInt(), |
4989 | expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0); |
4990 | |
4991 | QList<QQuickItem *> targetItems = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" , indexes: targetIndexes); |
4992 | |
4993 | // check the target and displaced items were animated |
4994 | model_targetItems_transitionVia.matchAgainst(other: expectedTargetData, error1: "wasn't animated from target 'from' pos" , error2: "shouldn't have been animated from target 'from' pos" ); |
4995 | model_displacedItems_transitionVia.matchAgainst(other: expectedDisplacedValues, error1: "wasn't animated with displaced anim" , error2: "shouldn't have been animated with displaced anim" ); |
4996 | |
4997 | // check attached properties |
4998 | matchItemsAndIndexes(items: gridview->property(name: "targetTrans_items" ).toMap(), model, expectedIndexes: targetIndexes); |
4999 | matchIndexLists(indexLists: gridview->property(name: "targetTrans_targetIndexes" ).toList(), expectedIndexes: targetIndexes); |
5000 | matchItemLists(itemLists: gridview->property(name: "targetTrans_targetItems" ).toList(), expectedItems: targetItems); |
5001 | if (expectedDisplacedIndexes.isValid()) { |
5002 | // adjust expectedDisplacedIndexes to their final values after the move |
5003 | QList<int> displacedIndexes = adjustIndexesForMove(indexes: expectedDisplacedIndexes.indexes, from: moveFrom, to: moveTo, count: moveCount); |
5004 | matchItemsAndIndexes(items: gridview->property(name: "displacedTrans_items" ).toMap(), model, expectedIndexes: displacedIndexes); |
5005 | matchIndexLists(indexLists: gridview->property(name: "displacedTrans_targetIndexes" ).toList(), expectedIndexes: targetIndexes); |
5006 | matchItemLists(itemLists: gridview->property(name: "displacedTrans_targetItems" ).toList(), expectedItems: targetItems); |
5007 | } |
5008 | |
5009 | QList<QQuickItem*> items = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ); |
5010 | int firstVisibleIndex = -1; |
5011 | for (int i=0; i<items.count(); i++) { |
5012 | if (items[i]->y() >= gridview->contentY()) { |
5013 | QQmlExpression e(qmlContext(items[i]), items[i], "index" ); |
5014 | firstVisibleIndex = e.evaluate().toInt(); |
5015 | break; |
5016 | } |
5017 | } |
5018 | QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); |
5019 | |
5020 | // verify all items moved to the correct final positions |
5021 | qreal pixelOffset = 60 * rowOffsetAfterMove; |
5022 | for (int i=firstVisibleIndex; i < model.count() && i < items.count(); ++i) { |
5023 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
5024 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
5025 | QCOMPARE(item->x(), (i%3)*80.0); |
5026 | QCOMPARE(item->y(), (i/3)*60.0 + pixelOffset); |
5027 | name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
5028 | QVERIFY(name != nullptr); |
5029 | QTRY_COMPARE(name->text(), model.name(i)); |
5030 | } |
5031 | |
5032 | releaseView(view: window); |
5033 | } |
5034 | |
5035 | void tst_QQuickGridView::moveTransitions_data() |
5036 | { |
5037 | QTest::addColumn<int>(name: "initialItemCount" ); |
5038 | QTest::addColumn<qreal>(name: "contentYRowOffset" ); |
5039 | QTest::addColumn<qreal>(name: "rowOffsetAfterMove" ); |
5040 | QTest::addColumn<int>(name: "moveFrom" ); |
5041 | QTest::addColumn<int>(name: "moveTo" ); |
5042 | QTest::addColumn<int>(name: "moveCount" ); |
5043 | QTest::addColumn<ListRange>(name: "expectedDisplacedIndexes" ); |
5044 | |
5045 | QTest::newRow(dataTag: "move from above view, outside visible items, move 1" ) |
5046 | << 30 << 2.0 << 0.0 |
5047 | << 1 << 10 << 1 << ListRange(6, 10); |
5048 | QTest::newRow(dataTag: "move from above view, outside visible items, move 1 (first item)" ) |
5049 | << 30 << 2.0 << 0.0 |
5050 | << 0 << 10 << 1 << ListRange(6, 10); |
5051 | QTest::newRow(dataTag: "move from above view, outside visible items, move multiple" ) |
5052 | << 30 << 2.0 << 1.0 |
5053 | << 1 << 10 << 3 << ListRange(13, 23); |
5054 | QTest::newRow(dataTag: "move from above view, mix of visible/non-visible" ) |
5055 | << 30 << 2.0 << 1.0 |
5056 | << 1 << 10 << 6 << (ListRange(7, 15) + ListRange(16, 23)); |
5057 | QTest::newRow(dataTag: "move from above view, mix of visible/non-visible (move first)" ) |
5058 | << 30 << 2.0 << 2.0 |
5059 | << 0 << 10 << 6 << ListRange(16, 23); |
5060 | |
5061 | QTest::newRow(dataTag: "move within view, move 1 down" ) |
5062 | << 30 << 0.0 << 0.0 |
5063 | << 1 << 10 << 1 << ListRange(2, 10); |
5064 | QTest::newRow(dataTag: "move within view, move 1 down, move first item" ) |
5065 | << 30 << 0.0 << 0.0 |
5066 | << 0 << 10 << 1 << ListRange(1, 10); |
5067 | QTest::newRow(dataTag: "move within view, move 1 down, move first item, contentY not 0" ) |
5068 | << 30 << 2.0 << 0.0 |
5069 | << 0+6 << 10+6 << 1 << ListRange(1+6, 10+6); |
5070 | QTest::newRow(dataTag: "move within view, move 1 down, to last item" ) |
5071 | << 30 << 0.0 << 0.0 |
5072 | << 10 << 17 << 1 << ListRange(11, 17); |
5073 | QTest::newRow(dataTag: "move within view, move first->last" ) |
5074 | << 30 << 0.0 << 0.0 |
5075 | << 0 << 17 << 1 << ListRange(1, 17); |
5076 | |
5077 | QTest::newRow(dataTag: "move within view, move multiple down" ) |
5078 | << 30 << 0.0 << 0.0 |
5079 | << 1 << 10 << 3 << ListRange(4, 12); |
5080 | QTest::newRow(dataTag: "move within view, move multiple down, move first item" ) |
5081 | << 30 << 0.0 << 0.0 |
5082 | << 0 << 10 << 3 << ListRange(3, 12); |
5083 | QTest::newRow(dataTag: "move within view, move multiple down, move first item, contentY not 0" ) |
5084 | << 30 << 1.0 << 0.0 |
5085 | << 0+3 << 10+3 << 3 << ListRange(3+3, 12+3); |
5086 | QTest::newRow(dataTag: "move within view, move multiple down, displace last item" ) |
5087 | << 30 << 0.0 << 0.0 |
5088 | << 5 << 15 << 3 << ListRange(8, 17); |
5089 | QTest::newRow(dataTag: "move within view, move multiple down, move first->last" ) |
5090 | << 30 << 0.0 << 0.0 |
5091 | << 0 << 15 << 3 << ListRange(3, 17); |
5092 | |
5093 | QTest::newRow(dataTag: "move within view, move 1 up" ) |
5094 | << 30 << 0.0 << 0.0 |
5095 | << 10 << 1 << 1 << ListRange(1, 9); |
5096 | QTest::newRow(dataTag: "move within view, move 1 up, move to first index" ) |
5097 | << 30 << 0.0 << 0.0 |
5098 | << 10 << 0 << 1 << ListRange(0, 9); |
5099 | QTest::newRow(dataTag: "move within view, move 1 up, move to first index, contentY not 0" ) |
5100 | << 30 << 2.0 << 0.0 |
5101 | << 10+6 << 0+6 << 1 << ListRange(0+6, 9+6); |
5102 | QTest::newRow(dataTag: "move within view, move 1 up, move to first index, contentY not on item border" ) |
5103 | << 30 << 1.5 << 0.0 |
5104 | << 10+3 << 0+3 << 1 << ListRange(0+3, 9+3); |
5105 | QTest::newRow(dataTag: "move within view, move 1 up, move last item" ) |
5106 | << 30 << 0.0 << 0.0 |
5107 | << 17 << 10 << 1 << ListRange(10, 16); |
5108 | QTest::newRow(dataTag: "move within view, move 1 up, move last->first" ) |
5109 | << 30 << 0.0 << 0.0 |
5110 | << 17 << 0 << 1 << ListRange(0, 16); |
5111 | |
5112 | QTest::newRow(dataTag: "move within view, move multiple up" ) |
5113 | << 30 << 0.0 << 0.0 |
5114 | << 10 << 1 << 3 << ListRange(1, 9); |
5115 | QTest::newRow(dataTag: "move within view, move multiple (> 1 row) up" ) |
5116 | << 30 << 0.0 << 0.0 |
5117 | << 10 << 1 << 5 << ListRange(1, 9); |
5118 | QTest::newRow(dataTag: "move within view, move multiple up, move to first index" ) |
5119 | << 30 << 0.0 << 0.0 |
5120 | << 10 << 0 << 3 << ListRange(0, 9); |
5121 | QTest::newRow(dataTag: "move within view, move multiple up, move to first index, contentY not 0" ) |
5122 | << 30 << 1.0 << 0.0 |
5123 | << 10+3 << 0+3 << 3 << ListRange(0+3, 9+3); |
5124 | QTest::newRow(dataTag: "move within view, move multiple up (> 1 row), move to first index, contentY not on border" ) |
5125 | << 30 << 1.5 << 0.0 |
5126 | << 10+3 << 0+3 << 5 << ListRange(0+3, 9+3); |
5127 | QTest::newRow(dataTag: "move within view, move multiple up, move last item" ) |
5128 | << 30 << 0.0 << 0.0 |
5129 | << 15 << 5 << 3 << ListRange(5, 14); |
5130 | QTest::newRow(dataTag: "move within view, move multiple up, move last->first" ) |
5131 | << 30 << 0.0 << 0.0 |
5132 | << 15 << 0 << 3 << ListRange(0, 14); |
5133 | |
5134 | QTest::newRow(dataTag: "move from below view, move 1 up" ) |
5135 | << 30 << 0.0 << 0.0 |
5136 | << 20 << 5 << 1 << ListRange(5, 17); |
5137 | QTest::newRow(dataTag: "move from below view, move 1 up, move to top" ) |
5138 | << 30 << 0.0 << 0.0 |
5139 | << 20 << 0 << 1 << ListRange(0, 17); |
5140 | QTest::newRow(dataTag: "move from below view, move 1 up, move to top, contentY not 0" ) |
5141 | << 30 << 1.0 << 0.0 |
5142 | << 25 << 3 << 1 << ListRange(0+3, 17+3); |
5143 | QTest::newRow(dataTag: "move from below view, move multiple (> 1 row) up" ) |
5144 | << 30 << 0.0 << 0.0 |
5145 | << 20 << 5 << 5 << ListRange(5, 17); |
5146 | QTest::newRow(dataTag: "move from below view, move multiple up, move to top" ) |
5147 | << 30 << 0.0 << 0.0 |
5148 | << 20 << 0 << 3 << ListRange(0, 17); |
5149 | QTest::newRow(dataTag: "move from below view, move multiple up, move to top, contentY not 0" ) |
5150 | << 30 << 1.0 << 0.0 |
5151 | << 25 << 3 << 3 << ListRange(0+3, 17+3); |
5152 | |
5153 | QTest::newRow(dataTag: "move from below view, move 1 up, move to bottom" ) |
5154 | << 30 << 0.0 << 0.0 |
5155 | << 20 << 17 << 1 << ListRange(17, 17); |
5156 | QTest::newRow(dataTag: "move from below view, move 1 up, move to bottom, contentY not 0" ) |
5157 | << 30 << 1.0 << 0.0 |
5158 | << 25 << 17+3 << 1 << ListRange(17+3, 17+3); |
5159 | QTest::newRow(dataTag: "move from below view, move multiple up, move to bottom" ) |
5160 | << 30 << 0.0 << 0.0 |
5161 | << 20 << 17 << 3 << ListRange(17, 17); |
5162 | QTest::newRow(dataTag: "move from below view, move multiple up, move to bottom, contentY not 0" ) |
5163 | << 30 << 1.0 << 0.0 |
5164 | << 25 << 17+3 << 3 << ListRange(17+3, 17+3); |
5165 | } |
5166 | |
5167 | void tst_QQuickGridView::removeTransitions() |
5168 | { |
5169 | QFETCH(int, initialItemCount); |
5170 | QFETCH(bool, shouldAnimateTargets); |
5171 | QFETCH(qreal, contentYRowOffset); |
5172 | QFETCH(int, removalIndex); |
5173 | QFETCH(int, removalCount); |
5174 | QFETCH(ListRange, expectedDisplacedIndexes); |
5175 | |
5176 | // added items should end here |
5177 | QPointF targetItems_transitionTo(-50, -50); |
5178 | |
5179 | // displaced items should pass through this points |
5180 | QPointF displacedItems_transitionVia(100, 100); |
5181 | |
5182 | QaimModel model; |
5183 | for (int i = 0; i < initialItemCount; i++) |
5184 | model.addItem(name: "Original item" + QString::number(i), number: "" ); |
5185 | QaimModel model_targetItems_transitionTo; |
5186 | QaimModel model_displacedItems_transitionVia; |
5187 | |
5188 | QQuickView *window = getView(); |
5189 | QQmlContext *ctxt = window->rootContext(); |
5190 | ctxt->setContextProperty("testModel" , &model); |
5191 | ctxt->setContextProperty("model_targetItems_transitionTo" , &model_targetItems_transitionTo); |
5192 | ctxt->setContextProperty("model_displacedItems_transitionVia" , &model_displacedItems_transitionVia); |
5193 | ctxt->setContextProperty("targetItems_transitionTo" , targetItems_transitionTo); |
5194 | ctxt->setContextProperty("displacedItems_transitionVia" , displacedItems_transitionVia); |
5195 | window->setSource(testFileUrl(fileName: "removeTransitions.qml" )); |
5196 | window->show(); |
5197 | |
5198 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
5199 | QTRY_VERIFY(gridview != nullptr); |
5200 | QQuickItem *contentItem = gridview->contentItem(); |
5201 | QVERIFY(contentItem != nullptr); |
5202 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
5203 | |
5204 | if (contentYRowOffset != 0) { |
5205 | gridview->setContentY(contentYRowOffset * 60.0); |
5206 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
5207 | } |
5208 | |
5209 | QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); |
5210 | |
5211 | // only target items that are visible should be animated |
5212 | QList<QPair<QString, QString> > expectedTargetData; |
5213 | QList<int> targetIndexes; |
5214 | if (shouldAnimateTargets) { |
5215 | for (int i=removalIndex; i<removalIndex+removalCount; i++) { |
5216 | int firstVisibleIndex = (gridview->contentY() / 60.0)*3; |
5217 | int lastVisibleIndex = (qCeil(v: (gridview->contentY() + gridview->height()) / 60.0)*3) - 1; |
5218 | if (i >= firstVisibleIndex && i <= lastVisibleIndex) { |
5219 | expectedTargetData << qMakePair(x: model.name(index: i), y: model.number(index: i)); |
5220 | targetIndexes << i; |
5221 | } |
5222 | } |
5223 | QVERIFY(expectedTargetData.count() > 0); |
5224 | } |
5225 | |
5226 | // calculate targetItems and expectedTargets before model changes |
5227 | QList<QQuickItem *> targetItems = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" , indexes: targetIndexes); |
5228 | QVariantMap expectedTargets; |
5229 | for (int i=0; i<targetIndexes.count(); i++) |
5230 | expectedTargets[model.name(index: targetIndexes[i])] = targetIndexes[i]; |
5231 | |
5232 | // start animation |
5233 | model.removeItems(index: removalIndex, count: removalCount); |
5234 | gridview->forceLayout(); |
5235 | QTRY_COMPARE(model.count(), gridview->count()); |
5236 | |
5237 | if (shouldAnimateTargets || expectedDisplacedIndexes.isValid()) { |
5238 | QTRY_COMPARE(gridview->property("targetTransitionsDone" ).toInt(), expectedTargetData.count()); |
5239 | QTRY_COMPARE(gridview->property("displaceTransitionsDone" ).toInt(), |
5240 | expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0); |
5241 | |
5242 | // check the target and displaced items were animated |
5243 | model_targetItems_transitionTo.matchAgainst(other: expectedTargetData, error1: "wasn't animated to target 'to' pos" , error2: "shouldn't have been animated to target 'to' pos" ); |
5244 | model_displacedItems_transitionVia.matchAgainst(other: expectedDisplacedValues, error1: "wasn't animated with displaced anim" , error2: "shouldn't have been animated with displaced anim" ); |
5245 | |
5246 | // check attached properties |
5247 | QCOMPARE(gridview->property("targetTrans_items" ).toMap(), expectedTargets); |
5248 | matchIndexLists(indexLists: gridview->property(name: "targetTrans_targetIndexes" ).toList(), expectedIndexes: targetIndexes); |
5249 | matchItemLists(itemLists: gridview->property(name: "targetTrans_targetItems" ).toList(), expectedItems: targetItems); |
5250 | if (expectedDisplacedIndexes.isValid()) { |
5251 | // adjust expectedDisplacedIndexes to their final values after the move |
5252 | QList<int> displacedIndexes = adjustIndexesForRemoveDisplaced(indexes: expectedDisplacedIndexes.indexes, index: removalIndex, count: removalCount); |
5253 | matchItemsAndIndexes(items: gridview->property(name: "displacedTrans_items" ).toMap(), model, expectedIndexes: displacedIndexes); |
5254 | matchIndexLists(indexLists: gridview->property(name: "displacedTrans_targetIndexes" ).toList(), expectedIndexes: targetIndexes); |
5255 | matchItemLists(itemLists: gridview->property(name: "displacedTrans_targetItems" ).toList(), expectedItems: targetItems); |
5256 | } |
5257 | } else { |
5258 | QTRY_COMPARE(model_targetItems_transitionTo.count(), 0); |
5259 | QTRY_COMPARE(model_displacedItems_transitionVia.count(), 0); |
5260 | } |
5261 | |
5262 | QList<QQuickItem*> items = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ); |
5263 | int itemCount = items.count(); |
5264 | int firstVisibleIndex = -1; |
5265 | for (int i=0; i<items.count(); i++) { |
5266 | QQmlExpression e(qmlContext(items[i]), items[i], "index" ); |
5267 | int index = e.evaluate().toInt(); |
5268 | if (firstVisibleIndex < 0 && items[i]->y() >= gridview->contentY()) |
5269 | firstVisibleIndex = index; |
5270 | else if (index < 0) |
5271 | itemCount--; // exclude deleted items |
5272 | } |
5273 | QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); |
5274 | |
5275 | // verify all items moved to the correct final positions |
5276 | for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) { |
5277 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
5278 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
5279 | QCOMPARE(item->x(), (i%3)*80.0); |
5280 | QCOMPARE(item->y(), gridview->contentY() + ((i-firstVisibleIndex)/3) * 60.0); |
5281 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
5282 | QVERIFY(name != nullptr); |
5283 | QTRY_COMPARE(name->text(), model.name(i)); |
5284 | } |
5285 | |
5286 | releaseView(view: window); |
5287 | } |
5288 | |
5289 | void tst_QQuickGridView::removeTransitions_data() |
5290 | { |
5291 | QTest::addColumn<int>(name: "initialItemCount" ); |
5292 | QTest::addColumn<qreal>(name: "contentYRowOffset" ); |
5293 | QTest::addColumn<bool>(name: "shouldAnimateTargets" ); |
5294 | QTest::addColumn<int>(name: "removalIndex" ); |
5295 | QTest::addColumn<int>(name: "removalCount" ); |
5296 | QTest::addColumn<ListRange>(name: "expectedDisplacedIndexes" ); |
5297 | |
5298 | // All items that are visible following the remove operation should be animated. |
5299 | // Remove targets that are outside of the view should not be animated. |
5300 | |
5301 | // For a GridView, removing any number of items other than a full row before the start |
5302 | // should displace all items in the view |
5303 | QTest::newRow(dataTag: "remove 1 before start" ) |
5304 | << 30 << 2.0 << false |
5305 | << 2 << 1 << ListRange(6, 24); // 6-24 are displaced |
5306 | QTest::newRow(dataTag: "remove 1 row, before start" ) |
5307 | << 30 << 2.0 << false |
5308 | << 3 << 3 << ListRange(); |
5309 | QTest::newRow(dataTag: "remove between 1-2 rows, before start" ) |
5310 | << 30 << 2.0 << false |
5311 | << 0 << 5 << ListRange(6, 25); |
5312 | QTest::newRow(dataTag: "remove 2 rows, before start" ) |
5313 | << 30 << 2.0 << false |
5314 | << 0 << 6 << ListRange(); |
5315 | QTest::newRow(dataTag: "remove mix of before and after start" ) |
5316 | << 30 << 1.0 << true |
5317 | << 2 << 3 << ListRange(5, 23); // 5-23 are displaced into view |
5318 | |
5319 | |
5320 | QTest::newRow(dataTag: "remove 1 from start" ) |
5321 | << 30 << 0.0 << true |
5322 | << 0 << 1 << ListRange(1, 18); // 1-18 are displaced into view |
5323 | QTest::newRow(dataTag: "remove multiple from start" ) |
5324 | << 30 << 0.0 << true |
5325 | << 0 << 3 << ListRange(3, 20); // 3-18 are displaced into view |
5326 | QTest::newRow(dataTag: "remove 1 from start, content y not 0" ) |
5327 | << 30 << 1.0 << true |
5328 | << 3 << 1 << ListRange(1 + 3, 18 + 3); |
5329 | QTest::newRow(dataTag: "remove multiple from start, content y not 0" ) |
5330 | << 30 << 1.0 << true |
5331 | << 3 << 3 << ListRange(3 + 3, 20 + 3); |
5332 | |
5333 | |
5334 | QTest::newRow(dataTag: "remove 1 from middle" ) |
5335 | << 30 << 0.0 << true |
5336 | << 5 << 1 << ListRange(6, 18); |
5337 | QTest::newRow(dataTag: "remove multiple from middle" ) |
5338 | << 30 << 0.0 << true |
5339 | << 5 << 3 << ListRange(8, 20); |
5340 | |
5341 | |
5342 | QTest::newRow(dataTag: "remove 1 from bottom" ) |
5343 | << 30 << 0.0 << true |
5344 | << 17 << 1 << ListRange(18, 18); |
5345 | QTest::newRow(dataTag: "remove multiple (1 row) from bottom" ) |
5346 | << 30 << 0.0 << true |
5347 | << 15 << 3 << ListRange(18, 20); |
5348 | QTest::newRow(dataTag: "remove multiple (> 1 row) from bottom" ) |
5349 | << 30 << 0.0 << true |
5350 | << 15 << 5 << ListRange(20, 22); |
5351 | QTest::newRow(dataTag: "remove 1 from bottom, content y not 0" ) |
5352 | << 30 << 1.0 << true |
5353 | << 17 + 3 << 1 << ListRange(18 + 3, 18 + 3); |
5354 | QTest::newRow(dataTag: "remove multiple (1 row) from bottom, content y not 0" ) |
5355 | << 30 << 1.0 << true |
5356 | << 15 + 3 << 3 << ListRange(18 + 3, 20 + 3); |
5357 | |
5358 | |
5359 | QTest::newRow(dataTag: "remove 1 after end" ) |
5360 | << 30 << 0.0 << false |
5361 | << 18 << 1 << ListRange(); |
5362 | QTest::newRow(dataTag: "remove multiple after end" ) |
5363 | << 30 << 0.0 << false |
5364 | << 18 << 3 << ListRange(); |
5365 | } |
5366 | |
5367 | void tst_QQuickGridView::displacedTransitions() |
5368 | { |
5369 | QFETCH(bool, useDisplaced); |
5370 | QFETCH(bool, displacedEnabled); |
5371 | QFETCH(bool, useAddDisplaced); |
5372 | QFETCH(bool, addDisplacedEnabled); |
5373 | QFETCH(bool, useMoveDisplaced); |
5374 | QFETCH(bool, moveDisplacedEnabled); |
5375 | QFETCH(bool, useRemoveDisplaced); |
5376 | QFETCH(bool, removeDisplacedEnabled); |
5377 | QFETCH(ListChange, change); |
5378 | QFETCH(ListRange, expectedDisplacedIndexes); |
5379 | |
5380 | QaimModel model; |
5381 | for (int i = 0; i < 30; i++) |
5382 | model.addItem(name: "Original item" + QString::number(i), number: "" ); |
5383 | QaimModel model_displaced_transitionVia; |
5384 | QaimModel model_addDisplaced_transitionVia; |
5385 | QaimModel model_moveDisplaced_transitionVia; |
5386 | QaimModel model_removeDisplaced_transitionVia; |
5387 | |
5388 | QPointF displaced_transitionVia(-50, -100); |
5389 | QPointF addDisplaced_transitionVia(-150, 100); |
5390 | QPointF moveDisplaced_transitionVia(50, -100); |
5391 | QPointF removeDisplaced_transitionVia(150, 100); |
5392 | |
5393 | QQuickView *window = getView(); |
5394 | QQmlContext *ctxt = window->rootContext(); |
5395 | ctxt->setContextProperty("testModel" , &model); |
5396 | ctxt->setContextProperty("model_displaced_transitionVia" , &model_displaced_transitionVia); |
5397 | ctxt->setContextProperty("model_addDisplaced_transitionVia" , &model_addDisplaced_transitionVia); |
5398 | ctxt->setContextProperty("model_moveDisplaced_transitionVia" , &model_moveDisplaced_transitionVia); |
5399 | ctxt->setContextProperty("model_removeDisplaced_transitionVia" , &model_removeDisplaced_transitionVia); |
5400 | ctxt->setContextProperty("displaced_transitionVia" , displaced_transitionVia); |
5401 | ctxt->setContextProperty("addDisplaced_transitionVia" , addDisplaced_transitionVia); |
5402 | ctxt->setContextProperty("moveDisplaced_transitionVia" , moveDisplaced_transitionVia); |
5403 | ctxt->setContextProperty("removeDisplaced_transitionVia" , removeDisplaced_transitionVia); |
5404 | ctxt->setContextProperty("useDisplaced" , useDisplaced); |
5405 | ctxt->setContextProperty("displacedEnabled" , displacedEnabled); |
5406 | ctxt->setContextProperty("useAddDisplaced" , useAddDisplaced); |
5407 | ctxt->setContextProperty("addDisplacedEnabled" , addDisplacedEnabled); |
5408 | ctxt->setContextProperty("useMoveDisplaced" , useMoveDisplaced); |
5409 | ctxt->setContextProperty("moveDisplacedEnabled" , moveDisplacedEnabled); |
5410 | ctxt->setContextProperty("useRemoveDisplaced" , useRemoveDisplaced); |
5411 | ctxt->setContextProperty("removeDisplacedEnabled" , removeDisplacedEnabled); |
5412 | window->setSource(testFileUrl(fileName: "displacedTransitions.qml" )); |
5413 | window->show(); |
5414 | qApp->processEvents(); |
5415 | |
5416 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
5417 | QTRY_VERIFY(gridview != nullptr); |
5418 | QQuickItem *contentItem = gridview->contentItem(); |
5419 | QVERIFY(contentItem != nullptr); |
5420 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
5421 | |
5422 | QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model); |
5423 | gridview->setProperty(name: "displaceTransitionsDone" , value: false); |
5424 | |
5425 | switch (change.type) { |
5426 | case ListChange::Inserted: |
5427 | { |
5428 | QList<QPair<QString, QString> > targetItemData; |
5429 | for (int i=change.index; i<change.index + change.count; ++i) |
5430 | targetItemData << qMakePair(x: QString("new item %1" ).arg(a: i), y: QString::number(i)); |
5431 | model.insertItems(index: change.index, items: targetItemData); |
5432 | QTRY_COMPARE(model.count(), gridview->count()); |
5433 | break; |
5434 | } |
5435 | case ListChange::Removed: |
5436 | model.removeItems(index: change.index, count: change.count); |
5437 | QTRY_COMPARE(model.count(), gridview->count()); |
5438 | break; |
5439 | case ListChange::Moved: |
5440 | model.moveItems(from: change.index, to: change.to, count: change.count); |
5441 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
5442 | break; |
5443 | case ListChange::SetCurrent: |
5444 | case ListChange::SetContentY: |
5445 | case ListChange::Polish: |
5446 | break; |
5447 | } |
5448 | gridview->forceLayout(); |
5449 | |
5450 | QVariantList resultTargetIndexes = gridview->property(name: "displacedTargetIndexes" ).toList(); |
5451 | QVariantList resultTargetItems = gridview->property(name: "displacedTargetItems" ).toList(); |
5452 | |
5453 | if ((useDisplaced && displacedEnabled) |
5454 | || (useAddDisplaced && addDisplacedEnabled) |
5455 | || (useMoveDisplaced && moveDisplacedEnabled) |
5456 | || (useRemoveDisplaced && removeDisplacedEnabled)) { |
5457 | QTRY_VERIFY(gridview->property("displaceTransitionsDone" ).toBool()); |
5458 | |
5459 | // check the correct number of target items and indexes were received |
5460 | QCOMPARE(resultTargetIndexes.count(), expectedDisplacedIndexes.count()); |
5461 | for (int i=0; i<resultTargetIndexes.count(); i++) |
5462 | QCOMPARE(resultTargetIndexes[i].value<QList<int> >().count(), change.count); |
5463 | QCOMPARE(resultTargetItems.count(), expectedDisplacedIndexes.count()); |
5464 | for (int i=0; i<resultTargetItems.count(); i++) |
5465 | QCOMPARE(resultTargetItems[i].toList().count(), change.count); |
5466 | } else { |
5467 | QCOMPARE(resultTargetIndexes.count(), 0); |
5468 | QCOMPARE(resultTargetItems.count(), 0); |
5469 | } |
5470 | |
5471 | if (change.type == ListChange::Inserted && useAddDisplaced && addDisplacedEnabled) |
5472 | model_addDisplaced_transitionVia.matchAgainst(other: expectedDisplacedValues, error1: "wasn't animated with add displaced" , error2: "shouldn't have been animated with add displaced" ); |
5473 | else |
5474 | QCOMPARE(model_addDisplaced_transitionVia.count(), 0); |
5475 | if (change.type == ListChange::Moved && useMoveDisplaced && moveDisplacedEnabled) |
5476 | model_moveDisplaced_transitionVia.matchAgainst(other: expectedDisplacedValues, error1: "wasn't animated with move displaced" , error2: "shouldn't have been animated with move displaced" ); |
5477 | else |
5478 | QCOMPARE(model_moveDisplaced_transitionVia.count(), 0); |
5479 | if (change.type == ListChange::Removed && useRemoveDisplaced && removeDisplacedEnabled) |
5480 | model_removeDisplaced_transitionVia.matchAgainst(other: expectedDisplacedValues, error1: "wasn't animated with remove displaced" , error2: "shouldn't have been animated with remove displaced" ); |
5481 | else |
5482 | QCOMPARE(model_removeDisplaced_transitionVia.count(), 0); |
5483 | |
5484 | if (useDisplaced && displacedEnabled |
5485 | && ( (change.type == ListChange::Inserted && (!useAddDisplaced || !addDisplacedEnabled)) |
5486 | || (change.type == ListChange::Moved && (!useMoveDisplaced || !moveDisplacedEnabled)) |
5487 | || (change.type == ListChange::Removed && (!useRemoveDisplaced || !removeDisplacedEnabled))) ) { |
5488 | model_displaced_transitionVia.matchAgainst(other: expectedDisplacedValues, error1: "wasn't animated with generic displaced" , error2: "shouldn't have been animated with generic displaced" ); |
5489 | } else { |
5490 | QCOMPARE(model_displaced_transitionVia.count(), 0); |
5491 | } |
5492 | |
5493 | // verify all items moved to the correct final positions |
5494 | QList<QQuickItem*> items = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ); |
5495 | for (int i=0; i < model.count() && i < items.count(); ++i) { |
5496 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
5497 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
5498 | QCOMPARE(item->x(), (i%3)*80.0); |
5499 | QCOMPARE(item->y(), (i/3)*60.0); |
5500 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
5501 | QVERIFY(name != nullptr); |
5502 | QTRY_COMPARE(name->text(), model.name(i)); |
5503 | } |
5504 | |
5505 | releaseView(view: window); |
5506 | } |
5507 | |
5508 | void tst_QQuickGridView::displacedTransitions_data() |
5509 | { |
5510 | QTest::addColumn<bool>(name: "useDisplaced" ); |
5511 | QTest::addColumn<bool>(name: "displacedEnabled" ); |
5512 | QTest::addColumn<bool>(name: "useAddDisplaced" ); |
5513 | QTest::addColumn<bool>(name: "addDisplacedEnabled" ); |
5514 | QTest::addColumn<bool>(name: "useMoveDisplaced" ); |
5515 | QTest::addColumn<bool>(name: "moveDisplacedEnabled" ); |
5516 | QTest::addColumn<bool>(name: "useRemoveDisplaced" ); |
5517 | QTest::addColumn<bool>(name: "removeDisplacedEnabled" ); |
5518 | QTest::addColumn<ListChange>(name: "change" ); |
5519 | QTest::addColumn<ListRange>(name: "expectedDisplacedIndexes" ); |
5520 | |
5521 | QTest::newRow(dataTag: "no displaced transitions at all" ) |
5522 | << false << false |
5523 | << false << false |
5524 | << false << false |
5525 | << false << false |
5526 | << ListChange::insert(index: 0, count: 1) << ListRange(0, 17); |
5527 | |
5528 | QTest::newRow(dataTag: "just displaced" ) |
5529 | << true << true |
5530 | << false << false |
5531 | << false << false |
5532 | << false << false |
5533 | << ListChange::insert(index: 0, count: 1) << ListRange(0, 17); |
5534 | |
5535 | QTest::newRow(dataTag: "just displaced (not enabled)" ) |
5536 | << true << false |
5537 | << false << false |
5538 | << false << false |
5539 | << false << false |
5540 | << ListChange::insert(index: 0, count: 1) << ListRange(0, 17); |
5541 | |
5542 | QTest::newRow(dataTag: "displaced + addDisplaced" ) |
5543 | << true << true |
5544 | << true << true |
5545 | << false << false |
5546 | << false << false |
5547 | << ListChange::insert(index: 0, count: 1) << ListRange(0, 17); |
5548 | |
5549 | QTest::newRow(dataTag: "displaced + addDisplaced (not enabled)" ) |
5550 | << true << true |
5551 | << true << false |
5552 | << false << false |
5553 | << false << false |
5554 | << ListChange::insert(index: 0, count: 1) << ListRange(0, 17); |
5555 | |
5556 | QTest::newRow(dataTag: "displaced + moveDisplaced" ) |
5557 | << true << true |
5558 | << false << false |
5559 | << true << true |
5560 | << false << false |
5561 | << ListChange::move(index: 0, to: 10, count: 1) << ListRange(1, 10); |
5562 | |
5563 | QTest::newRow(dataTag: "displaced + moveDisplaced (not enabled)" ) |
5564 | << true << true |
5565 | << false << false |
5566 | << true << false |
5567 | << false << false |
5568 | << ListChange::move(index: 0, to: 10, count: 1) << ListRange(1, 10); |
5569 | |
5570 | QTest::newRow(dataTag: "displaced + removeDisplaced" ) |
5571 | << true << true |
5572 | << false << false |
5573 | << false << false |
5574 | << true << true |
5575 | << ListChange::remove(index: 0, count: 1) << ListRange(1, 18); |
5576 | |
5577 | QTest::newRow(dataTag: "displaced + removeDisplaced (not enabled)" ) |
5578 | << true << true |
5579 | << false << false |
5580 | << false << false |
5581 | << true << false |
5582 | << ListChange::remove(index: 0, count: 1) << ListRange(1, 18); |
5583 | |
5584 | |
5585 | QTest::newRow(dataTag: "displaced + add, should use generic displaced for a remove" ) |
5586 | << true << true |
5587 | << true << true |
5588 | << false << false |
5589 | << true << false |
5590 | << ListChange::remove(index: 0, count: 1) << ListRange(1, 18); |
5591 | } |
5592 | |
5593 | void tst_QQuickGridView::multipleTransitions() |
5594 | { |
5595 | // Tests that if you interrupt a transition in progress with another action that |
5596 | // cancels the previous transition, the resulting items are still placed correctly. |
5597 | |
5598 | QFETCH(int, initialCount); |
5599 | QFETCH(qreal, contentY); |
5600 | QFETCH(QList<ListChange>, changes); |
5601 | QFETCH(bool, enableAddTransitions); |
5602 | QFETCH(bool, enableMoveTransitions); |
5603 | QFETCH(bool, enableRemoveTransitions); |
5604 | QFETCH(bool, rippleAddDisplaced); |
5605 | |
5606 | // add transitions on the left, moves on the right |
5607 | QPointF addTargets_transitionFrom(-50, -50); |
5608 | QPointF addDisplaced_transitionFrom(-50, 50); |
5609 | QPointF moveTargets_transitionFrom(50, -50); |
5610 | QPointF moveDisplaced_transitionFrom(50, 50); |
5611 | QPointF removeTargets_transitionTo(-100, 300); |
5612 | QPointF removeDisplaced_transitionFrom(100, 300); |
5613 | |
5614 | QaimModel model; |
5615 | for (int i = 0; i < initialCount; i++) |
5616 | model.addItem(name: "Original item" + QString::number(i), number: "" ); |
5617 | |
5618 | QQuickView *window = getView(); |
5619 | QQmlContext *ctxt = window->rootContext(); |
5620 | ctxt->setContextProperty("testModel" , &model); |
5621 | ctxt->setContextProperty("addTargets_transitionFrom" , addTargets_transitionFrom); |
5622 | ctxt->setContextProperty("addDisplaced_transitionFrom" , addDisplaced_transitionFrom); |
5623 | ctxt->setContextProperty("moveTargets_transitionFrom" , moveTargets_transitionFrom); |
5624 | ctxt->setContextProperty("moveDisplaced_transitionFrom" , moveDisplaced_transitionFrom); |
5625 | ctxt->setContextProperty("removeTargets_transitionTo" , removeTargets_transitionTo); |
5626 | ctxt->setContextProperty("removeDisplaced_transitionFrom" , removeDisplaced_transitionFrom); |
5627 | ctxt->setContextProperty("enableAddTransitions" , enableAddTransitions); |
5628 | ctxt->setContextProperty("enableMoveTransitions" , enableMoveTransitions); |
5629 | ctxt->setContextProperty("enableRemoveTransitions" , enableRemoveTransitions); |
5630 | ctxt->setContextProperty("rippleAddDisplaced" , rippleAddDisplaced); |
5631 | window->setSource(testFileUrl(fileName: "multipleTransitions.qml" )); |
5632 | window->show(); |
5633 | QVERIFY(QTest::qWaitForWindowExposed(window)); |
5634 | |
5635 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
5636 | QTRY_VERIFY(gridview != nullptr); |
5637 | QQuickItem *contentItem = gridview->contentItem(); |
5638 | QVERIFY(contentItem != nullptr); |
5639 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
5640 | |
5641 | if (contentY != 0) { |
5642 | gridview->setContentY(contentY); |
5643 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
5644 | } |
5645 | |
5646 | int timeBetweenActions = window->rootObject()->property(name: "timeBetweenActions" ).toInt(); |
5647 | |
5648 | for (int i=0; i<changes.count(); i++) { |
5649 | switch (changes[i].type) { |
5650 | case ListChange::Inserted: |
5651 | { |
5652 | QList<QPair<QString, QString> > targetItems; |
5653 | for (int j=changes[i].index; j<changes[i].index + changes[i].count; ++j) |
5654 | targetItems << qMakePair(x: QString("new item %1" ).arg(a: j), y: QString::number(j)); |
5655 | model.insertItems(index: changes[i].index, items: targetItems); |
5656 | gridview->forceLayout(); |
5657 | QTRY_COMPARE(model.count(), gridview->count()); |
5658 | if (i == changes.count() - 1) { |
5659 | QTRY_VERIFY(!gridview->property("runningAddTargets" ).toBool()); |
5660 | QTRY_VERIFY(!gridview->property("runningAddDisplaced" ).toBool()); |
5661 | } else { |
5662 | QTest::qWait(ms: timeBetweenActions); |
5663 | } |
5664 | break; |
5665 | } |
5666 | case ListChange::Removed: |
5667 | model.removeItems(index: changes[i].index, count: changes[i].count); |
5668 | gridview->forceLayout(); |
5669 | QTRY_COMPARE(model.count(), gridview->count()); |
5670 | if (i == changes.count() - 1) { |
5671 | QTRY_VERIFY(!gridview->property("runningRemoveTargets" ).toBool()); |
5672 | QTRY_VERIFY(!gridview->property("runningRemoveDisplaced" ).toBool()); |
5673 | } else { |
5674 | QTest::qWait(ms: timeBetweenActions); |
5675 | } |
5676 | break; |
5677 | case ListChange::Moved: |
5678 | model.moveItems(from: changes[i].index, to: changes[i].to, count: changes[i].count); |
5679 | gridview->forceLayout(); |
5680 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
5681 | if (i == changes.count() - 1) { |
5682 | QTRY_VERIFY(!gridview->property("runningMoveTargets" ).toBool()); |
5683 | QTRY_VERIFY(!gridview->property("runningMoveDisplaced" ).toBool()); |
5684 | } else { |
5685 | QTest::qWait(ms: timeBetweenActions); |
5686 | } |
5687 | break; |
5688 | case ListChange::SetCurrent: |
5689 | gridview->setCurrentIndex(changes[i].index); |
5690 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
5691 | gridview->forceLayout(); |
5692 | break; |
5693 | case ListChange::SetContentY: |
5694 | gridview->setContentY(changes[i].pos); |
5695 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
5696 | gridview->forceLayout(); |
5697 | break; |
5698 | case ListChange::Polish: |
5699 | break; |
5700 | } |
5701 | } |
5702 | |
5703 | QList<QQuickItem*> items = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ); |
5704 | int firstVisibleIndex = -1; |
5705 | for (int i=0; i<items.count(); i++) { |
5706 | if (items[i]->y() >= contentY) { |
5707 | QQmlExpression e(qmlContext(items[i]), items[i], "index" ); |
5708 | firstVisibleIndex = e.evaluate().toInt(); |
5709 | break; |
5710 | } |
5711 | } |
5712 | QTRY_COMPARE(gridview->count(), model.count()); |
5713 | QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex)); |
5714 | |
5715 | // verify all items moved to the correct final positions |
5716 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ).count(); |
5717 | for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) { |
5718 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
5719 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
5720 | QTRY_COMPARE(item->x(), (i%3)*80.0); |
5721 | QTRY_COMPARE(item->y(), (i/3)*60.0); |
5722 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
5723 | QVERIFY(name != nullptr); |
5724 | QTRY_COMPARE(name->text(), model.name(i)); |
5725 | } |
5726 | |
5727 | releaseView(view: window); |
5728 | } |
5729 | |
5730 | void tst_QQuickGridView::multipleTransitions_data() |
5731 | { |
5732 | QTest::addColumn<int>(name: "initialCount" ); |
5733 | QTest::addColumn<qreal>(name: "contentY" ); |
5734 | QTest::addColumn<QList<ListChange> >(name: "changes" ); |
5735 | QTest::addColumn<bool>(name: "enableAddTransitions" ); |
5736 | QTest::addColumn<bool>(name: "enableMoveTransitions" ); |
5737 | QTest::addColumn<bool>(name: "enableRemoveTransitions" ); |
5738 | QTest::addColumn<bool>(name: "rippleAddDisplaced" ); |
5739 | |
5740 | // the added item and displaced items should move to final dest correctly |
5741 | QTest::newRow(dataTag: "add item, then move it immediately" ) << 10 << 0.0 << (QList<ListChange>() |
5742 | << ListChange::insert(index: 0, count: 1) |
5743 | << ListChange::move(index: 0, to: 3, count: 1) |
5744 | ) |
5745 | << true << true << true << false; |
5746 | |
5747 | // items affected by the add should change from move to add transition |
5748 | QTest::newRow(dataTag: "move, then insert item before the moved item" ) << 20 << 0.0 << (QList<ListChange>() |
5749 | << ListChange::move(index: 1, to: 10, count: 3) |
5750 | << ListChange::insert(index: 0, count: 1) |
5751 | ) |
5752 | << true << true << true << false; |
5753 | |
5754 | // items should be placed correctly if you trigger a transition then refill for that index |
5755 | QTest::newRow(dataTag: "add at 0, flick down, flick back to top and add at 0 again" ) << 20 << 0.0 << (QList<ListChange>() |
5756 | << ListChange::insert(index: 0, count: 1) |
5757 | << ListChange::setContentY(160.0) |
5758 | << ListChange::setContentY(0.0) |
5759 | << ListChange::insert(index: 0, count: 1) |
5760 | ) |
5761 | << true << true << true << false; |
5762 | |
5763 | QTest::newRow(dataTag: "insert then remove same index, with ripple effect on add displaced" ) << 20 << 0.0 << (QList<ListChange>() |
5764 | << ListChange::insert(index: 1, count: 1) |
5765 | << ListChange::remove(index: 1, count: 1) |
5766 | ) |
5767 | << true << true << true << true; |
5768 | |
5769 | // if item is removed while undergoing a displaced transition, all other items should end up at their correct positions, |
5770 | // even if a remove-displace transition is not present to re-animate them |
5771 | QTest::newRow(dataTag: "insert then remove, with remove disabled" ) << 20 << 0.0 << (QList<ListChange>() |
5772 | << ListChange::insert(index: 0, count: 1) |
5773 | << ListChange::remove(index: 2, count: 1) |
5774 | ) |
5775 | << true << true << false << false; |
5776 | |
5777 | // if last item is not flush with the edge of the view, it should still be refilled in correctly after a |
5778 | // remove has changed the position of where it will move to |
5779 | QTest::newRow(dataTag: "insert twice then remove, with remove disabled" ) << 20 << 0.0 << (QList<ListChange>() |
5780 | << ListChange::setContentY(-10.0) |
5781 | << ListChange::insert(index: 0, count: 1) |
5782 | << ListChange::insert(index: 0, count: 1) |
5783 | << ListChange::remove(index: 2, count: 1) |
5784 | ) |
5785 | << true << true << false << false; |
5786 | } |
5787 | |
5788 | void tst_QQuickGridView::multipleDisplaced() |
5789 | { |
5790 | // multiple move() operations should only restart displace transitions for items that |
5791 | // moved from previously set positions, and not those that have moved from their current |
5792 | // item positions (which may e.g. still be changing from easing bounces in the last transition) |
5793 | |
5794 | QaimModel model; |
5795 | for (int i = 0; i < 30; i++) |
5796 | model.addItem(name: "Original item" + QString::number(i), number: "" ); |
5797 | |
5798 | QQuickView *window = createView(); |
5799 | QQmlContext *ctxt = window->rootContext(); |
5800 | ctxt->setContextProperty("testModel" , &model); |
5801 | window->setSource(testFileUrl(fileName: "multipleDisplaced.qml" )); |
5802 | window->show(); |
5803 | QVERIFY(QTest::qWaitForWindowExposed(window)); |
5804 | |
5805 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
5806 | QTRY_VERIFY(gridview != nullptr); |
5807 | QQuickItem *contentItem = gridview->contentItem(); |
5808 | QVERIFY(contentItem != nullptr); |
5809 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
5810 | |
5811 | model.moveItems(from: 12, to: 8, count: 1); |
5812 | QTest::qWait(ms: window->rootObject()->property(name: "duration" ).toInt() / 2); |
5813 | model.moveItems(from: 8, to: 3, count: 1); |
5814 | QTRY_VERIFY(gridview->property("displaceTransitionsDone" ).toBool()); |
5815 | |
5816 | QVariantMap transitionsStarted = gridview->property(name: "displaceTransitionsStarted" ).toMap(); |
5817 | foreach (const QString &name, transitionsStarted.keys()) { |
5818 | QVERIFY2(transitionsStarted[name] == 1, |
5819 | QTest::toString(QString("%1 was displaced %2 times" ).arg(name).arg(transitionsStarted[name].toInt()))); |
5820 | } |
5821 | |
5822 | // verify all items moved to the correct final positions |
5823 | QList<QQuickItem*> items = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" ); |
5824 | for (int i=0; i < model.count() && i < items.count(); ++i) { |
5825 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
5826 | QVERIFY2(item, QTest::toString(QString("Item %1 not found" ).arg(i))); |
5827 | QTRY_COMPARE(item->x(), (i%3)*80.0); |
5828 | QTRY_COMPARE(item->y(), (i/3)*60.0); |
5829 | QQuickText *name = findItem<QQuickText>(parent: contentItem, objectName: "textName" , index: i); |
5830 | QVERIFY(name != nullptr); |
5831 | QTRY_COMPARE(name->text(), model.name(i)); |
5832 | } |
5833 | |
5834 | delete window; |
5835 | } |
5836 | |
5837 | void tst_QQuickGridView::regression_QTBUG_57225() |
5838 | { |
5839 | QFETCH(int, initialCount); |
5840 | QFETCH(int, removeIndex); |
5841 | QFETCH(int, removeCount); |
5842 | QFETCH(int, expectedDisplaceTransitions); |
5843 | |
5844 | // deleting all visible items should not cause a repositioning of said items. |
5845 | |
5846 | QaimModel model; |
5847 | for (int i = 0; i < initialCount; i++) |
5848 | model.addItem(name: "Original item" + QString::number(i), number: "" ); |
5849 | |
5850 | QQuickView *window = createView(); |
5851 | QQmlContext *ctxt = window->rootContext(); |
5852 | ctxt->setContextProperty("testModel" , &model); |
5853 | window->setSource(testFileUrl(fileName: "qtbug57225.qml" )); |
5854 | window->show(); |
5855 | QVERIFY(QTest::qWaitForWindowExposed(window)); |
5856 | |
5857 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
5858 | QVERIFY(gridview != nullptr); |
5859 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
5860 | |
5861 | model.removeItems(index: removeIndex, count: removeCount); |
5862 | QTRY_VERIFY(gridview->property("animationDone" ).toBool()); |
5863 | |
5864 | // verify that none of the removed items has moved to a negative position |
5865 | QPoint minimumPosition = gridview->property(name: "minimumPosition" ).toPoint(); |
5866 | QVERIFY(minimumPosition.x() >= 0); |
5867 | QVERIFY(minimumPosition.y() >= 0); |
5868 | |
5869 | // wait some more time to let the displaced transition happen |
5870 | QTest::qWait(ms: window->rootObject()->property(name: "duration" ).toInt()); |
5871 | QTRY_VERIFY2(gridview->property("displaceTransitionsDone" ).toInt() >= expectedDisplaceTransitions, |
5872 | QByteArray::number(gridview->property("displaceTransitionsDone" ).toInt()).constData()); |
5873 | |
5874 | delete window; |
5875 | } |
5876 | |
5877 | void tst_QQuickGridView::regression_QTBUG_57225_data() |
5878 | { |
5879 | QTest::addColumn<int>(name: "initialCount" ); |
5880 | QTest::addColumn<int>(name: "removeIndex" ); |
5881 | QTest::addColumn<int>(name: "removeCount" ); |
5882 | QTest::addColumn<int>(name: "expectedDisplaceTransitions" ); |
5883 | |
5884 | // no displace transitions should happen |
5885 | QTest::newRow(dataTag: "remove all visible items" ) << |
5886 | 20 << 0 << 8 << 0; |
5887 | |
5888 | // check that the removal animation is performed |
5889 | QTest::newRow(dataTag: "remove items in between" ) << |
5890 | 20 << 1 << 2 << 3; |
5891 | |
5892 | QTest::newRow(dataTag: "remove items in between - 2" ) << |
5893 | 20 << 2 << 3 << 1; |
5894 | } |
5895 | |
5896 | void tst_QQuickGridView::cacheBuffer() |
5897 | { |
5898 | QQuickView *window = createView(); |
5899 | |
5900 | QaimModel model; |
5901 | for (int i = 0; i < 90; i++) |
5902 | model.addItem(name: "Item" + QString::number(i), number: "" ); |
5903 | |
5904 | window->rootContext()->setContextProperty("testModel" , &model); |
5905 | window->setSource(testFileUrl(fileName: "gridview1.qml" )); |
5906 | window->show(); |
5907 | qApp->processEvents(); |
5908 | |
5909 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
5910 | QVERIFY(gridview != nullptr); |
5911 | |
5912 | QQuickItem *contentItem = gridview->contentItem(); |
5913 | QVERIFY(contentItem != nullptr); |
5914 | QVERIFY(gridview->delegate() != nullptr); |
5915 | QVERIFY(gridview->model() != 0); |
5916 | |
5917 | // Confirm items positioned correctly |
5918 | int itemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" , visibleOnly: false).count(); |
5919 | for (int i = 0; i < model.count() && i < itemCount; ++i) { |
5920 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
5921 | QTRY_COMPARE(item->x(), (i%3)*80.0); |
5922 | QTRY_COMPARE(item->y(), (i/3)*60.0); |
5923 | } |
5924 | |
5925 | QQmlIncubationController controller; |
5926 | window->engine()->setIncubationController(&controller); |
5927 | |
5928 | window->rootObject()->setProperty(name: "cacheBuffer" , value: 200); |
5929 | QTRY_COMPARE(gridview->cacheBuffer(), 200); |
5930 | |
5931 | // items will be created one at a time |
5932 | for (int i = itemCount; i < qMin(a: itemCount+9,b: model.count()); ++i) { |
5933 | QVERIFY(findItem<QQuickItem>(gridview, "wrapper" , i) == nullptr); |
5934 | QQuickItem *item = nullptr; |
5935 | while (!item) { |
5936 | bool b = false; |
5937 | controller.incubateWhile(flag: &b); |
5938 | item = findItem<QQuickItem>(parent: gridview, objectName: "wrapper" , index: i); |
5939 | } |
5940 | } |
5941 | |
5942 | { |
5943 | bool b = true; |
5944 | controller.incubateWhile(flag: &b); |
5945 | } |
5946 | |
5947 | int newItemCount = 0; |
5948 | newItemCount = findItems<QQuickItem>(parent: contentItem, objectName: "wrapper" , visibleOnly: false).count(); |
5949 | |
5950 | // Confirm items positioned correctly |
5951 | for (int i = 0; i < model.count() && i < newItemCount; ++i) { |
5952 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
5953 | QVERIFY(item); |
5954 | QTRY_COMPARE(item->x(), (i%3)*80.0); |
5955 | QTRY_COMPARE(item->y(), (i/3)*60.0); |
5956 | } |
5957 | |
5958 | // move view and confirm items in view are visible immediately and outside are created async |
5959 | gridview->setContentY(300); |
5960 | |
5961 | for (int i = 15; i < 34; ++i) { // 34 due to staggered item creation |
5962 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
5963 | QVERIFY(item); |
5964 | QTRY_COMPARE(item->x(), (i%3)*80.0); |
5965 | QTRY_COMPARE(item->y(), (i/3)*60.0); |
5966 | } |
5967 | |
5968 | QVERIFY(findItem<QQuickItem>(gridview, "wrapper" , 34) == nullptr); |
5969 | |
5970 | // ensure buffered items are created |
5971 | for (int i = 34; i < qMin(a: 44,b: model.count()); ++i) { |
5972 | QQuickItem *item = nullptr; |
5973 | while (!item) { |
5974 | qGuiApp->processEvents(); // allow refill to happen |
5975 | bool b = false; |
5976 | controller.incubateWhile(flag: &b); |
5977 | item = findItem<QQuickItem>(parent: gridview, objectName: "wrapper" , index: i); |
5978 | } |
5979 | } |
5980 | |
5981 | { |
5982 | bool b = true; |
5983 | controller.incubateWhile(flag: &b); |
5984 | } |
5985 | |
5986 | delete window; |
5987 | } |
5988 | |
5989 | void tst_QQuickGridView::asynchronous() |
5990 | { |
5991 | QQuickView *window = createView(); |
5992 | window->show(); |
5993 | QQmlIncubationController controller; |
5994 | window->engine()->setIncubationController(&controller); |
5995 | |
5996 | window->setSource(testFileUrl(fileName: "asyncloader.qml" )); |
5997 | |
5998 | QQuickItem *rootObject = qobject_cast<QQuickItem*>(object: window->rootObject()); |
5999 | QVERIFY(rootObject); |
6000 | |
6001 | QQuickGridView *gridview = nullptr; |
6002 | while (!gridview) { |
6003 | bool b = false; |
6004 | controller.incubateWhile(flag: &b); |
6005 | gridview = rootObject->findChild<QQuickGridView*>(aName: "view" ); |
6006 | } |
6007 | |
6008 | // items will be created one at a time |
6009 | for (int i = 0; i < 12; ++i) { |
6010 | QVERIFY(findItem<QQuickItem>(gridview, "wrapper" , i) == nullptr); |
6011 | QQuickItem *item = nullptr; |
6012 | while (!item) { |
6013 | bool b = false; |
6014 | controller.incubateWhile(flag: &b); |
6015 | item = findItem<QQuickItem>(parent: gridview, objectName: "wrapper" , index: i); |
6016 | } |
6017 | } |
6018 | |
6019 | { |
6020 | bool b = true; |
6021 | controller.incubateWhile(flag: &b); |
6022 | } |
6023 | |
6024 | // verify positioning |
6025 | QQuickItem *contentItem = gridview->contentItem(); |
6026 | for (int i = 0; i < 12; ++i) { |
6027 | QQuickItem *item = findItem<QQuickItem>(parent: contentItem, objectName: "wrapper" , index: i); |
6028 | if (!item) qWarning() << "Item" << i << "not found" ; |
6029 | QCOMPARE(item->x(), qreal((i%3)*100)); |
6030 | QCOMPARE(item->y(), qreal((i/3)*100)); |
6031 | } |
6032 | |
6033 | delete window; |
6034 | } |
6035 | |
6036 | void tst_QQuickGridView::unrequestedVisibility() |
6037 | { |
6038 | QaimModel model; |
6039 | for (int i = 0; i < 30; i++) |
6040 | model.addItem(name: "Item" + QString::number(i), number: QString::number(i)); |
6041 | |
6042 | QQuickView *window = new QQuickView(nullptr); |
6043 | window->setGeometry(posx: 0,posy: 0,w: 240,h: 320); |
6044 | |
6045 | QQmlContext *ctxt = window->rootContext(); |
6046 | ctxt->setContextProperty("testModel" , &model); |
6047 | ctxt->setContextProperty("testWrap" , QVariant(false)); |
6048 | |
6049 | window->setSource(testFileUrl(fileName: "unrequestedItems.qml" )); |
6050 | |
6051 | window->show(); |
6052 | |
6053 | qApp->processEvents(); |
6054 | |
6055 | QQuickGridView *leftview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "leftGrid" ); |
6056 | QTRY_VERIFY(leftview != nullptr); |
6057 | |
6058 | QQuickGridView *rightview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "rightGrid" ); |
6059 | QTRY_VERIFY(rightview != nullptr); |
6060 | |
6061 | QQuickItem *leftContent = leftview->contentItem(); |
6062 | QTRY_VERIFY(leftContent != nullptr); |
6063 | |
6064 | QQuickItem *rightContent = rightview->contentItem(); |
6065 | QTRY_VERIFY(rightContent != nullptr); |
6066 | |
6067 | rightview->setCurrentIndex(12); |
6068 | |
6069 | QTRY_COMPARE(leftview->contentY(), 0.0); |
6070 | QTRY_COMPARE(rightview->contentY(), 240.0); |
6071 | |
6072 | QQuickItem *item; |
6073 | |
6074 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 1)); |
6075 | QCOMPARE(delegateVisible(item), true); |
6076 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 1)); |
6077 | QCOMPARE(delegateVisible(item), false); |
6078 | |
6079 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 11)); |
6080 | QCOMPARE(delegateVisible(item), false); |
6081 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 11)); |
6082 | QCOMPARE(delegateVisible(item), true); |
6083 | |
6084 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 9)); |
6085 | QCOMPARE(delegateVisible(item), true); |
6086 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 10)); |
6087 | QCOMPARE(delegateVisible(item), false); |
6088 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 3)); |
6089 | QCOMPARE(delegateVisible(item), false); |
6090 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 4)); |
6091 | QCOMPARE(delegateVisible(item), true); |
6092 | |
6093 | rightview->setCurrentIndex(0); |
6094 | |
6095 | QTRY_COMPARE(leftview->contentY(), 0.0); |
6096 | QTRY_COMPARE(rightview->contentY(), 0.0); |
6097 | |
6098 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 1)); |
6099 | QCOMPARE(delegateVisible(item), true); |
6100 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 1)); |
6101 | QTRY_COMPARE(delegateVisible(item), true); |
6102 | |
6103 | QVERIFY(!findItem<QQuickItem>(leftContent, "wrapper" , 11)); |
6104 | QVERIFY(!findItem<QQuickItem>(rightContent, "wrapper" , 11)); |
6105 | |
6106 | leftview->setCurrentIndex(12); |
6107 | |
6108 | QTRY_COMPARE(leftview->contentY(), 240.0); |
6109 | QTRY_COMPARE(rightview->contentY(), 0.0); |
6110 | |
6111 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 1)); |
6112 | QTRY_COMPARE(delegateVisible(item), false); |
6113 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 1)); |
6114 | QCOMPARE(delegateVisible(item), true); |
6115 | |
6116 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 11)); |
6117 | QCOMPARE(delegateVisible(item), true); |
6118 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 11)); |
6119 | QCOMPARE(delegateVisible(item), false); |
6120 | |
6121 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 3)); |
6122 | QCOMPARE(delegateVisible(item), false); |
6123 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 5)); |
6124 | QCOMPARE(delegateVisible(item), true); |
6125 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 9)); |
6126 | QCOMPARE(delegateVisible(item), true); |
6127 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 10)); |
6128 | QCOMPARE(delegateVisible(item), false); |
6129 | |
6130 | // move a non-visible item into view |
6131 | model.moveItems(from: 10, to: 9, count: 1); |
6132 | QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); |
6133 | |
6134 | QTRY_VERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 1)); |
6135 | QCOMPARE(delegateVisible(item), false); |
6136 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 1)); |
6137 | QCOMPARE(delegateVisible(item), true); |
6138 | |
6139 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 11)); |
6140 | QCOMPARE(delegateVisible(item), true); |
6141 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 11)); |
6142 | QCOMPARE(delegateVisible(item), false); |
6143 | |
6144 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 3)); |
6145 | QCOMPARE(delegateVisible(item), false); |
6146 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 5)); |
6147 | QCOMPARE(delegateVisible(item), true); |
6148 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 9)); |
6149 | QCOMPARE(delegateVisible(item), true); |
6150 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 10)); |
6151 | QCOMPARE(delegateVisible(item), false); |
6152 | |
6153 | // move a visible item out of view |
6154 | model.moveItems(from: 5, to: 3, count: 1); |
6155 | QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); |
6156 | |
6157 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 3)); |
6158 | QCOMPARE(delegateVisible(item), false); |
6159 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 5)); |
6160 | QCOMPARE(delegateVisible(item), true); |
6161 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 9)); |
6162 | QCOMPARE(delegateVisible(item), true); |
6163 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 10)); |
6164 | QCOMPARE(delegateVisible(item), false); |
6165 | |
6166 | // move a non-visible item into view |
6167 | model.moveItems(from: 3, to: 5, count: 1); |
6168 | QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); |
6169 | |
6170 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 3)); |
6171 | QCOMPARE(delegateVisible(item), false); |
6172 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 5)); |
6173 | QCOMPARE(delegateVisible(item), true); |
6174 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 9)); |
6175 | QCOMPARE(delegateVisible(item), true); |
6176 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 10)); |
6177 | QCOMPARE(delegateVisible(item), false); |
6178 | |
6179 | // move a visible item out of view |
6180 | model.moveItems(from: 9, to: 10, count: 1); |
6181 | QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); |
6182 | |
6183 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 3)); |
6184 | QCOMPARE(delegateVisible(item), false); |
6185 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 5)); |
6186 | QCOMPARE(delegateVisible(item), true); |
6187 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 9)); |
6188 | QCOMPARE(delegateVisible(item), true); |
6189 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 10)); |
6190 | QCOMPARE(delegateVisible(item), false); |
6191 | |
6192 | // move a non-visible item into view |
6193 | model.moveItems(from: 10, to: 9, count: 1); |
6194 | QVERIFY(QQuickTest::qWaitForItemPolished(leftview)); |
6195 | |
6196 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 3)); |
6197 | QCOMPARE(delegateVisible(item), false); |
6198 | QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper" , 5)); |
6199 | QCOMPARE(delegateVisible(item), true); |
6200 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 9)); |
6201 | QCOMPARE(delegateVisible(item), true); |
6202 | QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper" , 10)); |
6203 | QCOMPARE(delegateVisible(item), false); |
6204 | |
6205 | delete window; |
6206 | } |
6207 | |
6208 | |
6209 | void tst_QQuickGridView::inserted_leftToRight_RtL_TtB() |
6210 | { |
6211 | inserted_defaultLayout(flow: QQuickGridView::FlowLeftToRight, horizLayout: Qt::RightToLeft); |
6212 | } |
6213 | |
6214 | void tst_QQuickGridView::inserted_leftToRight_RtL_TtB_data() |
6215 | { |
6216 | inserted_defaultLayout_data(); |
6217 | } |
6218 | |
6219 | void tst_QQuickGridView::inserted_topToBottom_LtR_TtB() |
6220 | { |
6221 | inserted_defaultLayout(flow: QQuickGridView::FlowTopToBottom); |
6222 | } |
6223 | |
6224 | void tst_QQuickGridView::inserted_topToBottom_LtR_TtB_data() |
6225 | { |
6226 | inserted_defaultLayout_data(); |
6227 | } |
6228 | |
6229 | void tst_QQuickGridView::inserted_topToBottom_RtL_TtB() |
6230 | { |
6231 | inserted_defaultLayout(flow: QQuickGridView::FlowTopToBottom, horizLayout: Qt::RightToLeft); |
6232 | } |
6233 | |
6234 | void tst_QQuickGridView::inserted_topToBottom_RtL_TtB_data() |
6235 | { |
6236 | inserted_defaultLayout_data(); |
6237 | } |
6238 | |
6239 | void tst_QQuickGridView::inserted_leftToRight_LtR_BtT() |
6240 | { |
6241 | inserted_defaultLayout(flow: QQuickGridView::FlowLeftToRight, horizLayout: Qt::LeftToRight, verticalLayout: QQuickItemView::BottomToTop); |
6242 | } |
6243 | |
6244 | void tst_QQuickGridView::inserted_leftToRight_LtR_BtT_data() |
6245 | { |
6246 | inserted_defaultLayout_data(); |
6247 | } |
6248 | |
6249 | void tst_QQuickGridView::inserted_leftToRight_RtL_BtT() |
6250 | { |
6251 | inserted_defaultLayout(flow: QQuickGridView::FlowLeftToRight, horizLayout: Qt::RightToLeft, verticalLayout: QQuickItemView::BottomToTop); |
6252 | } |
6253 | |
6254 | void tst_QQuickGridView::inserted_leftToRight_RtL_BtT_data() |
6255 | { |
6256 | inserted_defaultLayout_data(); |
6257 | } |
6258 | |
6259 | void tst_QQuickGridView::inserted_topToBottom_LtR_BtT() |
6260 | { |
6261 | inserted_defaultLayout(flow: QQuickGridView::FlowTopToBottom, horizLayout: Qt::LeftToRight, verticalLayout: QQuickItemView::BottomToTop); |
6262 | } |
6263 | |
6264 | void tst_QQuickGridView::inserted_topToBottom_LtR_BtT_data() |
6265 | { |
6266 | inserted_defaultLayout_data(); |
6267 | } |
6268 | |
6269 | void tst_QQuickGridView::inserted_topToBottom_RtL_BtT() |
6270 | { |
6271 | inserted_defaultLayout(flow: QQuickGridView::FlowTopToBottom, horizLayout: Qt::RightToLeft, verticalLayout: QQuickItemView::BottomToTop); |
6272 | } |
6273 | |
6274 | void tst_QQuickGridView::inserted_topToBottom_RtL_BtT_data() |
6275 | { |
6276 | inserted_defaultLayout_data(); |
6277 | } |
6278 | |
6279 | |
6280 | void tst_QQuickGridView::removed_leftToRight_RtL_TtB() |
6281 | { |
6282 | removed_defaultLayout(flow: QQuickGridView::FlowLeftToRight, horizLayout: Qt::RightToLeft); |
6283 | } |
6284 | |
6285 | void tst_QQuickGridView::removed_leftToRight_RtL_TtB_data() |
6286 | { |
6287 | removed_defaultLayout_data(); |
6288 | } |
6289 | |
6290 | void tst_QQuickGridView::removed_topToBottom_LtR_TtB() |
6291 | { |
6292 | removed_defaultLayout(flow: QQuickGridView::FlowTopToBottom); |
6293 | } |
6294 | |
6295 | void tst_QQuickGridView::removed_topToBottom_LtR_TtB_data() |
6296 | { |
6297 | removed_defaultLayout_data(); |
6298 | } |
6299 | |
6300 | void tst_QQuickGridView::removed_topToBottom_RtL_TtB() |
6301 | { |
6302 | removed_defaultLayout(flow: QQuickGridView::FlowTopToBottom, horizLayout: Qt::RightToLeft); |
6303 | } |
6304 | |
6305 | void tst_QQuickGridView::removed_topToBottom_RtL_TtB_data() |
6306 | { |
6307 | removed_defaultLayout_data(); |
6308 | } |
6309 | |
6310 | void tst_QQuickGridView::removed_leftToRight_LtR_BtT() |
6311 | { |
6312 | removed_defaultLayout(flow: QQuickGridView::FlowLeftToRight, horizLayout: Qt::LeftToRight, verticalLayout: QQuickItemView::BottomToTop); |
6313 | } |
6314 | |
6315 | void tst_QQuickGridView::removed_leftToRight_LtR_BtT_data() |
6316 | { |
6317 | removed_defaultLayout_data(); |
6318 | } |
6319 | |
6320 | void tst_QQuickGridView::removed_leftToRight_RtL_BtT() |
6321 | { |
6322 | removed_defaultLayout(flow: QQuickGridView::FlowLeftToRight, horizLayout: Qt::RightToLeft, verticalLayout: QQuickItemView::BottomToTop); |
6323 | } |
6324 | |
6325 | void tst_QQuickGridView::removed_leftToRight_RtL_BtT_data() |
6326 | { |
6327 | removed_defaultLayout_data(); |
6328 | } |
6329 | |
6330 | void tst_QQuickGridView::removed_topToBottom_LtR_BtT() |
6331 | { |
6332 | removed_defaultLayout(flow: QQuickGridView::FlowTopToBottom, horizLayout: Qt::LeftToRight, verticalLayout: QQuickItemView::BottomToTop); |
6333 | } |
6334 | |
6335 | void tst_QQuickGridView::removed_topToBottom_LtR_BtT_data() |
6336 | { |
6337 | removed_defaultLayout_data(); |
6338 | } |
6339 | |
6340 | void tst_QQuickGridView::removed_topToBottom_RtL_BtT() |
6341 | { |
6342 | removed_defaultLayout(flow: QQuickGridView::FlowTopToBottom, horizLayout: Qt::RightToLeft, verticalLayout: QQuickItemView::BottomToTop); |
6343 | } |
6344 | |
6345 | void tst_QQuickGridView::removed_topToBottom_RtL_BtT_data() |
6346 | { |
6347 | removed_defaultLayout_data(); |
6348 | } |
6349 | |
6350 | |
6351 | void tst_QQuickGridView::moved_leftToRight_RtL_TtB() |
6352 | { |
6353 | moved_defaultLayout(flow: QQuickGridView::FlowLeftToRight, horizLayout: Qt::RightToLeft); |
6354 | } |
6355 | |
6356 | void tst_QQuickGridView::moved_leftToRight_RtL_TtB_data() |
6357 | { |
6358 | moved_defaultLayout_data(); |
6359 | } |
6360 | |
6361 | void tst_QQuickGridView::moved_topToBottom_LtR_TtB() |
6362 | { |
6363 | moved_defaultLayout(flow: QQuickGridView::FlowTopToBottom); |
6364 | } |
6365 | |
6366 | void tst_QQuickGridView::moved_topToBottom_LtR_TtB_data() |
6367 | { |
6368 | moved_defaultLayout_data(); |
6369 | } |
6370 | |
6371 | void tst_QQuickGridView::moved_topToBottom_RtL_TtB() |
6372 | { |
6373 | moved_defaultLayout(flow: QQuickGridView::FlowTopToBottom, horizLayout: Qt::RightToLeft); |
6374 | } |
6375 | |
6376 | void tst_QQuickGridView::moved_topToBottom_RtL_TtB_data() |
6377 | { |
6378 | moved_defaultLayout_data(); |
6379 | } |
6380 | |
6381 | void tst_QQuickGridView::moved_leftToRight_LtR_BtT() |
6382 | { |
6383 | moved_defaultLayout(flow: QQuickGridView::FlowLeftToRight, horizLayout: Qt::LeftToRight, verticalLayout: QQuickItemView::BottomToTop); |
6384 | } |
6385 | |
6386 | void tst_QQuickGridView::moved_leftToRight_LtR_BtT_data() |
6387 | { |
6388 | moved_defaultLayout_data(); |
6389 | } |
6390 | |
6391 | void tst_QQuickGridView::moved_leftToRight_RtL_BtT() |
6392 | { |
6393 | moved_defaultLayout(flow: QQuickGridView::FlowLeftToRight, horizLayout: Qt::RightToLeft, verticalLayout: QQuickItemView::BottomToTop); |
6394 | } |
6395 | |
6396 | void tst_QQuickGridView::moved_leftToRight_RtL_BtT_data() |
6397 | { |
6398 | moved_defaultLayout_data(); |
6399 | } |
6400 | |
6401 | void tst_QQuickGridView::moved_topToBottom_LtR_BtT() |
6402 | { |
6403 | moved_defaultLayout(flow: QQuickGridView::FlowTopToBottom, horizLayout: Qt::LeftToRight, verticalLayout: QQuickItemView::BottomToTop); |
6404 | } |
6405 | |
6406 | void tst_QQuickGridView::moved_topToBottom_LtR_BtT_data() |
6407 | { |
6408 | moved_defaultLayout_data(); |
6409 | } |
6410 | |
6411 | void tst_QQuickGridView::moved_topToBottom_RtL_BtT() |
6412 | { |
6413 | moved_defaultLayout(flow: QQuickGridView::FlowTopToBottom, horizLayout: Qt::RightToLeft, verticalLayout: QQuickItemView::BottomToTop); |
6414 | } |
6415 | |
6416 | void tst_QQuickGridView::moved_topToBottom_RtL_BtT_data() |
6417 | { |
6418 | moved_defaultLayout_data(); |
6419 | } |
6420 | |
6421 | |
6422 | QList<int> tst_QQuickGridView::toIntList(const QVariantList &list) |
6423 | { |
6424 | QList<int> ret; |
6425 | bool ok = true; |
6426 | for (int i=0; i<list.count(); i++) { |
6427 | ret << list[i].toInt(ok: &ok); |
6428 | if (!ok) |
6429 | qWarning() << "tst_QQuickGridView::toIntList(): not a number:" << list[i]; |
6430 | } |
6431 | |
6432 | return ret; |
6433 | } |
6434 | |
6435 | void tst_QQuickGridView::matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes) |
6436 | { |
6437 | const QSet<int> expectedIndexSet(expectedIndexes.cbegin(), expectedIndexes.cend()); |
6438 | for (int i=0; i<indexLists.count(); i++) { |
6439 | const auto ¤tList = indexLists[i].value<QList<int> >(); |
6440 | const QSet<int> current(currentList.cbegin(), currentList.cend()); |
6441 | if (current != expectedIndexSet) |
6442 | qDebug() << "Cannot match actual targets" << current << "with expected" << expectedIndexes; |
6443 | QCOMPARE(current, expectedIndexSet); |
6444 | } |
6445 | } |
6446 | |
6447 | void tst_QQuickGridView::matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes) |
6448 | { |
6449 | for (QVariantMap::const_iterator it = items.begin(); it != items.end(); ++it) { |
6450 | QCOMPARE(it.value().type(), QVariant::Int); |
6451 | QString name = it.key(); |
6452 | int itemIndex = it.value().toInt(); |
6453 | QVERIFY2(expectedIndexes.contains(itemIndex), QTest::toString(QString("Index %1 not found in expectedIndexes" ).arg(itemIndex))); |
6454 | if (model.name(index: itemIndex) != name) |
6455 | qDebug() << itemIndex; |
6456 | QCOMPARE(model.name(itemIndex), name); |
6457 | } |
6458 | QCOMPARE(items.count(), expectedIndexes.count()); |
6459 | } |
6460 | |
6461 | void tst_QQuickGridView::matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems) |
6462 | { |
6463 | for (int i=0; i<itemLists.count(); i++) { |
6464 | QVariantList current = itemLists[i].toList(); |
6465 | for (int j=0; j<current.count(); j++) { |
6466 | QQuickItem *o = qobject_cast<QQuickItem*>(object: current[j].value<QObject*>()); |
6467 | QVERIFY2(o, QTest::toString(QString("Invalid actual item at %1" ).arg(j))); |
6468 | QVERIFY2(expectedItems.contains(o), QTest::toString(QString("Cannot match item %1" ).arg(j))); |
6469 | } |
6470 | QCOMPARE(current.count(), expectedItems.count()); |
6471 | } |
6472 | } |
6473 | |
6474 | void tst_QQuickGridView::displayMargin() |
6475 | { |
6476 | QQuickView *window = createView(); |
6477 | window->setSource(testFileUrl(fileName: "displayMargin.qml" )); |
6478 | window->show(); |
6479 | QVERIFY(QTest::qWaitForWindowExposed(window)); |
6480 | |
6481 | QQuickGridView *gridview = window->rootObject()->findChild<QQuickGridView*>(); |
6482 | QVERIFY(gridview != nullptr); |
6483 | |
6484 | QQuickItem *content = gridview->contentItem(); |
6485 | QVERIFY(content != nullptr); |
6486 | |
6487 | QQuickItem *item0; |
6488 | QQuickItem *item97; |
6489 | |
6490 | QVERIFY(item0 = findItem<QQuickItem>(content, "delegate" , 0)); |
6491 | QCOMPARE(delegateVisible(item0), true); |
6492 | |
6493 | // the 97th item should be within the end margin |
6494 | QVERIFY(item97 = findItem<QQuickItem>(content, "delegate" , 96)); |
6495 | QCOMPARE(delegateVisible(item97), true); |
6496 | |
6497 | // GridView staggers item creation, so the 118th item should be outside the end margin. |
6498 | QVERIFY(findItem<QQuickItem>(content, "delegate" , 117) == nullptr); |
6499 | |
6500 | // the first delegate should still be within the begin margin |
6501 | gridview->positionViewAtIndex(index: 20, mode: QQuickGridView::Beginning); |
6502 | QCOMPARE(delegateVisible(item0), true); |
6503 | |
6504 | // the first delegate should now be outside the begin margin |
6505 | gridview->positionViewAtIndex(index: 36, mode: QQuickGridView::Beginning); |
6506 | QCOMPARE(delegateVisible(item0), false); |
6507 | |
6508 | delete window; |
6509 | } |
6510 | |
6511 | void tst_QQuickGridView::negativeDisplayMargin() |
6512 | { |
6513 | QQuickItem *item; |
6514 | QQuickView *window = createView(); |
6515 | window->setSource(testFileUrl(fileName: "negativeDisplayMargin.qml" )); |
6516 | window->show(); |
6517 | QVERIFY(QTest::qWaitForWindowExposed(window)); |
6518 | |
6519 | QQuickItem *listview = window->rootObject(); |
6520 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "grid" ); |
6521 | QVERIFY(gridview != nullptr); |
6522 | |
6523 | QTRY_COMPARE(gridview->property("createdItems" ).toInt(), 11); |
6524 | QCOMPARE(gridview->property("destroyedItem" ).toInt(), 0); |
6525 | |
6526 | QQuickItem *content = gridview->contentItem(); |
6527 | QVERIFY(content != nullptr); |
6528 | |
6529 | QVERIFY(item = findItem<QQuickItem>(content, "delegate" , 0)); |
6530 | QCOMPARE(delegateVisible(item), true); |
6531 | |
6532 | QVERIFY(item = findItem<QQuickItem>(content, "delegate" , 7)); |
6533 | QCOMPARE(delegateVisible(item), true); |
6534 | |
6535 | QVERIFY(item = findItem<QQuickItem>(content, "delegate" , 8)); |
6536 | QCOMPARE(delegateVisible(item), false); |
6537 | |
6538 | // Flick until contentY means that delegate8 should be visible |
6539 | listview->setProperty(name: "contentY" , value: 500); |
6540 | QVERIFY(item = findItem<QQuickItem>(content, "delegate" , 8)); |
6541 | QTRY_COMPARE(delegateVisible(item), true); |
6542 | |
6543 | listview->setProperty(name: "contentY" , value: 1000); |
6544 | QTRY_VERIFY(item = findItem<QQuickItem>(content, "delegate" , 14)); |
6545 | QTRY_COMPARE(delegateVisible(item), true); |
6546 | |
6547 | listview->setProperty(name: "contentY" , value: 0); |
6548 | QVERIFY(item = findItem<QQuickItem>(content, "delegate" , 4)); |
6549 | QTRY_COMPARE(delegateVisible(item), true); |
6550 | |
6551 | delete window; |
6552 | } |
6553 | |
6554 | void tst_QQuickGridView::jsArrayChange() |
6555 | { |
6556 | QQmlEngine engine; |
6557 | QQmlComponent component(&engine); |
6558 | component.setData("import QtQuick 2.4; GridView {}" , baseUrl: QUrl()); |
6559 | |
6560 | QScopedPointer<QQuickGridView> view(qobject_cast<QQuickGridView *>(object: component.create())); |
6561 | QVERIFY(!view.isNull()); |
6562 | |
6563 | QSignalSpy spy(view.data(), SIGNAL(modelChanged())); |
6564 | QVERIFY(spy.isValid()); |
6565 | |
6566 | QJSValue array1 = engine.newArray(length: 3); |
6567 | QJSValue array2 = engine.newArray(length: 3); |
6568 | for (int i = 0; i < 3; ++i) { |
6569 | array1.setProperty(arrayIndex: i, value: i); |
6570 | array2.setProperty(arrayIndex: i, value: i); |
6571 | } |
6572 | |
6573 | view->setModel(QVariant::fromValue(value: array1)); |
6574 | QCOMPARE(spy.count(), 1); |
6575 | |
6576 | // no change |
6577 | view->setModel(QVariant::fromValue(value: array2)); |
6578 | QCOMPARE(spy.count(), 1); |
6579 | } |
6580 | |
6581 | void tst_QQuickGridView::contentHeightWithDelayRemove_data() |
6582 | { |
6583 | QTest::addColumn<bool>(name: "useDelayRemove" ); |
6584 | QTest::addColumn<QByteArray>(name: "removeFunc" ); |
6585 | QTest::addColumn<int>(name: "countDelta" ); |
6586 | QTest::addColumn<qreal>(name: "contentHeightDelta" ); |
6587 | |
6588 | QTest::newRow(dataTag: "remove without delayRemove" ) |
6589 | << false |
6590 | << QByteArray("takeOne" ) |
6591 | << -1 |
6592 | << qreal(-1 * 100.0); |
6593 | |
6594 | QTest::newRow(dataTag: "remove with delayRemove" ) |
6595 | << true |
6596 | << QByteArray("takeOne" ) |
6597 | << -1 |
6598 | << qreal(-1 * 100.0); |
6599 | |
6600 | QTest::newRow(dataTag: "remove with multiple delayRemove" ) |
6601 | << true |
6602 | << QByteArray("takeThree" ) |
6603 | << -3 |
6604 | << qreal(-2 * 100.0); |
6605 | |
6606 | QTest::newRow(dataTag: "clear with delayRemove" ) |
6607 | << true |
6608 | << QByteArray("takeAll" ) |
6609 | << -5 |
6610 | << qreal(-3 * 100.0); |
6611 | } |
6612 | |
6613 | void tst_QQuickGridView::contentHeightWithDelayRemove() |
6614 | { |
6615 | QFETCH(bool, useDelayRemove); |
6616 | QFETCH(QByteArray, removeFunc); |
6617 | QFETCH(int, countDelta); |
6618 | QFETCH(qreal, contentHeightDelta); |
6619 | |
6620 | QQuickView *window = createView(); |
6621 | window->setSource(testFileUrl(fileName: "contentHeightWithDelayRemove.qml" )); |
6622 | window->show(); |
6623 | QVERIFY(QTest::qWaitForWindowExposed(window)); |
6624 | |
6625 | QQuickGridView *gridview = window->rootObject()->findChild<QQuickGridView*>(); |
6626 | QTRY_VERIFY(gridview != nullptr); |
6627 | |
6628 | const int initialCount(gridview->count()); |
6629 | const int eventualCount(initialCount + countDelta); |
6630 | |
6631 | const qreal initialContentHeight(gridview->contentHeight()); |
6632 | const int eventualContentHeight(qRound(d: initialContentHeight + contentHeightDelta)); |
6633 | |
6634 | gridview->setProperty(name: "useDelayRemove" , value: useDelayRemove); |
6635 | QMetaObject::invokeMethod(obj: window->rootObject(), member: removeFunc.constData()); |
6636 | QTest::qWait(ms: 50); |
6637 | QCOMPARE(gridview->count(), eventualCount); |
6638 | |
6639 | if (useDelayRemove) { |
6640 | QCOMPARE(qRound(gridview->contentHeight()), qRound(initialContentHeight)); |
6641 | QTRY_COMPARE(qRound(gridview->contentHeight()), eventualContentHeight); |
6642 | } else { |
6643 | QTRY_COMPARE(qRound(gridview->contentHeight()), eventualContentHeight); |
6644 | } |
6645 | |
6646 | delete window; |
6647 | } |
6648 | |
6649 | void tst_QQuickGridView::QTBUG_45640() |
6650 | { |
6651 | QQuickView *window = createView(); |
6652 | window->setSource(testFileUrl(fileName: "qtbug45640.qml" )); |
6653 | window->show(); |
6654 | QVERIFY(QTest::qWaitForWindowExposed(window)); |
6655 | |
6656 | QQuickGridView *gridview = qobject_cast<QQuickGridView*>(object: window->rootObject()); |
6657 | QVERIFY(gridview != nullptr); |
6658 | |
6659 | QCOMPARE(gridview->contentY(), qreal(-50.0)); |
6660 | |
6661 | gridview->moveCurrentIndexDown(); |
6662 | |
6663 | QTRY_VERIFY(gridview->contentY() > qreal(-50.0) && gridview->contentY() < qreal(0.0)); |
6664 | |
6665 | delete window; |
6666 | } |
6667 | |
6668 | void tst_QQuickGridView::QTBUG_49218() |
6669 | { |
6670 | QQuickView *window = createView(); |
6671 | window->setSource(testFileUrl(fileName: "qtbug49218.qml" )); |
6672 | window->show(); |
6673 | QVERIFY(QTest::qWaitForWindowExposed(window)); |
6674 | |
6675 | QQuickItem *rootItem = qobject_cast<QQuickItem*>(object: window->rootObject()); |
6676 | QQuickGridView *gridview = qobject_cast<QQuickGridView *>(object: rootItem->childItems().first()); |
6677 | QVERIFY(gridview != nullptr); |
6678 | |
6679 | auto processEventsAndForceLayout = [&gridview] () { |
6680 | for (int pass = 0; pass < 2; ++pass) { |
6681 | QCoreApplication::sendPostedEvents(receiver: nullptr, event_type: QEvent::DeferredDelete); |
6682 | gridview->forceLayout(); |
6683 | } |
6684 | }; |
6685 | QMetaObject::invokeMethod(obj: rootItem, member: "scrollToTop" ); |
6686 | processEventsAndForceLayout(); |
6687 | QMetaObject::invokeMethod(obj: rootItem, member: "changeModel" ); |
6688 | processEventsAndForceLayout(); |
6689 | QMetaObject::invokeMethod(obj: rootItem, member: "changeModel" ); |
6690 | processEventsAndForceLayout(); |
6691 | QMetaObject::invokeMethod(obj: rootItem, member: "scrollToTop" ); |
6692 | processEventsAndForceLayout(); |
6693 | |
6694 | QCOMPARE(gridview->indexAt(gridview->cellWidth() - 10, gridview->cellHeight() - 10), 0); |
6695 | delete window; |
6696 | } |
6697 | |
6698 | void tst_QQuickGridView::keyNavigationEnabled() |
6699 | { |
6700 | QScopedPointer<QQuickView> window(createView()); |
6701 | window->setSource(testFileUrl(fileName: "keyNavigationEnabled.qml" )); |
6702 | window->show(); |
6703 | window->requestActivate(); |
6704 | QVERIFY(QTest::qWaitForWindowActive(window.data())); |
6705 | |
6706 | QQuickGridView *gridView = qobject_cast<QQuickGridView *>(object: window->rootObject()); |
6707 | QVERIFY(gridView); |
6708 | QCOMPARE(gridView->isKeyNavigationEnabled(), true); |
6709 | |
6710 | gridView->setFocus(true); |
6711 | QVERIFY(gridView->hasActiveFocus()); |
6712 | |
6713 | gridView->setHighlightMoveDuration(0); |
6714 | |
6715 | // If keyNavigationEnabled is not explicitly set to true, respect the original behavior |
6716 | // of disabling both mouse and keyboard interaction. |
6717 | QSignalSpy enabledSpy(gridView, SIGNAL(keyNavigationEnabledChanged())); |
6718 | gridView->setInteractive(false); |
6719 | QCOMPARE(enabledSpy.count(), 1); |
6720 | QCOMPARE(gridView->isKeyNavigationEnabled(), false); |
6721 | |
6722 | flick(window: window.data(), from: QPoint(200, 175), to: QPoint(200, 50), duration: 100); |
6723 | QVERIFY(!gridView->isMoving()); |
6724 | QCOMPARE(gridView->contentY(), 0.0); |
6725 | QCOMPARE(gridView->currentIndex(), 0); |
6726 | |
6727 | QTest::keyClick(window: window.data(), key: Qt::Key_Right); |
6728 | QCOMPARE(gridView->currentIndex(), 0); |
6729 | |
6730 | // Check that isKeyNavigationEnabled implicitly follows the value of interactive. |
6731 | gridView->setInteractive(true); |
6732 | QCOMPARE(enabledSpy.count(), 2); |
6733 | QCOMPARE(gridView->isKeyNavigationEnabled(), true); |
6734 | |
6735 | // Change it back again for the next check. |
6736 | gridView->setInteractive(false); |
6737 | QCOMPARE(enabledSpy.count(), 3); |
6738 | QCOMPARE(gridView->isKeyNavigationEnabled(), false); |
6739 | |
6740 | // Setting keyNavigationEnabled to true shouldn't enable mouse interaction. |
6741 | gridView->setKeyNavigationEnabled(true); |
6742 | QCOMPARE(enabledSpy.count(), 4); |
6743 | flick(window: window.data(), from: QPoint(200, 175), to: QPoint(200, 50), duration: 100); |
6744 | QVERIFY(!gridView->isMoving()); |
6745 | QCOMPARE(gridView->contentY(), 0.0); |
6746 | QCOMPARE(gridView->currentIndex(), 0); |
6747 | |
6748 | // Should now work. |
6749 | QTest::keyClick(window: window.data(), key: Qt::Key_Right); |
6750 | QCOMPARE(gridView->currentIndex(), 1); |
6751 | |
6752 | // Changing interactive now shouldn't result in keyNavigationEnabled changing, |
6753 | // since we broke the "binding". |
6754 | gridView->setInteractive(true); |
6755 | QCOMPARE(enabledSpy.count(), 4); |
6756 | |
6757 | // Keyboard interaction shouldn't work now. |
6758 | gridView->setKeyNavigationEnabled(false); |
6759 | QTest::keyClick(window: window.data(), key: Qt::Key_Right); |
6760 | QCOMPARE(gridView->currentIndex(), 1); |
6761 | } |
6762 | |
6763 | void tst_QQuickGridView::QTBUG_48870_fastModelUpdates() |
6764 | { |
6765 | StressTestModel model; |
6766 | |
6767 | QScopedPointer<QQuickView> window(createView()); |
6768 | QQmlContext *ctxt = window->rootContext(); |
6769 | ctxt->setContextProperty("testModel" , &model); |
6770 | |
6771 | window->setSource(testFileUrl(fileName: "qtbug48870.qml" )); |
6772 | window->show(); |
6773 | QVERIFY(QTest::qWaitForWindowExposed(window.data())); |
6774 | |
6775 | QQuickGridView *view = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "view" ); |
6776 | QTRY_VERIFY(view != nullptr); |
6777 | |
6778 | QQuickItemViewPrivate *priv = QQuickItemViewPrivate::get(o: view); |
6779 | bool nonUnique; |
6780 | FxViewItem *item = nullptr; |
6781 | int expectedIdx; |
6782 | QVERIFY(testVisibleItems(priv, &nonUnique, &item, &expectedIdx)); |
6783 | |
6784 | for (int i = 0; i < 10; i++) { |
6785 | QTest::qWait(ms: 100); |
6786 | QVERIFY2(testVisibleItems(priv, &nonUnique, &item, &expectedIdx), |
6787 | qPrintable(!item ? QString("Unexpected null item" ) |
6788 | : nonUnique ? QString("Non-unique item at %1 and %2" ).arg(item->index).arg(expectedIdx) |
6789 | : QString("Found index %1, expected index is %3" ).arg(item->index).arg(expectedIdx))); |
6790 | if (i % 3 != 0) { |
6791 | if (i & 1) |
6792 | flick(window: window.data(), from: QPoint(100, 200), to: QPoint(100, 0), duration: 100); |
6793 | else |
6794 | flick(window: window.data(), from: QPoint(100, 200), to: QPoint(100, 400), duration: 100); |
6795 | } |
6796 | } |
6797 | } |
6798 | |
6799 | void tst_QQuickGridView::resizeDynamicCellWidthRtL() |
6800 | { |
6801 | QScopedPointer<QQuickView> window(createView()); |
6802 | window->setSource(testFileUrl(fileName: "qtbug92998.qml" )); |
6803 | window->show(); |
6804 | QVERIFY(QTest::qWaitForWindowExposed(window.data())); |
6805 | |
6806 | QQuickGridView *gridview = findItem<QQuickGridView>(parent: window->rootObject(), objectName: "gridview" ); |
6807 | QTRY_VERIFY(gridview != nullptr); |
6808 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
6809 | gridview->setWidth(460); |
6810 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
6811 | QTRY_COMPARE(gridview->contentX(), 0.f); |
6812 | gridview->setWidth(360); |
6813 | QVERIFY(QQuickTest::qWaitForItemPolished(gridview)); |
6814 | QTRY_COMPARE(gridview->contentX(), 0.f); |
6815 | } |
6816 | |
6817 | void tst_QQuickGridView::releaseItems() |
6818 | { |
6819 | QScopedPointer<QQuickView> view(createView()); |
6820 | view->setSource(testFileUrl(fileName: "releaseItems.qml" )); |
6821 | |
6822 | QQuickGridView *gridview = qobject_cast<QQuickGridView *>(object: view->rootObject()); |
6823 | QVERIFY(gridview); |
6824 | |
6825 | // don't crash (QTBUG-61294) |
6826 | gridview->setModel(123); |
6827 | } |
6828 | |
6829 | QTEST_MAIN(tst_QQuickGridView) |
6830 | |
6831 | #include "tst_qquickgridview.moc" |
6832 | |
6833 | |