diff options
author | Liang Qi <liang.qi@qt.io> | 2016-06-16 07:09:18 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-06-16 07:09:19 +0200 |
commit | 34956bc234bf1b2ebcf224a256297293ba4276aa (patch) | |
tree | 732fc88b9ea113e8ff3f106a5e5bc33610c5ed57 | |
parent | e3a6565c3832e6f3001d49c52ca59fa4fa555f1b (diff) | |
parent | 210617de78c78af44efdc251ba7a207c5c26e11c (diff) |
Merge remote-tracking branch 'origin/5.7.0' into 5.7
Change-Id: I7b0ad528da17ecdb955c2d0c792c9f113904623e
-rw-r--r-- | dist/changes-5.7.0 | 114 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 3 | ||||
-rw-r--r-- | src/quick/items/qquickitem.cpp | 78 | ||||
-rw-r--r-- | src/quick/items/qquickitem_p.h | 6 | ||||
-rw-r--r-- | tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp | 15 | ||||
-rw-r--r-- | tests/auto/quick/qquickitem2/tst_qquickitem.cpp | 198 |
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() { |