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 ****************************************************************************/
42 #include <QtQml/qqmlengine.h>
43 #include <QtQml/qqmlcomponent.h>
44 #include <QtQuick/qquickview.h>
45 #include <private/qquickstateoperations_p.h>
46 #include <private/qquickanchors_p_p.h>
47 #include <QtQuick/private/qquickrectangle_p.h>
48 #include <private/qquickimage_p.h>
49 #include <QtQuick/private/qquickpropertychanges_p.h>
50 #include <QtQuick/private/qquickstategroup_p.h>
51 #include <private/qquickitem_p.h>
52 #include <private/qqmlproperty_p.h>
53 #include "../../shared/util.h"
55 class MyAttached : public QObject
58 Q_PROPERTY(int foo READ foo WRITE setFoo)
60 MyAttached(QObject *parent) : QObject(parent), m_foo(13) {}
62 int foo() const { return m_foo; }
63 void setFoo(int f) { m_foo = f; }
69 class MyRect : public QQuickRectangle
72 Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal)
76 void doSomething() { emit didSomething(); }
78 int propertyWithNotify() const { return m_prop; }
79 void setPropertyWithNotify(int i) { m_prop = i; emit oddlyNamedNotifySignal(); }
81 static MyAttached *qmlAttachedProperties(QObject *o) {
82 return new MyAttached(o);
86 void oddlyNamedNotifySignal();
92 QML_DECLARE_TYPE(MyRect)
93 QML_DECLARE_TYPEINFO(MyRect, QML_HAS_ATTACHED_PROPERTIES)
95 class tst_qquickstates : public QQmlDataTest
102 QByteArray fullDataPath(const QString &path) const;
108 void attachedPropertyChanges();
109 void basicExtension();
111 void signalOverride();
112 void signalOverrideCrash();
113 void signalOverrideCrash2();
114 void signalOverrideCrash3();
115 void signalOverrideCrash4();
117 void parentChangeErrors();
118 void anchorChanges();
119 void anchorChanges2();
120 void anchorChanges3();
121 void anchorChanges4();
122 void anchorChanges5();
123 void anchorChangesRTL();
124 void anchorChangesRTL2();
125 void anchorChangesRTL3();
126 void anchorChangesCrash();
127 void anchorRewindBug();
128 void anchorRewindBug2();
130 void restoreEntryValues();
131 void explicitChanges();
132 void propertyErrors();
133 void incorrectRestoreBug();
134 void autoStateAtStartupRestoreBug();
135 void deletingChange();
136 void deletingState();
138 void illegalTempState();
139 void nonExistantProperty();
141 void illegalObjectCreation();
143 void urlResolution();
147 void editProperties();
149 void avoidFastForward();
150 void revertListBug();
153 void tst_qquickstates::initTestCase()
155 QQmlDataTest::initTestCase();
156 qmlRegisterType<MyRect>("Qt.test", 1, 0, "MyRectangle");
159 QByteArray tst_qquickstates::fullDataPath(const QString &path) const
161 return testFileUrl(path).toString().toUtf8();
164 void tst_qquickstates::basicChanges()
169 QQmlComponent rectComponent(&engine, testFileUrl("basicChanges.qml"));
170 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
171 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
174 QCOMPARE(rect->color(),QColor("red"));
176 rectPrivate->setState("blue");
177 QCOMPARE(rect->color(),QColor("blue"));
179 rectPrivate->setState("");
180 QCOMPARE(rect->color(),QColor("red"));
184 QQmlComponent rectComponent(&engine, testFileUrl("basicChanges2.qml"));
185 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
186 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
189 QCOMPARE(rect->color(),QColor("red"));
191 rectPrivate->setState("blue");
192 QCOMPARE(rect->color(),QColor("blue"));
194 rectPrivate->setState("green");
195 QCOMPARE(rect->color(),QColor("green"));
197 rectPrivate->setState("");
198 QCOMPARE(rect->color(),QColor("red"));
200 rectPrivate->setState("green");
201 QCOMPARE(rect->color(),QColor("green"));
205 QQmlComponent rectComponent(&engine, testFileUrl("basicChanges3.qml"));
206 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
207 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
210 QCOMPARE(rect->color(),QColor("red"));
211 QCOMPARE(rect->border()->width(),1.0);
213 rectPrivate->setState("blue");
214 QCOMPARE(rect->color(),QColor("blue"));
215 QCOMPARE(rect->border()->width(),1.0);
217 rectPrivate->setState("bordered");
218 QCOMPARE(rect->color(),QColor("red"));
219 QCOMPARE(rect->border()->width(),2.0);
221 rectPrivate->setState("");
222 QCOMPARE(rect->color(),QColor("red"));
223 QCOMPARE(rect->border()->width(),1.0);
224 //### we should be checking that this is an implicit rather than explicit 1 (which currently fails)
226 rectPrivate->setState("bordered");
227 QCOMPARE(rect->color(),QColor("red"));
228 QCOMPARE(rect->border()->width(),2.0);
230 rectPrivate->setState("blue");
231 QCOMPARE(rect->color(),QColor("blue"));
232 QCOMPARE(rect->border()->width(),1.0);
237 // Test basicChanges4.qml can magically connect to propertyWithNotify's notify
238 // signal using 'onPropertyWithNotifyChanged' even though the signal name is
239 // actually 'oddlyNamedNotifySignal'
241 QQmlComponent component(&engine, testFileUrl("basicChanges4.qml"));
242 QVERIFY(component.isReady());
244 MyRect *rect = qobject_cast<MyRect*>(component.create());
247 QMetaProperty prop = rect->metaObject()->property(rect->metaObject()->indexOfProperty("propertyWithNotify"));
248 QVERIFY(prop.hasNotifySignal());
249 QString notifySignal = prop.notifySignal().methodSignature();
250 QVERIFY(!notifySignal.startsWith("propertyWithNotifyChanged("));
252 QCOMPARE(rect->color(), QColor(Qt::red));
254 rect->setPropertyWithNotify(100);
255 QCOMPARE(rect->color(), QColor(Qt::blue));
259 void tst_qquickstates::attachedPropertyChanges()
263 QQmlComponent component(&engine, testFileUrl("attachedPropertyChanges.qml"));
264 QVERIFY(component.isReady());
266 QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
268 QCOMPARE(item->width(), 50.0);
270 // Ensure attached property has been changed
271 QObject *attObj = qmlAttachedPropertiesObject<MyRect>(item, false);
274 MyAttached *att = qobject_cast<MyAttached*>(attObj);
277 QCOMPARE(att->foo(), 1);
280 void tst_qquickstates::basicExtension()
285 QQmlComponent rectComponent(&engine, testFileUrl("basicExtension.qml"));
286 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
287 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
290 QCOMPARE(rect->color(),QColor("red"));
291 QCOMPARE(rect->border()->width(),1.0);
293 rectPrivate->setState("blue");
294 QCOMPARE(rect->color(),QColor("blue"));
295 QCOMPARE(rect->border()->width(),1.0);
297 rectPrivate->setState("bordered");
298 QCOMPARE(rect->color(),QColor("blue"));
299 QCOMPARE(rect->border()->width(),2.0);
301 rectPrivate->setState("blue");
302 QCOMPARE(rect->color(),QColor("blue"));
303 QCOMPARE(rect->border()->width(),1.0);
305 rectPrivate->setState("");
306 QCOMPARE(rect->color(),QColor("red"));
307 QCOMPARE(rect->border()->width(),1.0);
309 rectPrivate->setState("bordered");
310 QCOMPARE(rect->color(),QColor("blue"));
311 QCOMPARE(rect->border()->width(),2.0);
313 rectPrivate->setState("");
314 QCOMPARE(rect->color(),QColor("red"));
315 QCOMPARE(rect->border()->width(),1.0);
319 QQmlComponent rectComponent(&engine, testFileUrl("fakeExtension.qml"));
320 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
321 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
324 QCOMPARE(rect->color(),QColor("red"));
326 rectPrivate->setState("blue");
327 QCOMPARE(rect->color(),QColor("blue"));
329 rectPrivate->setState("green");
330 QCOMPARE(rect->color(),QColor("green"));
332 rectPrivate->setState("blue");
333 QCOMPARE(rect->color(),QColor("blue"));
335 rectPrivate->setState("green");
336 QCOMPARE(rect->color(),QColor("green"));
338 rectPrivate->setState("");
339 QCOMPARE(rect->color(),QColor("red"));
341 rectPrivate->setState("green");
342 QCOMPARE(rect->color(),QColor("green"));
346 void tst_qquickstates::basicBinding()
351 QQmlComponent rectComponent(&engine, testFileUrl("basicBinding.qml"));
352 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
353 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
356 QCOMPARE(rect->color(),QColor("red"));
358 rectPrivate->setState("blue");
359 QCOMPARE(rect->color(),QColor("blue"));
361 rectPrivate->setState("");
362 QCOMPARE(rect->color(),QColor("red"));
364 rectPrivate->setState("blue");
365 QCOMPARE(rect->color(),QColor("blue"));
366 rect->setProperty("sourceColor", QColor("green"));
367 QCOMPARE(rect->color(),QColor("green"));
369 rectPrivate->setState("");
370 QCOMPARE(rect->color(),QColor("red"));
371 rect->setProperty("sourceColor", QColor("yellow"));
372 QCOMPARE(rect->color(),QColor("red"));
374 rectPrivate->setState("blue");
375 QCOMPARE(rect->color(),QColor("yellow"));
379 QQmlComponent rectComponent(&engine, testFileUrl("basicBinding2.qml"));
380 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
381 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
384 QCOMPARE(rect->color(),QColor("red"));
386 rectPrivate->setState("blue");
387 QCOMPARE(rect->color(),QColor("blue"));
389 rectPrivate->setState("");
390 QCOMPARE(rect->color(),QColor("red"));
392 rectPrivate->setState("blue");
393 QCOMPARE(rect->color(),QColor("blue"));
394 rect->setProperty("sourceColor", QColor("green"));
395 QCOMPARE(rect->color(),QColor("blue"));
397 rectPrivate->setState("");
398 QCOMPARE(rect->color(),QColor("green"));
399 rect->setProperty("sourceColor", QColor("yellow"));
400 QCOMPARE(rect->color(),QColor("yellow"));
402 rectPrivate->setState("blue");
403 QCOMPARE(rect->color(),QColor("blue"));
405 rectPrivate->setState("");
406 QCOMPARE(rect->color(),QColor("yellow"));
410 QQmlComponent rectComponent(&engine, testFileUrl("basicBinding3.qml"));
411 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
412 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
415 QCOMPARE(rect->color(),QColor("red"));
416 rect->setProperty("sourceColor", QColor("green"));
417 QCOMPARE(rect->color(),QColor("green"));
419 rectPrivate->setState("blue");
420 QCOMPARE(rect->color(),QColor("blue"));
421 rect->setProperty("sourceColor", QColor("red"));
422 QCOMPARE(rect->color(),QColor("blue"));
423 rect->setProperty("sourceColor2", QColor("yellow"));
424 QCOMPARE(rect->color(),QColor("yellow"));
426 rectPrivate->setState("");
427 QCOMPARE(rect->color(),QColor("red"));
428 rect->setProperty("sourceColor2", QColor("green"));
429 QCOMPARE(rect->color(),QColor("red"));
430 rect->setProperty("sourceColor", QColor("yellow"));
431 QCOMPARE(rect->color(),QColor("yellow"));
435 QQmlComponent rectComponent(&engine, testFileUrl("basicBinding4.qml"));
436 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
437 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
440 QCOMPARE(rect->color(),QColor("red"));
442 rectPrivate->setState("blue");
443 QCOMPARE(rect->color(),QColor("blue"));
444 rect->setProperty("sourceColor", QColor("yellow"));
445 QCOMPARE(rect->color(),QColor("yellow"));
447 rectPrivate->setState("green");
448 QCOMPARE(rect->color(),QColor("green"));
449 rect->setProperty("sourceColor", QColor("purple"));
450 QCOMPARE(rect->color(),QColor("green"));
452 rectPrivate->setState("blue");
453 QCOMPARE(rect->color(),QColor("purple"));
455 rectPrivate->setState("green");
456 QCOMPARE(rect->color(),QColor("green"));
458 rectPrivate->setState("");
459 QCOMPARE(rect->color(),QColor("red"));
463 void tst_qquickstates::signalOverride()
468 QQmlComponent rectComponent(&engine, testFileUrl("signalOverride.qml"));
469 MyRect *rect = qobject_cast<MyRect*>(rectComponent.create());
472 QCOMPARE(rect->color(),QColor("red"));
474 QCOMPARE(rect->color(),QColor("blue"));
476 QQuickItemPrivate::get(rect)->setState("green");
478 QCOMPARE(rect->color(),QColor("green"));
484 QQmlComponent rectComponent(&engine, testFileUrl("signalOverride2.qml"));
485 MyRect *rect = qobject_cast<MyRect*>(rectComponent.create());
488 QCOMPARE(rect->color(),QColor("white"));
490 QCOMPARE(rect->color(),QColor("blue"));
492 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("extendedRect"));
493 QQuickItemPrivate::get(innerRect)->setState("green");
495 QCOMPARE(rect->color(),QColor("blue"));
496 QCOMPARE(innerRect->color(),QColor("green"));
497 QCOMPARE(innerRect->property("extendedColor").value<QColor>(),QColor("green"));
503 void tst_qquickstates::signalOverrideCrash()
507 QQmlComponent rectComponent(&engine, testFileUrl("signalOverrideCrash.qml"));
508 MyRect *rect = qobject_cast<MyRect*>(rectComponent.create());
511 QQuickItemPrivate::get(rect)->setState("overridden");
515 void tst_qquickstates::signalOverrideCrash2()
519 QQmlComponent rectComponent(&engine, testFileUrl("signalOverrideCrash2.qml"));
520 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
523 QQuickItemPrivate::get(rect)->setState("state1");
524 QQuickItemPrivate::get(rect)->setState("state2");
525 QQuickItemPrivate::get(rect)->setState("state1");
530 void tst_qquickstates::signalOverrideCrash3()
534 QQmlComponent rectComponent(&engine, testFileUrl("signalOverrideCrash3.qml"));
535 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
538 QQuickItemPrivate::get(rect)->setState("state1");
539 QQuickItemPrivate::get(rect)->setState("");
540 QQuickItemPrivate::get(rect)->setState("state2");
541 QQuickItemPrivate::get(rect)->setState("");
546 void tst_qquickstates::signalOverrideCrash4()
549 QQmlComponent c(&engine, testFileUrl("signalOverrideCrash4.qml"));
550 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
553 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
555 rectPrivate->setState("state1");
556 rectPrivate->setState("state2");
557 rectPrivate->setState("state1");
558 rectPrivate->setState("state2");
559 rectPrivate->setState("");
564 void tst_qquickstates::parentChange()
569 QQmlComponent rectComponent(&engine, testFileUrl("parentChange1.qml"));
570 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
573 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
574 QVERIFY(innerRect != 0);
576 QQmlListReference list(rect, "states");
577 QQuickState *state = qobject_cast<QQuickState*>(list.at(0));
580 qmlExecuteDeferred(state);
581 QQuickParentChange *pChange = qobject_cast<QQuickParentChange*>(state->operationAt(0));
582 QVERIFY(pChange != 0);
583 QQuickItem *nParent = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("NewParent"));
584 QVERIFY(nParent != 0);
586 QCOMPARE(pChange->parent(), nParent);
588 QQuickItemPrivate::get(rect)->setState("reparented");
589 QCOMPARE(innerRect->rotation(), qreal(0));
590 QCOMPARE(innerRect->scale(), qreal(1));
591 QCOMPARE(innerRect->x(), qreal(-133));
592 QCOMPARE(innerRect->y(), qreal(-300));
596 QQmlComponent rectComponent(&engine, testFileUrl("parentChange2.qml"));
597 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
599 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
600 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
601 QVERIFY(innerRect != 0);
603 rectPrivate->setState("reparented");
604 QCOMPARE(innerRect->rotation(), qreal(15));
605 QCOMPARE(innerRect->scale(), qreal(.5));
606 QCOMPARE(QString("%1").arg(innerRect->x()), QString("%1").arg(-19.9075));
607 QCOMPARE(QString("%1").arg(innerRect->y()), QString("%1").arg(-8.73433));
611 QQmlComponent rectComponent(&engine, testFileUrl("parentChange3.qml"));
612 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
614 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
615 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
616 QVERIFY(innerRect != 0);
618 rectPrivate->setState("reparented");
619 QCOMPARE(innerRect->rotation(), qreal(-37));
620 QCOMPARE(innerRect->scale(), qreal(.25));
621 QCOMPARE(QString("%1").arg(innerRect->x()), QString("%1").arg(-217.305));
622 QCOMPARE(QString("%1").arg(innerRect->y()), QString("%1").arg(-164.413));
624 rectPrivate->setState("");
625 QCOMPARE(innerRect->rotation(), qreal(0));
626 QCOMPARE(innerRect->scale(), qreal(1));
627 QCOMPARE(innerRect->x(), qreal(5));
628 //do a non-qFuzzyCompare fuzzy compare
629 QVERIFY(innerRect->y() < qreal(0.00001) && innerRect->y() > qreal(-0.00001));
633 QQmlComponent rectComponent(&engine, testFileUrl("parentChange6.qml"));
634 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
637 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
638 QVERIFY(innerRect != 0);
640 QQuickItemPrivate::get(rect)->setState("reparented");
641 QCOMPARE(innerRect->rotation(), qreal(180));
642 QCOMPARE(innerRect->scale(), qreal(1));
643 QCOMPARE(innerRect->x(), qreal(-105));
644 QCOMPARE(innerRect->y(), qreal(-105));
648 void tst_qquickstates::parentChangeErrors()
653 QQmlComponent rectComponent(&engine, testFileUrl("parentChange4.qml"));
654 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
657 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
658 QVERIFY(innerRect != 0);
660 QTest::ignoreMessage(QtWarningMsg, fullDataPath("parentChange4.qml") + ":25:9: QML ParentChange: Unable to preserve appearance under non-uniform scale");
661 QQuickItemPrivate::get(rect)->setState("reparented");
662 QCOMPARE(innerRect->rotation(), qreal(0));
663 QCOMPARE(innerRect->scale(), qreal(1));
664 QCOMPARE(innerRect->x(), qreal(5));
665 QCOMPARE(innerRect->y(), qreal(5));
669 QQmlComponent rectComponent(&engine, testFileUrl("parentChange5.qml"));
670 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
673 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
674 QVERIFY(innerRect != 0);
676 QTest::ignoreMessage(QtWarningMsg, fullDataPath("parentChange5.qml") + ":25:9: QML ParentChange: Unable to preserve appearance under complex transform");
677 QQuickItemPrivate::get(rect)->setState("reparented");
678 QCOMPARE(innerRect->rotation(), qreal(0));
679 QCOMPARE(innerRect->scale(), qreal(1));
680 QCOMPARE(innerRect->x(), qreal(5));
681 QCOMPARE(innerRect->y(), qreal(5));
685 void tst_qquickstates::anchorChanges()
689 QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges1.qml"));
690 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
692 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
694 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
695 QVERIFY(innerRect != 0);
697 QQmlListReference list(rect, "states");
698 QQuickState *state = qobject_cast<QQuickState*>(list.at(0));
701 qmlExecuteDeferred(state);
702 QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0));
703 QVERIFY(aChanges != 0);
705 QCOMPARE(aChanges->anchors()->left().isUndefinedLiteral(), true);
706 QVERIFY(!aChanges->anchors()->left().isEmpty());
707 QVERIFY(!aChanges->anchors()->right().isEmpty());
709 rectPrivate->setState("right");
710 QCOMPARE(innerRect->x(), qreal(150));
711 QCOMPARE(aChanges->object(), qobject_cast<QQuickItem*>(innerRect));
712 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QQuickAnchorLine::Invalid); //### was reset (how do we distinguish from not set at all)
713 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item);
714 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine);
716 rectPrivate->setState("");
717 QCOMPARE(innerRect->x(), qreal(5));
722 void tst_qquickstates::anchorChanges2()
726 QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges2.qml"));
727 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
729 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
731 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
732 QVERIFY(innerRect != 0);
734 rectPrivate->setState("right");
735 QCOMPARE(innerRect->x(), qreal(150));
737 rectPrivate->setState("");
738 QCOMPARE(innerRect->x(), qreal(5));
743 void tst_qquickstates::anchorChanges3()
747 QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges3.qml"));
748 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
750 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
752 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
753 QVERIFY(innerRect != 0);
755 QQuickItem *leftGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("LeftGuideline"));
756 QVERIFY(leftGuideline != 0);
758 QQuickItem *bottomGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("BottomGuideline"));
759 QVERIFY(bottomGuideline != 0);
761 QQmlListReference list(rect, "states");
762 QQuickState *state = qobject_cast<QQuickState*>(list.at(0));
765 qmlExecuteDeferred(state);
766 QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0));
767 QVERIFY(aChanges != 0);
769 QVERIFY(!aChanges->anchors()->top().isEmpty());
770 QVERIFY(!aChanges->anchors()->bottom().isEmpty());
772 rectPrivate->setState("reanchored");
773 QCOMPARE(aChanges->object(), qobject_cast<QQuickItem*>(innerRect));
774 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->left().item, QQuickItemPrivate::get(leftGuideline)->left().item);
775 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QQuickItemPrivate::get(leftGuideline)->left().anchorLine);
776 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item);
777 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine);
778 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->top().item, rectPrivate->top().item);
779 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->top().anchorLine, rectPrivate->top().anchorLine);
780 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->bottom().item, QQuickItemPrivate::get(bottomGuideline)->bottom().item);
781 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->bottom().anchorLine, QQuickItemPrivate::get(bottomGuideline)->bottom().anchorLine);
783 QCOMPARE(innerRect->x(), qreal(10));
784 QCOMPARE(innerRect->y(), qreal(0));
785 QCOMPARE(innerRect->width(), qreal(190));
786 QCOMPARE(innerRect->height(), qreal(150));
788 rectPrivate->setState("");
789 QCOMPARE(innerRect->x(), qreal(0));
790 QCOMPARE(innerRect->y(), qreal(10));
791 QCOMPARE(innerRect->width(), qreal(150));
792 QCOMPARE(innerRect->height(), qreal(190));
797 void tst_qquickstates::anchorChanges4()
801 QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges4.qml"));
802 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
805 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
806 QVERIFY(innerRect != 0);
808 QQuickItem *leftGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("LeftGuideline"));
809 QVERIFY(leftGuideline != 0);
811 QQuickItem *bottomGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("BottomGuideline"));
812 QVERIFY(bottomGuideline != 0);
814 QQmlListReference list(rect, "states");
815 QQuickState *state = qobject_cast<QQuickState*>(list.at(0));
818 qmlExecuteDeferred(state);
819 QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0));
820 QVERIFY(aChanges != 0);
822 QVERIFY(!aChanges->anchors()->horizontalCenter().isEmpty());
823 QVERIFY(!aChanges->anchors()->verticalCenter().isEmpty());
825 QQuickItemPrivate::get(rect)->setState("reanchored");
826 QCOMPARE(aChanges->object(), qobject_cast<QQuickItem*>(innerRect));
827 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->horizontalCenter().item, QQuickItemPrivate::get(bottomGuideline)->horizontalCenter().item);
828 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->horizontalCenter().anchorLine, QQuickItemPrivate::get(bottomGuideline)->horizontalCenter().anchorLine);
829 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->verticalCenter().item, QQuickItemPrivate::get(leftGuideline)->verticalCenter().item);
830 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->verticalCenter().anchorLine, QQuickItemPrivate::get(leftGuideline)->verticalCenter().anchorLine);
835 void tst_qquickstates::anchorChanges5()
839 QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges5.qml"));
840 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
843 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
844 QVERIFY(innerRect != 0);
846 QQuickItem *leftGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("LeftGuideline"));
847 QVERIFY(leftGuideline != 0);
849 QQuickItem *bottomGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("BottomGuideline"));
850 QVERIFY(bottomGuideline != 0);
852 QQmlListReference list(rect, "states");
853 QQuickState *state = qobject_cast<QQuickState*>(list.at(0));
856 qmlExecuteDeferred(state);
857 QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0));
858 QVERIFY(aChanges != 0);
860 QVERIFY(!aChanges->anchors()->baseline().isEmpty());
862 QQuickItemPrivate::get(rect)->setState("reanchored");
863 QCOMPARE(aChanges->object(), qobject_cast<QQuickItem*>(innerRect));
864 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->horizontalCenter().item, QQuickItemPrivate::get(bottomGuideline)->horizontalCenter().item);
865 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->horizontalCenter().anchorLine, QQuickItemPrivate::get(bottomGuideline)->horizontalCenter().anchorLine);
866 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->baseline().item, QQuickItemPrivate::get(leftGuideline)->baseline().item);
867 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->baseline().anchorLine, QQuickItemPrivate::get(leftGuideline)->baseline().anchorLine);
872 void mirrorAnchors(QQuickItem *item) {
873 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
874 itemPrivate->setLayoutMirror(true);
877 qreal offsetRTL(QQuickItem *anchorItem, QQuickItem *item) {
878 return anchorItem->width()+2*anchorItem->x()-item->width();
881 void tst_qquickstates::anchorChangesRTL()
885 QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges1.qml"));
886 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
888 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
890 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
891 QVERIFY(innerRect != 0);
892 mirrorAnchors(innerRect);
894 QQmlListReference list(rect, "states");
895 QQuickState *state = qobject_cast<QQuickState*>(list.at(0));
898 qmlExecuteDeferred(state);
899 QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0));
900 QVERIFY(aChanges != 0);
902 rectPrivate->setState("right");
903 QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(150));
904 QCOMPARE(aChanges->object(), qobject_cast<QQuickItem*>(innerRect));
905 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QQuickAnchorLine::Invalid); //### was reset (how do we distinguish from not set at all)
906 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item);
907 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine);
909 rectPrivate->setState("");
910 QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) -qreal(5));
915 void tst_qquickstates::anchorChangesRTL2()
919 QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges2.qml"));
920 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
922 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
924 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
925 QVERIFY(innerRect != 0);
926 mirrorAnchors(innerRect);
928 rectPrivate->setState("right");
929 QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(150));
931 rectPrivate->setState("");
932 QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(5));
937 void tst_qquickstates::anchorChangesRTL3()
941 QQmlComponent rectComponent(&engine, testFileUrl("anchorChanges3.qml"));
942 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
944 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
946 QQuickRectangle *innerRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRect"));
947 QVERIFY(innerRect != 0);
948 mirrorAnchors(innerRect);
950 QQuickItem *leftGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("LeftGuideline"));
951 QVERIFY(leftGuideline != 0);
953 QQuickItem *bottomGuideline = qobject_cast<QQuickItem*>(rect->findChild<QQuickItem*>("BottomGuideline"));
954 QVERIFY(bottomGuideline != 0);
956 QQmlListReference list(rect, "states");
957 QQuickState *state = qobject_cast<QQuickState*>(list.at(0));
960 qmlExecuteDeferred(state);
961 QQuickAnchorChanges *aChanges = qobject_cast<QQuickAnchorChanges*>(state->operationAt(0));
962 QVERIFY(aChanges != 0);
964 rectPrivate->setState("reanchored");
965 QCOMPARE(aChanges->object(), qobject_cast<QQuickItem*>(innerRect));
966 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->left().item, QQuickItemPrivate::get(leftGuideline)->left().item);
967 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QQuickItemPrivate::get(leftGuideline)->left().anchorLine);
968 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item);
969 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine);
970 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->top().item, rectPrivate->top().item);
971 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->top().anchorLine, rectPrivate->top().anchorLine);
972 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->bottom().item, QQuickItemPrivate::get(bottomGuideline)->bottom().item);
973 QCOMPARE(QQuickItemPrivate::get(aChanges->object())->anchors()->bottom().anchorLine, QQuickItemPrivate::get(bottomGuideline)->bottom().anchorLine);
975 QCOMPARE(innerRect->x(), offsetRTL(leftGuideline, innerRect) - qreal(10));
976 QCOMPARE(innerRect->y(), qreal(0));
977 // between left side of parent and leftGuideline.x: 10, which has width 0
978 QCOMPARE(innerRect->width(), qreal(10));
979 QCOMPARE(innerRect->height(), qreal(150));
981 rectPrivate->setState("");
982 QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(0));
983 QCOMPARE(innerRect->y(), qreal(10));
984 // between right side of parent and left side of rightGuideline.x: 150, which has width 0
985 QCOMPARE(innerRect->width(), qreal(50));
986 QCOMPARE(innerRect->height(), qreal(190));
992 void tst_qquickstates::anchorChangesCrash()
996 QQmlComponent rectComponent(&engine, testFileUrl("anchorChangesCrash.qml"));
997 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1000 QQuickItemPrivate::get(rect)->setState("reanchored");
1006 void tst_qquickstates::anchorRewindBug()
1008 QQuickView *view = new QQuickView;
1009 view->setSource(testFileUrl("anchorRewindBug.qml"));
1012 view->requestActivateWindow();
1014 QVERIFY(QTest::qWaitForWindowActive(view));
1016 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(view->rootObject());
1019 QQuickItem * column = rect->findChild<QQuickItem*>("column");
1021 QVERIFY(column != 0);
1022 QVERIFY(!QQuickItemPrivate::get(column)->heightValid);
1023 QVERIFY(!QQuickItemPrivate::get(column)->widthValid);
1024 QCOMPARE(column->height(), 200.0);
1025 QQuickItemPrivate::get(rect)->setState("reanchored");
1027 // column height and width should stay implicit
1028 // and column's implicit resizing should still work
1029 QVERIFY(!QQuickItemPrivate::get(column)->heightValid);
1030 QVERIFY(!QQuickItemPrivate::get(column)->widthValid);
1031 QTRY_COMPARE(column->height(), 100.0);
1033 QQuickItemPrivate::get(rect)->setState("");
1035 // column height and width should stay implicit
1036 // and column's implicit resizing should still work
1037 QVERIFY(!QQuickItemPrivate::get(column)->heightValid);
1038 QVERIFY(!QQuickItemPrivate::get(column)->widthValid);
1039 QTRY_COMPARE(column->height(), 200.0);
1045 void tst_qquickstates::anchorRewindBug2()
1049 QQmlComponent rectComponent(&engine, testFileUrl("anchorRewindBug2.qml"));
1050 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1053 QQuickRectangle *mover = rect->findChild<QQuickRectangle*>("mover");
1055 QVERIFY(mover != 0);
1056 QCOMPARE(mover->y(), qreal(0.0));
1057 QCOMPARE(mover->width(), qreal(50.0));
1059 QQuickItemPrivate::get(rect)->setState("anchored");
1060 QCOMPARE(mover->y(), qreal(250.0));
1061 QCOMPARE(mover->width(), qreal(200.0));
1063 QQuickItemPrivate::get(rect)->setState("");
1064 QCOMPARE(mover->y(), qreal(0.0));
1065 QCOMPARE(mover->width(), qreal(50.0));
1070 void tst_qquickstates::script()
1075 QQmlComponent rectComponent(&engine, testFileUrl("script.qml"));
1076 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1078 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1079 QCOMPARE(rect->color(),QColor("red"));
1081 rectPrivate->setState("blue");
1082 QCOMPARE(rect->color(),QColor("blue"));
1084 rectPrivate->setState("");
1085 QCOMPARE(rect->color(),QColor("blue")); // a script isn't reverted
1089 void tst_qquickstates::restoreEntryValues()
1093 QQmlComponent rectComponent(&engine, testFileUrl("restoreEntryValues.qml"));
1094 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1096 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1097 QCOMPARE(rect->color(),QColor("red"));
1099 rectPrivate->setState("blue");
1100 QCOMPARE(rect->color(),QColor("blue"));
1102 rectPrivate->setState("");
1103 QCOMPARE(rect->color(),QColor("blue"));
1106 void tst_qquickstates::explicitChanges()
1110 QQmlComponent rectComponent(&engine, testFileUrl("explicit.qml"));
1111 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1113 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1114 QQmlListReference list(rect, "states");
1115 QQuickState *state = qobject_cast<QQuickState*>(list.at(0));
1116 QVERIFY(state != 0);
1118 qmlExecuteDeferred(state);
1119 QQuickPropertyChanges *changes = qobject_cast<QQuickPropertyChanges*>(rect->findChild<QQuickPropertyChanges*>("changes"));
1120 QVERIFY(changes != 0);
1121 QVERIFY(changes->isExplicit());
1123 QCOMPARE(rect->color(),QColor("red"));
1125 rectPrivate->setState("blue");
1126 QCOMPARE(rect->color(),QColor("blue"));
1128 rect->setProperty("sourceColor", QColor("green"));
1129 QCOMPARE(rect->color(),QColor("blue"));
1131 rectPrivate->setState("");
1132 QCOMPARE(rect->color(),QColor("red"));
1133 rect->setProperty("sourceColor", QColor("yellow"));
1134 QCOMPARE(rect->color(),QColor("red"));
1136 rectPrivate->setState("blue");
1137 QCOMPARE(rect->color(),QColor("yellow"));
1140 void tst_qquickstates::propertyErrors()
1143 QQmlComponent rectComponent(&engine, testFileUrl("propertyErrors.qml"));
1144 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1147 QCOMPARE(rect->color(),QColor("red"));
1149 QTest::ignoreMessage(QtWarningMsg, fullDataPath("propertyErrors.qml") + ":8:9: QML PropertyChanges: Cannot assign to non-existent property \"colr\"");
1150 QTest::ignoreMessage(QtWarningMsg, fullDataPath("propertyErrors.qml") + ":8:9: QML PropertyChanges: Cannot assign to read-only property \"activeFocus\"");
1151 QQuickItemPrivate::get(rect)->setState("blue");
1154 void tst_qquickstates::incorrectRestoreBug()
1158 QQmlComponent rectComponent(&engine, testFileUrl("basicChanges.qml"));
1159 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1161 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1162 QCOMPARE(rect->color(),QColor("red"));
1164 rectPrivate->setState("blue");
1165 QCOMPARE(rect->color(),QColor("blue"));
1167 rectPrivate->setState("");
1168 QCOMPARE(rect->color(),QColor("red"));
1170 // make sure if we change the base state value, we then restore to it correctly
1171 rect->setColor(QColor("green"));
1173 rectPrivate->setState("blue");
1174 QCOMPARE(rect->color(),QColor("blue"));
1176 rectPrivate->setState("");
1177 QCOMPARE(rect->color(),QColor("green"));
1180 void tst_qquickstates::autoStateAtStartupRestoreBug()
1184 QQmlComponent component(&engine, testFileUrl("autoStateAtStartupRestoreBug.qml"));
1185 QObject *obj = component.create();
1188 QCOMPARE(obj->property("test").toInt(), 3);
1190 obj->setProperty("input", 2);
1192 QCOMPARE(obj->property("test").toInt(), 9);
1197 void tst_qquickstates::deletingChange()
1201 QQmlComponent rectComponent(&engine, testFileUrl("deleting.qml"));
1202 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1204 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1205 rectPrivate->setState("blue");
1206 QCOMPARE(rect->color(),QColor("blue"));
1207 QCOMPARE(rect->radius(),qreal(5));
1209 rectPrivate->setState("");
1210 QCOMPARE(rect->color(),QColor("red"));
1211 QCOMPARE(rect->radius(),qreal(0));
1213 QQuickPropertyChanges *pc = rect->findChild<QQuickPropertyChanges*>("pc1");
1217 QQuickState *state = rect->findChild<QQuickState*>();
1218 QVERIFY(state != 0);
1219 qmlExecuteDeferred(state);
1220 QCOMPARE(state->operationCount(), 1);
1222 rectPrivate->setState("blue");
1223 QCOMPARE(rect->color(),QColor("red"));
1224 QCOMPARE(rect->radius(),qreal(5));
1229 void tst_qquickstates::deletingState()
1233 QQmlComponent rectComponent(&engine, testFileUrl("deletingState.qml"));
1234 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1237 QQuickStateGroup *sg = rect->findChild<QQuickStateGroup*>();
1239 QVERIFY(sg->findState("blue") != 0);
1241 sg->setState("blue");
1242 QCOMPARE(rect->color(),QColor("blue"));
1245 QCOMPARE(rect->color(),QColor("red"));
1247 QQuickState *state = rect->findChild<QQuickState*>();
1248 QVERIFY(state != 0);
1251 QVERIFY(sg->findState("blue") == 0);
1253 //### should we warn that state doesn't exist
1254 sg->setState("blue");
1255 QCOMPARE(rect->color(),QColor("red"));
1260 void tst_qquickstates::tempState()
1264 QQmlComponent rectComponent(&engine, testFileUrl("legalTempState.qml"));
1265 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1267 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1268 QTest::ignoreMessage(QtDebugMsg, "entering placed");
1269 QTest::ignoreMessage(QtDebugMsg, "entering idle");
1270 rectPrivate->setState("placed");
1271 QCOMPARE(rectPrivate->state(), QLatin1String("idle"));
1274 void tst_qquickstates::illegalTempState()
1278 QQmlComponent rectComponent(&engine, testFileUrl("illegalTempState.qml"));
1279 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1281 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1282 QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML StateGroup: Can't apply a state change as part of a state definition.");
1283 rectPrivate->setState("placed");
1284 QCOMPARE(rectPrivate->state(), QLatin1String("placed"));
1287 void tst_qquickstates::nonExistantProperty()
1291 QQmlComponent rectComponent(&engine, testFileUrl("nonExistantProp.qml"));
1292 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(rectComponent.create());
1294 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1295 QTest::ignoreMessage(QtWarningMsg, fullDataPath("nonExistantProp.qml") + ":9:9: QML PropertyChanges: Cannot assign to non-existent property \"colr\"");
1296 rectPrivate->setState("blue");
1297 QCOMPARE(rectPrivate->state(), QLatin1String("blue"));
1300 void tst_qquickstates::reset()
1304 QQmlComponent c(&engine, testFileUrl("reset.qml"));
1305 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
1308 QQuickImage *image = rect->findChild<QQuickImage*>();
1309 QVERIFY(image != 0);
1310 QCOMPARE(image->width(), qreal(40.));
1311 QCOMPARE(image->height(), qreal(20.));
1313 QQuickItemPrivate::get(rect)->setState("state1");
1315 QCOMPARE(image->width(), 20.0);
1316 QCOMPARE(image->height(), qreal(20.));
1321 void tst_qquickstates::illegalObjectCreation()
1325 QQmlComponent component(&engine, testFileUrl("illegalObj.qml"));
1326 QList<QQmlError> errors = component.errors();
1327 QVERIFY(errors.count() == 1);
1328 const QQmlError &error = errors.at(0);
1329 QCOMPARE(error.line(), 9);
1330 QCOMPARE(error.column(), 23);
1331 QCOMPARE(error.description().toUtf8().constData(), "PropertyChanges does not support creating state-specific objects.");
1334 void tst_qquickstates::whenOrdering()
1338 QQmlComponent c(&engine, testFileUrl("whenOrdering.qml"));
1339 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
1341 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1343 QCOMPARE(rectPrivate->state(), QLatin1String(""));
1344 rect->setProperty("condition2", true);
1345 QCOMPARE(rectPrivate->state(), QLatin1String("state2"));
1346 rect->setProperty("condition1", true);
1347 QCOMPARE(rectPrivate->state(), QLatin1String("state1"));
1348 rect->setProperty("condition2", false);
1349 QCOMPARE(rectPrivate->state(), QLatin1String("state1"));
1350 rect->setProperty("condition2", true);
1351 QCOMPARE(rectPrivate->state(), QLatin1String("state1"));
1352 rect->setProperty("condition1", false);
1353 rect->setProperty("condition2", false);
1354 QCOMPARE(rectPrivate->state(), QLatin1String(""));
1357 void tst_qquickstates::urlResolution()
1361 QQmlComponent c(&engine, testFileUrl("urlResolution.qml"));
1362 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
1365 QQuickItem *myType = rect->findChild<QQuickItem*>("MyType");
1366 QQuickImage *image1 = rect->findChild<QQuickImage*>("image1");
1367 QQuickImage *image2 = rect->findChild<QQuickImage*>("image2");
1368 QQuickImage *image3 = rect->findChild<QQuickImage*>("image3");
1369 QVERIFY(myType != 0 && image1 != 0 && image2 != 0 && image3 != 0);
1371 QQuickItemPrivate::get(myType)->setState("SetImageState");
1372 QUrl resolved = testFileUrl("Implementation/images/qt-logo.png");
1373 QCOMPARE(image1->source(), resolved);
1374 QCOMPARE(image2->source(), resolved);
1375 QCOMPARE(image3->source(), resolved);
1380 void tst_qquickstates::unnamedWhen()
1384 QQmlComponent c(&engine, testFileUrl("unnamedWhen.qml"));
1385 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
1387 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1389 QCOMPARE(rectPrivate->state(), QLatin1String(""));
1390 QCOMPARE(rect->property("stateString").toString(), QLatin1String(""));
1391 rect->setProperty("triggerState", true);
1392 QCOMPARE(rectPrivate->state(), QLatin1String("anonymousState1"));
1393 QCOMPARE(rect->property("stateString").toString(), QLatin1String("inState"));
1394 rect->setProperty("triggerState", false);
1395 QCOMPARE(rectPrivate->state(), QLatin1String(""));
1396 QCOMPARE(rect->property("stateString").toString(), QLatin1String(""));
1399 void tst_qquickstates::returnToBase()
1403 QQmlComponent c(&engine, testFileUrl("returnToBase.qml"));
1404 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
1406 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1408 QCOMPARE(rectPrivate->state(), QLatin1String(""));
1409 QCOMPARE(rect->property("stateString").toString(), QLatin1String(""));
1410 rect->setProperty("triggerState", true);
1411 QCOMPARE(rectPrivate->state(), QLatin1String("anonymousState1"));
1412 QCOMPARE(rect->property("stateString").toString(), QLatin1String("inState"));
1413 rect->setProperty("triggerState", false);
1414 QCOMPARE(rectPrivate->state(), QLatin1String(""));
1415 QCOMPARE(rect->property("stateString").toString(), QLatin1String("originalState"));
1419 void tst_qquickstates::extendsBug()
1423 QQmlComponent c(&engine, testFileUrl("extendsBug.qml"));
1424 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
1426 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1427 QQuickRectangle *greenRect = rect->findChild<QQuickRectangle*>("greenRect");
1429 rectPrivate->setState("b");
1430 QCOMPARE(greenRect->x(), qreal(100));
1431 QCOMPARE(greenRect->y(), qreal(100));
1434 void tst_qquickstates::editProperties()
1438 QQmlComponent c(&engine, testFileUrl("editProperties.qml"));
1439 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
1442 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1444 QQuickStateGroup *stateGroup = rectPrivate->_states();
1445 QVERIFY(stateGroup != 0);
1446 qmlExecuteDeferred(stateGroup);
1448 QQuickState *blueState = stateGroup->findState("blue");
1449 QVERIFY(blueState != 0);
1450 qmlExecuteDeferred(blueState);
1452 QQuickPropertyChanges *propertyChangesBlue = qobject_cast<QQuickPropertyChanges*>(blueState->operationAt(0));
1453 QVERIFY(propertyChangesBlue != 0);
1455 QQuickState *greenState = stateGroup->findState("green");
1456 QVERIFY(greenState != 0);
1457 qmlExecuteDeferred(greenState);
1459 QQuickPropertyChanges *propertyChangesGreen = qobject_cast<QQuickPropertyChanges*>(greenState->operationAt(0));
1460 QVERIFY(propertyChangesGreen != 0);
1462 QQuickRectangle *childRect = rect->findChild<QQuickRectangle*>("rect2");
1463 QVERIFY(childRect != 0);
1464 QCOMPARE(childRect->width(), qreal(402));
1465 QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
1466 QCOMPARE(childRect->height(), qreal(200));
1468 rectPrivate->setState("blue");
1469 QCOMPARE(childRect->width(), qreal(50));
1470 QCOMPARE(childRect->height(), qreal(40));
1471 QVERIFY(!QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
1472 QVERIFY(blueState->bindingInRevertList(childRect, "width"));
1475 rectPrivate->setState("green");
1476 QCOMPARE(childRect->width(), qreal(200));
1477 QCOMPARE(childRect->height(), qreal(100));
1478 QVERIFY(greenState->bindingInRevertList(childRect, "width"));
1481 rectPrivate->setState("");
1484 QCOMPARE(propertyChangesBlue->actions().length(), 2);
1485 QVERIFY(propertyChangesBlue->containsValue("width"));
1486 QVERIFY(!propertyChangesBlue->containsProperty("x"));
1487 QCOMPARE(propertyChangesBlue->value("width").toInt(), 50);
1488 QVERIFY(!propertyChangesBlue->value("x").isValid());
1490 propertyChangesBlue->changeValue("width", 60);
1491 QCOMPARE(propertyChangesBlue->value("width").toInt(), 60);
1492 QCOMPARE(propertyChangesBlue->actions().length(), 2);
1495 propertyChangesBlue->changeExpression("width", "myRectangle.width / 2");
1496 QVERIFY(!propertyChangesBlue->containsValue("width"));
1497 QVERIFY(propertyChangesBlue->containsExpression("width"));
1498 QCOMPARE(propertyChangesBlue->value("width").toInt(), 0);
1499 QCOMPARE(propertyChangesBlue->actions().length(), 2);
1501 propertyChangesBlue->changeValue("width", 50);
1502 QVERIFY(propertyChangesBlue->containsValue("width"));
1503 QVERIFY(!propertyChangesBlue->containsExpression("width"));
1504 QCOMPARE(propertyChangesBlue->value("width").toInt(), 50);
1505 QCOMPARE(propertyChangesBlue->actions().length(), 2);
1507 QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
1508 rectPrivate->setState("blue");
1509 QCOMPARE(childRect->width(), qreal(50));
1510 QCOMPARE(childRect->height(), qreal(40));
1512 propertyChangesBlue->changeValue("width", 60);
1513 QCOMPARE(propertyChangesBlue->value("width").toInt(), 60);
1514 QCOMPARE(propertyChangesBlue->actions().length(), 2);
1515 QCOMPARE(childRect->width(), qreal(60));
1516 QVERIFY(!QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
1518 propertyChangesBlue->changeExpression("width", "myRectangle.width / 2");
1519 QVERIFY(!propertyChangesBlue->containsValue("width"));
1520 QVERIFY(propertyChangesBlue->containsExpression("width"));
1521 QCOMPARE(propertyChangesBlue->value("width").toInt(), 0);
1522 QCOMPARE(propertyChangesBlue->actions().length(), 2);
1523 QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
1524 QCOMPARE(childRect->width(), qreal(200));
1526 propertyChangesBlue->changeValue("width", 50);
1527 QCOMPARE(childRect->width(), qreal(50));
1529 rectPrivate->setState("");
1530 QCOMPARE(childRect->width(), qreal(402));
1531 QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
1533 QCOMPARE(propertyChangesGreen->actions().length(), 2);
1534 rectPrivate->setState("green");
1535 QCOMPARE(childRect->width(), qreal(200));
1536 QCOMPARE(childRect->height(), qreal(100));
1537 QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
1538 QVERIFY(greenState->bindingInRevertList(childRect, "width"));
1539 QCOMPARE(propertyChangesGreen->actions().length(), 2);
1542 propertyChangesGreen->removeProperty("height");
1543 QVERIFY(!QQmlPropertyPrivate::binding(QQmlProperty(childRect, "height")));
1544 QCOMPARE(childRect->height(), qreal(200));
1546 QVERIFY(greenState->bindingInRevertList(childRect, "width"));
1547 QVERIFY(greenState->containsPropertyInRevertList(childRect, "width"));
1548 propertyChangesGreen->removeProperty("width");
1549 QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
1550 QCOMPARE(childRect->width(), qreal(402));
1551 QVERIFY(!greenState->bindingInRevertList(childRect, "width"));
1552 QVERIFY(!greenState->containsPropertyInRevertList(childRect, "width"));
1554 propertyChangesBlue->removeProperty("width");
1555 QCOMPARE(childRect->width(), qreal(402));
1557 rectPrivate->setState("blue");
1558 QCOMPARE(childRect->width(), qreal(402));
1559 QCOMPARE(childRect->height(), qreal(40));
1562 void tst_qquickstates::QTBUG_14830()
1566 QQmlComponent c(&engine, testFileUrl("QTBUG-14830.qml"));
1567 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
1569 QQuickItem *item = rect->findChild<QQuickItem*>("area");
1571 QCOMPARE(item->width(), qreal(171));
1574 void tst_qquickstates::avoidFastForward()
1578 //shouldn't fast forward if there isn't a transition
1579 QQmlComponent c(&engine, testFileUrl("avoidFastForward.qml"));
1580 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
1583 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1584 rectPrivate->setState("a");
1585 QCOMPARE(rect->property("updateCount").toInt(), 1);
1589 void tst_qquickstates::revertListBug()
1593 QQmlComponent c(&engine, testFileUrl("revertListBug.qml"));
1594 QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(c.create());
1597 QQuickRectangle *rect1 = rect->findChild<QQuickRectangle*>("rect1");
1598 QQuickRectangle *rect2 = rect->findChild<QQuickRectangle*>("rect2");
1599 QQuickItem *origParent1 = rect->findChild<QQuickItem*>("originalParent1");
1600 QQuickItem *origParent2 = rect->findChild<QQuickItem*>("originalParent2");
1601 QQuickItem *newParent = rect->findChild<QQuickItem*>("newParent");
1603 QCOMPARE(rect1->parentItem(), origParent1);
1604 QCOMPARE(rect2->parentItem(), origParent2);
1606 QQuickItemPrivate *rectPrivate = QQuickItemPrivate::get(rect);
1607 rectPrivate->setState("reparented");
1609 QCOMPARE(rect1->parentItem(), newParent);
1610 QCOMPARE(rect2->parentItem(), origParent2);
1612 rectPrivate->setState("");
1614 QCOMPARE(rect1->parentItem(), origParent1);
1615 QCOMPARE(rect2->parentItem(), origParent2);
1617 QMetaObject::invokeMethod(rect, "switchTargetItem");
1619 rectPrivate->setState("reparented");
1621 QCOMPARE(rect1->parentItem(), origParent1);
1622 QCOMPARE(rect2->parentItem(), newParent);
1624 rectPrivate->setState("");
1626 QCOMPARE(rect1->parentItem(), origParent1);
1627 QCOMPARE(rect2->parentItem(), origParent2); //QTBUG-22583 causes rect2's parent item to be origParent1
1630 QTEST_MAIN(tst_qquickstates)
1632 #include "tst_qquickstates.moc"