1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include <QtTest/QtTest>
42 #include <private/qlistmodelinterface_p.h>
43 #include <QtQuick/qquickview.h>
44 #include <qqmlengine.h>
45 #include <QtQuick/private/qquickrectangle_p.h>
46 #include <QtQuick/private/qquickpositioners_p.h>
47 #include <QtQuick/private/qquicktransition_p.h>
48 #include <private/qquickitem_p.h>
49 #include <qqmlexpression.h>
50 #include "../shared/viewtestutil.h"
51 #include "../shared/visualtestutil.h"
52 #include "../../shared/util.h"
54 using namespace QQuickViewTestUtil;
55 using namespace QQuickVisualTestUtil;
57 class tst_qquickpositioners : public QQmlDataTest
61 tst_qquickpositioners();
64 void test_horizontal();
65 void test_horizontal_rtl();
66 void test_horizontal_spacing();
67 void test_horizontal_spacing_rightToLeft();
68 void test_horizontal_animated();
69 void test_horizontal_animated_rightToLeft();
70 void test_horizontal_animated_disabled();
72 void test_vertical_spacing();
73 void test_vertical_animated();
75 void test_grid_topToBottom();
76 void test_grid_rightToLeft();
77 void test_grid_spacing();
78 void test_grid_row_column_spacing();
79 void test_grid_animated();
80 void test_grid_animated_rightToLeft();
81 void test_grid_zero_columns();
82 void test_propertychanges();
85 void test_flow_rightToLeft();
86 void test_flow_topToBottom();
87 void test_flow_resize();
88 void test_flow_resize_rightToLeft();
89 void test_flow_implicit_resize();
90 void test_conflictinganchors();
91 void test_mirroring();
92 void test_allInvisible();
93 void test_attachedproperties();
94 void test_attachedproperties_data();
95 void test_attachedproperties_dynamic();
97 void populateTransitions_row();
98 void populateTransitions_row_data();
99 void populateTransitions_column();
100 void populateTransitions_column_data();
101 void populateTransitions_grid();
102 void populateTransitions_grid_data();
103 void populateTransitions_flow();
104 void populateTransitions_flow_data();
105 void addTransitions_row();
106 void addTransitions_row_data();
107 void addTransitions_column();
108 void addTransitions_column_data();
109 void addTransitions_grid();
110 void addTransitions_grid_data();
111 void addTransitions_flow();
112 void addTransitions_flow_data();
113 void moveTransitions_row();
114 void moveTransitions_row_data();
115 void moveTransitions_column();
116 void moveTransitions_column_data();
117 void moveTransitions_grid();
118 void moveTransitions_grid_data();
119 void moveTransitions_flow();
120 void moveTransitions_flow_data();
123 QQuickView *createView(const QString &filename, bool wait=true);
125 void populateTransitions(const QString &positionerObjectName);
126 void populateTransitions_data();
127 void addTransitions(const QString &positionerObjectName);
128 void addTransitions_data();
129 void moveTransitions(const QString &positionerObjectName);
130 void moveTransitions_data();
131 void matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes);
132 void matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes);
133 void matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems);
134 void checkItemPositions(QQuickItem *positioner, QaimModel *model, qreal incrementalSize);
137 void tst_qquickpositioners::populateTransitions_row()
139 populateTransitions("row");
142 void tst_qquickpositioners::populateTransitions_row_data()
144 populateTransitions_data();
147 void tst_qquickpositioners::populateTransitions_column()
149 populateTransitions("column");
152 void tst_qquickpositioners::populateTransitions_column_data()
154 populateTransitions_data();
157 void tst_qquickpositioners::populateTransitions_grid()
159 populateTransitions("grid");
162 void tst_qquickpositioners::populateTransitions_grid_data()
164 populateTransitions_data();
167 void tst_qquickpositioners::populateTransitions_flow()
169 populateTransitions("flow");
172 void tst_qquickpositioners::populateTransitions_flow_data()
174 populateTransitions_data();
177 void tst_qquickpositioners::addTransitions_row()
179 addTransitions("row");
182 void tst_qquickpositioners::addTransitions_row_data()
184 addTransitions_data();
187 void tst_qquickpositioners::addTransitions_column()
189 addTransitions("column");
192 void tst_qquickpositioners::addTransitions_column_data()
194 addTransitions_data();
197 void tst_qquickpositioners::addTransitions_grid()
199 addTransitions("grid");
202 void tst_qquickpositioners::addTransitions_grid_data()
204 // don't use addTransitions_data() because grid displaces items differently
205 // (adding items further down the grid can cause displace transitions at
206 // previous indexes, since grid is auto-resized to tightly fit all of its items)
208 QTest::addColumn<int>("initialItemCount");
209 QTest::addColumn<int>("insertionIndex");
210 QTest::addColumn<int>("insertionCount");
211 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
213 QTest::newRow("add one @ start") << 10 << 0 << 1 << ListRange(0, 9);
214 QTest::newRow("add one @ middle") << 10 << 5 << 1 << ListRange(3, 3) + ListRange(5, 9);
215 QTest::newRow("add one @ end") << 10 << 10 << 1 << ListRange(3, 3) + ListRange(7, 7);
217 QTest::newRow("add multiple @ start") << 10 << 0 << 3 << ListRange(0, 9);
218 QTest::newRow("add multiple @ middle") << 10 << 5 << 3 << ListRange(1, 3) + ListRange(5, 9);
219 QTest::newRow("add multiple @ end") << 10 << 10 << 3 << ListRange(1, 3) + ListRange(5, 7) + ListRange(9, 9);
222 void tst_qquickpositioners::addTransitions_flow()
224 addTransitions("flow");
227 void tst_qquickpositioners::addTransitions_flow_data()
229 addTransitions_data();
232 void tst_qquickpositioners::moveTransitions_row()
234 moveTransitions("row");
237 void tst_qquickpositioners::moveTransitions_row_data()
239 moveTransitions_data();
242 void tst_qquickpositioners::moveTransitions_column()
244 moveTransitions("column");
247 void tst_qquickpositioners::moveTransitions_column_data()
249 moveTransitions_data();
252 void tst_qquickpositioners::moveTransitions_grid()
254 moveTransitions("grid");
257 void tst_qquickpositioners::moveTransitions_grid_data()
259 // don't use moveTransitions_data() because grid displaces items differently
260 // (removing items further down the grid can cause displace transitions at
261 // previous indexes, since grid is auto-resized to tightly fit all of its items)
263 QTest::addColumn<int>("initialItemCount");
264 QTest::addColumn<ListChange>("change");
265 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
267 QTest::newRow("remove one @ start") << 10 << ListChange::remove(0, 1) << ListRange(1, 9);
268 QTest::newRow("remove one @ middle") << 10 << ListChange::remove(4, 1) << ListRange(2, 3) + ListRange(5, 9);
269 QTest::newRow("remove one @ end") << 10 << ListChange::remove(9, 1) << ListRange(2, 3) + ListRange(6, 7);
271 QTest::newRow("remove multiple @ start") << 10 << ListChange::remove(0, 3) << ListRange(3, 9);
272 QTest::newRow("remove multiple @ middle") << 10 << ListChange::remove(4, 3) << ListRange(1, 3) + ListRange(7, 9);
273 QTest::newRow("remove multiple @ end") << 10 << ListChange::remove(7, 3) << ListRange(1, 3) + ListRange(5, 6);
276 void tst_qquickpositioners::moveTransitions_flow()
278 moveTransitions("flow");
281 void tst_qquickpositioners::moveTransitions_flow_data()
283 moveTransitions_data();
286 tst_qquickpositioners::tst_qquickpositioners()
290 void tst_qquickpositioners::test_horizontal()
292 QQuickView *window = createView(testFile("horizontal.qml"));
294 window->rootObject()->setProperty("testRightToLeft", false);
296 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
299 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
302 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
305 QCOMPARE(one->x(), 0.0);
306 QCOMPARE(one->y(), 0.0);
307 QCOMPARE(two->x(), 50.0);
308 QCOMPARE(two->y(), 0.0);
309 QCOMPARE(three->x(), 70.0);
310 QCOMPARE(three->y(), 0.0);
312 QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row");
313 QCOMPARE(row->width(), 110.0);
314 QCOMPARE(row->height(), 50.0);
319 void tst_qquickpositioners::test_horizontal_rtl()
321 QQuickView *window = createView(testFile("horizontal.qml"));
323 window->rootObject()->setProperty("testRightToLeft", true);
325 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
328 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
331 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
334 QCOMPARE(one->x(), 60.0);
335 QCOMPARE(one->y(), 0.0);
336 QCOMPARE(two->x(), 40.0);
337 QCOMPARE(two->y(), 0.0);
338 QCOMPARE(three->x(), 0.0);
339 QCOMPARE(three->y(), 0.0);
341 QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row");
342 QCOMPARE(row->width(), 110.0);
343 QCOMPARE(row->height(), 50.0);
345 // Change the width of the row and check that items stay to the right
347 QTRY_COMPARE(one->x(), 150.0);
348 QCOMPARE(one->y(), 0.0);
349 QCOMPARE(two->x(), 130.0);
350 QCOMPARE(two->y(), 0.0);
351 QCOMPARE(three->x(), 90.0);
352 QCOMPARE(three->y(), 0.0);
357 void tst_qquickpositioners::test_horizontal_spacing()
359 QQuickView *window = createView(testFile("horizontal-spacing.qml"));
361 window->rootObject()->setProperty("testRightToLeft", false);
363 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
366 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
369 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
372 QCOMPARE(one->x(), 0.0);
373 QCOMPARE(one->y(), 0.0);
374 QCOMPARE(two->x(), 60.0);
375 QCOMPARE(two->y(), 0.0);
376 QCOMPARE(three->x(), 90.0);
377 QCOMPARE(three->y(), 0.0);
379 QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row");
380 QCOMPARE(row->width(), 130.0);
381 QCOMPARE(row->height(), 50.0);
386 void tst_qquickpositioners::test_horizontal_spacing_rightToLeft()
388 QQuickView *window = createView(testFile("horizontal-spacing.qml"));
390 window->rootObject()->setProperty("testRightToLeft", true);
392 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
395 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
398 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
401 QCOMPARE(one->x(), 80.0);
402 QCOMPARE(one->y(), 0.0);
403 QCOMPARE(two->x(), 50.0);
404 QCOMPARE(two->y(), 0.0);
405 QCOMPARE(three->x(), 00.0);
406 QCOMPARE(three->y(), 0.0);
408 QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row");
409 QCOMPARE(row->width(), 130.0);
410 QCOMPARE(row->height(), 50.0);
415 void tst_qquickpositioners::test_horizontal_animated()
417 QQuickView *window = createView(testFile("horizontal-animated.qml"), false);
419 window->rootObject()->setProperty("testRightToLeft", false);
421 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
424 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
427 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
430 //Note that they animate in
431 QCOMPARE(one->x(), -100.0);
432 QCOMPARE(two->x(), -100.0);
433 QCOMPARE(three->x(), -100.0);
435 QTest::qWaitForWindowShown(window); //It may not relayout until the next frame, so it needs to be drawn
437 QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row");
439 QCOMPARE(row->width(), 100.0);
440 QCOMPARE(row->height(), 50.0);
442 //QTRY_COMPARE used instead of waiting for the expected time of animation completion
443 //Note that this means the duration of the animation is NOT tested
445 QTRY_COMPARE(one->x(), 0.0);
446 QTRY_COMPARE(one->y(), 0.0);
447 QTRY_COMPARE(two->isVisible(), false);
448 QTRY_COMPARE(two->x(), -100.0);//Not 'in' yet
449 QTRY_COMPARE(two->y(), 0.0);
450 QTRY_COMPARE(three->x(), 50.0);
451 QTRY_COMPARE(three->y(), 0.0);
454 two->setVisible(true);
455 QTRY_COMPARE(two->isVisible(), true);
456 QTRY_COMPARE(row->width(), 150.0);
457 QTRY_COMPARE(row->height(), 50.0);
459 QTest::qWait(0);//Let the animation start
460 QVERIFY(two->x() >= -100.0 && two->x() < 50.0);
461 QVERIFY(three->x() >= 50.0 && three->x() < 100.0);
463 QTRY_COMPARE(two->x(), 50.0);
464 QTRY_COMPARE(three->x(), 100.0);
469 void tst_qquickpositioners::test_horizontal_animated_rightToLeft()
471 QQuickView *window = createView(testFile("horizontal-animated.qml"), false);
473 window->rootObject()->setProperty("testRightToLeft", true);
475 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
478 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
481 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
484 //Note that they animate in
485 QCOMPARE(one->x(), -100.0);
486 QCOMPARE(two->x(), -100.0);
487 QCOMPARE(three->x(), -100.0);
489 QTest::qWaitForWindowShown(window); //It may not relayout until the next frame, so it needs to be drawn
491 QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row");
493 QCOMPARE(row->width(), 100.0);
494 QCOMPARE(row->height(), 50.0);
496 //QTRY_COMPARE used instead of waiting for the expected time of animation completion
497 //Note that this means the duration of the animation is NOT tested
499 QTRY_COMPARE(one->x(), 50.0);
500 QTRY_COMPARE(one->y(), 0.0);
501 QTRY_COMPARE(two->isVisible(), false);
502 QTRY_COMPARE(two->x(), -100.0);//Not 'in' yet
503 QTRY_COMPARE(two->y(), 0.0);
504 QTRY_COMPARE(three->x(), 0.0);
505 QTRY_COMPARE(three->y(), 0.0);
508 two->setVisible(true);
509 QTRY_COMPARE(two->isVisible(), true);
511 // New size should propagate after visible change
512 QTRY_COMPARE(row->width(), 150.0);
513 QTRY_COMPARE(row->height(), 50.0);
515 QTest::qWait(0);//Let the animation start
516 QVERIFY(one->x() >= 50.0 && one->x() < 100);
517 QVERIFY(two->x() >= -100.0 && two->x() < 50.0);
519 QTRY_COMPARE(one->x(), 100.0);
520 QTRY_COMPARE(two->x(), 50.0);
525 void tst_qquickpositioners::test_horizontal_animated_disabled()
527 QQuickView *window = createView(testFile("horizontal-animated-disabled.qml"));
529 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
532 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
535 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
538 QQuickItem *row = window->rootObject()->findChild<QQuickItem*>("row");
541 qApp->processEvents();
543 QCOMPARE(one->x(), 0.0);
544 QCOMPARE(one->y(), 0.0);
545 QCOMPARE(two->isVisible(), false);
546 QCOMPARE(two->x(), -100.0);//Not 'in' yet
547 QCOMPARE(two->y(), 0.0);
548 QCOMPARE(three->x(), 50.0);
549 QCOMPARE(three->y(), 0.0);
552 two->setVisible(true);
553 QCOMPARE(two->isVisible(), true);
554 QTRY_COMPARE(row->width(), 150.0);
555 QTRY_COMPARE(row->height(), 50.0);
557 QTRY_COMPARE(two->x(), 50.0);
558 QTRY_COMPARE(three->x(), 100.0);
563 void tst_qquickpositioners::populateTransitions(const QString &positionerObjectName)
565 QFETCH(bool, dynamicallyPopulate);
566 QFETCH(bool, usePopulateTransition);
568 QPointF targetItems_transitionFrom(-50, -50);
569 QPointF displacedItems_transitionVia(100, 100);
572 if (!dynamicallyPopulate) {
573 for (int i = 0; i < 30; i++)
574 model.addItem("Original item" + QString::number(i), "");
577 QaimModel model_targetItems_transitionFrom;
578 QaimModel model_displacedItems_transitionVia;
580 QQuickView *window = QQuickViewTestUtil::createView();
581 QQmlContext *ctxt = window->rootContext();
582 ctxt->setContextProperty("usePopulateTransition", usePopulateTransition);
583 ctxt->setContextProperty("enableAddTransition", true);
584 ctxt->setContextProperty("dynamicallyPopulate", dynamicallyPopulate);
585 ctxt->setContextProperty("testModel", &model);
586 ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom);
587 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
588 ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom);
589 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
590 ctxt->setContextProperty("testedPositioner", positionerObjectName);
591 window->setSource(testFileUrl("transitions.qml"));
593 QQuickItem *positioner = window->rootObject()->findChild<QQuickItem*>(positionerObjectName);
596 qApp->processEvents();
598 if (!dynamicallyPopulate && usePopulateTransition) {
599 QTRY_COMPARE(window->rootObject()->property("populateTransitionsDone").toInt(), model.count());
600 QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), 0);
602 QList<QPair<QString, QString> > targetData;
603 QList<int> targetIndexes;
604 for (int i=0; i<model.count(); i++) {
605 targetData << qMakePair(model.name(i), model.number(i));
608 QList<QQuickItem *> targetItems = findItems<QQuickItem>(positioner, "wrapper", targetIndexes);
609 model_targetItems_transitionFrom.matchAgainst(targetData, "wasn't animated from target 'from' pos", "shouldn't have been animated from target 'from' pos");
610 matchItemsAndIndexes(window->rootObject()->property("targetTrans_items").toMap(), model, targetIndexes);
611 matchIndexLists(window->rootObject()->property("targetTrans_targetIndexes").toList(), targetIndexes);
612 matchItemLists(window->rootObject()->property("targetTrans_targetItems").toList(), targetItems);
614 } else if (dynamicallyPopulate) {
615 QTRY_COMPARE(window->rootObject()->property("populateTransitionsDone").toInt(), 0);
616 QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), model.count());
618 QTRY_COMPARE(QQuickItemPrivate::get(positioner)->polishScheduled, false);
619 QTRY_COMPARE(window->rootObject()->property("populateTransitionsDone").toInt(), 0);
620 QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), 0);
623 checkItemPositions(positioner, &model, window->rootObject()->property("incrementalSize").toInt());
625 // add an item and check this is done with add transition, not populate
626 window->rootObject()->setProperty("populateTransitionsDone", 0);
627 window->rootObject()->setProperty("addTransitionsDone", 0);
628 model.insertItem(0, "new item", "");
629 QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), 1);
630 QTRY_COMPARE(window->rootObject()->property("populateTransitionsDone").toInt(), 0);
635 void tst_qquickpositioners::populateTransitions_data()
637 QTest::addColumn<bool>("dynamicallyPopulate");
638 QTest::addColumn<bool>("usePopulateTransition");
640 QTest::newRow("statically populate") << false << true;
641 QTest::newRow("statically populate, no populate transition") << false << false;
643 QTest::newRow("dynamically populate") << true << true;
644 QTest::newRow("dynamically populate, no populate transition") << true << false;
647 void tst_qquickpositioners::addTransitions(const QString &positionerObjectName)
649 QFETCH(int, initialItemCount);
650 QFETCH(int, insertionIndex);
651 QFETCH(int, insertionCount);
652 QFETCH(ListRange, expectedDisplacedIndexes);
654 QPointF targetItems_transitionFrom(-50, -50);
655 QPointF displacedItems_transitionVia(100, 100);
658 QaimModel model_targetItems_transitionFrom;
659 QaimModel model_displacedItems_transitionVia;
661 QQuickView *window = QQuickViewTestUtil::createView();
662 QQmlContext *ctxt = window->rootContext();
663 ctxt->setContextProperty("usePopulateTransition", QVariant(false));
664 ctxt->setContextProperty("enableAddTransition", QVariant(true));
665 ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom);
666 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
667 ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom);
668 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
669 window->setSource(testFileUrl("transitions.qml"));
671 qApp->processEvents();
673 QQuickItem *positioner = window->rootObject()->findChild<QQuickItem*>(positionerObjectName);
675 positioner->findChild<QQuickItem*>("repeater")->setProperty("model", QVariant::fromValue(&model));
676 QTRY_COMPARE(QQuickItemPrivate::get(positioner)->polishScheduled, false);
678 for (int i = 0; i < initialItemCount; i++)
679 model.addItem("Original item" + QString::number(i), "");
681 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
682 QList<QPair<QString, QString> > targetData;
683 QList<int> targetIndexes;
684 for (int i=0; i<model.count(); i++) {
685 targetData << qMakePair(model.name(i), model.number(i));
688 QList<QQuickItem *> targetItems = findItems<QQuickItem>(positioner, "wrapper", targetIndexes);
690 // check add transition was run for first lot of added items
691 QTRY_COMPARE(window->rootObject()->property("populateTransitionsDone").toInt(), 0);
692 QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), initialItemCount);
693 QTRY_COMPARE(window->rootObject()->property("displaceTransitionsDone").toInt(), 0);
694 model_targetItems_transitionFrom.matchAgainst(targetData, "wasn't animated from target 'from' pos", "shouldn't have been animated from target 'from' pos");
695 matchItemsAndIndexes(window->rootObject()->property("targetTrans_items").toMap(), model, targetIndexes);
696 matchIndexLists(window->rootObject()->property("targetTrans_targetIndexes").toList(), targetIndexes);
697 matchItemLists(window->rootObject()->property("targetTrans_targetItems").toList(), targetItems);
699 model_targetItems_transitionFrom.clear();
700 window->rootObject()->setProperty("addTransitionsDone", 0);
701 window->rootObject()->setProperty("targetTrans_items", QVariantMap());
702 window->rootObject()->setProperty("targetTrans_targetIndexes", QVariantList());
703 window->rootObject()->setProperty("targetTrans_targetItems", QVariantList());
707 targetIndexes.clear();
708 for (int i=insertionIndex; i<insertionIndex+insertionCount; i++) {
709 targetData << qMakePair(QString("New item %1").arg(i), QString(""));
712 model.insertItems(insertionIndex, targetData);
713 QTRY_COMPARE(model.count(), positioner->property("count").toInt());
715 targetItems = findItems<QQuickItem>(positioner, "wrapper", targetIndexes);
717 QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), targetData.count());
718 QTRY_COMPARE(window->rootObject()->property("displaceTransitionsDone").toInt(), expectedDisplacedIndexes.count());
720 // check the target and displaced items were animated
721 model_targetItems_transitionFrom.matchAgainst(targetData, "wasn't animated from target 'from' pos", "shouldn't have been animated from target 'from' pos");
722 model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
724 // check attached properties
725 matchItemsAndIndexes(window->rootObject()->property("targetTrans_items").toMap(), model, targetIndexes);
726 matchIndexLists(window->rootObject()->property("targetTrans_targetIndexes").toList(), targetIndexes);
727 matchItemLists(window->rootObject()->property("targetTrans_targetItems").toList(), targetItems);
728 if (expectedDisplacedIndexes.isValid()) {
729 // adjust expectedDisplacedIndexes to their final values after the move
730 QList<int> displacedIndexes = adjustIndexesForAddDisplaced(expectedDisplacedIndexes.indexes, insertionIndex, insertionCount);
731 matchItemsAndIndexes(window->rootObject()->property("displacedTrans_items").toMap(), model, displacedIndexes);
732 matchIndexLists(window->rootObject()->property("displacedTrans_targetIndexes").toList(), targetIndexes);
733 matchItemLists(window->rootObject()->property("displacedTrans_targetItems").toList(), targetItems);
736 checkItemPositions(positioner, &model, window->rootObject()->property("incrementalSize").toInt());
741 void tst_qquickpositioners::addTransitions_data()
743 // If this data changes, update addTransitions_grid_data() also
745 QTest::addColumn<int>("initialItemCount");
746 QTest::addColumn<int>("insertionIndex");
747 QTest::addColumn<int>("insertionCount");
748 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
750 QTest::newRow("add one @ start") << 10 << 0 << 1 << ListRange(0, 9);
751 QTest::newRow("add one @ middle") << 10 << 5 << 1 << ListRange(5, 9);
752 QTest::newRow("add one @ end") << 10 << 10 << 1 << ListRange();
754 QTest::newRow("add multiple @ start") << 10 << 0 << 3 << ListRange(0, 9);
755 QTest::newRow("add multiple @ middle") << 10 << 5 << 3 << ListRange(5, 9);
756 QTest::newRow("add multiple @ end") << 10 << 10 << 3 << ListRange();
759 void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName)
761 QFETCH(int, initialItemCount);
762 QFETCH(ListChange, change);
763 QFETCH(ListRange, expectedDisplacedIndexes);
765 QPointF targetItems_transitionFrom(-50, -50);
766 QPointF displacedItems_transitionVia(100, 100);
769 for (int i = 0; i < initialItemCount; i++)
770 model.addItem("Item" + QString::number(i), "");
771 QaimModel model_targetItems_transitionFrom;
772 QaimModel model_displacedItems_transitionVia;
774 QQuickView *window = QQuickViewTestUtil::createView();
775 QQmlContext *ctxt = window->rootContext();
776 ctxt->setContextProperty("usePopulateTransition", QVariant(false));
777 ctxt->setContextProperty("enableAddTransition", QVariant(false));
778 ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom);
779 ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
780 ctxt->setContextProperty("targetItems_transitionFrom", targetItems_transitionFrom);
781 ctxt->setContextProperty("displacedItems_transitionVia", displacedItems_transitionVia);
782 window->setSource(testFileUrl("transitions.qml"));
784 qApp->processEvents();
786 QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
788 QQuickItem *positioner = window->rootObject()->findChild<QQuickItem*>(positionerObjectName);
790 positioner->findChild<QQuickItem*>("repeater")->setProperty("model", QVariant::fromValue(&model));
791 QTRY_COMPARE(QQuickItemPrivate::get(positioner)->polishScheduled, false);
793 switch (change.type) {
794 case ListChange::Removed:
795 model.removeItems(change.index, change.count);
796 QTRY_COMPARE(model.count(), positioner->property("count").toInt());
798 case ListChange::Moved:
799 model.moveItems(change.index, change.to, change.count);
800 QTRY_COMPARE(QQuickItemPrivate::get(positioner)->polishScheduled, false);
802 case ListChange::Inserted:
803 case ListChange::SetCurrent:
804 case ListChange::SetContentY:
807 case ListChange::Polish:
811 QTRY_COMPARE(window->rootObject()->property("displaceTransitionsDone").toInt(), expectedDisplacedIndexes.count());
812 QCOMPARE(window->rootObject()->property("addTransitionsDone").toInt(), 0);
814 // check the target and displaced items were animated
815 QCOMPARE(model_targetItems_transitionFrom.count(), 0);
816 model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
818 // check attached properties
819 QCOMPARE(window->rootObject()->property("targetTrans_items").toMap().count(), 0);
820 QCOMPARE(window->rootObject()->property("targetTrans_targetIndexes").toList().count(), 0);
821 QCOMPARE(window->rootObject()->property("targetTrans_targetItems").toList().count(), 0);
822 if (expectedDisplacedIndexes.isValid()) {
823 // adjust expectedDisplacedIndexes to their final values after the move
824 QList<int> displacedIndexes;
825 if (change.type == ListChange::Inserted)
826 displacedIndexes = adjustIndexesForAddDisplaced(expectedDisplacedIndexes.indexes, change.index, change.count);
827 else if (change.type == ListChange::Moved)
828 displacedIndexes = adjustIndexesForMove(expectedDisplacedIndexes.indexes, change.index, change.to, change.count);
829 else if (change.type == ListChange::Removed)
830 displacedIndexes = adjustIndexesForRemoveDisplaced(expectedDisplacedIndexes.indexes, change.index, change.count);
833 matchItemsAndIndexes(window->rootObject()->property("displacedTrans_items").toMap(), model, displacedIndexes);
835 QVariantList listOfEmptyIntLists;
836 for (int i=0; i<displacedIndexes.count(); i++)
837 listOfEmptyIntLists << QVariant::fromValue(QList<int>());
838 QCOMPARE(window->rootObject()->property("displacedTrans_targetIndexes").toList(), listOfEmptyIntLists);
839 QVariantList listOfEmptyObjectLists;
840 for (int i=0; i<displacedIndexes.count(); i++)
841 listOfEmptyObjectLists.insert(listOfEmptyObjectLists.count(), QVariantList());
842 QCOMPARE(window->rootObject()->property("displacedTrans_targetItems").toList(), listOfEmptyObjectLists);
845 checkItemPositions(positioner, &model, window->rootObject()->property("incrementalSize").toInt());
850 void tst_qquickpositioners::moveTransitions_data()
852 // If this data changes, update moveTransitions_grid_data() also
854 QTest::addColumn<int>("initialItemCount");
855 QTest::addColumn<ListChange>("change");
856 QTest::addColumn<ListRange>("expectedDisplacedIndexes");
858 QTest::newRow("remove one @ start") << 10 << ListChange::remove(0, 1) << ListRange(1, 9);
859 QTest::newRow("remove one @ middle") << 10 << ListChange::remove(4, 1) << ListRange(5, 9);
860 QTest::newRow("remove one @ end") << 10 << ListChange::remove(9, 1) << ListRange();
862 QTest::newRow("remove multiple @ start") << 10 << ListChange::remove(0, 3) << ListRange(3, 9);
863 QTest::newRow("remove multiple @ middle") << 10 << ListChange::remove(4, 3) << ListRange(7, 9);
864 QTest::newRow("remove multiple @ end") << 10 << ListChange::remove(7, 3) << ListRange();
868 void tst_qquickpositioners::checkItemPositions(QQuickItem *positioner, QaimModel *model, qreal incrementalSize)
870 QVERIFY(model->count() > 0);
872 qreal currentSize = 30;
876 for (int i=0; i<model->count(); ++i) {
877 QQuickItem *item = findItem<QQuickItem>(positioner, "wrapper", i);
878 QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
880 QCOMPARE(item->width(), currentSize);
881 QCOMPARE(item->height(), currentSize);
883 if (qobject_cast<QQuickRow*>(positioner)) {
884 QCOMPARE(item->x(), (i * 30.0) + padding);
885 QCOMPARE(item->y(), 0.0);
886 } else if (qobject_cast<QQuickColumn*>(positioner)) {
887 QCOMPARE(item->x(), 0.0);
888 QCOMPARE(item->y(), (i * 30.0) + padding);
889 } else if (qobject_cast<QQuickGrid*>(positioner)) {
891 int rows = qCeil(model->count() / qreal(columns));
892 int lastMatchingRowIndex = (rows * columns) - (columns - i%columns);
893 if (lastMatchingRowIndex >= model->count())
894 lastMatchingRowIndex -= columns;
895 if (i % columns > 0) {
896 QQuickItem *finalAlignedRowItem = findItem<QQuickItem>(positioner, "wrapper", lastMatchingRowIndex);
897 QVERIFY(finalAlignedRowItem);
898 QCOMPARE(item->x(), finalAlignedRowItem->x());
900 QCOMPARE(item->x(), 0.0);
902 if (i / columns > 0) {
903 QQuickItem *prevRowLastItem = findItem<QQuickItem>(positioner, "wrapper", (i/columns * columns) - 1);
904 QVERIFY(prevRowLastItem);
905 QCOMPARE(item->y(), prevRowLastItem->y() + prevRowLastItem->height());
907 QCOMPARE(item->y(), 0.0);
909 } else if (qobject_cast<QQuickFlow*>(positioner)) {
910 if (rowX + item->width() > positioner->width()) {
911 QQuickItem *prevItem = findItem<QQuickItem>(positioner, "wrapper", i-1);
914 rowY = prevItem->y() + prevItem->height();
916 QCOMPARE(item->x(), rowX);
917 QCOMPARE(item->y(), rowY);
918 rowX += item->width();
920 QVERIFY2(false, "Unknown positioner type");
922 QQuickText *name = findItem<QQuickText>(positioner, "name", i);
924 QTRY_COMPARE(name->text(), model->name(i));
926 padding += i * incrementalSize;
927 currentSize += incrementalSize;
931 void tst_qquickpositioners::test_vertical()
933 QQuickView *window = createView(testFile("vertical.qml"));
935 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
938 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
941 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
944 QCOMPARE(one->x(), 0.0);
945 QCOMPARE(one->y(), 0.0);
946 QCOMPARE(two->x(), 0.0);
947 QCOMPARE(two->y(), 50.0);
948 QCOMPARE(three->x(), 0.0);
949 QCOMPARE(three->y(), 60.0);
951 QQuickItem *column = window->rootObject()->findChild<QQuickItem*>("column");
953 QCOMPARE(column->height(), 80.0);
954 QCOMPARE(column->width(), 50.0);
959 void tst_qquickpositioners::test_vertical_spacing()
961 QQuickView *window = createView(testFile("vertical-spacing.qml"));
963 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
966 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
969 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
972 QCOMPARE(one->x(), 0.0);
973 QCOMPARE(one->y(), 0.0);
974 QCOMPARE(two->x(), 0.0);
975 QCOMPARE(two->y(), 60.0);
976 QCOMPARE(three->x(), 0.0);
977 QCOMPARE(three->y(), 80.0);
979 QQuickItem *column = window->rootObject()->findChild<QQuickItem*>("column");
980 QCOMPARE(column->height(), 100.0);
981 QCOMPARE(column->width(), 50.0);
986 void tst_qquickpositioners::test_vertical_animated()
988 QQuickView *window = createView(testFile("vertical-animated.qml"), false);
990 //Note that they animate in
991 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
993 QCOMPARE(one->y(), -100.0);
995 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
997 QCOMPARE(two->y(), -100.0);
999 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1000 QVERIFY(three != 0);
1001 QCOMPARE(three->y(), -100.0);
1003 QTest::qWaitForWindowShown(window); //It may not relayout until the next frame, so it needs to be drawn
1005 QQuickItem *column = window->rootObject()->findChild<QQuickItem*>("column");
1007 QCOMPARE(column->height(), 100.0);
1008 QCOMPARE(column->width(), 50.0);
1010 //QTRY_COMPARE used instead of waiting for the expected time of animation completion
1011 //Note that this means the duration of the animation is NOT tested
1013 QTRY_COMPARE(one->y(), 0.0);
1014 QTRY_COMPARE(one->x(), 0.0);
1015 QTRY_COMPARE(two->isVisible(), false);
1016 QTRY_COMPARE(two->y(), -100.0);//Not 'in' yet
1017 QTRY_COMPARE(two->x(), 0.0);
1018 QTRY_COMPARE(three->y(), 50.0);
1019 QTRY_COMPARE(three->x(), 0.0);
1022 two->setVisible(true);
1023 QTRY_COMPARE(two->isVisible(), true);
1024 QTRY_COMPARE(column->height(), 150.0);
1025 QTRY_COMPARE(column->width(), 50.0);
1026 QTest::qWait(0);//Let the animation start
1027 QVERIFY(two->y() >= -100.0 && two->y() < 50.0);
1028 QVERIFY(three->y() >= 50.0 && three->y() < 100.0);
1030 QTRY_COMPARE(two->y(), 50.0);
1031 QTRY_COMPARE(three->y(), 100.0);
1036 void tst_qquickpositioners::test_grid()
1038 QQuickView *window = createView(testFile("gridtest.qml"));
1040 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1042 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1044 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1045 QVERIFY(three != 0);
1046 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1048 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1051 QCOMPARE(one->x(), 0.0);
1052 QCOMPARE(one->y(), 0.0);
1053 QCOMPARE(two->x(), 50.0);
1054 QCOMPARE(two->y(), 0.0);
1055 QCOMPARE(three->x(), 70.0);
1056 QCOMPARE(three->y(), 0.0);
1057 QCOMPARE(four->x(), 0.0);
1058 QCOMPARE(four->y(), 50.0);
1059 QCOMPARE(five->x(), 50.0);
1060 QCOMPARE(five->y(), 50.0);
1062 QQuickGrid *grid = window->rootObject()->findChild<QQuickGrid*>("grid");
1063 QCOMPARE(grid->flow(), QQuickGrid::LeftToRight);
1064 QCOMPARE(grid->width(), 100.0);
1065 QCOMPARE(grid->height(), 100.0);
1070 void tst_qquickpositioners::test_grid_topToBottom()
1072 QQuickView *window = createView(testFile("grid-toptobottom.qml"));
1074 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1076 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1078 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1079 QVERIFY(three != 0);
1080 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1082 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1085 QCOMPARE(one->x(), 0.0);
1086 QCOMPARE(one->y(), 0.0);
1087 QCOMPARE(two->x(), 0.0);
1088 QCOMPARE(two->y(), 50.0);
1089 QCOMPARE(three->x(), 0.0);
1090 QCOMPARE(three->y(), 100.0);
1091 QCOMPARE(four->x(), 50.0);
1092 QCOMPARE(four->y(), 0.0);
1093 QCOMPARE(five->x(), 50.0);
1094 QCOMPARE(five->y(), 50.0);
1096 QQuickGrid *grid = window->rootObject()->findChild<QQuickGrid*>("grid");
1097 QCOMPARE(grid->flow(), QQuickGrid::TopToBottom);
1098 QCOMPARE(grid->width(), 100.0);
1099 QCOMPARE(grid->height(), 120.0);
1104 void tst_qquickpositioners::test_grid_rightToLeft()
1106 QQuickView *window = createView(testFile("gridtest.qml"));
1108 window->rootObject()->setProperty("testRightToLeft", true);
1110 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1112 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1114 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1115 QVERIFY(three != 0);
1116 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1118 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1121 QCOMPARE(one->x(), 50.0);
1122 QCOMPARE(one->y(), 0.0);
1123 QCOMPARE(two->x(), 30.0);
1124 QCOMPARE(two->y(), 0.0);
1125 QCOMPARE(three->x(), 0.0);
1126 QCOMPARE(three->y(), 0.0);
1127 QCOMPARE(four->x(), 50.0);
1128 QCOMPARE(four->y(), 50.0);
1129 QCOMPARE(five->x(), 40.0);
1130 QCOMPARE(five->y(), 50.0);
1132 QQuickGrid *grid = window->rootObject()->findChild<QQuickGrid*>("grid");
1133 QCOMPARE(grid->layoutDirection(), Qt::RightToLeft);
1134 QCOMPARE(grid->width(), 100.0);
1135 QCOMPARE(grid->height(), 100.0);
1137 // Change the width of the grid and check that items stay to the right
1138 grid->setWidth(200);
1139 QTRY_COMPARE(one->x(), 150.0);
1140 QCOMPARE(one->y(), 0.0);
1141 QCOMPARE(two->x(), 130.0);
1142 QCOMPARE(two->y(), 0.0);
1143 QCOMPARE(three->x(), 100.0);
1144 QCOMPARE(three->y(), 0.0);
1145 QCOMPARE(four->x(), 150.0);
1146 QCOMPARE(four->y(), 50.0);
1147 QCOMPARE(five->x(), 140.0);
1148 QCOMPARE(five->y(), 50.0);
1153 void tst_qquickpositioners::test_grid_spacing()
1155 QQuickView *window = createView(testFile("grid-spacing.qml"));
1157 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1159 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1161 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1162 QVERIFY(three != 0);
1163 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1165 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1168 QCOMPARE(one->x(), 0.0);
1169 QCOMPARE(one->y(), 0.0);
1170 QCOMPARE(two->x(), 54.0);
1171 QCOMPARE(two->y(), 0.0);
1172 QCOMPARE(three->x(), 78.0);
1173 QCOMPARE(three->y(), 0.0);
1174 QCOMPARE(four->x(), 0.0);
1175 QCOMPARE(four->y(), 54.0);
1176 QCOMPARE(five->x(), 54.0);
1177 QCOMPARE(five->y(), 54.0);
1179 QQuickItem *grid = window->rootObject()->findChild<QQuickItem*>("grid");
1180 QCOMPARE(grid->width(), 128.0);
1181 QCOMPARE(grid->height(), 104.0);
1186 void tst_qquickpositioners::test_grid_row_column_spacing()
1188 QQuickView *window = createView(testFile("grid-row-column-spacing.qml"));
1190 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1192 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1194 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1195 QVERIFY(three != 0);
1196 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1198 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1201 QCOMPARE(one->x(), 0.0);
1202 QCOMPARE(one->y(), 0.0);
1203 QCOMPARE(two->x(), 61.0);
1204 QCOMPARE(two->y(), 0.0);
1205 QCOMPARE(three->x(), 92.0);
1206 QCOMPARE(three->y(), 0.0);
1207 QCOMPARE(four->x(), 0.0);
1208 QCOMPARE(four->y(), 57.0);
1209 QCOMPARE(five->x(), 61.0);
1210 QCOMPARE(five->y(), 57.0);
1212 QQuickItem *grid = window->rootObject()->findChild<QQuickItem*>("grid");
1213 QCOMPARE(grid->width(), 142.0);
1214 QCOMPARE(grid->height(), 107.0);
1219 void tst_qquickpositioners::test_grid_animated()
1221 QQuickView *window = createView(testFile("grid-animated.qml"), false);
1223 window->rootObject()->setProperty("testRightToLeft", false);
1225 //Note that all animate in
1226 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1228 QCOMPARE(one->x(), -100.0);
1229 QCOMPARE(one->y(), -100.0);
1231 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1233 QCOMPARE(two->x(), -100.0);
1234 QCOMPARE(two->y(), -100.0);
1236 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1237 QVERIFY(three != 0);
1238 QCOMPARE(three->x(), -100.0);
1239 QCOMPARE(three->y(), -100.0);
1241 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1243 QCOMPARE(four->x(), -100.0);
1244 QCOMPARE(four->y(), -100.0);
1246 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1248 QCOMPARE(five->x(), -100.0);
1249 QCOMPARE(five->y(), -100.0);
1251 QTest::qWaitForWindowShown(window); //It may not relayout until the next frame, so it needs to be drawn
1253 QQuickItem *grid = window->rootObject()->findChild<QQuickItem*>("grid");
1255 QCOMPARE(grid->width(), 150.0);
1256 QCOMPARE(grid->height(), 100.0);
1258 //QTRY_COMPARE used instead of waiting for the expected time of animation completion
1259 //Note that this means the duration of the animation is NOT tested
1261 QTRY_COMPARE(one->y(), 0.0);
1262 QTRY_COMPARE(one->x(), 0.0);
1263 QTRY_COMPARE(two->isVisible(), false);
1264 QTRY_COMPARE(two->y(), -100.0);
1265 QTRY_COMPARE(two->x(), -100.0);
1266 QTRY_COMPARE(three->y(), 0.0);
1267 QTRY_COMPARE(three->x(), 50.0);
1268 QTRY_COMPARE(four->y(), 0.0);
1269 QTRY_COMPARE(four->x(), 100.0);
1270 QTRY_COMPARE(five->y(), 50.0);
1271 QTRY_COMPARE(five->x(), 0.0);
1274 two->setVisible(true);
1275 QCOMPARE(two->isVisible(), true);
1276 QCOMPARE(grid->width(), 150.0);
1277 QCOMPARE(grid->height(), 100.0);
1278 QTest::qWait(0);//Let the animation start
1279 QCOMPARE(two->x(), -100.0);
1280 QCOMPARE(two->y(), -100.0);
1281 QCOMPARE(one->x(), 0.0);
1282 QCOMPARE(one->y(), 0.0);
1283 QCOMPARE(three->x(), 50.0);
1284 QCOMPARE(three->y(), 0.0);
1285 QCOMPARE(four->x(), 100.0);
1286 QCOMPARE(four->y(), 0.0);
1287 QCOMPARE(five->x(), 0.0);
1288 QCOMPARE(five->y(), 50.0);
1289 //Let the animation complete
1290 QTRY_COMPARE(two->x(), 50.0);
1291 QTRY_COMPARE(two->y(), 0.0);
1292 QTRY_COMPARE(one->x(), 0.0);
1293 QTRY_COMPARE(one->y(), 0.0);
1294 QTRY_COMPARE(three->x(), 100.0);
1295 QTRY_COMPARE(three->y(), 0.0);
1296 QTRY_COMPARE(four->x(), 0.0);
1297 QTRY_COMPARE(four->y(), 50.0);
1298 QTRY_COMPARE(five->x(), 50.0);
1299 QTRY_COMPARE(five->y(), 50.0);
1304 void tst_qquickpositioners::test_grid_animated_rightToLeft()
1306 QQuickView *window = createView(testFile("grid-animated.qml"), false);
1308 window->rootObject()->setProperty("testRightToLeft", true);
1310 //Note that all animate in
1311 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1313 QCOMPARE(one->x(), -100.0);
1314 QCOMPARE(one->y(), -100.0);
1316 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1318 QCOMPARE(two->x(), -100.0);
1319 QCOMPARE(two->y(), -100.0);
1321 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1322 QVERIFY(three != 0);
1323 QCOMPARE(three->x(), -100.0);
1324 QCOMPARE(three->y(), -100.0);
1326 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1328 QCOMPARE(four->x(), -100.0);
1329 QCOMPARE(four->y(), -100.0);
1331 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1333 QCOMPARE(five->x(), -100.0);
1334 QCOMPARE(five->y(), -100.0);
1336 QTest::qWaitForWindowShown(window); //It may not relayout until the next frame, so it needs to be drawn
1338 QQuickItem *grid = window->rootObject()->findChild<QQuickItem*>("grid");
1340 QCOMPARE(grid->width(), 150.0);
1341 QCOMPARE(grid->height(), 100.0);
1343 //QTRY_COMPARE used instead of waiting for the expected time of animation completion
1344 //Note that this means the duration of the animation is NOT tested
1346 QTRY_COMPARE(one->y(), 0.0);
1347 QTRY_COMPARE(one->x(), 100.0);
1348 QTRY_COMPARE(two->isVisible(), false);
1349 QTRY_COMPARE(two->y(), -100.0);
1350 QTRY_COMPARE(two->x(), -100.0);
1351 QTRY_COMPARE(three->y(), 0.0);
1352 QTRY_COMPARE(three->x(), 50.0);
1353 QTRY_COMPARE(four->y(), 0.0);
1354 QTRY_COMPARE(four->x(), 0.0);
1355 QTRY_COMPARE(five->y(), 50.0);
1356 QTRY_COMPARE(five->x(), 100.0);
1359 two->setVisible(true);
1360 QCOMPARE(two->isVisible(), true);
1361 QCOMPARE(grid->width(), 150.0);
1362 QCOMPARE(grid->height(), 100.0);
1363 QTest::qWait(0);//Let the animation start
1364 QCOMPARE(two->x(), -100.0);
1365 QCOMPARE(two->y(), -100.0);
1366 QCOMPARE(one->x(), 100.0);
1367 QCOMPARE(one->y(), 0.0);
1368 QCOMPARE(three->x(), 50.0);
1369 QCOMPARE(three->y(), 0.0);
1370 QCOMPARE(four->x(), 0.0);
1371 QCOMPARE(four->y(), 0.0);
1372 QCOMPARE(five->x(), 100.0);
1373 QCOMPARE(five->y(), 50.0);
1374 //Let the animation complete
1375 QTRY_COMPARE(two->x(), 50.0);
1376 QTRY_COMPARE(two->y(), 0.0);
1377 QTRY_COMPARE(one->x(), 100.0);
1378 QTRY_COMPARE(one->y(), 0.0);
1379 QTRY_COMPARE(three->x(), 0.0);
1380 QTRY_COMPARE(three->y(), 0.0);
1381 QTRY_COMPARE(four->x(), 100.0);
1382 QTRY_COMPARE(four->y(), 50.0);
1383 QTRY_COMPARE(five->x(), 50.0);
1384 QTRY_COMPARE(five->y(), 50.0);
1389 void tst_qquickpositioners::test_grid_zero_columns()
1391 QQuickView *window = createView(testFile("gridzerocolumns.qml"));
1393 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1395 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1397 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1398 QVERIFY(three != 0);
1399 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1401 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1404 QCOMPARE(one->x(), 0.0);
1405 QCOMPARE(one->y(), 0.0);
1406 QCOMPARE(two->x(), 50.0);
1407 QCOMPARE(two->y(), 0.0);
1408 QCOMPARE(three->x(), 70.0);
1409 QCOMPARE(three->y(), 0.0);
1410 QCOMPARE(four->x(), 120.0);
1411 QCOMPARE(four->y(), 0.0);
1412 QCOMPARE(five->x(), 0.0);
1413 QCOMPARE(five->y(), 50.0);
1415 QQuickItem *grid = window->rootObject()->findChild<QQuickItem*>("grid");
1416 QCOMPARE(grid->width(), 170.0);
1417 QCOMPARE(grid->height(), 60.0);
1422 void tst_qquickpositioners::test_propertychanges()
1424 QQuickView *window = createView(testFile("propertychangestest.qml"));
1426 QQuickGrid *grid = qobject_cast<QQuickGrid*>(window->rootObject());
1428 QQuickTransition *rowTransition = window->rootObject()->findChild<QQuickTransition*>("rowTransition");
1429 QQuickTransition *columnTransition = window->rootObject()->findChild<QQuickTransition*>("columnTransition");
1431 QSignalSpy addSpy(grid, SIGNAL(addChanged()));
1432 QSignalSpy moveSpy(grid, SIGNAL(moveChanged()));
1433 QSignalSpy columnsSpy(grid, SIGNAL(columnsChanged()));
1434 QSignalSpy rowsSpy(grid, SIGNAL(rowsChanged()));
1437 QVERIFY(rowTransition);
1438 QVERIFY(columnTransition);
1439 QCOMPARE(grid->add(), columnTransition);
1440 QCOMPARE(grid->move(), columnTransition);
1441 QCOMPARE(grid->columns(), 4);
1442 QCOMPARE(grid->rows(), -1);
1444 grid->setAdd(rowTransition);
1445 grid->setMove(rowTransition);
1446 QCOMPARE(grid->add(), rowTransition);
1447 QCOMPARE(grid->move(), rowTransition);
1448 QCOMPARE(addSpy.count(),1);
1449 QCOMPARE(moveSpy.count(),1);
1451 grid->setAdd(rowTransition);
1452 grid->setMove(rowTransition);
1453 QCOMPARE(addSpy.count(),1);
1454 QCOMPARE(moveSpy.count(),1);
1458 QCOMPARE(addSpy.count(),2);
1459 QCOMPARE(moveSpy.count(),2);
1461 grid->setColumns(-1);
1463 QCOMPARE(grid->columns(), -1);
1464 QCOMPARE(grid->rows(), 3);
1465 QCOMPARE(columnsSpy.count(),1);
1466 QCOMPARE(rowsSpy.count(),1);
1468 grid->setColumns(-1);
1470 QCOMPARE(columnsSpy.count(),1);
1471 QCOMPARE(rowsSpy.count(),1);
1473 grid->setColumns(2);
1475 QCOMPARE(columnsSpy.count(),2);
1476 QCOMPARE(rowsSpy.count(),2);
1481 void tst_qquickpositioners::test_repeater()
1483 QQuickView *window = createView(testFile("repeatertest.qml"));
1485 QQuickRectangle *one = findItem<QQuickRectangle>(window->rootItem(), "one");
1488 QQuickRectangle *two = findItem<QQuickRectangle>(window->rootItem(), "two");
1491 QQuickRectangle *three = findItem<QQuickRectangle>(window->rootItem(), "three");
1492 QVERIFY(three != 0);
1494 QCOMPARE(one->x(), 0.0);
1495 QCOMPARE(one->y(), 0.0);
1496 QCOMPARE(two->x(), 50.0);
1497 QCOMPARE(two->y(), 0.0);
1498 QCOMPARE(three->x(), 100.0);
1499 QCOMPARE(three->y(), 0.0);
1504 void tst_qquickpositioners::test_flow()
1506 QQuickView *window = createView(testFile("flowtest.qml"));
1508 window->rootObject()->setProperty("testRightToLeft", false);
1510 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1512 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1514 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1515 QVERIFY(three != 0);
1516 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1518 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1521 QCOMPARE(one->x(), 0.0);
1522 QCOMPARE(one->y(), 0.0);
1523 QCOMPARE(two->x(), 50.0);
1524 QCOMPARE(two->y(), 0.0);
1525 QCOMPARE(three->x(), 0.0);
1526 QCOMPARE(three->y(), 50.0);
1527 QCOMPARE(four->x(), 0.0);
1528 QCOMPARE(four->y(), 70.0);
1529 QCOMPARE(five->x(), 50.0);
1530 QCOMPARE(five->y(), 70.0);
1532 QQuickItem *flow = window->rootObject()->findChild<QQuickItem*>("flow");
1534 QCOMPARE(flow->width(), 90.0);
1535 QCOMPARE(flow->height(), 120.0);
1540 void tst_qquickpositioners::test_flow_rightToLeft()
1542 QQuickView *window = createView(testFile("flowtest.qml"));
1544 window->rootObject()->setProperty("testRightToLeft", true);
1546 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1548 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1550 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1551 QVERIFY(three != 0);
1552 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1554 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1557 QCOMPARE(one->x(), 40.0);
1558 QCOMPARE(one->y(), 0.0);
1559 QCOMPARE(two->x(), 20.0);
1560 QCOMPARE(two->y(), 0.0);
1561 QCOMPARE(three->x(), 40.0);
1562 QCOMPARE(three->y(), 50.0);
1563 QCOMPARE(four->x(), 40.0);
1564 QCOMPARE(four->y(), 70.0);
1565 QCOMPARE(five->x(), 30.0);
1566 QCOMPARE(five->y(), 70.0);
1568 QQuickItem *flow = window->rootObject()->findChild<QQuickItem*>("flow");
1570 QCOMPARE(flow->width(), 90.0);
1571 QCOMPARE(flow->height(), 120.0);
1576 void tst_qquickpositioners::test_flow_topToBottom()
1578 QQuickView *window = createView(testFile("flowtest-toptobottom.qml"));
1580 window->rootObject()->setProperty("testRightToLeft", false);
1582 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1584 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1586 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1587 QVERIFY(three != 0);
1588 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1590 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1593 QCOMPARE(one->x(), 0.0);
1594 QCOMPARE(one->y(), 0.0);
1595 QCOMPARE(two->x(), 50.0);
1596 QCOMPARE(two->y(), 0.0);
1597 QCOMPARE(three->x(), 50.0);
1598 QCOMPARE(three->y(), 50.0);
1599 QCOMPARE(four->x(), 100.0);
1600 QCOMPARE(four->y(), 00.0);
1601 QCOMPARE(five->x(), 100.0);
1602 QCOMPARE(five->y(), 50.0);
1604 QQuickItem *flow = window->rootObject()->findChild<QQuickItem*>("flow");
1606 QCOMPARE(flow->height(), 90.0);
1607 QCOMPARE(flow->width(), 150.0);
1609 window->rootObject()->setProperty("testRightToLeft", true);
1612 QCOMPARE(flow->height(), 90.0);
1613 QCOMPARE(flow->width(), 150.0);
1615 QCOMPARE(one->x(), 100.0);
1616 QCOMPARE(one->y(), 0.0);
1617 QCOMPARE(two->x(), 80.0);
1618 QCOMPARE(two->y(), 0.0);
1619 QCOMPARE(three->x(), 50.0);
1620 QCOMPARE(three->y(), 50.0);
1621 QCOMPARE(four->x(), 0.0);
1622 QCOMPARE(four->y(), 0.0);
1623 QCOMPARE(five->x(), 40.0);
1624 QCOMPARE(five->y(), 50.0);
1629 void tst_qquickpositioners::test_flow_resize()
1631 QQuickView *window = createView(testFile("flowtest.qml"));
1633 QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
1635 root->setWidth(125);
1636 root->setProperty("testRightToLeft", false);
1638 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1640 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1642 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1643 QVERIFY(three != 0);
1644 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1646 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1649 QTRY_COMPARE(one->x(), 0.0);
1650 QTRY_COMPARE(one->y(), 0.0);
1651 QTRY_COMPARE(two->x(), 50.0);
1652 QTRY_COMPARE(two->y(), 0.0);
1653 QTRY_COMPARE(three->x(), 70.0);
1654 QTRY_COMPARE(three->y(), 0.0);
1655 QTRY_COMPARE(four->x(), 0.0);
1656 QTRY_COMPARE(four->y(), 50.0);
1657 QTRY_COMPARE(five->x(), 50.0);
1658 QTRY_COMPARE(five->y(), 50.0);
1663 void tst_qquickpositioners::test_flow_resize_rightToLeft()
1665 QQuickView *window = createView(testFile("flowtest.qml"));
1667 QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
1669 root->setWidth(125);
1670 root->setProperty("testRightToLeft", true);
1672 QQuickRectangle *one = window->rootObject()->findChild<QQuickRectangle*>("one");
1673 QTRY_VERIFY(one != 0);
1674 QQuickRectangle *two = window->rootObject()->findChild<QQuickRectangle*>("two");
1676 QQuickRectangle *three = window->rootObject()->findChild<QQuickRectangle*>("three");
1677 QVERIFY(three != 0);
1678 QQuickRectangle *four = window->rootObject()->findChild<QQuickRectangle*>("four");
1680 QQuickRectangle *five = window->rootObject()->findChild<QQuickRectangle*>("five");
1683 QCOMPARE(one->x(), 75.0);
1684 QCOMPARE(one->y(), 0.0);
1685 QCOMPARE(two->x(), 55.0);
1686 QCOMPARE(two->y(), 0.0);
1687 QCOMPARE(three->x(), 5.0);
1688 QCOMPARE(three->y(), 0.0);
1689 QCOMPARE(four->x(), 75.0);
1690 QCOMPARE(four->y(), 50.0);
1691 QCOMPARE(five->x(), 65.0);
1692 QCOMPARE(five->y(), 50.0);
1697 void tst_qquickpositioners::test_flow_implicit_resize()
1699 QQuickView *window = createView(testFile("flow-testimplicitsize.qml"));
1700 QVERIFY(window->rootObject() != 0);
1702 QQuickFlow *flow = window->rootObject()->findChild<QQuickFlow*>("flow");
1705 QCOMPARE(flow->width(), 100.0);
1706 QCOMPARE(flow->height(), 120.0);
1708 window->rootObject()->setProperty("flowLayout", 0);
1709 QCOMPARE(flow->flow(), QQuickFlow::LeftToRight);
1710 QCOMPARE(flow->width(), 220.0);
1711 QCOMPARE(flow->height(), 50.0);
1713 window->rootObject()->setProperty("flowLayout", 1);
1714 QCOMPARE(flow->flow(), QQuickFlow::TopToBottom);
1715 QCOMPARE(flow->width(), 100.0);
1716 QCOMPARE(flow->height(), 120.0);
1718 window->rootObject()->setProperty("flowLayout", 2);
1719 QCOMPARE(flow->layoutDirection(), Qt::RightToLeft);
1720 QCOMPARE(flow->width(), 220.0);
1721 QCOMPARE(flow->height(), 50.0);
1726 QString warningMessage;
1728 void interceptWarnings(QtMsgType type, const char *msg)
1731 warningMessage = msg;
1734 void tst_qquickpositioners::test_conflictinganchors()
1736 QtMsgHandler oldMsgHandler = qInstallMsgHandler(interceptWarnings);
1738 QQmlComponent component(&engine);
1740 component.setData("import QtQuick 2.0\nColumn { Item { width: 100; height: 100; } }", QUrl::fromLocalFile(""));
1741 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
1743 QVERIFY(warningMessage.isEmpty());
1746 component.setData("import QtQuick 2.0\nRow { Item { width: 100; height: 100; } }", QUrl::fromLocalFile(""));
1747 item = qobject_cast<QQuickItem*>(component.create());
1749 QVERIFY(warningMessage.isEmpty());
1752 component.setData("import QtQuick 2.0\nGrid { Item { width: 100; height: 100; } }", QUrl::fromLocalFile(""));
1753 item = qobject_cast<QQuickItem*>(component.create());
1755 QVERIFY(warningMessage.isEmpty());
1758 component.setData("import QtQuick 2.0\nFlow { Item { width: 100; height: 100; } }", QUrl::fromLocalFile(""));
1759 item = qobject_cast<QQuickItem*>(component.create());
1761 QVERIFY(warningMessage.isEmpty());
1764 component.setData("import QtQuick 2.0\nColumn { Item { width: 100; height: 100; anchors.top: parent.top } }", QUrl::fromLocalFile(""));
1765 item = qobject_cast<QQuickItem*>(component.create());
1767 QCOMPARE(warningMessage, QString("file::2:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column. Column will not function."));
1768 warningMessage.clear();
1771 component.setData("import QtQuick 2.0\nColumn { Item { width: 100; height: 100; anchors.centerIn: parent } }", QUrl::fromLocalFile(""));
1772 item = qobject_cast<QQuickItem*>(component.create());
1774 QCOMPARE(warningMessage, QString("file::2:1: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column. Column will not function."));
1775 warningMessage.clear();
1778 component.setData("import QtQuick 2.0\nColumn { Item { width: 100; height: 100; anchors.left: parent.left } }", QUrl::fromLocalFile(""));
1779 item = qobject_cast<QQuickItem*>(component.create());
1781 QVERIFY(warningMessage.isEmpty());
1782 warningMessage.clear();
1785 component.setData("import QtQuick 2.0\nRow { Item { width: 100; height: 100; anchors.left: parent.left } }", QUrl::fromLocalFile(""));
1786 item = qobject_cast<QQuickItem*>(component.create());
1788 QCOMPARE(warningMessage, QString("file::2:1: QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row. Row will not function."));
1789 warningMessage.clear();
1792 component.setData("import QtQuick 2.0\nRow { width: 100; height: 100; Item { anchors.fill: parent } }", QUrl::fromLocalFile(""));
1793 item = qobject_cast<QQuickItem*>(component.create());
1795 QCOMPARE(warningMessage, QString("file::2:1: QML Row: Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row. Row will not function."));
1796 warningMessage.clear();
1799 component.setData("import QtQuick 2.0\nRow { Item { width: 100; height: 100; anchors.top: parent.top } }", QUrl::fromLocalFile(""));
1800 item = qobject_cast<QQuickItem*>(component.create());
1802 QVERIFY(warningMessage.isEmpty());
1803 warningMessage.clear();
1806 component.setData("import QtQuick 2.0\nGrid { Item { width: 100; height: 100; anchors.horizontalCenter: parent.horizontalCenter } }", QUrl::fromLocalFile(""));
1807 item = qobject_cast<QQuickItem*>(component.create());
1809 QCOMPARE(warningMessage, QString("file::2:1: QML Grid: Cannot specify anchors for items inside Grid. Grid will not function."));
1810 warningMessage.clear();
1813 component.setData("import QtQuick 2.0\nGrid { Item { width: 100; height: 100; anchors.centerIn: parent } }", QUrl::fromLocalFile(""));
1814 item = qobject_cast<QQuickItem*>(component.create());
1816 QCOMPARE(warningMessage, QString("file::2:1: QML Grid: Cannot specify anchors for items inside Grid. Grid will not function."));
1817 warningMessage.clear();
1820 component.setData("import QtQuick 2.0\nFlow { Item { width: 100; height: 100; anchors.verticalCenter: parent.verticalCenter } }", QUrl::fromLocalFile(""));
1821 item = qobject_cast<QQuickItem*>(component.create());
1823 QCOMPARE(warningMessage, QString("file::2:1: QML Flow: Cannot specify anchors for items inside Flow. Flow will not function."));
1826 component.setData("import QtQuick 2.0\nFlow { width: 100; height: 100; Item { anchors.fill: parent } }", QUrl::fromLocalFile(""));
1827 item = qobject_cast<QQuickItem*>(component.create());
1829 QCOMPARE(warningMessage, QString("file::2:1: QML Flow: Cannot specify anchors for items inside Flow. Flow will not function."));
1830 qInstallMsgHandler(oldMsgHandler);
1834 void tst_qquickpositioners::test_mirroring()
1836 QList<QString> qmlFiles;
1837 qmlFiles << "horizontal.qml" << "gridtest.qml" << "flowtest.qml";
1838 QList<QString> objectNames;
1839 objectNames << "one" << "two" << "three" << "four" << "five";
1841 foreach (const QString qmlFile, qmlFiles) {
1842 QQuickView *windowA = createView(testFile(qmlFile));
1843 QQuickItem *rootA = qobject_cast<QQuickItem*>(windowA->rootObject());
1845 QQuickView *windowB = createView(testFile(qmlFile));
1846 QQuickItem *rootB = qobject_cast<QQuickItem*>(windowB->rootObject());
1848 rootA->setProperty("testRightToLeft", true); // layoutDirection: Qt.RightToLeft
1851 foreach (const QString objectName, objectNames) {
1852 // horizontal.qml only has three items
1853 if (qmlFile == QString("horizontal.qml") && objectName == QString("four"))
1855 QQuickItem *itemA = rootA->findChild<QQuickItem*>(objectName);
1856 QQuickItem *itemB = rootB->findChild<QQuickItem*>(objectName);
1857 QTRY_VERIFY(itemA->x() != itemB->x());
1860 QQmlProperty enabledProp(rootB, "LayoutMirroring.enabled", qmlContext(rootB));
1861 enabledProp.write(true);
1862 QQmlProperty inheritProp(rootB, "LayoutMirroring.childrenInherit", qmlContext(rootB));
1863 inheritProp.write(true);
1866 foreach (const QString objectName, objectNames) {
1867 // horizontal.qml only has three items
1868 if (qmlFile == QString("horizontal.qml") && objectName == QString("four"))
1870 QQuickItem *itemA = rootA->findChild<QQuickItem*>(objectName);
1871 QQuickItem *itemB = rootB->findChild<QQuickItem*>(objectName);
1872 QTRY_COMPARE(itemA->x(), itemB->x());
1875 rootA->setProperty("testRightToLeft", false); // layoutDirection: Qt.LeftToRight
1876 rootB->setProperty("testRightToLeft", true); // layoutDirection: Qt.RightToLeft
1878 // LTR == RTL + mirror
1879 foreach (const QString objectName, objectNames) {
1880 // horizontal.qml only has three items
1881 if (qmlFile == QString("horizontal.qml") && objectName == QString("four"))
1883 QQuickItem *itemA = rootA->findChild<QQuickItem*>(objectName);
1884 QQuickItem *itemB = rootB->findChild<QQuickItem*>(objectName);
1885 QTRY_COMPARE(itemA->x(), itemB->x());
1892 void tst_qquickpositioners::test_allInvisible()
1895 QQuickView *window = createView(testFile("allInvisible.qml"));
1897 QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
1900 QQuickRow *row = window->rootObject()->findChild<QQuickRow*>("row");
1902 QVERIFY(row->width() == 0);
1903 QVERIFY(row->height() == 0);
1904 QQuickColumn *column = window->rootObject()->findChild<QQuickColumn*>("column");
1905 QVERIFY(column != 0);
1906 QVERIFY(column->width() == 0);
1907 QVERIFY(column->height() == 0);
1910 void tst_qquickpositioners::test_attachedproperties()
1912 QFETCH(QString, filename);
1914 QQuickView *window = createView(filename);
1915 QVERIFY(window->rootObject() != 0);
1917 QQuickRectangle *greenRect = window->rootObject()->findChild<QQuickRectangle *>("greenRect");
1918 QVERIFY(greenRect != 0);
1920 int posIndex = greenRect->property("posIndex").toInt();
1921 QVERIFY(posIndex == 0);
1922 bool isFirst = greenRect->property("isFirstItem").toBool();
1923 QVERIFY(isFirst == true);
1924 bool isLast = greenRect->property("isLastItem").toBool();
1925 QVERIFY(isLast == false);
1927 QQuickRectangle *yellowRect = window->rootObject()->findChild<QQuickRectangle *>("yellowRect");
1928 QVERIFY(yellowRect != 0);
1930 posIndex = yellowRect->property("posIndex").toInt();
1931 QVERIFY(posIndex == -1);
1932 isFirst = yellowRect->property("isFirstItem").toBool();
1933 QVERIFY(isFirst == false);
1934 isLast = yellowRect->property("isLastItem").toBool();
1935 QVERIFY(isLast == false);
1937 yellowRect->metaObject()->invokeMethod(yellowRect, "onDemandPositioner");
1939 posIndex = yellowRect->property("posIndex").toInt();
1940 QVERIFY(posIndex == 1);
1941 isFirst = yellowRect->property("isFirstItem").toBool();
1942 QVERIFY(isFirst == false);
1943 isLast = yellowRect->property("isLastItem").toBool();
1944 QVERIFY(isLast == true);
1949 void tst_qquickpositioners::test_attachedproperties_data()
1951 QTest::addColumn<QString>("filename");
1953 QTest::newRow("column") << testFile("attachedproperties-column.qml");
1954 QTest::newRow("row") << testFile("attachedproperties-row.qml");
1955 QTest::newRow("grid") << testFile("attachedproperties-grid.qml");
1956 QTest::newRow("flow") << testFile("attachedproperties-flow.qml");
1959 void tst_qquickpositioners::test_attachedproperties_dynamic()
1961 QQuickView *window = createView(testFile("attachedproperties-dynamic.qml"));
1962 QVERIFY(window->rootObject() != 0);
1964 QQuickRow *row = window->rootObject()->findChild<QQuickRow *>("pos");
1967 QQuickRectangle *rect0 = window->rootObject()->findChild<QQuickRectangle *>("rect0");
1968 QVERIFY(rect0 != 0);
1970 int posIndex = rect0->property("index").toInt();
1971 QVERIFY(posIndex == 0);
1972 bool isFirst = rect0->property("firstItem").toBool();
1973 QVERIFY(isFirst == true);
1974 bool isLast = rect0->property("lastItem").toBool();
1975 QVERIFY(isLast == false);
1977 QQuickRectangle *rect1 = window->rootObject()->findChild<QQuickRectangle *>("rect1");
1978 QVERIFY(rect1 != 0);
1980 posIndex = rect1->property("index").toInt();
1981 QVERIFY(posIndex == 1);
1982 isFirst = rect1->property("firstItem").toBool();
1983 QVERIFY(isFirst == false);
1984 isLast = rect1->property("lastItem").toBool();
1985 QVERIFY(isLast == true);
1987 row->metaObject()->invokeMethod(row, "createSubRect");
1989 QTRY_VERIFY(rect1->property("index").toInt() == 1);
1990 QTRY_VERIFY(rect1->property("firstItem").toBool() == false);
1991 QTRY_VERIFY(rect1->property("lastItem").toBool() == false);
1993 QQuickRectangle *rect2 = window->rootObject()->findChild<QQuickRectangle *>("rect2");
1994 QVERIFY(rect2 != 0);
1996 posIndex = rect2->property("index").toInt();
1997 QVERIFY(posIndex == 2);
1998 isFirst = rect2->property("firstItem").toBool();
1999 QVERIFY(isFirst == false);
2000 isLast = rect2->property("lastItem").toBool();
2001 QVERIFY(isLast == true);
2003 row->metaObject()->invokeMethod(row, "destroySubRect");
2005 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2006 QCoreApplication::processEvents();
2008 QTRY_VERIFY(rect1->property("index").toInt() == 1);
2009 QTRY_VERIFY(rect1->property("firstItem").toBool() == false);
2010 QTRY_VERIFY(rect1->property("lastItem").toBool() == true);
2015 QQuickView *tst_qquickpositioners::createView(const QString &filename, bool wait)
2017 QQuickView *window = new QQuickView(0);
2020 window->setSource(QUrl::fromLocalFile(filename));
2025 QTest::qWaitForWindowShown(window); //It may not relayout until the next frame, so it needs to be drawn
2031 void tst_qquickpositioners::matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes)
2033 for (int i=0; i<indexLists.count(); i++) {
2034 QSet<int> current = indexLists[i].value<QList<int> >().toSet();
2035 if (current != expectedIndexes.toSet())
2036 qDebug() << "Cannot match actual targets" << current << "with expected" << expectedIndexes;
2037 QCOMPARE(current, expectedIndexes.toSet());
2041 void tst_qquickpositioners::matchItemsAndIndexes(const QVariantMap &items, const QaimModel &model, const QList<int> &expectedIndexes)
2043 for (QVariantMap::const_iterator it = items.begin(); it != items.end(); ++it) {
2044 QVERIFY(it.value().type() == QVariant::Int);
2045 QString name = it.key();
2046 int itemIndex = it.value().toInt();
2047 QVERIFY2(expectedIndexes.contains(itemIndex), QTest::toString(QString("Index %1 not found in expectedIndexes").arg(itemIndex)));
2048 if (model.name(itemIndex) != name)
2049 qDebug() << itemIndex;
2050 QCOMPARE(model.name(itemIndex), name);
2052 QCOMPARE(items.count(), expectedIndexes.count());
2055 void tst_qquickpositioners::matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems)
2057 for (int i=0; i<itemLists.count(); i++) {
2058 QVERIFY(itemLists[i].type() == QVariant::List);
2059 QVariantList current = itemLists[i].toList();
2060 for (int j=0; j<current.count(); j++) {
2061 QQuickItem *o = qobject_cast<QQuickItem*>(current[j].value<QObject*>());
2062 QVERIFY2(o, QTest::toString(QString("Invalid actual item at %1").arg(j)));
2063 QVERIFY2(expectedItems.contains(o), QTest::toString(QString("Cannot match item %1").arg(j)));
2065 QCOMPARE(current.count(), expectedItems.count());
2069 QTEST_MAIN(tst_qquickpositioners)
2071 #include "tst_qquickpositioners.moc"