aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-06-16 07:09:18 +0200
committerLiang Qi <liang.qi@qt.io>2016-06-16 07:09:19 +0200
commit34956bc234bf1b2ebcf224a256297293ba4276aa (patch)
tree732fc88b9ea113e8ff3f106a5e5bc33610c5ed57
parente3a6565c3832e6f3001d49c52ca59fa4fa555f1b (diff)
parent210617de78c78af44efdc251ba7a207c5c26e11c (diff)
Merge remote-tracking branch 'origin/5.7.0' into 5.7
-rw-r--r--dist/changes-5.7.0114
-rw-r--r--src/qml/qml/qqmltypeloader.cpp3
-rw-r--r--src/quick/items/qquickitem.cpp78
-rw-r--r--src/quick/items/qquickitem_p.h6
-rw-r--r--tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp15
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp198
6 files changed, 371 insertions, 43 deletions
diff --git a/dist/changes-5.7.0 b/dist/changes-5.7.0
new file mode 100644
index 0000000000..ac8c63b2ad
--- /dev/null
+++ b/dist/changes-5.7.0
@@ -0,0 +1,114 @@
+Qt 5.7 introduces many new features and improvements as well as bugfixes
+over the 5.6.x series. Also, there is a change in the licensing terms.
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+ http://doc.qt.io/qt-5/index.html
+
+The Qt version 5.7 series is binary compatible with the 5.6.x series.
+Applications compiled for 5.6 will continue to run with 5.7.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+ https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Important License Changes *
+****************************************************************************
+
+ This module is no longer available under LGPLv2.1. The libraries are
+ now available under the following licenses:
+ * Commercial License
+ * GNU General Public License v2.0 (LICENSE.GPL2) and later
+ * GNU Lesser General Public License v3.0 (LICENSE.LGPL3)
+
+ The tools are now available under the following licenses:
+ * Commercial License
+ * GNU General Public License 3.0 (LICENSE.GPL3) with exceptions
+ described in The Qt Company GPL Exception 1.0 (LICENSE.GPL3-EXCEPT)
+
+****************************************************************************
+* Important Behavior Changes *
+****************************************************************************
+
+QtQuick
+-------
+
+ * [QTBUG-41833] QQuickItem::childAt was incorrectly including any child
+ whose right or bottom edge was adjacent to the point being checked,
+ as if it had width+1 and height+1. An Item with a width of 100
+ covers pixels from x=0..x=99, and likewise with height; so now,
+ calling childAt(100, 100) on its parent will not return it.
+
+ * [QTBUG-51115] TextEdit and TextInput now clear their selection when
+ becoming read-only.
+
+ * QtQuick.Layouts moved to the qtdeclarative repository.
+
+****************************************************************************
+* Library *
+****************************************************************************
+
+QtQml
+-----
+
+ - [QTBUG-52556] Made the QML Engine capable of locating QML sub-modules
+ from within a versioned parent module path. For example, QtQml.Models
+ 2.x can be either in QT_INSTALL_QML/QtQml/Models.2 or in
+ QT_INSTALL_QML/QtQml.2/Models.
+ - [QTBUG-36350] Added Connections::enabled property to allow toggling of the
+ signal handlers inside a Connections element.
+ - Enabled JIT for x86/x64 targets on Windows 10 and later.
+ - Enabled JIT for Aarch64.
+
+QtQuick
+-------
+
+ - Window:
+ * Added Window.window attached property, allowing access to the QQuickWindow
+ an Item belongs to.
+
+ - GridView & ListView:
+ * [QTBUG-17051] Added keyNavigationEnabled property to allow mouse and
+ keyboard interaction to be selectively enabled/disabled.
+ * Sticky headers or footers are now correctly positioned in the case of
+ an empty view.
+
+ - MouseArea:
+ * Added mouse.source property to enable distinguishing genuine mouse
+ events from those that are synthesized from touch or tablet events.
+
+ - PathView:
+ * Added PathView::movementDirection, which sets the direction in which items
+ move when setting currentIndex.
+
+ - QQuickItem:
+ * Added isAncestorOf() to determine if an item is the ancestor of another
+ item (i.e. the parent, or a parent further up the item tree).
+ * [QTBUG-28668] Added support for mapping item's coordinates to and from global
+ screen coordinates, in the form of Item::mapToGlobal() and
+ Item::mapFromGlobal().
+
+ - TextEdit/TextInput:
+ * [QTBUG-49503] Added TextEdit::preeditText & TextInput::preeditText,
+ which allow access to partial (uncommitted) text from an input method.
+ * [QTBUG-50428] Added TextEdit::clear() and TextInput::clear() which sets the
+ text to an empty string, but in addition, also clears partial (uncommitted)
+ text.
+
+ - Loader:
+ * [QTBUG-29789] Object creation previously started asynchronously can be
+ forced to complete synchronously by changing the "asynchronous" property
+ from true to false.
+
+Qt.labs.folderlistmodel
+-----------------------
+
+ - FolderListModel
+ * [QTBUG-45566] Added FolderListModel::caseSensitive, to control whether or
+ not filtering is applied case sensitively.
+
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 29fdf78797..739a833a30 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1950,7 +1950,8 @@ void QQmlTypeLoader::trimCache()
QList<TypeCache::Iterator> unneededTypes;
for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter) {
QQmlTypeData *typeData = iter.value();
- if (typeData->m_compiledData && typeData->m_compiledData->count() == 1) {
+ if (typeData->m_compiledData && typeData->count() == 1
+ && typeData->m_compiledData->count() == 1) {
// There are no live objects of this type
unneededTypes.append(iter);
}
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 67a2b8a892..0ff04ce71c 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -2359,8 +2359,9 @@ QQuickItem::~QQuickItem()
while (!d->childItems.isEmpty())
d->childItems.constFirst()->setParentItem(0);
- for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
- QQuickAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
+ const auto listeners = d->changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
+ QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
if (anchor)
anchor->clearItem(this);
}
@@ -2369,14 +2370,13 @@ QQuickItem::~QQuickItem()
update item anchors that depended on us unless they are our child (and will also be destroyed),
or our sibling, and our parent is also being destroyed.
*/
- for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
- QQuickAnchorsPrivate *anchor = d->changeListeners.at(ii).listener->anchorPrivate();
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
+ QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
if (anchor && anchor->item && anchor->item->parentItem() && anchor->item->parentItem() != this)
anchor->update();
}
- for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Destroyed)
change.listener->itemDestroyed(this);
}
@@ -3618,8 +3618,8 @@ QQuickAnchors *QQuickItemPrivate::anchors() const
void QQuickItemPrivate::siblingOrderChanged()
{
Q_Q(QQuickItem);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::SiblingOrder) {
change.listener->itemSiblingOrderChanged(q);
}
@@ -3727,8 +3727,8 @@ void QQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
bool widthChange = (newGeometry.width() != oldGeometry.width());
bool heightChange = (newGeometry.height() != oldGeometry.height());
- for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ const auto listeners = d->changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Geometry) {
if (change.gTypes == QQuickItemPrivate::GeometryChange) {
change.listener->itemGeometryChanged(this, newGeometry, oldGeometry);
@@ -3864,7 +3864,7 @@ void QQuickItemPrivate::removeItemChangeListener(QQuickItemChangeListener *liste
void QQuickItemPrivate::updateOrAddGeometryChangeListener(QQuickItemChangeListener *listener, GeometryChangeTypes types)
{
ChangeListener change(listener, types);
- int index = changeListeners.find(change);
+ int index = changeListeners.indexOf(change);
if (index > -1)
changeListeners[index].gTypes = change.gTypes; //we may have different GeometryChangeTypes
else
@@ -3878,7 +3878,7 @@ void QQuickItemPrivate::updateOrRemoveGeometryChangeListener(QQuickItemChangeLis
if (types == NoChange) {
changeListeners.removeOne(change);
} else {
- int index = changeListeners.find(change);
+ int index = changeListeners.indexOf(change);
if (index > -1)
changeListeners[index].gTypes = change.gTypes; //we may have different GeometryChangeTypes
}
@@ -4287,8 +4287,8 @@ void QQuickItem::setBaselineOffset(qreal offset)
d->baselineOffset = offset;
- for (int ii = 0; ii < d->changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = d->changeListeners.at(ii);
+ const auto listeners = d->changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Geometry) {
QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
if (anchor)
@@ -5959,66 +5959,72 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
{
Q_Q(QQuickItem);
switch (change) {
- case QQuickItem::ItemChildAddedChange:
+ case QQuickItem::ItemChildAddedChange: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Children) {
change.listener->itemChildAdded(q, data.item);
}
}
break;
- case QQuickItem::ItemChildRemovedChange:
+ }
+ case QQuickItem::ItemChildRemovedChange: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Children) {
change.listener->itemChildRemoved(q, data.item);
}
}
break;
+ }
case QQuickItem::ItemSceneChange:
q->itemChange(change, data);
break;
- case QQuickItem::ItemVisibleHasChanged:
+ case QQuickItem::ItemVisibleHasChanged: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Visibility) {
change.listener->itemVisibilityChanged(q);
}
}
break;
- case QQuickItem::ItemParentHasChanged:
+ }
+ case QQuickItem::ItemParentHasChanged: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Parent) {
change.listener->itemParentChanged(q, data.item);
}
}
break;
- case QQuickItem::ItemOpacityHasChanged:
+ }
+ case QQuickItem::ItemOpacityHasChanged: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Opacity) {
change.listener->itemOpacityChanged(q);
}
}
break;
+ }
case QQuickItem::ItemActiveFocusHasChanged:
q->itemChange(change, data);
break;
- case QQuickItem::ItemRotationHasChanged:
+ case QQuickItem::ItemRotationHasChanged: {
q->itemChange(change, data);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::Rotation) {
change.listener->itemRotationChanged(q);
}
}
break;
+ }
case QQuickItem::ItemAntialiasingHasChanged:
// fall through
case QQuickItem::ItemDevicePixelRatioHasChanged:
@@ -6373,8 +6379,8 @@ void QQuickItem::resetWidth()
void QQuickItemPrivate::implicitWidthChanged()
{
Q_Q(QQuickItem);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::ImplicitWidth) {
change.listener->itemImplicitWidthChanged(q);
}
@@ -6537,8 +6543,8 @@ void QQuickItem::resetHeight()
void QQuickItemPrivate::implicitHeightChanged()
{
Q_Q(QQuickItem);
- for (int ii = 0; ii < changeListeners.count(); ++ii) {
- const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ const auto listeners = changeListeners;
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
if (change.types & QQuickItemPrivate::ImplicitHeight) {
change.listener->itemImplicitHeightChanged(q);
}
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index ad649e5b5f..fed3e88b68 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -62,7 +62,6 @@
#include <QtQuick/qsgnode.h>
#include "qquickclipnode_p.h"
-#include <private/qpodvector_p.h>
#include <QtQuick/private/qquickstate_p.h>
#include <private/qqmlnullablevalue_p.h>
#include <private/qqmlnotifier_p.h>
@@ -332,7 +331,7 @@ public:
Q_DECLARE_FLAGS(GeometryChangeTypes, GeometryChangeType)
struct ChangeListener {
- ChangeListener(QQuickItemChangeListener *l, QQuickItemPrivate::ChangeTypes t) : listener(l), types(t), gTypes(GeometryChange) {}
+ ChangeListener(QQuickItemChangeListener *l = Q_NULLPTR, QQuickItemPrivate::ChangeTypes t = 0) : listener(l), types(t), gTypes(GeometryChange) {}
ChangeListener(QQuickItemChangeListener *l, QQuickItemPrivate::GeometryChangeTypes gt) : listener(l), types(Geometry), gTypes(gt) {}
QQuickItemChangeListener *listener;
QQuickItemPrivate::ChangeTypes types;
@@ -386,7 +385,7 @@ public:
inline Qt::MouseButtons acceptedMouseButtons() const;
- QPODVector<QQuickItemPrivate::ChangeListener,4> changeListeners;
+ QVector<QQuickItemPrivate::ChangeListener> changeListeners;
void addItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types);
void removeItemChangeListener(QQuickItemChangeListener *, ChangeTypes types);
@@ -932,6 +931,7 @@ QSGNode *QQuickItemPrivate::childContainerNode()
}
Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickItemPrivate::ChangeTypes)
+Q_DECLARE_TYPEINFO(QQuickItemPrivate::ChangeListener, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
index ef1ea3a897..3e8e1d23ea 100644
--- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
+++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp
@@ -81,10 +81,19 @@ void tst_QQMLTypeLoader::trimCache()
url.setQuery(QString::number(i));
QQmlTypeData *data = loader.getType(url);
- if (i % 5 == 0) // keep references to some of them so that they aren't trimmed
- data->compiledData()->addref();
+ // Run an event loop to receive the callback that release()es.
+ QTRY_COMPARE(data->count(), 2);
- data->release();
+ // keep references to some of them so that they aren't trimmed. References to either the
+ // QQmlTypeData or its compiledData() should prevent the trimming.
+ if (i % 10 == 0) {
+ // keep ref on data, don't add ref on data->compiledData()
+ } else if (i % 5 == 0) {
+ data->compiledData()->addref();
+ data->release();
+ } else {
+ data->release();
+ }
}
for (int i = 0; i < 256; ++i) {
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index 62ff09e698..a087efd6b8 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -35,6 +35,7 @@
#include <QtGui/private/qinputmethod_p.h>
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/private/qquicktextinput_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
#include <QtGui/qstylehints.h>
#include <private/qquickitem_p.h>
#include "../../shared/util.h"
@@ -107,6 +108,7 @@ private slots:
void childrenProperty();
void resourcesProperty();
+ void changeListener();
void transformCrash();
void implicitSize();
void qtbug_16871();
@@ -2694,6 +2696,202 @@ void tst_QQuickItem::childrenRectBottomRightCorner()
delete window;
}
+struct TestListener : public QQuickItemChangeListener
+{
+ TestListener(bool remove = false) : remove(remove) { reset(); }
+
+ void itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &) override { ++itemGeometryChanges; value = newGeometry; }
+ 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);
+ }
+ void itemChildAdded(QQuickItem *item, QQuickItem *child) override
+ {
+ ++itemChildAdditions;
+ value = QVariant::fromValue(child);
+ // QTBUG-53453
+ if (remove)
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Children);
+ }
+ void itemChildRemoved(QQuickItem *item, QQuickItem *child) override
+ {
+ ++itemChildRemovals;
+ value = QVariant::fromValue(child);
+ // QTBUG-53453
+ if (remove)
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Children);
+ }
+ void itemParentChanged(QQuickItem *item, QQuickItem *parent) override
+ {
+ ++itemParentChanges;
+ value = QVariant::fromValue(parent);
+ // QTBUG-53453
+ if (remove)
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Parent);
+ }
+
+ QQuickAnchorsPrivate *anchorPrivate() override { return nullptr; }
+
+ void reset()
+ {
+ value = QVariant();
+ itemGeometryChanges = 0;
+ itemSiblingOrderChanges = 0;
+ itemVisibilityChanges = 0;
+ itemOpacityChanges = 0;
+ itemDestructions = 0;
+ itemChildAdditions = 0;
+ itemChildRemovals = 0;
+ itemParentChanges = 0;
+ itemRotationChanges = 0;
+ itemImplicitWidthChanges = 0;
+ itemImplicitHeightChanges = 0;
+ }
+
+ 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;
+};
+
+void tst_QQuickItem::changeListener()
+{
+ QQuickItem item;
+ TestListener itemListener;
+ QQuickItemPrivate::get(&item)->addItemChangeListener(&itemListener, QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight |
+ QQuickItemPrivate::Opacity | QQuickItemPrivate::Rotation);
+
+ item.setImplicitWidth(50);
+ QCOMPARE(itemListener.itemImplicitWidthChanges, 1);
+ QCOMPARE(itemListener.itemGeometryChanges, 1);
+ QCOMPARE(itemListener.value, QVariant(QRectF(0,0,50,0)));
+
+ item.setImplicitHeight(50);
+ QCOMPARE(itemListener.itemImplicitHeightChanges, 1);
+ QCOMPARE(itemListener.itemGeometryChanges, 2);
+ QCOMPARE(itemListener.value, QVariant(QRectF(0,0,50,50)));
+
+ item.setWidth(100);
+ QCOMPARE(itemListener.itemGeometryChanges, 3);
+ QCOMPARE(itemListener.value, QVariant(QRectF(0,0,100,50)));
+
+ item.setHeight(100);
+ QCOMPARE(itemListener.itemGeometryChanges, 4);
+ QCOMPARE(itemListener.value, QVariant(QRectF(0,0,100,100)));
+
+ item.setOpacity(0.5);
+ QCOMPARE(itemListener.itemOpacityChanges, 1);
+
+ item.setRotation(90);
+ QCOMPARE(itemListener.itemRotationChanges, 1);
+
+ QQuickItem *parent = new QQuickItem;
+ TestListener parentListener;
+ QQuickItemPrivate::get(parent)->addItemChangeListener(&parentListener, QQuickItemPrivate::Children);
+
+ QQuickItem *child1 = new QQuickItem;
+ QQuickItem *child2 = new QQuickItem;
+ TestListener child1Listener;
+ TestListener child2Listener;
+ QQuickItemPrivate::get(child1)->addItemChangeListener(&child1Listener, QQuickItemPrivate::Parent | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Destroyed);
+ 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));
+
+ child2->setParentItem(parent);
+ QCOMPARE(parentListener.itemChildAdditions, 2);
+ QCOMPARE(parentListener.value, QVariant::fromValue(child2));
+ QCOMPARE(child2Listener.itemParentChanges, 1);
+ QCOMPARE(child2Listener.value, QVariant::fromValue(parent));
+
+ child2->stackBefore(child1);
+ QCOMPARE(child1Listener.itemSiblingOrderChanges, 1);
+ QCOMPARE(child2Listener.itemSiblingOrderChanges, 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));
+
+ delete child1;
+ QCOMPARE(child1Listener.itemDestructions, 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);
+
+ 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
+ QList<TestListener *> listeners;
+ for (int i = 0; i < 5; ++i)
+ listeners << new TestListener(true);
+
+ // 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(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemParentChanged() x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(child1)->addItemChangeListener(listener, QQuickItemPrivate::Parent);
+ QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), listeners.count());
+ child1->setParentItem(nullptr);
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->itemParentChanges, 1);
+ QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), 0);
+
+ // itemChildRemoved() x 5
+ child1->setParentItem(parent);
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ delete child1;
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->itemChildRemovals, 1);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+
+ // itemDestroyed() x 5
+ foreach (TestListener *listener, listeners)
+ QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Destroyed);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ delete parent;
+ foreach (TestListener *listener, listeners)
+ QCOMPARE(listener->itemDestructions, 1);
+}
+
// QTBUG-13893
void tst_QQuickItem::transformCrash()
{