diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-09-11 03:02:28 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-09-11 03:02:28 +0200 |
commit | b9e7d9aadc8f70644c24469d802e9366a2a422bf (patch) | |
tree | 4445aff3e662916b5f5e5729da8e9dcbcc736430 | |
parent | 7e38097fb03b1b304a90630b475fe1f771a44d4e (diff) | |
parent | b41a32bc8ed42001c59af22345af4b733398aa34 (diff) |
Merge remote-tracking branch 'origin/5.11' into 5.12
Change-Id: I3fa0011d8b69db2a004feb177a7f89ccb75a724d
18 files changed, 436 insertions, 31 deletions
diff --git a/dist/changes-5.11.2 b/dist/changes-5.11.2 new file mode 100644 index 00000000..335804a4 --- /dev/null +++ b/dist/changes-5.11.2 @@ -0,0 +1,32 @@ +Qt 5.11.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.11.0 through 5.11.1. + +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.11 series is binary compatible with the 5.10.x series. +Applications compiled for 5.10 will continue to run with 5.11. + +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. + +**************************************************************************** +* Qt 5.11.2 Changes * +**************************************************************************** + + - [QTBUG-69897] StackView: fixed a crash in viewItemTransitionFinished() + - [QTBUG-69839] ColorDialog: fixed a crash when initializing the platform dialog helper + - [QTBUG-69506] IconImage: prevented the color from being applied twice + - [QTBUG-66483] Popup: fixed a crash on exit when using a shader + - [QTBUG-68219] Styles: fixed handling of QRC paths in QT_QUICK_CONTROLS_STYLE_PATH + - [QTBUG-68858] Menu: fixed items not being scrollable when using Window + - [QTBUG-68737] Tumbler: fixed to respect currentIndex changes in onModelChanged + - [QTBUG-68769] TextArea, TextField: fixed to use the control's renderType in placeholder text + - SpinBox: fixed "function expressions as statements" warnings diff --git a/examples/quickcontrols2/wearable/qml/Alarms/AlarmsPage.qml b/examples/quickcontrols2/wearable/qml/Alarms/AlarmsPage.qml index e07908ee..82a7716f 100644 --- a/examples/quickcontrols2/wearable/qml/Alarms/AlarmsPage.qml +++ b/examples/quickcontrols2/wearable/qml/Alarms/AlarmsPage.qml @@ -50,6 +50,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.0 as QQC2 +import ".." import "../Style" Item { @@ -64,7 +65,7 @@ Item { ListElement { name: qsTr("Week Ends"); state: false; time: "07:30 AM" } } - Item { + SwipeViewPage { Column { spacing: 30 anchors.centerIn: parent diff --git a/examples/quickcontrols2/wearable/qml/Fitness/FitnessPage.qml b/examples/quickcontrols2/wearable/qml/Fitness/FitnessPage.qml index b3b0a0c5..a9a1cb98 100644 --- a/examples/quickcontrols2/wearable/qml/Fitness/FitnessPage.qml +++ b/examples/quickcontrols2/wearable/qml/Fitness/FitnessPage.qml @@ -50,6 +50,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.0 as QQ2 +import ".." import "../Style" import "fitness.js" as FitnessData @@ -59,7 +60,7 @@ Item { anchors.fill: parent - Item { + SwipeViewPage { id: fitnessPage1 Column { @@ -87,7 +88,7 @@ Item { } } - Item { + SwipeViewPage { id: fitnessPage2 Column { diff --git a/examples/quickcontrols2/wearable/qml/Settings/SettingsPage.qml b/examples/quickcontrols2/wearable/qml/Settings/SettingsPage.qml index 48f3a3d6..3ed59eb8 100644 --- a/examples/quickcontrols2/wearable/qml/Settings/SettingsPage.qml +++ b/examples/quickcontrols2/wearable/qml/Settings/SettingsPage.qml @@ -51,6 +51,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.0 as QQC2 import Qt.labs.settings 1.0 +import ".." import "../Style" Item { @@ -68,7 +69,7 @@ Item { anchors.fill: parent - Item { + SwipeViewPage { id: settingsPage1 Column { @@ -102,7 +103,7 @@ Item { } } - Item { + SwipeViewPage { id: settingsPage2 Column { diff --git a/examples/quickcontrols2/wearable/qml/SwipeViewPage.qml b/examples/quickcontrols2/wearable/qml/SwipeViewPage.qml new file mode 100644 index 00000000..0a9ada57 --- /dev/null +++ b/examples/quickcontrols2/wearable/qml/SwipeViewPage.qml @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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.7 +import QtQuick.Controls 2.1 + +Item { + // Don't show the item when the StackView that contains us + // is being popped off the stack, as we use an x animation + // and hence would show pages that we shouldn't since we + // also don't have our own background. + visible: SwipeView.isCurrentItem || (SwipeView.view.contentItem.moving && (SwipeView.isPreviousItem || SwipeView.isNextItem)) +} diff --git a/examples/quickcontrols2/wearable/qml/Weather/WeatherPage.qml b/examples/quickcontrols2/wearable/qml/Weather/WeatherPage.qml index 2ef0133c..a02b44ee 100644 --- a/examples/quickcontrols2/wearable/qml/Weather/WeatherPage.qml +++ b/examples/quickcontrols2/wearable/qml/Weather/WeatherPage.qml @@ -50,6 +50,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.0 as QQC2 +import ".." import "../Style" import "weather.js" as WeatherData @@ -59,7 +60,7 @@ Item { anchors.fill: parent - Item { + SwipeViewPage { id: weatherPage1 Row { @@ -114,7 +115,7 @@ Item { } } - Item { + SwipeViewPage { id: weatherPage2 Column { @@ -169,7 +170,7 @@ Item { } } - Item { + SwipeViewPage { id: weatherPage3 Row { @@ -224,7 +225,7 @@ Item { } } - Item { + SwipeViewPage { id: weatherPage4 Column { diff --git a/examples/quickcontrols2/wearable/qml/WorldClock/Clock.qml b/examples/quickcontrols2/wearable/qml/WorldClock/Clock.qml index a6e67e8c..e3da38c7 100644 --- a/examples/quickcontrols2/wearable/qml/WorldClock/Clock.qml +++ b/examples/quickcontrols2/wearable/qml/WorldClock/Clock.qml @@ -49,9 +49,11 @@ ****************************************************************************/ import QtQuick 2.7 +import QtQuick.Controls 2.0 as QQC2 +import ".." import "../Style" -Item { +SwipeViewPage { id: clock property int hours diff --git a/examples/quickcontrols2/wearable/wearable.qrc b/examples/quickcontrols2/wearable/wearable.qrc index ea81edc6..d71b5bab 100644 --- a/examples/quickcontrols2/wearable/wearable.qrc +++ b/examples/quickcontrols2/wearable/wearable.qrc @@ -103,5 +103,6 @@ <file>qml/WorldClock/images/swissnighthour@2x.png</file> <file>qml/WorldClock/images/swissnightminute.png</file> <file>qml/WorldClock/images/swissnightminute@2x.png</file> + <file>qml/SwipeViewPage.qml</file> </qresource> </RCC> diff --git a/src/quicktemplates2/qquickmenu.cpp b/src/quicktemplates2/qquickmenu.cpp index f52405c9..7086db91 100644 --- a/src/quicktemplates2/qquickmenu.cpp +++ b/src/quicktemplates2/qquickmenu.cpp @@ -251,6 +251,41 @@ void QQuickMenuPrivate::removeItem(int index, QQuickItem *item) } } +void QQuickMenuPrivate::createAndAppendItem(QObject *object) +{ + Q_Q(QQuickMenu); + QQuickItem *item = qobject_cast<QQuickItem *>(object); + if (!item) { + if (QQuickAction *action = qobject_cast<QQuickAction *>(object)) + item = createItem(action); + else if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(object)) + item = createItem(menu); + } + + if (item) { + if (QQuickItemPrivate::get(item)->isTransparentForPositioner()) { + QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::SiblingOrder); + item->setParentItem(contentItem); + } else if (contentModel->indexOf(item, nullptr) == -1) { + q->addItem(item); + } + } else { + contentData.append(object); + } +} + +void QQuickMenuPrivate::recreateItems() +{ + // removeItem() will remove stuff from contentData, so we have to make a copy of it. + const auto originalContentData = contentData; + + while (contentModel->count() > 0) + removeItem(0, itemAt(0)); + + for (QObject *object : originalContentData) + createAndAppendItem(object); +} + QQuickItem *QQuickMenuPrivate::beginCreateItem() { Q_Q(QQuickMenu); @@ -626,24 +661,14 @@ void QQuickMenuPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObj QQuickMenu *q = qobject_cast<QQuickMenu *>(prop->object); QQuickMenuPrivate *p = QQuickMenuPrivate::get(q); - QQuickItem *item = qobject_cast<QQuickItem *>(obj); - if (!item) { - if (QQuickAction *action = qobject_cast<QQuickAction *>(obj)) - item = p->createItem(action); - else if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(obj)) - item = p->createItem(menu); - } - - if (item) { - if (QQuickItemPrivate::get(item)->isTransparentForPositioner()) { - QQuickItemPrivate::get(item)->addItemChangeListener(p, QQuickItemPrivate::SiblingOrder); - item->setParentItem(p->contentItem); - } else if (p->contentModel->indexOf(item, nullptr) == -1) { - q->addItem(item); - } - } else { + if (!p->complete) { + // Don't add items until we're complete, as the delegate could change in the meantime. + // We'll add it to contentData and create it when we're complete. p->contentData.append(obj); + return; } + + p->createAndAppendItem(obj); } int QQuickMenuPrivate::contentData_count(QQmlListProperty<QObject> *prop) @@ -1356,7 +1381,7 @@ void QQuickMenu::componentComplete() { Q_D(QQuickMenu); QQuickPopup::componentComplete(); - d->resizeItems(); + d->recreateItems(); } void QQuickMenu::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) diff --git a/src/quicktemplates2/qquickmenu_p_p.h b/src/quicktemplates2/qquickmenu_p_p.h index 6146b960..c0bb2702 100644 --- a/src/quicktemplates2/qquickmenu_p_p.h +++ b/src/quicktemplates2/qquickmenu_p_p.h @@ -78,6 +78,9 @@ public: void moveItem(int from, int to); void removeItem(int index, QQuickItem *item); + void createAndAppendItem(QObject *object); + void recreateItems(); + QQuickItem *beginCreateItem(); void completeCreateItem(); diff --git a/src/quicktemplates2/qquickswipeview.cpp b/src/quicktemplates2/qquickswipeview.cpp index f887be7b..e6a88b47 100644 --- a/src/quicktemplates2/qquickswipeview.cpp +++ b/src/quicktemplates2/qquickswipeview.cpp @@ -72,10 +72,10 @@ QT_BEGIN_NAMESPACE It is generally not advisable to add excessive amounts of pages to a SwipeView. However, when the amount of pages grows larger, or individual - pages are relatively complex, it may be desired free up resources by - unloading pages that are outside the reach. The following example presents - how to use \l Loader to keep a maximum of three pages simultaneously - instantiated. + pages are relatively complex, it may be desirable to free up resources by + unloading pages that are outside the immediate reach of the user. + The following example presents how to use \l Loader to keep a maximum of + three pages simultaneously instantiated. \code SwipeView { diff --git a/tests/auto/qquickmenu/data/delegateFromSeparateComponent.qml b/tests/auto/qquickmenu/data/delegateFromSeparateComponent.qml new file mode 100644 index 00000000..48176d37 --- /dev/null +++ b/tests/auto/qquickmenu/data/delegateFromSeparateComponent.qml @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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.10 +import QtQuick.Controls 2.3 + +ApplicationWindow { + width: 800 + height: 800 + + property alias menu: menu + + Component { + id: menuItemComponent + + MenuItem { + contentItem: Text { + text: parent.text + color: "blue" + } + background: Rectangle { + color: "#00ff00" + } + } + } + + Menu { + id: menu + title: "Root Menu" + + Action { + text: "Action Item 1" + } + Menu { + title: "Sub-menu" + delegate: menuItemComponent + + Action { + text: "Sub-menu Action Item 1" + } + Menu { + title: "Sub-sub-menu" + delegate: menuItemComponent + + Action { + text: "Sub-sub-menu Action Item 1" + } + } + Action { + text: "Sub-menu Action Item 2" + } + } + Action { + text: "Action Item 2" + } + + delegate: menuItemComponent + visible: true + } +} diff --git a/tests/auto/qquickmenu/qquickmenu.pro b/tests/auto/qquickmenu/qquickmenu.pro index ee539842..7e1080b9 100644 --- a/tests/auto/qquickmenu/qquickmenu.pro +++ b/tests/auto/qquickmenu/qquickmenu.pro @@ -1,5 +1,6 @@ CONFIG += testcase TARGET = tst_qquickmenu +HEADERS += ../shared/menuutil.h SOURCES += tst_qquickmenu.cpp macos:CONFIG -= app_bundle diff --git a/tests/auto/qquickmenu/tst_qquickmenu.cpp b/tests/auto/qquickmenu/tst_qquickmenu.cpp index 5a676c03..adb3d7aa 100644 --- a/tests/auto/qquickmenu/tst_qquickmenu.cpp +++ b/tests/auto/qquickmenu/tst_qquickmenu.cpp @@ -43,6 +43,8 @@ #include <QtQml/qqmlcontext.h> #include <QtQuick/qquickview.h> #include <QtQuick/private/qquickitem_p.h> +#include <QtQuick/private/qquicklistview_p.h> +#include "../shared/menuutil.h" #include "../shared/util.h" #include "../shared/visualtestutil.h" @@ -86,6 +88,7 @@ private slots: void addRemoveSubMenus(); void scrollable_data(); void scrollable(); + void delegateFromSeparateComponent(); }; void tst_QQuickMenu::defaults() @@ -145,6 +148,7 @@ void tst_QQuickMenu::mouse() menu->open(); QVERIFY(menu->isVisible()); QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + waitForMenuListViewPolish(menu); QQuickItem *firstItem = menu->itemAt(0); QSignalSpy clickedSpy(firstItem, SIGNAL(clicked())); @@ -268,6 +272,8 @@ void tst_QQuickMenu::contextMenuKeyboard() QCOMPARE(visibleSpy.count(), 1); QVERIFY(menu->isVisible()); QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + waitForMenuListViewPolish(menu); + QVERIFY(!firstItem->hasActiveFocus()); QVERIFY(!firstItem->property("highlighted").toBool()); QCOMPARE(menu->currentIndex(), -1); @@ -934,6 +940,7 @@ void tst_QQuickMenu::subMenuMouse() QVERIFY(!subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); + waitForMenuListViewPolish(mainMenu); // open the sub-menu with mouse click QQuickMenuItem *subMenu1Item = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(1)); @@ -944,6 +951,7 @@ void tst_QQuickMenu::subMenuMouse() QVERIFY(subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); + waitForMenuListViewPolish(subMenu1); // open the cascading sub-sub-menu with mouse hover QQuickMenuItem *subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2)); @@ -954,6 +962,7 @@ void tst_QQuickMenu::subMenuMouse() QVERIFY(subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); + QVERIFY(subSubMenu1Item->isHovered()); if (cascade) QTRY_VERIFY(subSubMenu1->isVisible()); @@ -973,6 +982,7 @@ void tst_QQuickMenu::subMenuMouse() QVERIFY(subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); + QVERIFY(subSubMenu1Item->isHovered()); if (cascade) QTRY_VERIFY(subSubMenu1->isVisible()); @@ -1199,6 +1209,7 @@ void tst_QQuickMenu::subMenuPosition() QVERIFY(!subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); + waitForMenuListViewPolish(mainMenu); // open the sub-menu (never flips) QQuickMenuItem *subMenu1Item = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(1)); @@ -1333,9 +1344,96 @@ void tst_QQuickMenu::scrollable() QVERIFY(menu->isVisible()); QQuickItem *contentItem = menu->contentItem(); + // Can only be scrollable if it exceeds the height of the window. + QTRY_VERIFY(contentItem->property("contentHeight").toReal() > window->height()); QCOMPARE(contentItem->property("interactive").toBool(), true); } +// QTBUG-67559 +// Test that Actions and MenuItems declared as children of a Menu have the +// correct delegate when it is declared outside of the Menu as a Component. +void tst_QQuickMenu::delegateFromSeparateComponent() +{ + QQuickApplicationHelper helper(this, QLatin1String("delegateFromSeparateComponent.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + const QColor green = QColor::fromRgb(0x00ff00); + + QQuickMenu *menu = window->property("menu").value<QQuickMenu*>(); + QVERIFY(menu); + + // "Action Item 1" + QQuickMenuItem *actionItem1 = qobject_cast<QQuickMenuItem*>(menu->itemAt(0)); + QVERIFY(actionItem1); + QCOMPARE(actionItem1->text(), QLatin1String("Action Item 1")); + + QQuickItem *actionItem1Bg = actionItem1->property("background").value<QQuickItem*>(); + QVERIFY(actionItem1Bg); + QCOMPARE(actionItem1Bg->property("color").value<QColor>(), green); + + // "Sub-menu" + QQuickMenuItem *subMenuItem = qobject_cast<QQuickMenuItem*>(menu->itemAt(1)); + QVERIFY(subMenuItem); + QCOMPARE(subMenuItem->text(), QLatin1String("Sub-menu")); + + QQuickItem *subMenuItemBg = subMenuItem->property("background").value<QQuickItem*>(); + QVERIFY(subMenuItemBg); + QCOMPARE(subMenuItemBg->property("color").value<QColor>(), green); + + QQuickMenu *subMenu = subMenuItem->subMenu(); + QVERIFY(subMenu); + + // "Sub-menu Action Item 1" + QQuickMenuItem *subMenuActionItem1 = qobject_cast<QQuickMenuItem*>(subMenu->itemAt(0)); + QVERIFY(subMenuActionItem1); + QCOMPARE(subMenuActionItem1->text(), QLatin1String("Sub-menu Action Item 1")); + + QQuickItem *subMenuActionItem1Bg = subMenuActionItem1->property("background").value<QQuickItem*>(); + QVERIFY(subMenuActionItem1Bg); + QCOMPARE(subMenuActionItem1Bg->property("color").value<QColor>(), green); + + // "Sub-sub-menu" + QQuickMenuItem *subSubMenuItem = qobject_cast<QQuickMenuItem*>(subMenu->itemAt(1)); + QVERIFY(subSubMenuItem); + QCOMPARE(subSubMenuItem->text(), QLatin1String("Sub-sub-menu")); + + QQuickItem *subSubMenuItemBg = subSubMenuItem->property("background").value<QQuickItem*>(); + QVERIFY(subSubMenuItemBg); + QCOMPARE(subSubMenuItemBg->property("color").value<QColor>(), green); + + QQuickMenu *subSubMenu = subSubMenuItem->subMenu(); + QVERIFY(subSubMenu); + + // "Sub-sub-menu Action Item 1" + QQuickMenuItem *subSubMenuActionItem1 = qobject_cast<QQuickMenuItem*>(subSubMenu->itemAt(0)); + QVERIFY(subSubMenuActionItem1); + QCOMPARE(subSubMenuActionItem1->text(), QLatin1String("Sub-sub-menu Action Item 1")); + + QQuickItem *subSubMenuActionItem1Bg = subSubMenuActionItem1->property("background").value<QQuickItem*>(); + QVERIFY(subSubMenuActionItem1Bg); + QCOMPARE(subSubMenuActionItem1Bg->property("color").value<QColor>(), green); + + // "Sub-menu Action Item 2" + QQuickMenuItem *subMenuActionItem2 = qobject_cast<QQuickMenuItem*>(subMenu->itemAt(2)); + QVERIFY(subMenuActionItem2); + QCOMPARE(subMenuActionItem2->text(), QLatin1String("Sub-menu Action Item 2")); + + QQuickItem *subMenuActionItem2Bg = subMenuActionItem2->property("background").value<QQuickItem*>(); + QVERIFY(subMenuActionItem2Bg); + QCOMPARE(subMenuActionItem2Bg->property("color").value<QColor>(), green); + + // "Action Item 2" + QQuickMenuItem *actionItem2 = qobject_cast<QQuickMenuItem*>(menu->itemAt(2)); + QVERIFY(actionItem2); + QCOMPARE(actionItem2->text(), QLatin1String("Action Item 2")); + + QQuickItem *actionItem2Bg = actionItem2->property("background").value<QQuickItem*>(); + QVERIFY(actionItem2Bg); + QCOMPARE(actionItem2Bg->property("color").value<QColor>(), green); +} + QTEST_MAIN(tst_QQuickMenu) #include "tst_qquickmenu.moc" diff --git a/tests/auto/qquickmenubar/qquickmenubar.pro b/tests/auto/qquickmenubar/qquickmenubar.pro index b7d41f0f..d2f28e47 100644 --- a/tests/auto/qquickmenubar/qquickmenubar.pro +++ b/tests/auto/qquickmenubar/qquickmenubar.pro @@ -1,5 +1,6 @@ CONFIG += testcase TARGET = tst_qquickmenubar +HEADERS += ../shared/menuutil.h SOURCES += tst_qquickmenubar.cpp macos:CONFIG -= app_bundle diff --git a/tests/auto/qquickmenubar/tst_qquickmenubar.cpp b/tests/auto/qquickmenubar/tst_qquickmenubar.cpp index 19d67eac..754e915b 100644 --- a/tests/auto/qquickmenubar/tst_qquickmenubar.cpp +++ b/tests/auto/qquickmenubar/tst_qquickmenubar.cpp @@ -36,6 +36,8 @@ #include <QtTest> #include <QtQml> +#include <QtQuick/private/qquicklistview_p.h> +#include "../shared/menuutil.h" #include "../shared/util.h" #include "../shared/visualtestutil.h" #include "../shared/qtest_quickcontrols.h" @@ -146,6 +148,7 @@ void tst_qquickmenubar::mouse() QVERIFY(helpMenuBarMenu->isVisible()); QTRY_VERIFY(!editMenuBarMenu->isVisible()); QTRY_VERIFY(helpMenuBarMenu->isOpened()); + waitForMenuListViewPolish(helpMenuBarMenu); // trigger a menu item to close the menu QQuickMenuItem *aboutMenuItem = qobject_cast<QQuickMenuItem *>(helpMenuBarMenu->itemAt(0)); @@ -167,6 +170,7 @@ void tst_qquickmenubar::mouse() QVERIFY(viewMenuBarItem->isHighlighted()); QVERIFY(viewMenuBarMenu->isVisible()); QTRY_VERIFY(viewMenuBarMenu->isOpened()); + waitForMenuListViewPolish(viewMenuBarMenu); // trigger a menu item to open a sub-menu QQuickMenuItem *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(viewMenuBarMenu->itemAt(0)); @@ -177,6 +181,7 @@ void tst_qquickmenubar::mouse() QVERIFY(viewMenuBarMenu->isVisible()); QVERIFY(alignmentSubMenu->isVisible()); QTRY_VERIFY(alignmentSubMenu->isOpened()); + waitForMenuListViewPolish(alignmentSubMenu); // trigger a menu item to open a sub-sub-menu QQuickMenuItem *verticalSubMenuItem = qobject_cast<QQuickMenuItem *>(alignmentSubMenu->itemAt(1)); @@ -188,6 +193,7 @@ void tst_qquickmenubar::mouse() QVERIFY(alignmentSubMenu->isVisible()); QVERIFY(verticalSubMenu->isVisible()); QTRY_VERIFY(verticalSubMenu->isOpened()); + waitForMenuListViewPolish(verticalSubMenu); // trigger a menu item to close the whole chain of menus QQuickMenuItem *centerMenuItem = qobject_cast<QQuickMenuItem *>(verticalSubMenu->itemAt(1)); diff --git a/tests/auto/qquickpopup/tst_qquickpopup.cpp b/tests/auto/qquickpopup/tst_qquickpopup.cpp index 9230116b..6c860d6e 100644 --- a/tests/auto/qquickpopup/tst_qquickpopup.cpp +++ b/tests/auto/qquickpopup/tst_qquickpopup.cpp @@ -36,6 +36,7 @@ #include <QtTest/qtest.h> #include <QtTest/qsignalspy.h> +#include "../shared/menuutil.h" #include "../shared/util.h" #include "../shared/visualtestutil.h" #include "../shared/qtest_quickcontrols.h" @@ -858,6 +859,7 @@ void tst_QQuickPopup::grabber() menu->open(); QTRY_COMPARE(menu->isOpened(), true); + waitForMenuListViewPolish(menu); QCOMPARE(popup->isVisible(), false); QCOMPARE(combo->isVisible(), false); @@ -880,6 +882,7 @@ void tst_QQuickPopup::grabber() menu->open(); QTRY_COMPARE(menu->isOpened(), true); + waitForMenuListViewPolish(menu); QCOMPARE(popup->isVisible(), false); QCOMPARE(combo->isVisible(), false); @@ -971,6 +974,7 @@ void tst_QQuickPopup::closeOnEscapeWithNestedPopups() QQuickPopup *optionsMenu = window->findChild<QQuickPopup*>("optionsMenu"); QVERIFY(optionsMenu); QTRY_VERIFY(optionsMenu->isVisible()); + waitForMenuListViewPolish(optionsMenu); QQuickItem *settingsMenuItem = window->findChild<QQuickItem*>("settingsMenuItem"); QVERIFY(settingsMenuItem); diff --git a/tests/auto/shared/menuutil.h b/tests/auto/shared/menuutil.h new file mode 100644 index 00000000..067b7e55 --- /dev/null +++ b/tests/auto/shared/menuutil.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKMENUTUTIL_H +#define QQUICKMENUTUTIL_H + +#include <QtQuick/private/qquickitem_p.h> +#include <QtQuick/private/qquicklistview_p.h> + +/* + QQuickMenuPrivate::insertItem() culls newly added items to ensure + that they don't show up when they shouldn't, but now that QQuickMenu + postpones item creation until after component completion (QTBUG-67559), + the culled flag being set means that mouse events don't get delivered + to menu items (see the culled check in QQuickWindowPrivate::pointerTargets()). + + ListView unculls the items in FxViewItem::setVisible(), and waiting until + polishes are finished is a reliable way of ensuring that that happens + before we send mouse events. +*/ +#define waitForMenuListViewPolish(menu) \ +{ \ + const auto listView = qobject_cast<QQuickListView*>((menu)->contentItem()); \ + Q_ASSERT(listView); \ + QTRY_COMPARE(QQuickItemPrivate::get(listView)->polishScheduled, false); \ +} + +#endif // QQUICKMENUTUTIL_H |