aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2016-07-13 11:22:11 +0200
committerJ-P Nurmi <jpnurmi@qt.io>2016-07-13 13:00:13 +0000
commit35d500526990fafe5b71d97b051a770a2a81e82a (patch)
tree4af57439b5b58fb2cf0e0a20f18429ff2fcd2bd7 /tests/auto/quick/qquickitem2/tst_qquickitem.cpp
parent15621772e288c33d697cb7345ee04b8c33436d1f (diff)
Fix itemGeometryChanged() listeners
We must iterate a (cheap) copy of changeListeners, because the container might be indirectly modified during the loop. For example, listeners may remove themselves from the list. In such scenario, the copy gets detached and the loop remains safe. I've added notes in comments, and extended the tests to prevent the issue re-surfacing again. Change-Id: Ib48d6e0765d45370d2fffa119a4c351e0119e40a Task-number: QTBUG-54732 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'tests/auto/quick/qquickitem2/tst_qquickitem.cpp')
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp263
1 files changed, 161 insertions, 102 deletions
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index 62133d6475..169ef1cbab 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -2698,117 +2698,122 @@ void tst_QQuickItem::childrenRectBottomRightCorner()
struct TestListener : public QQuickItemChangeListener
{
- TestListener(bool remove = false) : remove(remove) { reset(); }
+ TestListener(bool remove = false) : remove(remove) { }
- void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange, const QRectF &) override
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange, const QRectF &diff) override
{
- ++itemGeometryChanges;
- value = QRectF(item->x(), item->y(), item->width(), item->height());
+ record(item, QQuickItemPrivate::Geometry, diff);
+ }
+ void itemSiblingOrderChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::SiblingOrder);
+ }
+ void itemVisibilityChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::Visibility);
+ }
+ void itemOpacityChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::Opacity);
+ }
+ void itemRotationChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::Rotation);
+ }
+ void itemImplicitWidthChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::ImplicitWidth);
+ }
+ void itemImplicitHeightChanged(QQuickItem *item) override
+ {
+ record(item, QQuickItemPrivate::ImplicitHeight);
}
- void itemSiblingOrderChanged(QQuickItem *) override { ++itemSiblingOrderChanges; }
- void itemVisibilityChanged(QQuickItem *) override { ++itemVisibilityChanges; }
- void itemOpacityChanged(QQuickItem *) override { ++itemOpacityChanges; }
- void itemRotationChanged(QQuickItem *) override { ++itemRotationChanges; }
- void itemImplicitWidthChanged(QQuickItem *) override { ++itemImplicitWidthChanges; }
- void itemImplicitHeightChanged(QQuickItem *) override { ++itemImplicitHeightChanges; }
-
void itemDestroyed(QQuickItem *item) override
{
- ++itemDestructions;
- // QTBUG-53453
- if (remove)
- QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed);
+ record(item, QQuickItemPrivate::Destroyed);
}
void itemChildAdded(QQuickItem *item, QQuickItem *child) override
{
- ++itemChildAdditions;
- value = QVariant::fromValue(child);
- // QTBUG-53453
- if (remove)
- QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Children);
+ record(item, QQuickItemPrivate::Children, QVariant::fromValue(child));
}
void itemChildRemoved(QQuickItem *item, QQuickItem *child) override
{
- ++itemChildRemovals;
- value = QVariant::fromValue(child);
- // QTBUG-53453
- if (remove)
- QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Children);
+ record(item, QQuickItemPrivate::Children, QVariant::fromValue(child));
}
void itemParentChanged(QQuickItem *item, QQuickItem *parent) override
{
- ++itemParentChanges;
- value = QVariant::fromValue(parent);
- // QTBUG-53453
- if (remove)
- QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Parent);
+ record(item, QQuickItemPrivate::Parent, QVariant::fromValue(parent));
}
QQuickAnchorsPrivate *anchorPrivate() override { return nullptr; }
- void reset()
+ void record(QQuickItem *item, QQuickItemPrivate::ChangeType change, const QVariant &value = QVariant())
+ {
+ changes += change;
+ values[change] = value;
+ // QTBUG-54732
+ if (remove)
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, change);
+ }
+
+ int count(QQuickItemPrivate::ChangeType change) const
{
- value = QVariant();
- itemGeometryChanges = 0;
- itemSiblingOrderChanges = 0;
- itemVisibilityChanges = 0;
- itemOpacityChanges = 0;
- itemDestructions = 0;
- itemChildAdditions = 0;
- itemChildRemovals = 0;
- itemParentChanges = 0;
- itemRotationChanges = 0;
- itemImplicitWidthChanges = 0;
- itemImplicitHeightChanges = 0;
+ return changes.count(change);
+ }
+
+ QVariant value(QQuickItemPrivate::ChangeType change) const
+ {
+ return values.value(change);
}
bool remove;
- QVariant value;
- int itemGeometryChanges;
- int itemSiblingOrderChanges;
- int itemVisibilityChanges;
- int itemOpacityChanges;
- int itemDestructions;
- int itemChildAdditions;
- int itemChildRemovals;
- int itemParentChanges;
- int itemRotationChanges;
- int itemImplicitWidthChanges;
- int itemImplicitHeightChanges;
+ QList<QQuickItemPrivate::ChangeType> changes;
+ QHash<QQuickItemPrivate::ChangeType, QVariant> values;
};
void tst_QQuickItem::changeListener()
{
- QQuickItem item;
+ QQuickWindow window;
+ window.show();
+ QTest::qWaitForWindowExposed(&window);
+
+ QQuickItem *item = new QQuickItem;
TestListener itemListener;
- QQuickItemPrivate::get(&item)->addItemChangeListener(&itemListener, QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight |
- QQuickItemPrivate::Opacity | QQuickItemPrivate::Rotation);
+ QQuickItemPrivate::get(item)->addItemChangeListener(&itemListener, QQuickItemPrivate::ChangeTypes(0xffff));
+
+ item->setImplicitWidth(10);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitWidth), 1);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 1);
+ QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,10,0)));
- item.setImplicitWidth(50);
- QCOMPARE(itemListener.itemImplicitWidthChanges, 1);
- QCOMPARE(itemListener.itemGeometryChanges, 1);
- QCOMPARE(itemListener.value, QVariant(QRectF(0,0,50,0)));
+ item->setImplicitHeight(20);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitHeight), 1);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 2);
+ QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,0,20)));
- item.setImplicitHeight(50);
- QCOMPARE(itemListener.itemImplicitHeightChanges, 1);
- QCOMPARE(itemListener.itemGeometryChanges, 2);
- QCOMPARE(itemListener.value, QVariant(QRectF(0,0,50,50)));
+ item->setWidth(item->width() + 30);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 3);
+ QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,30,0)));
- item.setWidth(100);
- QCOMPARE(itemListener.itemGeometryChanges, 3);
- QCOMPARE(itemListener.value, QVariant(QRectF(0,0,100,50)));
+ item->setHeight(item->height() + 40);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 4);
+ QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,0,40)));
- item.setHeight(100);
- QCOMPARE(itemListener.itemGeometryChanges, 4);
- QCOMPARE(itemListener.value, QVariant(QRectF(0,0,100,100)));
+ item->setOpacity(0.5);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Opacity), 1);
- item.setOpacity(0.5);
- QCOMPARE(itemListener.itemOpacityChanges, 1);
+ item->setRotation(90);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Rotation), 1);
+
+ item->setParentItem(window.contentItem());
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Parent), 1);
+
+ item->setVisible(false);
+ QCOMPARE(itemListener.count(QQuickItemPrivate::Visibility), 1);
- item.setRotation(90);
- QCOMPARE(itemListener.itemRotationChanges, 1);
+ QQuickItemPrivate::get(item)->removeItemChangeListener(&itemListener, QQuickItemPrivate::ChangeTypes(0xffff));
- QQuickItem *parent = new QQuickItem;
+ QQuickItem *parent = new QQuickItem(window.contentItem());
TestListener parentListener;
QQuickItemPrivate::get(parent)->addItemChangeListener(&parentListener, QQuickItemPrivate::Children);
@@ -2820,52 +2825,79 @@ void tst_QQuickItem::changeListener()
QQuickItemPrivate::get(child2)->addItemChangeListener(&child2Listener, QQuickItemPrivate::Parent | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Destroyed);
child1->setParentItem(parent);
- QCOMPARE(parentListener.itemChildAdditions, 1);
- QCOMPARE(parentListener.value, QVariant::fromValue(child1));
- QCOMPARE(child1Listener.itemParentChanges, 1);
- QCOMPARE(child1Listener.value, QVariant::fromValue(parent));
+ QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 1);
+ QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child1));
+ QCOMPARE(child1Listener.count(QQuickItemPrivate::Parent), 1);
+ QCOMPARE(child1Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue(parent));
child2->setParentItem(parent);
- QCOMPARE(parentListener.itemChildAdditions, 2);
- QCOMPARE(parentListener.value, QVariant::fromValue(child2));
- QCOMPARE(child2Listener.itemParentChanges, 1);
- QCOMPARE(child2Listener.value, QVariant::fromValue(parent));
+ QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 2);
+ QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child2));
+ QCOMPARE(child2Listener.count(QQuickItemPrivate::Parent), 1);
+ QCOMPARE(child2Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue(parent));
child2->stackBefore(child1);
- QCOMPARE(child1Listener.itemSiblingOrderChanges, 1);
- QCOMPARE(child2Listener.itemSiblingOrderChanges, 1);
+ QCOMPARE(child1Listener.count(QQuickItemPrivate::SiblingOrder), 1);
+ QCOMPARE(child2Listener.count(QQuickItemPrivate::SiblingOrder), 1);
child1->setParentItem(nullptr);
- QCOMPARE(parentListener.itemChildRemovals, 1);
- QCOMPARE(parentListener.value, QVariant::fromValue(child1));
- QCOMPARE(child1Listener.itemParentChanges, 2);
- QCOMPARE(child1Listener.value, QVariant::fromValue<QQuickItem *>(nullptr));
+ QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 3);
+ QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child1));
+ QCOMPARE(child1Listener.count(QQuickItemPrivate::Parent), 2);
+ QCOMPARE(child1Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue<QQuickItem *>(nullptr));
delete child1;
- QCOMPARE(child1Listener.itemDestructions, 1);
+ QCOMPARE(child1Listener.count(QQuickItemPrivate::Destroyed), 1);
delete child2;
- QCOMPARE(parentListener.itemChildRemovals, 2);
- QCOMPARE(parentListener.value, QVariant::fromValue(child2));
- QCOMPARE(child2Listener.itemParentChanges, 2);
- QCOMPARE(child2Listener.value, QVariant::fromValue<QQuickItem *>(nullptr));
- QCOMPARE(child2Listener.itemDestructions, 1);
+ QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 4);
+ QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child2));
+ QCOMPARE(child2Listener.count(QQuickItemPrivate::Parent), 2);
+ QCOMPARE(child2Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue<QQuickItem *>(nullptr));
+ QCOMPARE(child2Listener.count(QQuickItemPrivate::Destroyed), 1);
QQuickItemPrivate::get(parent)->removeItemChangeListener(&parentListener, QQuickItemPrivate::Children);
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
- // QTBUG-53453: all listeners should get invoked even if they remove themselves while iterating the listeners
+ // QTBUG-54732: all listeners should get invoked even if they remove themselves while iterating the listeners
QList<TestListener *> listeners;
for (int i = 0; i < 5; ++i)
listeners << new TestListener(true);
+ // itemVisibilityChanged x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Visibility);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setVisible(false);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Visibility), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemRotationChanged x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Rotation);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setRotation(90);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Rotation), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemOpacityChanged x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Opacity);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setOpacity(0.5);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Opacity), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
// itemChildAdded() x 5
foreach (TestListener *listener, listeners)
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children);
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
child1 = new QQuickItem(parent);
foreach (TestListener *listener, listeners)
- QCOMPARE(listener->itemChildAdditions, 1);
+ QCOMPARE(listener->count(QQuickItemPrivate::Children), 1);
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
// itemParentChanged() x 5
@@ -2874,9 +2906,36 @@ void tst_QQuickItem::changeListener()
QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), listeners.count());
child1->setParentItem(nullptr);
foreach (TestListener *listener, listeners)
- QCOMPARE(listener->itemParentChanges, 1);
+ QCOMPARE(listener->count(QQuickItemPrivate::Parent), 1);
QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), 0);
+ // itemImplicitWidthChanged() x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitWidth);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setImplicitWidth(parent->implicitWidth() + 1);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::ImplicitWidth), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemImplicitHeightChanged() x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitHeight);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setImplicitHeight(parent->implicitHeight() + 1);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::ImplicitHeight), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemGeometryChanged() x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Geometry);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ parent->setWidth(parent->width() + 1);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->count(QQuickItemPrivate::Geometry), 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
// itemChildRemoved() x 5
child1->setParentItem(parent);
foreach (TestListener *listener, listeners)
@@ -2884,7 +2943,7 @@ void tst_QQuickItem::changeListener()
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
delete child1;
foreach (TestListener *listener, listeners)
- QCOMPARE(listener->itemChildRemovals, 1);
+ QCOMPARE(listener->count(QQuickItemPrivate::Children), 2);
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
// itemDestroyed() x 5
@@ -2893,7 +2952,7 @@ void tst_QQuickItem::changeListener()
QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
delete parent;
foreach (TestListener *listener, listeners)
- QCOMPARE(listener->itemDestructions, 1);
+ QCOMPARE(listener->count(QQuickItemPrivate::Destroyed), 1);
}
// QTBUG-13893