From 406059366f88d4f0d862cd9d0a8d746e8c2335c1 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 28 Dec 2016 20:24:18 +0100 Subject: QQuickMenu: fix Repeater support QQuickMenu had itemChildAdded() copied from QQuickContainer, but it did not actually install an item change listener on the content item so itemChildAdded() got never called. Change-Id: Idfe558c7055b9a3df124b1f009941c423ecef4bb Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickmenu.cpp | 7 +++- tests/auto/menu/data/order.qml | 71 ++++++++++++++++++++++++++++++++++++++ tests/auto/menu/data/repeater.qml | 59 +++++++++++++++++++++++++++++++ tests/auto/menu/tst_menu.cpp | 67 +++++++++++++++++++++++++++++++++++ 4 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 tests/auto/menu/data/order.qml create mode 100644 tests/auto/menu/data/repeater.qml diff --git a/src/quicktemplates2/qquickmenu.cpp b/src/quicktemplates2/qquickmenu.cpp index ab5415d3..74239cf2 100644 --- a/src/quicktemplates2/qquickmenu.cpp +++ b/src/quicktemplates2/qquickmenu.cpp @@ -461,8 +461,13 @@ void QQuickMenu::componentComplete() void QQuickMenu::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) { Q_D(QQuickMenu); - Q_UNUSED(oldItem); QQuickPopup::contentItemChange(newItem, oldItem); + + if (oldItem) + QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Children); + if (newItem) + QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Children); + d->contentItem = newItem; } diff --git a/tests/auto/menu/data/order.qml b/tests/auto/menu/data/order.qml new file mode 100644 index 00000000..678f27e2 --- /dev/null +++ b/tests/auto/menu/data/order.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.1 + +ApplicationWindow { + width: 200 + height: 200 + + property alias menu: menu + + Component { + id: menuItem + MenuItem { } + } + + Menu { + id: menu + property alias repeater: repeater + MenuItem { text: "static_1" } + Repeater { + id: repeater + model: 2 + MenuItem { text: "repeated_" + (index + 2) } + } + MenuItem { text: "static_4" } + Component.onCompleted: { + addItem(menuItem.createObject(menu.contentItem, {text: "dynamic_5"})) + addItem(menuItem.createObject(menu.contentItem, {text: "dynamic_6"})) + insertItem(0, menuItem.createObject(menu.contentItem, {text: "dynamic_0"})) + } + } +} diff --git a/tests/auto/menu/data/repeater.qml b/tests/auto/menu/data/repeater.qml new file mode 100644 index 00000000..e4619053 --- /dev/null +++ b/tests/auto/menu/data/repeater.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 2.1 + +ApplicationWindow { + width: 200 + height: 200 + + property alias menu: menu + property alias repeater: repeater + + Menu { + id: menu + Repeater { + id: repeater + model: 5 + MenuItem { property int idx: index } + } + } +} diff --git a/tests/auto/menu/tst_menu.cpp b/tests/auto/menu/tst_menu.cpp index 0635ad81..e3133b43 100644 --- a/tests/auto/menu/tst_menu.cpp +++ b/tests/auto/menu/tst_menu.cpp @@ -67,6 +67,8 @@ private slots: void menuButton(); void addItem(); void menuSeparator(); + void repeater(); + void order(); }; void tst_menu::defaults() @@ -317,6 +319,71 @@ void tst_menu::menuSeparator() QTRY_VERIFY(!menu->isVisible()); } +void tst_menu::repeater() +{ + QQuickApplicationHelper helper(this, QLatin1String("repeater.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value(); + QVERIFY(menu); + menu->open(); + QVERIFY(menu->isVisible()); + + QObject *repeater = window->property("repeater").value(); + QVERIFY(repeater); + + int count = repeater->property("count").toInt(); + QCOMPARE(count, 5); + + for (int i = 0; i < count; ++i) { + QQuickItem *item = menu->itemAt(i); + QVERIFY(item); + QCOMPARE(item->property("idx").toInt(), i); + + QQuickItem *repeaterItem = nullptr; + QVERIFY(QMetaObject::invokeMethod(repeater, "itemAt", Q_RETURN_ARG(QQuickItem*, repeaterItem), Q_ARG(int, i))); + QCOMPARE(item, repeaterItem); + } + + repeater->setProperty("model", 3); + + count = repeater->property("count").toInt(); + QCOMPARE(count, 3); + + for (int i = 0; i < count; ++i) { + QQuickItem *item = menu->itemAt(i); + QVERIFY(item); + QCOMPARE(item->property("idx").toInt(), i); + + QQuickItem *repeaterItem = nullptr; + QVERIFY(QMetaObject::invokeMethod(repeater, "itemAt", Q_RETURN_ARG(QQuickItem*, repeaterItem), Q_ARG(int, i))); + QCOMPARE(item, repeaterItem); + } +} + +void tst_menu::order() +{ + QQuickApplicationHelper helper(this, QLatin1String("order.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value(); + QVERIFY(menu); + menu->open(); + QVERIFY(menu->isVisible()); + + const QStringList texts = {"dynamic_0", "static_1", "repeated_2", "repeated_3", "static_4", "dynamic_5", "dynamic_6"}; + + for (int i = 0; i < texts.count(); ++i) { + QQuickItem *item = menu->itemAt(i); + QVERIFY(item); + QCOMPARE(item->property("text").toString(), texts.at(i)); + } +} + QTEST_MAIN(tst_menu) #include "tst_menu.moc" -- cgit v1.2.3