From 2da5559cc43a3d8bdf49f634ed8add4e929aaa03 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 2 May 2019 15:49:19 +0200 Subject: Doc: fix currentText link, add more \sa links Change-Id: Ibde952a165c9e0fb40133ce554e90ba35c93feee Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickcombobox.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/quicktemplates2/qquickcombobox.cpp b/src/quicktemplates2/qquickcombobox.cpp index 328797b8..78ec7ef8 100644 --- a/src/quicktemplates2/qquickcombobox.cpp +++ b/src/quicktemplates2/qquickcombobox.cpp @@ -168,7 +168,7 @@ QT_BEGIN_NAMESPACE This signal is emitted when the \uicontrol Return or \uicontrol Enter key is pressed on an \l editable combo box. If the confirmed string is not currently in the model, - the \l currentIndex will be set to \c -1 and the \c currentText will be updated + the \l currentIndex will be set to \c -1 and the \l currentText will be updated accordingly. \note If there is a \l validator set on the combo box, the signal will only be @@ -923,7 +923,7 @@ void QQuickComboBox::setCurrentIndex(int index) This property holds the text of the current item in the combo box. - \sa currentIndex, displayText, textRole + \sa currentIndex, displayText, textRole, editText */ QString QQuickComboBox::currentText() const { @@ -1266,7 +1266,7 @@ void QQuickComboBox::setEditable(bool editable) This property holds the text in the text field of an editable combo box. - \sa editable + \sa editable, currentText, displayText */ QString QQuickComboBox::editText() const { -- cgit v1.2.3 From 51f6c17ff2b5b6ce23d115e1871fea7d8350a049 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 25 Mar 2019 11:02:16 +0100 Subject: Doc: bindings to x/y/width/height of contentItem aren't respected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Idecee26bcae178ed294c062819f55e12a65af37d Reviewed-by: Henning Gründl Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickcontrol.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp index a61df3ca..dd954b2b 100644 --- a/src/quicktemplates2/qquickcontrol.cpp +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -1626,8 +1626,9 @@ void QQuickControl::setBackground(QQuickItem *background) } \endcode - \note The content item is automatically resized to fit within the - \l padding of the control. + \note The content item is automatically positioned and resized to fit + within the \l padding of the control. Bindings to the \l x, \l y, \l width, + and \l height properties of the contentItem are not respected. \note Most controls use the implicit size of the content item to calculate the implicit size of the control itself. If you replace the content item -- cgit v1.2.3 From 7f1d0976d3ac0c6226bef1947a4eafd44b60e5e9 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Mon, 29 Apr 2019 13:03:25 +0200 Subject: Make tst_qquickmenu run with all styles This is a prerequisite for ensuring that an Imagine-style-specific fix works. Fixes: QTBUG-75141 Change-Id: Iafef3bf947151cb35b88a1230e3541d8e4e15fd9 Reviewed-by: Richard Moe Gustavsen --- tests/auto/qquickmenu/data/popup.qml | 2 +- tests/auto/qquickmenu/data/subMenus.qml | 60 +++++++-- tests/auto/qquickmenu/tst_qquickmenu.cpp | 210 +++++++++++++++++++------------ 3 files changed, 180 insertions(+), 92 deletions(-) diff --git a/tests/auto/qquickmenu/data/popup.qml b/tests/auto/qquickmenu/data/popup.qml index e044a527..3272cd6f 100644 --- a/tests/auto/qquickmenu/data/popup.qml +++ b/tests/auto/qquickmenu/data/popup.qml @@ -53,7 +53,7 @@ import QtQuick.Controls 2.12 ApplicationWindow { width: 400 - height: 400 + height: 600 property alias menu: menu property alias menuItem1: menuItem1 diff --git a/tests/auto/qquickmenu/data/subMenus.qml b/tests/auto/qquickmenu/data/subMenus.qml index 413e442d..4952e7a1 100644 --- a/tests/auto/qquickmenu/data/subMenus.qml +++ b/tests/auto/qquickmenu/data/subMenus.qml @@ -62,31 +62,73 @@ ApplicationWindow { Menu { id: mainMenu - MenuItem { id: mainMenuItem1; text: "Main 1" } + MenuItem { + id: mainMenuItem1 + objectName: "mainMenuItem1" + text: "Main 1" + } Menu { id: subMenu1 + objectName: "subMenu1" title: "Sub Menu 1" - MenuItem { id: subMenuItem1; text: "Sub 1" } - MenuItem { id: subMenuItem2; text: "Sub 2" } + + MenuItem { + id: subMenuItem1 + objectName: "subMenuItem1" + text: "Sub 1" + } + MenuItem { + id: subMenuItem2 + objectName: "subMenuItem2" + text: "Sub 2" + } Menu { id: subSubMenu1 + objectName: "subSubMenu1" title: "Sub Sub Menu 1" - MenuItem { id: subSubMenuItem1; text: "Sub Sub 1" } - MenuItem { id: subSubMenuItem2; text: "Sub Sub 2" } + + MenuItem { + id: subSubMenuItem1 + objectName: "subSubMenuItem1" + text: "Sub Sub 1" + } + MenuItem { + id: subSubMenuItem2 + objectName: "subSubMenuItem2" + text: "Sub Sub 2" + } } } - MenuItem { id: mainMenuItem2; text: "Main 2" } + MenuItem { + id: mainMenuItem2 + objectName: "mainMenuItem2" + text: "Main 2" + } Menu { id: subMenu2 + objectName: "subMenu2" title: "Sub Menu 2" - MenuItem { id: subMenuItem3; text: "Sub 3" } - MenuItem { id: subMenuItem4; text: "Sub 4" } + + MenuItem { + id: subMenuItem3 + objectName: "subMenuItem3" + text: "Sub 3" + } + MenuItem { + id: subMenuItem4 + objectName: "subMenuItem4" + text: "Sub 4" + } } - MenuItem { id: mainMenuItem3; text: "Main 3" } + MenuItem { + id: mainMenuItem3 + objectName: "mainMenuItem3" + text: "Main 3" + } } } diff --git a/tests/auto/qquickmenu/tst_qquickmenu.cpp b/tests/auto/qquickmenu/tst_qquickmenu.cpp index e1f5d35f..1b00817f 100644 --- a/tests/auto/qquickmenu/tst_qquickmenu.cpp +++ b/tests/auto/qquickmenu/tst_qquickmenu.cpp @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#include -#include +#include +#include #include #include #include @@ -45,6 +45,7 @@ #include #include "../shared/util.h" #include "../shared/visualtestutil.h" +#include "../shared/qtest_quickcontrols.h" #include #include @@ -152,6 +153,7 @@ void tst_QQuickMenu::mouse() menu->open(); QVERIFY(menu->isVisible()); QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + QTRY_VERIFY(menu->isOpened()); QQuickItem *firstItem = menu->itemAt(0); QSignalSpy clickedSpy(firstItem, SIGNAL(clicked())); @@ -160,16 +162,18 @@ void tst_QQuickMenu::mouse() // Ensure that presses cause the current index to change, // so that the highlight acts as a way of illustrating press state. - QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(firstItem->width() / 2, firstItem->height() / 2)); + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, + QPoint(menu->leftPadding() + firstItem->width() / 2, menu->topPadding() + firstItem->height() / 2)); QVERIFY(firstItem->hasActiveFocus()); QCOMPARE(menu->currentIndex(), 0); QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0)); QVERIFY(menu->isVisible()); - QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(firstItem->width() / 2, firstItem->height() / 2)); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, + QPoint(menu->leftPadding() + firstItem->width() / 2, menu->topPadding() + firstItem->height() / 2)); QCOMPARE(clickedSpy.count(), 1); QCOMPARE(triggeredSpy.count(), 1); - QCOMPARE(visibleSpy.count(), 1); + QTRY_COMPARE(visibleSpy.count(), 1); QVERIFY(!menu->isVisible()); QVERIFY(!window->overlay()->childItems().contains(menu->contentItem())); QCOMPARE(menu->currentIndex(), -1); @@ -179,13 +183,14 @@ void tst_QQuickMenu::mouse() QCOMPARE(visibleSpy.count(), 2); QVERIFY(menu->isVisible()); QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + QTRY_VERIFY(menu->isOpened()); // Ensure that we have enough space to click outside of the menu. QVERIFY(window->width() > menu->contentItem()->width()); QVERIFY(window->height() > menu->contentItem()->height()); QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(menu->contentItem()->width() + 1, menu->contentItem()->height() + 1)); - QCOMPARE(visibleSpy.count(), 3); + QTRY_COMPARE(visibleSpy.count(), 3); QVERIFY(!menu->isVisible()); QVERIFY(!window->overlay()->childItems().contains(menu->contentItem()->parentItem())); @@ -193,16 +198,19 @@ void tst_QQuickMenu::mouse() QCOMPARE(visibleSpy.count(), 4); QVERIFY(menu->isVisible()); QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + QTRY_VERIFY(menu->isOpened()); // Hover-highlight through the menu items one by one QQuickItem *prevHoverItem = nullptr; QQuickItem *listView = menu->contentItem(); - for (int y = 0; y < listView->height(); ++y) { + for (int y = menu->topPadding(); y < listView->height(); ++y) { QQuickItem *hoverItem = nullptr; QVERIFY(QMetaObject::invokeMethod(listView, "itemAt", Q_RETURN_ARG(QQuickItem *, hoverItem), Q_ARG(qreal, 0), Q_ARG(qreal, listView->property("contentY").toReal() + y))); if (!hoverItem || !hoverItem->isVisible() || hoverItem == prevHoverItem) continue; - QTest::mouseMove(window, QPoint(hoverItem->x() + hoverItem->width() / 2, hoverItem->y() + hoverItem->height() / 2)); + QTest::mouseMove(window, QPoint( + menu->leftPadding() + hoverItem->x() + hoverItem->width() / 2, + menu->topPadding() + hoverItem->y() + hoverItem->height() / 2)); QTRY_VERIFY(hoverItem->property("highlighted").toBool()); if (prevHoverItem) QVERIFY(!prevHoverItem->property("highlighted").toBool()); @@ -275,6 +283,7 @@ void tst_QQuickMenu::contextMenuKeyboard() QCOMPARE(visibleSpy.count(), 1); QVERIFY(menu->isVisible()); QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + QTRY_VERIFY(menu->isOpened()); QVERIFY(!firstItem->hasActiveFocus()); QVERIFY(!firstItem->property("highlighted").toBool()); QCOMPARE(menu->currentIndex(), -1); @@ -304,7 +313,7 @@ void tst_QQuickMenu::contextMenuKeyboard() QSignalSpy secondTriggeredSpy(secondItem, SIGNAL(triggered())); QTest::keyClick(window, Qt::Key_Space); QCOMPARE(secondTriggeredSpy.count(), 1); - QCOMPARE(visibleSpy.count(), 2); + QTRY_COMPARE(visibleSpy.count(), 2); QVERIFY(!menu->isVisible()); QVERIFY(!window->overlay()->childItems().contains(menu->contentItem())); QVERIFY(!firstItem->hasActiveFocus()); @@ -321,6 +330,7 @@ void tst_QQuickMenu::contextMenuKeyboard() menu->open(); QCOMPARE(visibleSpy.count(), 3); QVERIFY(menu->isVisible()); + QTRY_VERIFY(menu->isOpened()); // Give the first item focus. QTest::keyClick(window, Qt::Key_Tab); QVERIFY(firstItem->hasActiveFocus()); @@ -333,7 +343,7 @@ void tst_QQuickMenu::contextMenuKeyboard() QSignalSpy firstTriggeredSpy(firstItem, SIGNAL(triggered())); QTest::keyClick(window, Qt::Key_Return); QCOMPARE(firstTriggeredSpy.count(), 1); - QCOMPARE(visibleSpy.count(), 4); + QTRY_COMPARE(visibleSpy.count(), 4); QVERIFY(!menu->isVisible()); QVERIFY(!window->overlay()->childItems().contains(menu->contentItem())); QVERIFY(!firstItem->hasActiveFocus()); @@ -349,6 +359,7 @@ void tst_QQuickMenu::contextMenuKeyboard() QCOMPARE(visibleSpy.count(), 5); QVERIFY(menu->isVisible()); QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem())); + QTRY_VERIFY(menu->isOpened()); QVERIFY(!firstItem->hasActiveFocus()); QVERIFY(!firstItem->hasVisualFocus()); QVERIFY(!firstItem->isHighlighted()); @@ -422,7 +433,7 @@ void tst_QQuickMenu::contextMenuKeyboard() QVERIFY(!thirdItem->isHighlighted()); QTest::keyClick(window, Qt::Key_Escape); - QCOMPARE(visibleSpy.count(), 6); + QTRY_COMPARE(visibleSpy.count(), 6); QVERIFY(!menu->isVisible()); } @@ -458,6 +469,7 @@ void tst_QQuickMenu::disabledMenuItemKeyNavigation() menu->setFocus(true); menu->open(); QVERIFY(menu->isVisible()); + QTRY_VERIFY(menu->isOpened()); QVERIFY(!firstItem->hasActiveFocus()); QVERIFY(!firstItem->property("highlighted").toBool()); QCOMPARE(menu->currentIndex(), -1); @@ -486,7 +498,7 @@ void tst_QQuickMenu::disabledMenuItemKeyNavigation() QCOMPARE(firstItem->focusReason(), Qt::BacktabFocusReason); QTest::keyClick(window, Qt::Key_Escape); - QVERIFY(!menu->isVisible()); + QTRY_VERIFY(!menu->isVisible()); } void tst_QQuickMenu::mnemonics() @@ -559,6 +571,7 @@ void tst_QQuickMenu::menuButton() menuButton->mapToScene(QPointF(menuButton->width() / 2, menuButton->height() / 2)).toPoint()); QCOMPARE(visibleSpy.count(), 1); QVERIFY(menu->isVisible()); + QTRY_VERIFY(menu->isOpened()); QTest::keyClick(window, Qt::Key_Tab); QQuickItem *firstItem = menu->itemAt(0); @@ -634,6 +647,7 @@ void tst_QQuickMenu::menuSeparator() menu->open(); QVERIFY(menu->isVisible()); + QTRY_VERIFY(menu->isOpened()); // Key navigation skips separators QTest::keyClick(window, Qt::Key_Down); @@ -761,24 +775,30 @@ void tst_QQuickMenu::popup() QCOMPARE(menu->parentItem(), window->contentItem()); QCOMPARE(menu->currentIndex(), -1); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); - QTRY_COMPARE(menu->x(), 11); - QTRY_COMPARE(menu->y(), 22); + const qreal elevenOrLeftMargin = qMax(qreal(11), menu->leftMargin()); + const qreal twentyTwoOrTopMargin = qMax(qreal(22), menu->topMargin()); + // If the Menu has large margins, it may be moved to stay within them. + // QTBUG-75503: QTRY_COMPARE doesn't use qFuzzyCompare() in all cases, + // meaning a lot of these comparisons could trigger a 10 second wait; + // use QTRY_VERIFY and qFuzzyCompare instead. + QTRY_VERIFY(qFuzzyCompare(menu->x(), elevenOrLeftMargin)); + QTRY_VERIFY(qFuzzyCompare(menu->y(), twentyTwoOrTopMargin)); menu->close(); QVERIFY(QMetaObject::invokeMethod(window, "popupAtPos", Q_ARG(QVariant, QPointF(33, 44)))); QCOMPARE(menu->parentItem(), window->contentItem()); QCOMPARE(menu->currentIndex(), -1); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); - QTRY_COMPARE(menu->x(), 33); - QTRY_COMPARE(menu->y(), 44); + QTRY_VERIFY(qFuzzyCompare(menu->x(), 33)); + QTRY_VERIFY(qFuzzyCompare(menu->y(), 44)); menu->close(); QVERIFY(QMetaObject::invokeMethod(window, "popupAtCoord", Q_ARG(QVariant, 55), Q_ARG(QVariant, 66))); QCOMPARE(menu->parentItem(), window->contentItem()); QCOMPARE(menu->currentIndex(), -1); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); - QTRY_COMPARE(menu->x(), 55); - QTRY_COMPARE(menu->y(), 66); + QTRY_VERIFY(qFuzzyCompare(menu->x(), 55)); + QTRY_VERIFY(qFuzzyCompare(menu->y(), 66)); menu->close(); menu->setParentItem(nullptr); @@ -786,8 +806,8 @@ void tst_QQuickMenu::popup() QCOMPARE(menu->parentItem(), button); QCOMPARE(menu->currentIndex(), -1); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); - QTRY_COMPARE(menu->x(), button->mapFromScene(QPointF(11, 22)).x()); - QTRY_COMPARE(menu->y(), button->mapFromScene(QPointF(11, 22)).y()); + QTRY_VERIFY(qFuzzyCompare(menu->x(), button->mapFromScene(QPointF(elevenOrLeftMargin, twentyTwoOrTopMargin)).x())); + QTRY_VERIFY(qFuzzyCompare(menu->y(), button->mapFromScene(QPointF(elevenOrLeftMargin, twentyTwoOrTopMargin)).y())); menu->close(); menu->setParentItem(nullptr); @@ -795,8 +815,10 @@ void tst_QQuickMenu::popup() QCOMPARE(menu->parentItem(), button); QCOMPARE(menu->currentIndex(), -1); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); - QTRY_COMPARE(menu->x(), -11); - QTRY_COMPARE(menu->y(), -22); + // Don't need to worry about margins here because we're opening close + // to the center of the window. + QTRY_VERIFY(qFuzzyCompare(menu->x(), -11)); + QTRY_VERIFY(qFuzzyCompare(menu->y(), -22)); QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-11, -22))); menu->close(); @@ -805,12 +827,13 @@ void tst_QQuickMenu::popup() QCOMPARE(menu->parentItem(), button); QCOMPARE(menu->currentIndex(), -1); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1); - QTRY_COMPARE(menu->x(), -33); - QTRY_COMPARE(menu->y(), -44); + QTRY_VERIFY(qFuzzyCompare(menu->x(), -33)); + QTRY_VERIFY(qFuzzyCompare(menu->y(), -44)); QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-33, -44))); menu->close(); - cursorPos = window->mapToGlobal(QPoint(12, window->height() / 2)); + const qreal twelveOrLeftMargin = qMax(qreal(12), menu->leftMargin()); + cursorPos = window->mapToGlobal(QPoint(twelveOrLeftMargin, window->height() / 2)); QCursor::setPos(cursorPos); QTRY_COMPARE(QCursor::pos(), cursorPos); @@ -821,22 +844,22 @@ void tst_QQuickMenu::popup() QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtCursor", Q_ARG(QVariant, QVariant::fromValue(menuItem)))); QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); - QTRY_COMPARE(menu->x(), 12); - QTRY_COMPARE(menu->y(), window->height() / 2 + menu->topPadding() - menuItem->y()); + QTRY_VERIFY(qFuzzyCompare(menu->x(), twelveOrLeftMargin)); + QTRY_VERIFY(qFuzzyCompare(menu->y(), window->height() / 2 - menu->topPadding() - menuItem->y())); menu->close(); QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtPos", Q_ARG(QVariant, QPointF(33, window->height() / 3)), Q_ARG(QVariant, QVariant::fromValue(menuItem)))); QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); - QTRY_COMPARE(menu->x(), 33); - QTRY_COMPARE(menu->y(), window->height() / 3 + menu->topPadding() - menuItem->y()); + QTRY_VERIFY(qFuzzyCompare(menu->x(), 33)); + QTRY_VERIFY(qFuzzyCompare(menu->y(), window->height() / 3 - menu->topPadding() - menuItem->y())); menu->close(); QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtCoord", Q_ARG(QVariant, 55), Q_ARG(QVariant, window->height() / 3 * 2), Q_ARG(QVariant, QVariant::fromValue(menuItem)))); QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); - QTRY_COMPARE(menu->x(), 55); - QTRY_COMPARE(menu->y(), window->height() / 3 * 2 + menu->topPadding() - menuItem->y()); + QTRY_VERIFY(qFuzzyCompare(menu->x(), 55)); + QTRY_COMPARE_WITH_TIMEOUT(menu->y(), window->height() / 3 * 2 - menu->topPadding() - menuItem->y(), 500); menu->close(); menu->setParentItem(nullptr); @@ -844,8 +867,8 @@ void tst_QQuickMenu::popup() QCOMPARE(menu->parentItem(), button); QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); - QTRY_COMPARE(menu->x(), button->mapFromScene(QPoint(12, window->height() / 2)).x()); - QTRY_COMPARE(menu->y(), button->mapFromScene(QPoint(12, window->height() / 2)).y() + menu->topPadding() - menuItem->y()); + QTRY_VERIFY(qFuzzyCompare(menu->x(), button->mapFromScene(QPoint(twelveOrLeftMargin, window->height() / 2)).x())); + QTRY_VERIFY(qFuzzyCompare(menu->y(), button->mapFromScene(QPoint(twelveOrLeftMargin, window->height() / 2)).y() - menu->topPadding() - menuItem->y())); menu->close(); menu->setParentItem(nullptr); @@ -853,9 +876,9 @@ void tst_QQuickMenu::popup() QCOMPARE(menu->parentItem(), button); QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); - QTRY_COMPARE(menu->x(), -11); - QTRY_COMPARE(menu->y(), -22 + menu->topPadding() - menuItem->y()); - QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-11, -22 + menu->topPadding() - menuItem->y()))); + QTRY_VERIFY(qFuzzyCompare(menu->x(), -11)); + QTRY_VERIFY(qFuzzyCompare(menu->y(), -22 - menu->topPadding() - menuItem->y())); + QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-11, -22 - menu->topPadding() - menuItem->y()))); menu->close(); menu->setParentItem(nullptr); @@ -863,9 +886,9 @@ void tst_QQuickMenu::popup() QCOMPARE(menu->parentItem(), button); QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem)); QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem)); - QTRY_COMPARE(menu->x(), -33); - QTRY_COMPARE(menu->y(), -44 + menu->topPadding() - menuItem->y()); - QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-33, -44 + menu->topPadding() - menuItem->y()))); + QTRY_VERIFY(qFuzzyCompare(menu->x(), -33)); + QTRY_VERIFY(qFuzzyCompare(menu->y(), -44 - menu->topPadding() - menuItem->y())); + QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-33, -44 - menu->topPadding() - menuItem->y()))); menu->close(); } @@ -1030,6 +1053,7 @@ void tst_QQuickMenu::subMenuMouse() mainMenu->open(); QVERIFY(mainMenu->isVisible()); + QTRY_VERIFY(mainMenu->isOpened()); QVERIFY(!subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); @@ -1039,8 +1063,9 @@ void tst_QQuickMenu::subMenuMouse() QVERIFY(subMenu1Item); QCOMPARE(subMenu1Item->subMenu(), subMenu1); QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, subMenu1Item->mapToScene(QPoint(1, 1)).toPoint()); - QCOMPARE(mainMenu->isVisible(), cascade); + QTRY_COMPARE(mainMenu->isVisible(), cascade); QVERIFY(subMenu1->isVisible()); + QTRY_VERIFY(subMenu1->isOpened()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); @@ -1053,8 +1078,10 @@ void tst_QQuickMenu::subMenuMouse() QVERIFY(subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); - if (cascade) + if (cascade) { QTRY_VERIFY(subSubMenu1->isVisible()); + QTRY_VERIFY(subSubMenu1->isOpened()); + } // close the sub-sub-menu with mouse hover over another parent menu item QQuickMenuItem *subMenuItem1 = qobject_cast(subMenu1->itemAt(0)); @@ -1064,7 +1091,7 @@ void tst_QQuickMenu::subMenuMouse() QCOMPARE(mainMenu->isVisible(), cascade); QVERIFY(subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); - QVERIFY(!subSubMenu1->isVisible()); + QTRY_VERIFY(!subSubMenu1->isVisible()); // re-open the sub-sub-menu with mouse hover QTest::mouseMove(window, subSubMenu1Item->mapToScene(QPoint(1, 1)).toPoint()); @@ -1072,24 +1099,24 @@ void tst_QQuickMenu::subMenuMouse() QVERIFY(subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); - if (cascade) + if (cascade) { QTRY_VERIFY(subSubMenu1->isVisible()); + QTRY_VERIFY(subSubMenu1->isOpened()); + } // close sub-menu and sub-sub-menu with mouse hover in the main menu QQuickMenuItem *mainMenuItem1 = qobject_cast(mainMenu->itemAt(0)); QVERIFY(mainMenuItem1); QTest::mouseMove(window, mainMenuItem1->mapToScene(QPoint(1, 1)).toPoint()); QCOMPARE(mainMenu->isVisible(), cascade); - QCOMPARE(subMenu1->isVisible(), !cascade); + QTRY_COMPARE(subMenu1->isVisible(), !cascade); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); // close all menus by click triggering an item - QQuickMenuItem *subSubMenuItem1 = qobject_cast(subSubMenu1->itemAt(0)); - QVERIFY(subSubMenuItem1); - QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, subSubMenuItem1->mapToScene(QPoint(1, 1)).toPoint()); - QVERIFY(!mainMenu->isVisible()); - QVERIFY(!subMenu1->isVisible()); + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, mainMenuItem1->mapToScene(QPoint(1, 1)).toPoint()); + QTRY_VERIFY(!mainMenu->isVisible()); + QTRY_VERIFY(!subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); } @@ -1133,7 +1160,9 @@ void tst_QQuickMenu::subMenuDisabledMouse() // Open the sub-menu with a mouse click. QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, menuItem1->mapToScene(QPoint(1, 1)).toPoint()); - QCOMPARE(mainMenu->isVisible(), cascade); + // Need to use the TRY variant here when cascade is false, + // as e.g. Material style menus have transitions and don't close immediately. + QTRY_COMPARE(mainMenu->isVisible(), cascade); QVERIFY(subMenu->isVisible()); QVERIFY(menuItem1->isHighlighted()); // Now the sub-menu is open. The current behavior is that the first menu item @@ -1148,8 +1177,8 @@ void tst_QQuickMenu::subMenuDisabledMouse() // Close all menus by clicking on the item that isn't disabled. QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, subMenuItem2->mapToScene(QPoint(1, 1)).toPoint()); - QVERIFY(!mainMenu->isVisible()); - QVERIFY(!subMenu->isVisible()); + QTRY_VERIFY(!mainMenu->isVisible()); + QTRY_VERIFY(!subMenu->isVisible()); } void tst_QQuickMenu::subMenuKeyboard_data() @@ -1194,11 +1223,12 @@ void tst_QQuickMenu::subMenuKeyboard() mainMenu->open(); QVERIFY(mainMenu->isVisible()); + QTRY_VERIFY(mainMenu->isOpened()); QVERIFY(!subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); - // navigate to the sub-menu item and trigger it + // navigate to the sub-menu item and trigger it to open the sub-menu QQuickMenuItem *subMenu1Item = qobject_cast(mainMenu->itemAt(1)); QVERIFY(subMenu1Item); QVERIFY(!subMenu1Item->isHighlighted()); @@ -1207,8 +1237,9 @@ void tst_QQuickMenu::subMenuKeyboard() QTest::keyClick(window, Qt::Key_Down); QVERIFY(subMenu1Item->isHighlighted()); QTest::keyClick(window, Qt::Key_Space); - QCOMPARE(mainMenu->isVisible(), cascade); + QTRY_COMPARE(mainMenu->isVisible(), cascade); QVERIFY(subMenu1->isVisible()); + QTRY_VERIFY(subMenu1->isOpened()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); @@ -1221,15 +1252,16 @@ void tst_QQuickMenu::subMenuKeyboard() QTest::keyClick(window, Qt::Key_Down); QTest::keyClick(window, Qt::Key_Down); QVERIFY(subSubMenu1Item->isHighlighted()); - QCOMPARE(mainMenu->isVisible(), cascade); + QTRY_COMPARE(mainMenu->isVisible(), cascade); QVERIFY(subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); QTest::keyClick(window, mirrored ? Qt::Key_Left : Qt::Key_Right); QCOMPARE(mainMenu->isVisible(), cascade); - QCOMPARE(subMenu1->isVisible(), cascade); + QTRY_COMPARE(subMenu1->isVisible(), cascade); QVERIFY(!subMenu2->isVisible()); QVERIFY(subSubMenu1->isVisible()); + QTRY_VERIFY(subSubMenu1->isOpened()); // navigate within the sub-sub-menu QQuickMenuItem *subSubMenuItem1 = qobject_cast(subSubMenu1->itemAt(0)); @@ -1248,7 +1280,7 @@ void tst_QQuickMenu::subMenuKeyboard() QCOMPARE(mainMenu->isVisible(), cascade); QVERIFY(subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); - QVERIFY(!subSubMenu1->isVisible()); + QTRY_VERIFY(!subSubMenu1->isVisible()); // navigate within the sub-menu QQuickMenuItem *subMenuItem1 = qobject_cast(subMenu1->itemAt(0)); @@ -1266,11 +1298,11 @@ void tst_QQuickMenu::subMenuKeyboard() // close the menus with esc QTest::keyClick(window, Qt::Key_Escape); QCOMPARE(mainMenu->isVisible(), cascade); - QVERIFY(!subMenu1->isVisible()); + QTRY_VERIFY(!subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); QTest::keyClick(window, Qt::Key_Escape); - QVERIFY(!mainMenu->isVisible()); + QTRY_VERIFY(!mainMenu->isVisible()); QVERIFY(!subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); @@ -1310,6 +1342,7 @@ void tst_QQuickMenu::subMenuDisabledKeyboard() mainMenu->open(); QVERIFY(mainMenu->isVisible()); + QTRY_VERIFY(mainMenu->isOpened()); QVERIFY(!menuItem1->isHighlighted()); QVERIFY(!subMenu->isVisible()); @@ -1330,10 +1363,10 @@ void tst_QQuickMenu::subMenuDisabledKeyboard() // Close the menus with escape. QTest::keyClick(window, Qt::Key_Escape); - QCOMPARE(mainMenu->isVisible(), cascade); - QVERIFY(!subMenu->isVisible()); + QTRY_COMPARE(mainMenu->isVisible(), cascade); + QTRY_VERIFY(!subMenu->isVisible()); QTest::keyClick(window, Qt::Key_Escape); - QVERIFY(!mainMenu->isVisible()); + QTRY_VERIFY(!mainMenu->isVisible()); QVERIFY(!subMenu->isVisible()); } @@ -1365,11 +1398,16 @@ void tst_QQuickMenu::subMenuPosition() QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml")); QQuickApplicationWindow *window = helper.appWindow; + // Ensure that the default size of the window fits three menus side by side. + QQuickMenu *mainMenu = window->property("mainMenu").value(); + QVERIFY(mainMenu); + window->setWidth(mainMenu->width() * 3 + mainMenu->leftMargin() + mainMenu->rightMargin()); + // the default size of the window fits three menus side by side. // when testing flipping, we resize the window so that the first // sub-menu fits, but the second doesn't if (flip) - window->setWidth(window->width() - 200); + window->setWidth(window->width() - mainMenu->width()); window->show(); QVERIFY(QTest::qWaitForWindowActive(window)); @@ -1379,8 +1417,6 @@ void tst_QQuickMenu::subMenuPosition() if (mirrored) window->setLocale(QLocale("ar_EG")); - QQuickMenu *mainMenu = window->property("mainMenu").value(); - QVERIFY(mainMenu); mainMenu->setCascade(cascade); QCOMPARE(mainMenu->cascade(), cascade); mainMenu->setOverlap(overlap); @@ -1410,10 +1446,11 @@ void tst_QQuickMenu::subMenuPosition() // choose the main menu position so that there's room for the // sub-menus to cascade to the left when mirrored if (mirrored) - mainMenu->setX(window->width() - 200); + mainMenu->setX(window->width() - mainMenu->width()); mainMenu->open(); QVERIFY(mainMenu->isVisible()); + QTRY_VERIFY(mainMenu->isOpened()); QVERIFY(!subMenu1->isVisible()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); @@ -1423,19 +1460,23 @@ void tst_QQuickMenu::subMenuPosition() QVERIFY(subMenu1Item); QCOMPARE(subMenu1Item->subMenu(), subMenu1); emit subMenu1Item->triggered(); - QCOMPARE(mainMenu->isVisible(), cascade); + QTRY_COMPARE(mainMenu->isVisible(), cascade); QVERIFY(subMenu1->isVisible()); + QTRY_VERIFY(subMenu1->isOpened()); QVERIFY(!subMenu2->isVisible()); QVERIFY(!subSubMenu1->isVisible()); if (cascade) { QCOMPARE(subMenu1->parentItem(), subMenu1Item); // vertically aligned to the parent menu item - QCOMPARE(subMenu1->popupItem()->y(), mainMenu->popupItem()->y() + subMenu1Item->y() - subMenu1->topPadding()); - if (mirrored) - QCOMPARE(subMenu1->popupItem()->x(), mainMenu->popupItem()->x() - subMenu1->width() + overlap); // on the left of the parent menu - else - QCOMPARE(subMenu1->popupItem()->x(), mainMenu->popupItem()->x() + mainMenu->width() - overlap); // on the right of the parent menu + QCOMPARE(subMenu1->popupItem()->y(), mainMenu->popupItem()->y() + subMenu1Item->y()); + if (mirrored) { + // on the left of the parent menu + QCOMPARE(subMenu1->popupItem()->x(), mainMenu->popupItem()->x() - subMenu1->width() + overlap); + } else { + // on the right of the parent menu + QCOMPARE(subMenu1->popupItem()->x(), mainMenu->popupItem()->x() + mainMenu->width() - overlap); + } } else { QCOMPARE(subMenu1->parentItem(), mainMenu->parentItem()); // centered over the parent menu @@ -1448,19 +1489,23 @@ void tst_QQuickMenu::subMenuPosition() QVERIFY(subSubMenu1Item); QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1); emit subSubMenu1Item->triggered(); - QCOMPARE(mainMenu->isVisible(), cascade); - QCOMPARE(subMenu1->isVisible(), cascade); + QTRY_COMPARE(mainMenu->isVisible(), cascade); + QTRY_COMPARE(subMenu1->isVisible(), cascade); QVERIFY(!subMenu2->isVisible()); QVERIFY(subSubMenu1->isVisible()); + QTRY_VERIFY(subSubMenu1->isOpened()); if (cascade) { QCOMPARE(subSubMenu1->parentItem(), subSubMenu1Item); // vertically aligned to the parent menu item - QCOMPARE(subSubMenu1->popupItem()->y(), subMenu1->popupItem()->y() + subSubMenu1Item->y() - subSubMenu1->topPadding()); - if (mirrored != flip) - QCOMPARE(subSubMenu1->popupItem()->x(), subMenu1->popupItem()->x() - subSubMenu1->width() + overlap); // on the left of the parent menu - else - QCOMPARE(subSubMenu1->popupItem()->x(), subMenu1->popupItem()->x() + subMenu1->width() - overlap); // on the right of the parent menu + QCOMPARE(subSubMenu1->popupItem()->y(), subMenu1->popupItem()->y() + subSubMenu1Item->y()); + if (mirrored != flip) { + // on the left of the parent menu + QCOMPARE(subSubMenu1->popupItem()->x(), subMenu1->popupItem()->x() - subSubMenu1->width() + overlap); + } else { + // on the right of the parent menu + QCOMPARE(subSubMenu1->popupItem()->x(), subMenu1->popupItem()->x() + subMenu1->width() - overlap); + } } else { QCOMPARE(subSubMenu1->parentItem(), subMenu1->parentItem()); // centered over the parent menu @@ -1590,6 +1635,7 @@ void tst_QQuickMenu::disableWhenTriggered() menu->open(); QVERIFY(menu->isVisible()); + QTRY_VERIFY(menu->isOpened()); QPointer menuItem = qobject_cast(menu->itemAt(menuItemIndex)); QVERIFY(menuItem); @@ -1599,7 +1645,7 @@ void tst_QQuickMenu::disableWhenTriggered() QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, menuItem->mapToScene(QPointF(menuItem->width() / 2, menuItem->height() / 2)).toPoint()); QCOMPARE(menuItem->isEnabled(), false); - QVERIFY(!menu->isVisible()); + QTRY_VERIFY(!menu->isVisible()); } else { // Click a sub-menu item. QPointer subMenu = menuItem->subMenu(); @@ -1618,10 +1664,10 @@ void tst_QQuickMenu::disableWhenTriggered() QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, subMenuItem->mapToScene(QPointF(subMenuItem->width() / 2, subMenuItem->height() / 2)).toPoint()); QCOMPARE(subMenuItem->isEnabled(), false); - QVERIFY(!menu->isVisible()); + QTRY_VERIFY(!menu->isVisible()); } } -QTEST_MAIN(tst_QQuickMenu) +QTEST_QUICKCONTROLS_MAIN(tst_QQuickMenu) #include "tst_qquickmenu.moc" -- cgit v1.2.3 From 0525d640cd11ddced2ec418be182c585204fc45f Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Fri, 12 Apr 2019 15:21:42 +0200 Subject: Fix MenuItem width not matching Menu's available width Short version: There are currently two problems with MenuItems: - Mirrored MenuItems don't fill the Menu's available width. - MenuItem does not fill the Menu's available width when changed after Component completion. This patch fixes both of them by listening to geometry changes in both the contentItem and individual menu items, and setting the explicit width of those menu items when either changes. Longer version: The first problem can be seen whenever the MenuItem's implicitWidth changes: - QQmlEngine::retranslate() is called, causing all bindings to be re-evaluated - The MenuItem's font size changes - The MenuItem's icon size changes - etc. We fix this by making Menu listen to the width of each of its MenuItems and call resizeItem() if it doesn't have an explicit width. The second problem can be seen when e.g. resizing a Menu to account for new items that are wider and hence require more space. This can be fixed by listening to width changes in Menu's contentItem, which was actually done in earlier versions but (probably accidentally) removed in 482ecb0f. I had tried to solve both issues by setting the explicit width of MenuItem to the width of its Menu, or undefined if it has none (which means it reverts to its implicit width). However, this does not account for e.g. MenuSeparator and custom items that can be added to Menu - they should also have their width fill the Menu automatically if they don't have an explicit width set. Change-Id: I95dd0da0919a1e297f2e2030da746ff1f1a17644 Fixes: QTBUG-75051 Fixes: QTBUG-75142 Reviewed-by: Richard Moe Gustavsen --- src/quicktemplates2/qquickmenu.cpp | 24 ++++- tests/auto/qquickmenu/data/menuItemWidths.qml | 103 ++++++++++++++++++ tests/auto/qquickmenu/tst_qquickmenu.cpp | 150 ++++++++++++++++++++++++++ 3 files changed, 273 insertions(+), 4 deletions(-) create mode 100644 tests/auto/qquickmenu/data/menuItemWidths.qml diff --git a/src/quicktemplates2/qquickmenu.cpp b/src/quicktemplates2/qquickmenu.cpp index f91d15a5..aa44e845 100644 --- a/src/quicktemplates2/qquickmenu.cpp +++ b/src/quicktemplates2/qquickmenu.cpp @@ -213,6 +213,7 @@ void QQuickMenuPrivate::insertItem(int index, QQuickItem *item) if (complete) resizeItem(item); QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); + QQuickItemPrivate::get(item)->updateOrAddGeometryChangeListener(this, QQuickGeometryChange::Width); contentModel->insert(index, item); QQuickMenuItem *menuItem = qobject_cast(item); @@ -237,6 +238,7 @@ void QQuickMenuPrivate::removeItem(int index, QQuickItem *item) contentData.removeOne(item); QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent); + QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Geometry); item->setParentItem(nullptr); contentModel->remove(index); @@ -358,10 +360,20 @@ void QQuickMenuPrivate::itemDestroyed(QQuickItem *item) removeItem(index, item); } -void QQuickMenuPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) +void QQuickMenuPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange, const QRectF &) { - if (complete) + if (!complete) + return; + + if (item == contentItem) { + // The contentItem's geometry changed, so resize any items + // that don't have explicit widths set so that they fill the width of the menu. resizeItems(); + } else { + // The geometry of an item in the menu changed. If the item + // doesn't have an explicit width set, make it fill the width of the menu. + resizeItem(item); + } } QQuickPopupPositioner *QQuickMenuPrivate::getPositioner() @@ -1382,10 +1394,14 @@ void QQuickMenu::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) Q_D(QQuickMenu); QQuickPopup::contentItemChange(newItem, oldItem); - if (oldItem) + if (oldItem) { QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Children); - if (newItem) + QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); + } + if (newItem) { QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Children); + QQuickItemPrivate::get(newItem)->updateOrAddGeometryChangeListener(d, QQuickGeometryChange::Width); + } d->contentItem = newItem; } diff --git a/tests/auto/qquickmenu/data/menuItemWidths.qml b/tests/auto/qquickmenu/data/menuItemWidths.qml new file mode 100644 index 00000000..6d2baa32 --- /dev/null +++ b/tests/auto/qquickmenu/data/menuItemWidths.qml @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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.12 +import QtQuick.Controls 2.12 + +ApplicationWindow { + width: 600 + height: 600 + + property alias menu: menu + + Menu { + id: menu + MenuItem { + objectName: "MenuItem" + text: "MenuItem" + } + MenuSeparator { + objectName: "MenuSeparator" + } + Menu { + title: "Sub-menu" + objectName: "Sub-menu" + + MenuItem { + objectName: "SubMenuItem" + text: "SubMenuItem" + } + } + Rectangle { + objectName: "CustomSeparator" + height: 2 + color: "salmon" + } + Rectangle { + // Use a binding to test retranslate(), which re-evaluates all bindings. + implicitWidth: someValue + objectName: "CustomRectangleSeparator" + height: 2 + color: "salmon" + + property int someValue: 120 + } + Control { + objectName: "CustomControlSeparator" + implicitWidth: someOtherValue + height: 2 + background: Rectangle { + color: "navajowhite" + } + + property int someOtherValue: 180 + } + } +} diff --git a/tests/auto/qquickmenu/tst_qquickmenu.cpp b/tests/auto/qquickmenu/tst_qquickmenu.cpp index 1b00817f..49fdc066 100644 --- a/tests/auto/qquickmenu/tst_qquickmenu.cpp +++ b/tests/auto/qquickmenu/tst_qquickmenu.cpp @@ -94,6 +94,13 @@ private slots: void scrollable(); void disableWhenTriggered_data(); void disableWhenTriggered(); + void menuItemWidth_data(); + void menuItemWidth(); + void menuItemWidthAfterMenuWidthChanged_data(); + void menuItemWidthAfterMenuWidthChanged(); + void menuItemWidthAfterImplicitWidthChanged_data(); + void menuItemWidthAfterImplicitWidthChanged(); + void menuItemWidthAfterRetranslate(); }; void tst_QQuickMenu::defaults() @@ -1668,6 +1675,149 @@ void tst_QQuickMenu::disableWhenTriggered() } } +void tst_QQuickMenu::menuItemWidth_data() +{ + QTest::addColumn("mirrored"); + + QTest::newRow("non-mirrored") << false; + QTest::newRow("mirrored") << true; +} + +void tst_QQuickMenu::menuItemWidth() +{ + QFETCH(bool, mirrored); + + QQuickApplicationHelper helper(this, QLatin1String("menuItemWidths.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + if (mirrored) + window->setLocale(QLocale("ar_EG")); + + QQuickMenu *menu = window->property("menu").value(); + QVERIFY(menu); + menu->open(); + QTRY_VERIFY(menu->isOpened()); + for (int i = 0; i < menu->count(); ++i) + QCOMPARE(menu->itemAt(i)->width(), menu->availableWidth()); +} + +void tst_QQuickMenu::menuItemWidthAfterMenuWidthChanged_data() +{ + QTest::addColumn("mirrored"); + + QTest::newRow("non-mirrored") << false; + QTest::newRow("mirrored") << true; +} + +void tst_QQuickMenu::menuItemWidthAfterMenuWidthChanged() +{ + QFETCH(bool, mirrored); + + QQuickApplicationHelper helper(this, QLatin1String("menuItemWidths.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + if (mirrored) + window->setLocale(QLocale("ar_EG")); + + QQuickMenu *menu = window->property("menu").value(); + QVERIFY(menu); + menu->open(); + QTRY_VERIFY(menu->isOpened()); + for (int i = 0; i < menu->count(); ++i) { + // Check that the width of menu items is correct before we resize the menu. + const QQuickItem *item = menu->itemAt(i); + QVERIFY2(qFuzzyCompare(item->width(), menu->availableWidth()), + qPrintable(QString::fromLatin1("Expected width of %1 to be %2, but it's %3") + .arg(item->objectName()).arg(menu->availableWidth()).arg(item->width()))); + } + + menu->setWidth(menu->width() + 10); + + // Check that the width of menu items is correct after we resize the menu. + for (int i = 0; i < menu->count(); ++i) { + // Check that the width of menu items is correct after we resize the menu. + const QQuickItem *item = menu->itemAt(i); + QVERIFY2(qFuzzyCompare(item->width(), menu->availableWidth()), + qPrintable(QString::fromLatin1("Expected width of %1 to be %2, but it's %3") + .arg(item->objectName()).arg(menu->availableWidth()).arg(item->width()))); + } +} + +void tst_QQuickMenu::menuItemWidthAfterImplicitWidthChanged_data() +{ + QTest::addColumn("mirrored"); + + QTest::newRow("non-mirrored") << false; + QTest::newRow("mirrored") << true; +} + +void tst_QQuickMenu::menuItemWidthAfterImplicitWidthChanged() +{ + QFETCH(bool, mirrored); + + QQuickApplicationHelper helper(this, QLatin1String("menuItemWidths.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + if (mirrored) + window->setLocale(QLocale("ar_EG")); + + QQuickMenu *menu = window->property("menu").value(); + QVERIFY(menu); + menu->open(); + QTRY_VERIFY(menu->isOpened()); + // Check that the width of the menu item is correct before we change its font size. + QQuickMenuItem *menuItem = qobject_cast(menu->itemAt(0)); + QCOMPARE(menuItem->width(), menu->availableWidth()); + + // Add some text to increase the implicitWidth of the MenuItem. + const qreal oldImplicitWidth = menuItem->implicitWidth(); + for (int i = 0; menuItem->implicitWidth() <= oldImplicitWidth; ++i) { + menuItem->setText(menuItem->text() + QLatin1String("---")); + if (i == 100) + QFAIL("Shouldn't need 100 iterations to increase MenuItem's implicitWidth; something is wrong here"); + } + + // Check that the width of the menu item is correct after we change its font size. + QCOMPARE(menuItem->width(), menu->availableWidth()); +} + +void tst_QQuickMenu::menuItemWidthAfterRetranslate() +{ + QQuickApplicationHelper helper(this, QLatin1String("menuItemWidths.qml")); + QQuickApplicationWindow *window = helper.appWindow; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value(); + QVERIFY(menu); + menu->open(); + QTRY_VERIFY(menu->isOpened()); + for (int i = 0; i < menu->count(); ++i) { + // Check that the width of each menu item is correct before we retranslate. + const QQuickItem *item = menu->itemAt(i); + QVERIFY2(qFuzzyCompare(item->width(), menu->availableWidth()), + qPrintable(QString::fromLatin1("Expected width of %1 to be %2, but it's %3") + .arg(item->objectName()).arg(menu->availableWidth()).arg(item->width()))); + } + + // Call retranslate() and cause all bindings to be re-evaluated. + helper.engine.retranslate(); + + for (int i = 0; i < menu->count(); ++i) { + // Check that the width of each menu item is correct after we retranslate. + const QQuickItem *item = menu->itemAt(i); + QVERIFY2(qFuzzyCompare(item->width(), menu->availableWidth()), + qPrintable(QString::fromLatin1("Expected width of %1 to be %2, but it's %3") + .arg(item->objectName()).arg(menu->availableWidth()).arg(item->width()))); + } +} + QTEST_QUICKCONTROLS_MAIN(tst_QQuickMenu) #include "tst_qquickmenu.moc" -- cgit v1.2.3