2015-11-16 15:06:07 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2017-01-09 16:13:48 +00:00
|
|
|
** Copyright (C) 2017 The Qt Company Ltd.
|
2015-11-16 15:06:07 +00:00
|
|
|
** 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$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <qtest.h>
|
|
|
|
#include <QtTest/QSignalSpy>
|
2017-05-17 15:35:00 +00:00
|
|
|
#include <QtGui/qcursor.h>
|
2015-11-16 15:06:07 +00:00
|
|
|
#include <QtGui/qstylehints.h>
|
|
|
|
#include <QtQml/qqmlengine.h>
|
|
|
|
#include <QtQml/qqmlcomponent.h>
|
|
|
|
#include <QtQml/qqmlcontext.h>
|
|
|
|
#include <QtQuick/qquickview.h>
|
|
|
|
#include <QtQuick/private/qquickitem_p.h>
|
|
|
|
#include "../shared/util.h"
|
|
|
|
#include "../shared/visualtestutil.h"
|
|
|
|
|
2017-06-09 08:09:28 +00:00
|
|
|
#include <QtQuickTemplates2/private/qquickaction_p.h>
|
2016-04-13 13:59:53 +00:00
|
|
|
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
|
|
|
|
#include <QtQuickTemplates2/private/qquickoverlay_p.h>
|
|
|
|
#include <QtQuickTemplates2/private/qquickbutton_p.h>
|
|
|
|
#include <QtQuickTemplates2/private/qquickmenu_p.h>
|
|
|
|
#include <QtQuickTemplates2/private/qquickmenuitem_p.h>
|
2016-07-21 14:04:18 +00:00
|
|
|
#include <QtQuickTemplates2/private/qquickmenuseparator_p.h>
|
2015-11-16 15:06:07 +00:00
|
|
|
|
|
|
|
using namespace QQuickVisualTestUtil;
|
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
class tst_QQuickMenu : public QQmlDataTest
|
2015-11-16 15:06:07 +00:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
void defaults();
|
2017-07-12 13:58:02 +00:00
|
|
|
void count();
|
2015-11-16 15:06:07 +00:00
|
|
|
void mouse();
|
2017-06-29 11:15:24 +00:00
|
|
|
void pressAndHold();
|
2015-11-16 15:06:07 +00:00
|
|
|
void contextMenuKeyboard();
|
2017-06-29 12:23:13 +00:00
|
|
|
void mnemonics();
|
2015-11-16 15:06:07 +00:00
|
|
|
void menuButton();
|
2016-05-10 11:58:05 +00:00
|
|
|
void addItem();
|
2016-07-21 14:04:18 +00:00
|
|
|
void menuSeparator();
|
2016-12-28 19:24:18 +00:00
|
|
|
void repeater();
|
|
|
|
void order();
|
2017-05-17 15:35:00 +00:00
|
|
|
void popup();
|
2017-06-01 18:09:44 +00:00
|
|
|
void actions();
|
2017-06-02 14:18:56 +00:00
|
|
|
void removeTakeItem();
|
2017-06-01 21:36:57 +00:00
|
|
|
void subMenuMouse_data();
|
|
|
|
void subMenuMouse();
|
2019-01-28 12:14:30 +00:00
|
|
|
void subMenuDisabledMouse_data();
|
|
|
|
void subMenuDisabledMouse();
|
2017-06-01 21:36:57 +00:00
|
|
|
void subMenuKeyboard_data();
|
|
|
|
void subMenuKeyboard();
|
2019-01-28 12:14:30 +00:00
|
|
|
void subMenuDisabledKeyboard_data();
|
|
|
|
void subMenuDisabledKeyboard();
|
2017-06-01 21:36:57 +00:00
|
|
|
void subMenuPosition_data();
|
|
|
|
void subMenuPosition();
|
2017-06-07 17:43:58 +00:00
|
|
|
void addRemoveSubMenus();
|
2018-06-18 09:38:40 +00:00
|
|
|
void scrollable_data();
|
|
|
|
void scrollable();
|
Fix Menu not being dismissed when the triggered item disables itself
Problem
Consider the following code:
Menu {
title: "Menu"
Action {
text: "Item"
onTriggered: enabled = false
}
}
A MenuItem (AbstractButton) is created for the Action, and when it is
clicked, this function is called:
void QQuickAbstractButtonPrivate::trigger()
{
Q_Q(QQuickAbstractButton);
if (action && action->isEnabled())
QQuickActionPrivate::get(action)->trigger(q, false);
else if (effectiveEnable)
emit q->clicked();
}
QQuickActionPrivate::get(action)->trigger(q, false) results in this
function being called:
void QQuickAbstractButtonPrivate::click()
{
Q_Q(QQuickAbstractButton);
if (effectiveEnable)
emit q->clicked();
}
Since the action (and hence the menu item) was disabled in the signal
handler, the effectiveEnable check fails and clicked() is not emitted.
This causes the menu to not be dismissed.
Solution
Before calling QQuickActionPrivate::get(action)->trigger(), store
the button's enabled state. If triggering the action causes the action
to be disabled (due to the signal handler), we can then choose whether
or not we emit QQuickAbstractButton::clicked(). Specifically, we emit
clicked() if:
- we were enabled before triggering the action, and
- we have no associated action, or it's no longer enabled
Task-number: QTBUG-69682
Change-Id: Ib4e3c313b776decc74089a6beffe415605c430be
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
2018-07-30 12:28:44 +00:00
|
|
|
void disableWhenTriggered_data();
|
|
|
|
void disableWhenTriggered();
|
2015-11-16 15:06:07 +00:00
|
|
|
};
|
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
void tst_QQuickMenu::defaults()
|
2015-11-16 15:06:07 +00:00
|
|
|
{
|
2015-12-09 14:37:01 +00:00
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
|
2015-11-16 15:06:07 +00:00
|
|
|
|
2016-09-03 13:15:53 +00:00
|
|
|
QQuickMenu *emptyMenu = helper.appWindow->property("emptyMenu").value<QQuickMenu*>();
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(emptyMenu->isVisible(), false);
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(emptyMenu->currentIndex(), -1);
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(emptyMenu->contentItem()->property("currentIndex"), QVariant(-1));
|
2017-07-12 13:58:02 +00:00
|
|
|
QCOMPARE(emptyMenu->count(), 0);
|
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::count()
|
2017-07-12 13:58:02 +00:00
|
|
|
{
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
|
|
|
|
|
|
|
|
QQuickMenu *menu = helper.window->property("emptyMenu").value<QQuickMenu*>();
|
|
|
|
QVERIFY(menu);
|
|
|
|
|
|
|
|
QSignalSpy countSpy(menu, &QQuickMenu::countChanged);
|
|
|
|
QVERIFY(countSpy.isValid());
|
|
|
|
|
|
|
|
menu->addItem(new QQuickItem);
|
|
|
|
QCOMPARE(menu->count(), 1);
|
|
|
|
QCOMPARE(countSpy.count(), 1);
|
|
|
|
|
|
|
|
menu->insertItem(0, new QQuickItem);
|
|
|
|
QCOMPARE(menu->count(), 2);
|
|
|
|
QCOMPARE(countSpy.count(), 2);
|
|
|
|
|
|
|
|
menu->removeItem(menu->itemAt(1));
|
|
|
|
QCOMPARE(menu->count(), 1);
|
|
|
|
QCOMPARE(countSpy.count(), 3);
|
|
|
|
|
tst_qquickmenu: fix memory leak
takeItem() unparents the item, so we need to make sure it gets deleted.
The leak was caught by valgrind:
==10039== 832 (32 direct, 800 indirect) bytes in 1 blocks are definitely lost in loss record 6,465 of 6,706
==10039== at 0x4C3017F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10039== by 0x112C1E: tst_QQuickMenu::count() (tst_qquickmenu.cpp:121)
==10039== by 0x12F313: tst_QQuickMenu::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) (tst_qquickmenu.moc:156)
==10039== by 0x612B6B2: QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericReturnArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const (qmetaobject.cpp:2305)
==10039== by 0x41B07CD: invoke (qmetaobject.h:123)
==10039== by 0x41B07CD: QTest::TestMethods::invokeTestOnData(int) const (qtestcase.cpp:915)
==10039== by 0x41B15BF: QTest::TestMethods::invokeTest(int, char const*, QTest::WatchDog*) const (qtestcase.cpp:1114)
==10039== by 0x41B1D07: QTest::TestMethods::invokeTests(QObject*) const (qtestcase.cpp:1456)
==10039== by 0x41B2381: QTest::qRun() (qtestcase.cpp:1896)
==10039== by 0x41B24E1: QTest::qExec(QObject*, int, char**) (qtestcase.cpp:1783)
==10039== by 0x12F468: main (tst_qquickmenu.cpp:1505)
Change-Id: I459c7897c1088c8b58152d2e0b5ceb8f3684e589
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
2018-10-12 13:17:41 +00:00
|
|
|
QScopedPointer<QQuickItem> item(menu->takeItem(0));
|
2017-07-12 13:58:02 +00:00
|
|
|
QVERIFY(item);
|
|
|
|
QCOMPARE(menu->count(), 0);
|
|
|
|
QCOMPARE(countSpy.count(), 4);
|
2015-11-16 15:06:07 +00:00
|
|
|
}
|
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
void tst_QQuickMenu::mouse()
|
2015-11-16 15:06:07 +00:00
|
|
|
{
|
2017-06-05 09:48:40 +00:00
|
|
|
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|
|
|
|
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
|
|
|
|
QSKIP("Mouse hovering not functional on offscreen/minimal platforms");
|
|
|
|
|
2015-12-09 14:37:01 +00:00
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
|
2015-11-16 15:06:07 +00:00
|
|
|
|
2016-09-03 13:15:53 +00:00
|
|
|
QQuickApplicationWindow *window = helper.appWindow;
|
2015-11-16 15:06:07 +00:00
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
2017-08-09 10:51:40 +00:00
|
|
|
centerOnScreen(window);
|
2017-06-10 08:18:21 +00:00
|
|
|
moveMouseAway(window);
|
2015-11-16 15:06:07 +00:00
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
|
2015-12-11 14:34:55 +00:00
|
|
|
menu->open();
|
2015-11-16 15:06:07 +00:00
|
|
|
QVERIFY(menu->isVisible());
|
2016-01-22 11:10:12 +00:00
|
|
|
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem()));
|
2015-11-16 15:06:07 +00:00
|
|
|
|
|
|
|
QQuickItem *firstItem = menu->itemAt(0);
|
2016-01-25 14:14:27 +00:00
|
|
|
QSignalSpy clickedSpy(firstItem, SIGNAL(clicked()));
|
2015-11-16 15:06:07 +00:00
|
|
|
QSignalSpy triggeredSpy(firstItem, SIGNAL(triggered()));
|
|
|
|
QSignalSpy visibleSpy(menu, SIGNAL(visibleChanged()));
|
|
|
|
|
|
|
|
// 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));
|
|
|
|
QVERIFY(firstItem->hasActiveFocus());
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), 0);
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0));
|
|
|
|
QVERIFY(menu->isVisible());
|
|
|
|
|
|
|
|
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(firstItem->width() / 2, firstItem->height() / 2));
|
|
|
|
QCOMPARE(clickedSpy.count(), 1);
|
|
|
|
QCOMPARE(triggeredSpy.count(), 1);
|
|
|
|
QCOMPARE(visibleSpy.count(), 1);
|
|
|
|
QVERIFY(!menu->isVisible());
|
|
|
|
QVERIFY(!window->overlay()->childItems().contains(menu->contentItem()));
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), -1);
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
|
|
|
|
|
2015-12-11 14:34:55 +00:00
|
|
|
menu->open();
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(visibleSpy.count(), 2);
|
|
|
|
QVERIFY(menu->isVisible());
|
2016-01-22 11:10:12 +00:00
|
|
|
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem()));
|
2015-11-16 15:06:07 +00:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
QVERIFY(!menu->isVisible());
|
2016-01-22 11:10:12 +00:00
|
|
|
QVERIFY(!window->overlay()->childItems().contains(menu->contentItem()->parentItem()));
|
2015-11-16 15:06:07 +00:00
|
|
|
|
2015-12-11 14:34:55 +00:00
|
|
|
menu->open();
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(visibleSpy.count(), 4);
|
|
|
|
QVERIFY(menu->isVisible());
|
2016-01-22 11:10:12 +00:00
|
|
|
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem()));
|
2015-11-16 15:06:07 +00:00
|
|
|
|
2017-06-06 13:58:36 +00:00
|
|
|
// Hover-highlight through the menu items one by one
|
|
|
|
QQuickItem *prevHoverItem = nullptr;
|
|
|
|
QQuickItem *listView = menu->contentItem();
|
|
|
|
for (int y = 0; 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));
|
|
|
|
QTRY_VERIFY(hoverItem->property("highlighted").toBool());
|
|
|
|
if (prevHoverItem)
|
|
|
|
QVERIFY(!prevHoverItem->property("highlighted").toBool());
|
|
|
|
prevHoverItem = hoverItem;
|
|
|
|
}
|
|
|
|
|
2015-11-16 15:06:07 +00:00
|
|
|
// Try pressing within the menu and releasing outside of it; it should close.
|
2015-12-08 13:26:51 +00:00
|
|
|
// TODO: won't work until QQuickPopup::releasedOutside() actually gets emitted
|
2015-11-16 15:06:07 +00:00
|
|
|
// QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(firstItem->width() / 2, firstItem->height() / 2));
|
|
|
|
// QVERIFY(firstItem->hasActiveFocus());
|
|
|
|
// QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0));
|
|
|
|
// QVERIFY(menu->isVisible());
|
|
|
|
// QCOMPARE(triggeredSpy.count(), 1);
|
|
|
|
|
|
|
|
// QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(menu->contentItem()->width() + 1, firstItem->height() / 2));
|
|
|
|
// QCOMPARE(clickedSpy.count(), 1);
|
|
|
|
// QCOMPARE(triggeredSpy.count(), 1);
|
|
|
|
// QCOMPARE(visibleSpy.count(), 5);
|
|
|
|
// QVERIFY(!menu->isVisible());
|
|
|
|
// QVERIFY(!window->overlay()->childItems().contains(menu->contentItem()));
|
|
|
|
// QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
|
|
|
|
}
|
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
void tst_QQuickMenu::pressAndHold()
|
2017-06-29 11:15:24 +00:00
|
|
|
{
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("pressAndHold.qml"));
|
|
|
|
|
|
|
|
QQuickWindow *window = helper.window;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(menu);
|
|
|
|
|
|
|
|
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
|
|
|
|
QTRY_VERIFY(menu->isVisible());
|
|
|
|
|
|
|
|
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
|
|
|
|
QVERIFY(menu->isVisible());
|
|
|
|
|
|
|
|
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
|
|
|
|
QTRY_VERIFY(!menu->isVisible());
|
|
|
|
}
|
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
void tst_QQuickMenu::contextMenuKeyboard()
|
2015-11-16 15:06:07 +00:00
|
|
|
{
|
|
|
|
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
|
|
|
|
QSKIP("This platform only allows tab focus for text controls");
|
|
|
|
|
2015-12-09 14:37:01 +00:00
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
|
2015-11-16 15:06:07 +00:00
|
|
|
|
2016-09-03 13:15:53 +00:00
|
|
|
QQuickApplicationWindow *window = helper.appWindow;
|
2015-11-16 15:06:07 +00:00
|
|
|
window->show();
|
|
|
|
window->requestActivate();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
QVERIFY(QGuiApplication::focusWindow() == window);
|
2017-08-09 10:51:40 +00:00
|
|
|
centerOnScreen(window);
|
2017-06-10 08:18:21 +00:00
|
|
|
moveMouseAway(window);
|
2015-11-16 15:06:07 +00:00
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), -1);
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
|
|
|
|
|
2017-06-08 18:19:50 +00:00
|
|
|
QQuickMenuItem *firstItem = qobject_cast<QQuickMenuItem *>(menu->itemAt(0));
|
|
|
|
QVERIFY(firstItem);
|
2015-11-16 15:06:07 +00:00
|
|
|
QSignalSpy visibleSpy(menu, SIGNAL(visibleChanged()));
|
|
|
|
|
|
|
|
menu->setFocus(true);
|
2015-12-11 14:34:55 +00:00
|
|
|
menu->open();
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(visibleSpy.count(), 1);
|
|
|
|
QVERIFY(menu->isVisible());
|
2016-01-22 11:10:12 +00:00
|
|
|
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem()));
|
2015-11-16 15:06:07 +00:00
|
|
|
QVERIFY(!firstItem->hasActiveFocus());
|
2017-06-06 13:58:36 +00:00
|
|
|
QVERIFY(!firstItem->property("highlighted").toBool());
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), -1);
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
|
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Tab);
|
|
|
|
QVERIFY(firstItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(firstItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(firstItem->isHighlighted());
|
2017-06-08 18:19:50 +00:00
|
|
|
QCOMPARE(firstItem->focusReason(), Qt::TabFocusReason);
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), 0);
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(0));
|
|
|
|
|
2017-06-08 18:19:50 +00:00
|
|
|
QQuickMenuItem *secondItem = qobject_cast<QQuickMenuItem *>(menu->itemAt(1));
|
|
|
|
QVERIFY(secondItem);
|
2015-11-16 15:06:07 +00:00
|
|
|
QTest::keyClick(window, Qt::Key_Tab);
|
|
|
|
QVERIFY(!firstItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(!firstItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!firstItem->isHighlighted());
|
2015-11-16 15:06:07 +00:00
|
|
|
QVERIFY(secondItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(secondItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(secondItem->isHighlighted());
|
2017-06-08 18:19:50 +00:00
|
|
|
QCOMPARE(secondItem->focusReason(), Qt::TabFocusReason);
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), 1);
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(1));
|
|
|
|
|
|
|
|
QSignalSpy secondTriggeredSpy(secondItem, SIGNAL(triggered()));
|
|
|
|
QTest::keyClick(window, Qt::Key_Space);
|
|
|
|
QCOMPARE(secondTriggeredSpy.count(), 1);
|
|
|
|
QCOMPARE(visibleSpy.count(), 2);
|
|
|
|
QVERIFY(!menu->isVisible());
|
|
|
|
QVERIFY(!window->overlay()->childItems().contains(menu->contentItem()));
|
|
|
|
QVERIFY(!firstItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(!firstItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!firstItem->isHighlighted());
|
2015-11-16 15:06:07 +00:00
|
|
|
QVERIFY(!secondItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(!secondItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!secondItem->isHighlighted());
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), -1);
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
|
|
|
|
|
2015-12-11 14:34:55 +00:00
|
|
|
menu->open();
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(visibleSpy.count(), 3);
|
|
|
|
QVERIFY(menu->isVisible());
|
2016-01-22 11:10:12 +00:00
|
|
|
QVERIFY(window->overlay()->childItems().contains(menu->contentItem()->parentItem()));
|
2015-11-16 15:06:07 +00:00
|
|
|
QVERIFY(!firstItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(!firstItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!firstItem->isHighlighted());
|
2015-11-16 15:06:07 +00:00
|
|
|
QVERIFY(!secondItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(!secondItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!secondItem->isHighlighted());
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), -1);
|
2015-11-16 15:06:07 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
|
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QVERIFY(firstItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(firstItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(firstItem->isHighlighted());
|
2017-06-08 18:19:50 +00:00
|
|
|
QCOMPARE(firstItem->focusReason(), Qt::TabFocusReason);
|
2015-11-16 15:06:07 +00:00
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QVERIFY(secondItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(secondItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(secondItem->isHighlighted());
|
2017-06-08 18:19:50 +00:00
|
|
|
QCOMPARE(secondItem->focusReason(), Qt::TabFocusReason);
|
2015-11-16 15:06:07 +00:00
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
2017-06-08 18:19:50 +00:00
|
|
|
QQuickMenuItem *thirdItem = qobject_cast<QQuickMenuItem *>(menu->itemAt(2));
|
|
|
|
QVERIFY(thirdItem);
|
2015-11-16 15:06:07 +00:00
|
|
|
QVERIFY(!firstItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(!firstItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!firstItem->isHighlighted());
|
2015-11-16 15:06:07 +00:00
|
|
|
QVERIFY(!secondItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(!secondItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!secondItem->isHighlighted());
|
2015-11-16 15:06:07 +00:00
|
|
|
QVERIFY(thirdItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(thirdItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(thirdItem->isHighlighted());
|
2017-06-08 18:19:50 +00:00
|
|
|
QCOMPARE(thirdItem->focusReason(), Qt::TabFocusReason);
|
2015-11-16 15:06:07 +00:00
|
|
|
|
|
|
|
// Key navigation shouldn't wrap by default.
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QVERIFY(!firstItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(!firstItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!firstItem->isHighlighted());
|
2015-11-16 15:06:07 +00:00
|
|
|
QVERIFY(!secondItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(!secondItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!secondItem->isHighlighted());
|
2015-11-16 15:06:07 +00:00
|
|
|
QVERIFY(thirdItem->hasActiveFocus());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(thirdItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(thirdItem->isHighlighted());
|
2017-06-08 18:19:50 +00:00
|
|
|
QCOMPARE(thirdItem->focusReason(), Qt::TabFocusReason);
|
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Up);
|
|
|
|
QVERIFY(!firstItem->hasActiveFocus());
|
|
|
|
QVERIFY(!firstItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!firstItem->isHighlighted());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(secondItem->hasActiveFocus());
|
|
|
|
QVERIFY(secondItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(secondItem->isHighlighted());
|
2017-06-08 18:19:50 +00:00
|
|
|
QCOMPARE(secondItem->focusReason(), Qt::BacktabFocusReason);
|
|
|
|
QVERIFY(!thirdItem->hasActiveFocus());
|
|
|
|
QVERIFY(!thirdItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!thirdItem->isHighlighted());
|
2017-06-08 18:19:50 +00:00
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Backtab);
|
|
|
|
QVERIFY(firstItem->hasActiveFocus());
|
|
|
|
QVERIFY(firstItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(firstItem->isHighlighted());
|
2017-06-08 18:19:50 +00:00
|
|
|
QCOMPARE(firstItem->focusReason(), Qt::BacktabFocusReason);
|
|
|
|
QVERIFY(!secondItem->hasActiveFocus());
|
|
|
|
QVERIFY(!secondItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!secondItem->isHighlighted());
|
2017-06-08 18:19:50 +00:00
|
|
|
QVERIFY(!thirdItem->hasActiveFocus());
|
|
|
|
QVERIFY(!thirdItem->hasVisualFocus());
|
2017-06-15 09:41:19 +00:00
|
|
|
QVERIFY(!thirdItem->isHighlighted());
|
2015-12-03 09:29:00 +00:00
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Escape);
|
|
|
|
QCOMPARE(visibleSpy.count(), 4);
|
|
|
|
QVERIFY(!menu->isVisible());
|
2015-11-16 15:06:07 +00:00
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::mnemonics()
|
2017-06-29 12:23:13 +00:00
|
|
|
{
|
|
|
|
#ifdef Q_OS_MACOS
|
|
|
|
QSKIP("Mnemonics are not used on macOS");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("mnemonics.qml"));
|
|
|
|
|
|
|
|
QQuickWindow *window = helper.window;
|
|
|
|
window->show();
|
|
|
|
window->requestActivate();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
|
|
|
|
QQuickAction *action = window->property("action").value<QQuickAction *>();
|
|
|
|
QQuickMenuItem *menuItem = window->property("menuItem").value<QQuickMenuItem *>();
|
|
|
|
QQuickMenu *subMenu = window->property("subMenu").value<QQuickMenu *>();
|
|
|
|
QQuickMenuItem *subMenuItem = window->property("subMenuItem").value<QQuickMenuItem *>();
|
|
|
|
QVERIFY(menu && action && menuItem && subMenu && subMenuItem);
|
|
|
|
|
|
|
|
menu->open();
|
|
|
|
QTRY_VERIFY(menu->isOpened());
|
|
|
|
|
|
|
|
QSignalSpy actionSpy(action, &QQuickAction::triggered);
|
|
|
|
QVERIFY(actionSpy.isValid());
|
|
|
|
QTest::keyClick(window, Qt::Key_A, Qt::AltModifier); // "&Action"
|
|
|
|
QCOMPARE(actionSpy.count(), 1);
|
|
|
|
|
|
|
|
menu->open();
|
|
|
|
QTRY_VERIFY(menu->isOpened());
|
|
|
|
|
|
|
|
QSignalSpy menuItemSpy(menuItem, &QQuickMenuItem::triggered);
|
|
|
|
QVERIFY(menuItemSpy.isValid());
|
|
|
|
QTest::keyClick(window, Qt::Key_I, Qt::AltModifier); // "Menu &Item"
|
|
|
|
QCOMPARE(menuItemSpy.count(), 1);
|
|
|
|
|
|
|
|
menu->open();
|
|
|
|
QTRY_VERIFY(menu->isOpened());
|
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_M, Qt::AltModifier); // "Sub &Menu"
|
|
|
|
QTRY_VERIFY(subMenu->isOpened());
|
|
|
|
|
|
|
|
QSignalSpy subMenuItemSpy(subMenuItem, &QQuickMenuItem::triggered);
|
|
|
|
QVERIFY(subMenuItemSpy.isValid());
|
|
|
|
QTest::keyClick(window, Qt::Key_S, Qt::AltModifier); // "&Sub Menu Item"
|
|
|
|
QCOMPARE(subMenuItemSpy.count(), 1);
|
|
|
|
}
|
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
void tst_QQuickMenu::menuButton()
|
2015-11-16 15:06:07 +00:00
|
|
|
{
|
|
|
|
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
|
|
|
|
QSKIP("This platform only allows tab focus for text controls");
|
|
|
|
|
2015-12-09 14:37:01 +00:00
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
|
2015-11-16 15:06:07 +00:00
|
|
|
|
2016-09-03 13:15:53 +00:00
|
|
|
QQuickApplicationWindow *window = helper.appWindow;
|
2015-11-16 15:06:07 +00:00
|
|
|
window->show();
|
|
|
|
window->requestActivate();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
QVERIFY(QGuiApplication::focusWindow() == window);
|
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
|
|
|
|
QQuickButton *menuButton = window->property("menuButton").value<QQuickButton*>();
|
|
|
|
QSignalSpy visibleSpy(menu, SIGNAL(visibleChanged()));
|
|
|
|
|
|
|
|
menuButton->setVisible(true);
|
|
|
|
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier,
|
|
|
|
menuButton->mapToScene(QPointF(menuButton->width() / 2, menuButton->height() / 2)).toPoint());
|
|
|
|
QCOMPARE(visibleSpy.count(), 1);
|
|
|
|
QVERIFY(menu->isVisible());
|
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Tab);
|
|
|
|
QQuickItem *firstItem = menu->itemAt(0);
|
|
|
|
QVERIFY(firstItem->hasActiveFocus());
|
|
|
|
}
|
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
void tst_QQuickMenu::addItem()
|
2016-05-10 11:58:05 +00:00
|
|
|
{
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("addItem.qml"));
|
2016-09-03 13:15:53 +00:00
|
|
|
QQuickApplicationWindow *window = helper.appWindow;
|
2016-05-10 11:58:05 +00:00
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
|
|
|
|
QVERIFY(menu);
|
|
|
|
menu->open();
|
2016-05-11 13:15:17 +00:00
|
|
|
QVERIFY(menu->isVisible());
|
2016-05-10 11:58:05 +00:00
|
|
|
|
|
|
|
QQuickItem *menuItem = menu->itemAt(0);
|
2016-05-11 13:15:17 +00:00
|
|
|
QVERIFY(menuItem);
|
|
|
|
QTRY_VERIFY(!QQuickItemPrivate::get(menuItem)->culled); // QTBUG-53262
|
|
|
|
|
2016-05-10 11:58:05 +00:00
|
|
|
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier,
|
|
|
|
menuItem->mapToScene(QPointF(menuItem->width() / 2, menuItem->height() / 2)).toPoint());
|
2016-05-11 13:15:17 +00:00
|
|
|
QTRY_VERIFY(!menu->isVisible());
|
2016-05-10 11:58:05 +00:00
|
|
|
}
|
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
void tst_QQuickMenu::menuSeparator()
|
2016-07-21 14:04:18 +00:00
|
|
|
{
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("menuSeparator.qml"));
|
2016-09-06 16:52:28 +00:00
|
|
|
QQuickWindow *window = helper.window;
|
2016-07-21 14:04:18 +00:00
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
2017-08-09 10:51:40 +00:00
|
|
|
centerOnScreen(window);
|
2017-06-29 13:15:31 +00:00
|
|
|
moveMouseAway(window);
|
2016-07-21 14:04:18 +00:00
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
|
|
|
|
QVERIFY(menu);
|
|
|
|
menu->open();
|
|
|
|
QVERIFY(menu->isVisible());
|
|
|
|
|
|
|
|
QQuickMenuItem *newMenuItem = qobject_cast<QQuickMenuItem*>(menu->itemAt(0));
|
|
|
|
QVERIFY(newMenuItem);
|
|
|
|
QCOMPARE(newMenuItem->text(), QStringLiteral("New"));
|
|
|
|
|
|
|
|
QQuickMenuSeparator *menuSeparator = qobject_cast<QQuickMenuSeparator*>(menu->itemAt(1));
|
|
|
|
QVERIFY(menuSeparator);
|
|
|
|
|
|
|
|
QQuickMenuItem *saveMenuItem = qobject_cast<QQuickMenuItem*>(menu->itemAt(2));
|
|
|
|
QVERIFY(saveMenuItem);
|
|
|
|
QCOMPARE(saveMenuItem->text(), QStringLiteral("Save"));
|
|
|
|
QTRY_VERIFY(!QQuickItemPrivate::get(saveMenuItem)->culled); // QTBUG-53262
|
|
|
|
|
|
|
|
// Clicking on items should still close the menu.
|
|
|
|
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier,
|
|
|
|
newMenuItem->mapToScene(QPointF(newMenuItem->width() / 2, newMenuItem->height() / 2)).toPoint());
|
|
|
|
QTRY_VERIFY(!menu->isVisible());
|
|
|
|
|
|
|
|
menu->open();
|
|
|
|
QVERIFY(menu->isVisible());
|
|
|
|
|
|
|
|
// Clicking on a separator shouldn't close the menu.
|
|
|
|
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier,
|
|
|
|
menuSeparator->mapToScene(QPointF(menuSeparator->width() / 2, menuSeparator->height() / 2)).toPoint());
|
|
|
|
QVERIFY(menu->isVisible());
|
|
|
|
|
|
|
|
// Clicking on items should still close the menu.
|
|
|
|
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier,
|
|
|
|
saveMenuItem->mapToScene(QPointF(saveMenuItem->width() / 2, saveMenuItem->height() / 2)).toPoint());
|
|
|
|
QTRY_VERIFY(!menu->isVisible());
|
2017-06-08 18:19:50 +00:00
|
|
|
|
2017-07-06 12:51:52 +00:00
|
|
|
moveMouseAway(window);
|
2017-07-03 08:32:29 +00:00
|
|
|
|
2017-06-08 18:19:50 +00:00
|
|
|
menu->open();
|
|
|
|
QVERIFY(menu->isVisible());
|
|
|
|
|
|
|
|
// Key navigation skips separators
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QVERIFY(newMenuItem->hasActiveFocus());
|
|
|
|
QVERIFY(newMenuItem->hasVisualFocus());
|
|
|
|
QCOMPARE(newMenuItem->focusReason(), Qt::TabFocusReason);
|
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QVERIFY(saveMenuItem->hasActiveFocus());
|
|
|
|
QVERIFY(saveMenuItem->hasVisualFocus());
|
|
|
|
QCOMPARE(saveMenuItem->focusReason(), Qt::TabFocusReason);
|
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QVERIFY(saveMenuItem->hasActiveFocus());
|
|
|
|
QVERIFY(saveMenuItem->hasVisualFocus());
|
|
|
|
QCOMPARE(saveMenuItem->focusReason(), Qt::TabFocusReason);
|
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Up);
|
|
|
|
QVERIFY(newMenuItem->hasActiveFocus());
|
|
|
|
QVERIFY(newMenuItem->hasVisualFocus());
|
|
|
|
QCOMPARE(newMenuItem->focusReason(), Qt::BacktabFocusReason);
|
|
|
|
|
|
|
|
QTest::keyClick(window, Qt::Key_Up);
|
|
|
|
QVERIFY(newMenuItem->hasActiveFocus());
|
|
|
|
QVERIFY(newMenuItem->hasVisualFocus());
|
|
|
|
QCOMPARE(newMenuItem->focusReason(), Qt::BacktabFocusReason);
|
2016-07-21 14:04:18 +00:00
|
|
|
}
|
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
void tst_QQuickMenu::repeater()
|
2016-12-28 19:24:18 +00:00
|
|
|
{
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("repeater.qml"));
|
|
|
|
QQuickWindow *window = helper.window;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
|
|
|
|
QVERIFY(menu);
|
|
|
|
menu->open();
|
|
|
|
QVERIFY(menu->isVisible());
|
|
|
|
|
|
|
|
QObject *repeater = window->property("repeater").value<QObject*>();
|
|
|
|
QVERIFY(repeater);
|
|
|
|
|
|
|
|
int count = repeater->property("count").toInt();
|
|
|
|
QCOMPARE(count, 5);
|
|
|
|
|
|
|
|
for (int i = 0; i < count; ++i) {
|
|
|
|
QQuickItem *item = menu->itemAt(i);
|
2018-11-14 10:13:15 +00:00
|
|
|
QVERIFY(item);
|
2016-12-28 19:24:18 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
void tst_QQuickMenu::order()
|
2016-12-28 19:24:18 +00:00
|
|
|
{
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("order.qml"));
|
|
|
|
QQuickWindow *window = helper.window;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::popup()
|
2017-05-17 15:35:00 +00:00
|
|
|
{
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("popup.qml"));
|
2017-07-11 12:20:37 +00:00
|
|
|
QQuickApplicationWindow *window = helper.appWindow;
|
2017-05-17 15:35:00 +00:00
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
2017-08-09 10:51:40 +00:00
|
|
|
centerOnScreen(window);
|
2017-06-29 13:15:31 +00:00
|
|
|
moveMouseAway(window);
|
2017-05-17 15:35:00 +00:00
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(menu);
|
|
|
|
|
|
|
|
QQuickMenuItem *menuItem1 = window->property("menuItem1").value<QQuickMenuItem *>();
|
|
|
|
QVERIFY(menuItem1);
|
|
|
|
|
|
|
|
QQuickMenuItem *menuItem2 = window->property("menuItem2").value<QQuickMenuItem *>();
|
|
|
|
QVERIFY(menuItem2);
|
|
|
|
|
|
|
|
QQuickMenuItem *menuItem3 = window->property("menuItem3").value<QQuickMenuItem *>();
|
|
|
|
QVERIFY(menuItem3);
|
|
|
|
|
2017-07-11 12:20:37 +00:00
|
|
|
QQuickItem *button = window->property("button").value<QQuickItem *>();
|
|
|
|
QVERIFY(button);
|
|
|
|
|
2017-05-17 15:35:00 +00:00
|
|
|
#if QT_CONFIG(cursor)
|
2017-06-10 08:18:21 +00:00
|
|
|
QPoint oldCursorPos = QCursor::pos();
|
2017-05-17 15:35:00 +00:00
|
|
|
QPoint cursorPos = window->mapToGlobal(QPoint(11, 22));
|
|
|
|
QCursor::setPos(cursorPos);
|
|
|
|
QTRY_COMPARE(QCursor::pos(), cursorPos);
|
|
|
|
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupAtCursor"));
|
2017-07-11 12:20:37 +00:00
|
|
|
QCOMPARE(menu->parentItem(), window->contentItem());
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), -1);
|
2017-06-06 18:56:54 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1);
|
2017-07-11 12:20:37 +00:00
|
|
|
QTRY_COMPARE(menu->x(), 11);
|
|
|
|
QTRY_COMPARE(menu->y(), 22);
|
2017-05-17 15:35:00 +00:00
|
|
|
menu->close();
|
|
|
|
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupAtPos", Q_ARG(QVariant, QPointF(33, 44))));
|
2017-07-11 12:20:37 +00:00
|
|
|
QCOMPARE(menu->parentItem(), window->contentItem());
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), -1);
|
2017-06-06 18:56:54 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1);
|
2017-07-11 12:20:37 +00:00
|
|
|
QTRY_COMPARE(menu->x(), 33);
|
|
|
|
QTRY_COMPARE(menu->y(), 44);
|
2017-05-17 15:35:00 +00:00
|
|
|
menu->close();
|
|
|
|
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupAtCoord", Q_ARG(QVariant, 55), Q_ARG(QVariant, 66)));
|
2017-07-11 12:20:37 +00:00
|
|
|
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);
|
|
|
|
menu->close();
|
|
|
|
|
|
|
|
menu->setParentItem(nullptr);
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupAtParentCursor", Q_ARG(QVariant, QVariant::fromValue(button))));
|
|
|
|
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());
|
|
|
|
menu->close();
|
|
|
|
|
|
|
|
menu->setParentItem(nullptr);
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupAtParentPos", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, QPointF(-11, -22))));
|
|
|
|
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);
|
|
|
|
QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-11, -22)));
|
|
|
|
menu->close();
|
|
|
|
|
|
|
|
menu->setParentItem(nullptr);
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupAtParentCoord", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, -33), Q_ARG(QVariant, -44)));
|
|
|
|
QCOMPARE(menu->parentItem(), button);
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), -1);
|
2017-06-06 18:56:54 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), -1);
|
2017-07-11 12:20:37 +00:00
|
|
|
QTRY_COMPARE(menu->x(), -33);
|
|
|
|
QTRY_COMPARE(menu->y(), -44);
|
|
|
|
QCOMPARE(menu->popupItem()->position(), button->mapToScene(QPointF(-33, -44)));
|
2017-05-17 15:35:00 +00:00
|
|
|
menu->close();
|
|
|
|
|
|
|
|
cursorPos = window->mapToGlobal(QPoint(12, window->height() / 2));
|
|
|
|
QCursor::setPos(cursorPos);
|
|
|
|
QTRY_COMPARE(QCursor::pos(), cursorPos);
|
|
|
|
|
|
|
|
const QList<QQuickMenuItem *> menuItems = QList<QQuickMenuItem *>() << menuItem1 << menuItem2 << menuItem3;
|
|
|
|
for (QQuickMenuItem *menuItem : menuItems) {
|
2017-07-11 12:20:37 +00:00
|
|
|
menu->resetParentItem();
|
|
|
|
|
2017-05-17 15:35:00 +00:00
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtCursor", Q_ARG(QVariant, QVariant::fromValue(menuItem))));
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem));
|
2017-06-06 18:56:54 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem));
|
2017-07-11 12:20:37 +00:00
|
|
|
QTRY_COMPARE(menu->x(), 12);
|
|
|
|
QTRY_COMPARE(menu->y(), window->height() / 2 + menu->topPadding() - menuItem->y());
|
2017-05-17 15:35:00 +00:00
|
|
|
menu->close();
|
|
|
|
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtPos", Q_ARG(QVariant, QPointF(33, window->height() / 3)), Q_ARG(QVariant, QVariant::fromValue(menuItem))));
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem));
|
2017-06-06 18:56:54 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem));
|
2017-07-11 12:20:37 +00:00
|
|
|
QTRY_COMPARE(menu->x(), 33);
|
|
|
|
QTRY_COMPARE(menu->y(), window->height() / 3 + menu->topPadding() - menuItem->y());
|
2017-05-17 15:35:00 +00:00
|
|
|
menu->close();
|
|
|
|
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtCoord", Q_ARG(QVariant, 55), Q_ARG(QVariant, window->height() / 3 * 2), Q_ARG(QVariant, QVariant::fromValue(menuItem))));
|
2017-06-14 22:16:57 +00:00
|
|
|
QCOMPARE(menu->currentIndex(), menuItems.indexOf(menuItem));
|
2017-06-06 18:56:54 +00:00
|
|
|
QCOMPARE(menu->contentItem()->property("currentIndex").toInt(), menuItems.indexOf(menuItem));
|
2017-07-11 12:20:37 +00:00
|
|
|
QTRY_COMPARE(menu->x(), 55);
|
|
|
|
QTRY_COMPARE(menu->y(), window->height() / 3 * 2 + menu->topPadding() - menuItem->y());
|
|
|
|
menu->close();
|
|
|
|
|
|
|
|
menu->setParentItem(nullptr);
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtParentCursor", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, QVariant::fromValue(menuItem))));
|
|
|
|
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());
|
|
|
|
menu->close();
|
|
|
|
|
|
|
|
menu->setParentItem(nullptr);
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtParentPos", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, QPointF(-11, -22)), Q_ARG(QVariant, QVariant::fromValue(menuItem))));
|
|
|
|
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())));
|
|
|
|
menu->close();
|
|
|
|
|
|
|
|
menu->setParentItem(nullptr);
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "popupItemAtParentCoord", Q_ARG(QVariant, QVariant::fromValue(button)), Q_ARG(QVariant, -33), Q_ARG(QVariant, -44), Q_ARG(QVariant, QVariant::fromValue(menuItem))));
|
|
|
|
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())));
|
2017-05-17 15:35:00 +00:00
|
|
|
menu->close();
|
|
|
|
}
|
2017-06-10 08:18:21 +00:00
|
|
|
|
|
|
|
QCursor::setPos(oldCursorPos);
|
|
|
|
QTRY_COMPARE(QCursor::pos(), oldCursorPos);
|
2017-05-17 15:35:00 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::actions()
|
2017-06-01 18:09:44 +00:00
|
|
|
{
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("actions.qml"));
|
|
|
|
QQuickWindow *window = helper.window;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(menu);
|
|
|
|
|
2017-07-10 09:59:47 +00:00
|
|
|
QPointer<QQuickAction> action1 = menu->actionAt(0);
|
|
|
|
QVERIFY(!action1.isNull());
|
|
|
|
|
|
|
|
QPointer<QQuickAction> action3 = menu->actionAt(2);
|
|
|
|
QVERIFY(!action3.isNull());
|
|
|
|
|
|
|
|
QVERIFY(!menu->actionAt(1));
|
|
|
|
QVERIFY(!menu->actionAt(3));
|
|
|
|
|
2017-06-09 08:09:28 +00:00
|
|
|
QPointer<QQuickMenuItem> menuItem1 = qobject_cast<QQuickMenuItem *>(menu->itemAt(0));
|
|
|
|
QVERIFY(!menuItem1.isNull());
|
2017-07-10 09:59:47 +00:00
|
|
|
QCOMPARE(menuItem1->action(), action1.data());
|
2017-06-01 18:09:44 +00:00
|
|
|
QCOMPARE(menuItem1->text(), "action1");
|
|
|
|
|
2017-06-09 08:09:28 +00:00
|
|
|
QPointer<QQuickMenuItem> menuItem2 = qobject_cast<QQuickMenuItem *>(menu->itemAt(1));
|
|
|
|
QVERIFY(!menuItem2.isNull());
|
2017-06-01 18:09:44 +00:00
|
|
|
QVERIFY(!menuItem2->action());
|
|
|
|
QCOMPARE(menuItem2->text(), "menuitem2");
|
|
|
|
|
2017-06-09 08:09:28 +00:00
|
|
|
QPointer<QQuickMenuItem> menuItem3 = qobject_cast<QQuickMenuItem *>(menu->itemAt(2));
|
|
|
|
QVERIFY(!menuItem3.isNull());
|
2017-07-10 09:59:47 +00:00
|
|
|
QCOMPARE(menuItem3->action(), action3.data());
|
2017-06-01 18:09:44 +00:00
|
|
|
QCOMPARE(menuItem3->text(), "action3");
|
|
|
|
|
2017-06-09 08:09:28 +00:00
|
|
|
QPointer<QQuickMenuItem> menuItem4 = qobject_cast<QQuickMenuItem *>(menu->itemAt(3));
|
|
|
|
QVERIFY(!menuItem4.isNull());
|
2017-06-01 18:09:44 +00:00
|
|
|
QVERIFY(!menuItem4->action());
|
|
|
|
QCOMPARE(menuItem4->text(), "menuitem4");
|
2017-06-09 08:09:28 +00:00
|
|
|
|
|
|
|
// takeAction(int) does not destroy the action, but does destroy the respective item
|
|
|
|
QCOMPARE(menu->takeAction(0), action1.data());
|
|
|
|
QVERIFY(!menu->itemAt(3));
|
|
|
|
QCoreApplication::sendPostedEvents(action1, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(!action1.isNull());
|
|
|
|
QCoreApplication::sendPostedEvents(menuItem1, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(menuItem1.isNull());
|
|
|
|
|
|
|
|
// takeAction(int) does not destroy an item that doesn't have an action
|
|
|
|
QVERIFY(!menuItem2->subMenu());
|
|
|
|
QVERIFY(!menu->takeAction(0));
|
|
|
|
QCoreApplication::sendPostedEvents(menuItem2, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(!menuItem2.isNull());
|
|
|
|
|
|
|
|
// addAction(Action) re-creates the respective item in the menu
|
|
|
|
menu->addAction(action1);
|
|
|
|
menuItem1 = qobject_cast<QQuickMenuItem *>(menu->itemAt(3));
|
|
|
|
QVERIFY(!menuItem1.isNull());
|
|
|
|
QCOMPARE(menuItem1->action(), action1.data());
|
|
|
|
|
|
|
|
// removeAction(Action) destroys both the action and the respective item
|
|
|
|
menu->removeAction(action1);
|
|
|
|
QVERIFY(!menu->itemAt(3));
|
|
|
|
QCoreApplication::sendPostedEvents(action1, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(action1.isNull());
|
|
|
|
QCoreApplication::sendPostedEvents(menuItem1, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(menuItem1.isNull());
|
2017-06-01 18:09:44 +00:00
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::removeTakeItem()
|
2017-06-02 14:18:56 +00:00
|
|
|
{
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("removeTakeItem.qml"));
|
|
|
|
QQuickWindow *window = helper.window;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(menu);
|
|
|
|
|
|
|
|
QPointer<QQuickMenuItem> menuItem1 = window->property("menuItem1").value<QQuickMenuItem *>();
|
|
|
|
QVERIFY(!menuItem1.isNull());
|
|
|
|
QCOMPARE(menuItem1->menu(), menu);
|
|
|
|
|
|
|
|
QPointer<QQuickMenuItem> menuItem2 = window->property("menuItem2").value<QQuickMenuItem *>();
|
|
|
|
QVERIFY(!menuItem2.isNull());
|
|
|
|
QCOMPARE(menuItem2->menu(), menu);
|
|
|
|
|
|
|
|
QPointer<QQuickMenuItem> menuItem3 = window->property("menuItem3").value<QQuickMenuItem *>();
|
|
|
|
QVERIFY(!menuItem3.isNull());
|
|
|
|
QCOMPARE(menuItem3->menu(), menu);
|
|
|
|
|
|
|
|
// takeItem(int) does not destroy
|
|
|
|
QVariant ret;
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "takeSecondItem", Q_RETURN_ARG(QVariant, ret)));
|
|
|
|
QCOMPARE(ret.value<QQuickMenuItem *>(), menuItem2);
|
|
|
|
QVERIFY(!menuItem2->menu());
|
|
|
|
QCoreApplication::sendPostedEvents(menuItem2, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(!menuItem2.isNull());
|
|
|
|
|
|
|
|
// removeItem(Item) destroys
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "removeFirstItem"));
|
|
|
|
QVERIFY(!menuItem1->menu());
|
|
|
|
QCoreApplication::sendPostedEvents(menuItem1, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(menuItem1.isNull());
|
|
|
|
|
|
|
|
// removeItem(null) must not call removeItem(0)
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "removeNullItem"));
|
|
|
|
QCOMPARE(menuItem3->menu(), menu);
|
|
|
|
QCoreApplication::sendPostedEvents(menuItem3, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(!menuItem3.isNull());
|
|
|
|
|
|
|
|
// deprecated removeItem(int) does not destroy
|
|
|
|
QVERIFY(QMetaObject::invokeMethod(window, "removeFirstIndex"));
|
|
|
|
QVERIFY(!menuItem3->menu());
|
|
|
|
QCoreApplication::sendPostedEvents(menuItem3, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(!menuItem3.isNull());
|
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::subMenuMouse_data()
|
2017-06-01 21:36:57 +00:00
|
|
|
{
|
|
|
|
QTest::addColumn<bool>("cascade");
|
|
|
|
|
|
|
|
QTest::newRow("cascading") << true;
|
|
|
|
QTest::newRow("non-cascading") << false;
|
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::subMenuMouse()
|
2017-06-01 21:36:57 +00:00
|
|
|
{
|
2017-06-05 09:48:40 +00:00
|
|
|
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|
|
|
|
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
|
|
|
|
QSKIP("Mouse hovering not functional on offscreen/minimal platforms");
|
|
|
|
|
2017-06-01 21:36:57 +00:00
|
|
|
QFETCH(bool, cascade);
|
|
|
|
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml"));
|
|
|
|
QQuickApplicationWindow *window = helper.appWindow;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
2017-08-09 10:51:40 +00:00
|
|
|
centerOnScreen(window);
|
2017-06-01 21:36:57 +00:00
|
|
|
moveMouseAway(window);
|
|
|
|
|
|
|
|
QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(mainMenu);
|
|
|
|
mainMenu->setCascade(cascade);
|
|
|
|
QCOMPARE(mainMenu->cascade(), cascade);
|
|
|
|
|
|
|
|
QQuickMenu *subMenu1 = window->property("subMenu1").value<QQuickMenu *>();
|
|
|
|
QVERIFY(subMenu1);
|
|
|
|
|
|
|
|
QQuickMenu *subMenu2 = window->property("subMenu2").value<QQuickMenu *>();
|
|
|
|
QVERIFY(subMenu2);
|
|
|
|
|
|
|
|
QQuickMenu *subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>();
|
|
|
|
QVERIFY(subSubMenu1);
|
|
|
|
|
|
|
|
mainMenu->open();
|
|
|
|
QVERIFY(mainMenu->isVisible());
|
|
|
|
QVERIFY(!subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
|
|
|
|
// open the sub-menu with mouse click
|
|
|
|
QQuickMenuItem *subMenu1Item = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(1));
|
|
|
|
QVERIFY(subMenu1Item);
|
|
|
|
QCOMPARE(subMenu1Item->subMenu(), subMenu1);
|
|
|
|
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, subMenu1Item->mapToScene(QPoint(1, 1)).toPoint());
|
|
|
|
QCOMPARE(mainMenu->isVisible(), cascade);
|
|
|
|
QVERIFY(subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
|
|
|
|
// open the cascading sub-sub-menu with mouse hover
|
|
|
|
QQuickMenuItem *subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2));
|
|
|
|
QVERIFY(subSubMenu1Item);
|
|
|
|
QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1);
|
|
|
|
QTest::mouseMove(window, subSubMenu1Item->mapToScene(QPoint(1, 1)).toPoint());
|
|
|
|
QCOMPARE(mainMenu->isVisible(), cascade);
|
|
|
|
QVERIFY(subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
2017-06-08 05:12:53 +00:00
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
if (cascade)
|
|
|
|
QTRY_VERIFY(subSubMenu1->isVisible());
|
2017-06-01 21:36:57 +00:00
|
|
|
|
|
|
|
// close the sub-sub-menu with mouse hover over another parent menu item
|
|
|
|
QQuickMenuItem *subMenuItem1 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0));
|
|
|
|
QVERIFY(subMenuItem1);
|
|
|
|
QVERIFY(!subMenuItem1->subMenu());
|
|
|
|
QTest::mouseMove(window, subMenuItem1->mapToScene(QPoint(1, 1)).toPoint());
|
|
|
|
QCOMPARE(mainMenu->isVisible(), cascade);
|
|
|
|
QVERIFY(subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
|
|
|
|
// re-open the sub-sub-menu with mouse hover
|
|
|
|
QTest::mouseMove(window, subSubMenu1Item->mapToScene(QPoint(1, 1)).toPoint());
|
|
|
|
QCOMPARE(mainMenu->isVisible(), cascade);
|
|
|
|
QVERIFY(subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
2017-06-08 05:12:53 +00:00
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
if (cascade)
|
|
|
|
QTRY_VERIFY(subSubMenu1->isVisible());
|
2017-06-01 21:36:57 +00:00
|
|
|
|
|
|
|
// close sub-menu and sub-sub-menu with mouse hover in the main menu
|
|
|
|
QQuickMenuItem *mainMenuItem1 = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(0));
|
|
|
|
QVERIFY(mainMenuItem1);
|
|
|
|
QTest::mouseMove(window, mainMenuItem1->mapToScene(QPoint(1, 1)).toPoint());
|
|
|
|
QCOMPARE(mainMenu->isVisible(), cascade);
|
|
|
|
QCOMPARE(subMenu1->isVisible(), !cascade);
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
|
|
|
|
// close all menus by click triggering an item
|
|
|
|
QQuickMenuItem *subSubMenuItem1 = qobject_cast<QQuickMenuItem *>(subSubMenu1->itemAt(0));
|
|
|
|
QVERIFY(subSubMenuItem1);
|
|
|
|
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, subSubMenuItem1->mapToScene(QPoint(1, 1)).toPoint());
|
|
|
|
QVERIFY(!mainMenu->isVisible());
|
|
|
|
QVERIFY(!subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
}
|
|
|
|
|
2019-01-28 12:14:30 +00:00
|
|
|
void tst_QQuickMenu::subMenuDisabledMouse_data()
|
|
|
|
{
|
|
|
|
subMenuMouse_data();
|
|
|
|
}
|
|
|
|
|
|
|
|
// QTBUG-69540
|
|
|
|
void tst_QQuickMenu::subMenuDisabledMouse()
|
|
|
|
{
|
|
|
|
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|
|
|
|
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
|
|
|
|
QSKIP("Mouse hovering not functional on offscreen/minimal platforms");
|
|
|
|
|
|
|
|
QFETCH(bool, cascade);
|
|
|
|
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("subMenuDisabled.qml"));
|
|
|
|
QQuickApplicationWindow *window = helper.appWindow;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
centerOnScreen(window);
|
|
|
|
moveMouseAway(window);
|
|
|
|
|
|
|
|
QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(mainMenu);
|
|
|
|
mainMenu->setCascade(cascade);
|
|
|
|
QCOMPARE(mainMenu->cascade(), cascade);
|
|
|
|
|
|
|
|
QQuickMenuItem *menuItem1 = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(0));
|
|
|
|
QVERIFY(menuItem1);
|
|
|
|
|
|
|
|
QQuickMenu *subMenu = window->property("subMenu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(subMenu);
|
|
|
|
|
|
|
|
mainMenu->open();
|
|
|
|
QVERIFY(mainMenu->isVisible());
|
|
|
|
QVERIFY(!menuItem1->isHighlighted());
|
|
|
|
QVERIFY(!subMenu->isVisible());
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
QVERIFY(subMenu->isVisible());
|
|
|
|
QVERIFY(menuItem1->isHighlighted());
|
|
|
|
// Now the sub-menu is open. The current behavior is that the first menu item
|
|
|
|
// in the new menu is highlighted; make sure that we choose the next item if
|
|
|
|
// the first is disabled.
|
|
|
|
QQuickMenuItem *subMenuItem1 = qobject_cast<QQuickMenuItem *>(subMenu->itemAt(0));
|
|
|
|
QVERIFY(subMenuItem1);
|
|
|
|
QQuickMenuItem *subMenuItem2 = qobject_cast<QQuickMenuItem *>(subMenu->itemAt(1));
|
|
|
|
QVERIFY(subMenuItem2);
|
|
|
|
QVERIFY(!subMenuItem1->isHighlighted());
|
|
|
|
QVERIFY(subMenuItem2->isHighlighted());
|
|
|
|
|
|
|
|
// 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());
|
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::subMenuKeyboard_data()
|
2017-06-01 21:36:57 +00:00
|
|
|
{
|
|
|
|
QTest::addColumn<bool>("cascade");
|
|
|
|
QTest::addColumn<bool>("mirrored");
|
|
|
|
|
|
|
|
QTest::newRow("cascading") << true << false;
|
|
|
|
QTest::newRow("cascading,mirrored") << true << true;
|
|
|
|
QTest::newRow("non-cascading") << false << false;
|
|
|
|
QTest::newRow("non-cascading,mirrored") << false << true;
|
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::subMenuKeyboard()
|
2017-06-01 21:36:57 +00:00
|
|
|
{
|
|
|
|
QFETCH(bool, cascade);
|
|
|
|
QFETCH(bool, mirrored);
|
|
|
|
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml"));
|
|
|
|
QQuickApplicationWindow *window = helper.appWindow;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
2017-08-09 10:51:40 +00:00
|
|
|
centerOnScreen(window);
|
2017-06-01 21:36:57 +00:00
|
|
|
moveMouseAway(window);
|
|
|
|
|
|
|
|
if (mirrored)
|
|
|
|
window->setLocale(QLocale("ar_EG"));
|
|
|
|
|
|
|
|
QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(mainMenu);
|
|
|
|
mainMenu->setCascade(cascade);
|
|
|
|
QCOMPARE(mainMenu->cascade(), cascade);
|
|
|
|
|
|
|
|
QQuickMenu *subMenu1 = window->property("subMenu1").value<QQuickMenu *>();
|
|
|
|
QVERIFY(subMenu1);
|
|
|
|
|
|
|
|
QQuickMenu *subMenu2 = window->property("subMenu2").value<QQuickMenu *>();
|
|
|
|
QVERIFY(subMenu2);
|
|
|
|
|
|
|
|
QQuickMenu *subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>();
|
|
|
|
QVERIFY(subSubMenu1);
|
|
|
|
|
|
|
|
mainMenu->open();
|
|
|
|
QVERIFY(mainMenu->isVisible());
|
|
|
|
QVERIFY(!subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
|
|
|
|
// navigate to the sub-menu item and trigger it
|
|
|
|
QQuickMenuItem *subMenu1Item = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(1));
|
|
|
|
QVERIFY(subMenu1Item);
|
|
|
|
QVERIFY(!subMenu1Item->isHighlighted());
|
|
|
|
QCOMPARE(subMenu1Item->subMenu(), subMenu1);
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QVERIFY(subMenu1Item->isHighlighted());
|
|
|
|
QTest::keyClick(window, Qt::Key_Space);
|
|
|
|
QCOMPARE(mainMenu->isVisible(), cascade);
|
|
|
|
QVERIFY(subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
|
|
|
|
// navigate to the sub-sub-menu item and open it with the arrow key
|
|
|
|
QQuickMenuItem *subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2));
|
|
|
|
QVERIFY(subSubMenu1Item);
|
|
|
|
QVERIFY(!subSubMenu1Item->isHighlighted());
|
|
|
|
QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1);
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QVERIFY(subSubMenu1Item->isHighlighted());
|
|
|
|
QCOMPARE(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);
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(subSubMenu1->isVisible());
|
|
|
|
|
|
|
|
// navigate within the sub-sub-menu
|
|
|
|
QQuickMenuItem *subSubMenuItem1 = qobject_cast<QQuickMenuItem *>(subSubMenu1->itemAt(0));
|
|
|
|
QVERIFY(subSubMenuItem1);
|
|
|
|
QQuickMenuItem *subSubMenuItem2 = qobject_cast<QQuickMenuItem *>(subSubMenu1->itemAt(1));
|
|
|
|
QVERIFY(subSubMenuItem2);
|
|
|
|
QVERIFY(subSubMenuItem1->isHighlighted());
|
|
|
|
QVERIFY(!subSubMenuItem2->isHighlighted());
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QVERIFY(!subSubMenuItem1->isHighlighted());
|
|
|
|
QVERIFY(subSubMenuItem2->isHighlighted());
|
|
|
|
|
|
|
|
// navigate to the parent menu with the arrow key
|
|
|
|
QTest::keyClick(window, mirrored ? Qt::Key_Right : Qt::Key_Left);
|
|
|
|
QVERIFY(subSubMenu1Item->isHighlighted());
|
|
|
|
QCOMPARE(mainMenu->isVisible(), cascade);
|
|
|
|
QVERIFY(subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
|
|
|
|
// navigate within the sub-menu
|
|
|
|
QQuickMenuItem *subMenuItem1 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0));
|
|
|
|
QVERIFY(subMenuItem1);
|
|
|
|
QQuickMenuItem *subMenuItem2 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(1));
|
|
|
|
QVERIFY(subMenuItem2);
|
|
|
|
QVERIFY(!subMenuItem1->isHighlighted());
|
|
|
|
QVERIFY(!subMenuItem2->isHighlighted());
|
|
|
|
QVERIFY(subSubMenu1Item->isHighlighted());
|
|
|
|
QTest::keyClick(window, Qt::Key_Up);
|
|
|
|
QVERIFY(!subMenuItem1->isHighlighted());
|
|
|
|
QVERIFY(subMenuItem2->isHighlighted());
|
|
|
|
QVERIFY(!subSubMenu1Item->isHighlighted());
|
|
|
|
|
|
|
|
// close the menus with esc
|
|
|
|
QTest::keyClick(window, Qt::Key_Escape);
|
|
|
|
QCOMPARE(mainMenu->isVisible(), cascade);
|
|
|
|
QVERIFY(!subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
QTest::keyClick(window, Qt::Key_Escape);
|
|
|
|
QVERIFY(!mainMenu->isVisible());
|
|
|
|
QVERIFY(!subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
}
|
|
|
|
|
2019-01-28 12:14:30 +00:00
|
|
|
void tst_QQuickMenu::subMenuDisabledKeyboard_data()
|
|
|
|
{
|
|
|
|
subMenuKeyboard_data();
|
|
|
|
}
|
|
|
|
|
|
|
|
// QTBUG-69540
|
|
|
|
void tst_QQuickMenu::subMenuDisabledKeyboard()
|
|
|
|
{
|
|
|
|
QFETCH(bool, cascade);
|
|
|
|
QFETCH(bool, mirrored);
|
|
|
|
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("subMenuDisabled.qml"));
|
|
|
|
QQuickApplicationWindow *window = helper.appWindow;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
centerOnScreen(window);
|
|
|
|
moveMouseAway(window);
|
|
|
|
|
|
|
|
if (mirrored)
|
|
|
|
window->setLocale(QLocale("ar_EG"));
|
|
|
|
|
|
|
|
QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(mainMenu);
|
|
|
|
mainMenu->setCascade(cascade);
|
|
|
|
QCOMPARE(mainMenu->cascade(), cascade);
|
|
|
|
|
|
|
|
QQuickMenuItem *menuItem1 = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(0));
|
|
|
|
QVERIFY(menuItem1);
|
|
|
|
|
|
|
|
QQuickMenu *subMenu = window->property("subMenu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(subMenu);
|
|
|
|
|
|
|
|
mainMenu->open();
|
|
|
|
QVERIFY(mainMenu->isVisible());
|
|
|
|
QVERIFY(!menuItem1->isHighlighted());
|
|
|
|
QVERIFY(!subMenu->isVisible());
|
|
|
|
|
|
|
|
// Highlight the top-level menu item.
|
|
|
|
QTest::keyClick(window, Qt::Key_Down);
|
|
|
|
QVERIFY(menuItem1->isHighlighted());
|
|
|
|
|
|
|
|
QQuickMenuItem *subMenuItem1 = qobject_cast<QQuickMenuItem *>(subMenu->itemAt(0));
|
|
|
|
QVERIFY(subMenuItem1);
|
|
|
|
QQuickMenuItem *subMenuItem2 = qobject_cast<QQuickMenuItem *>(subMenu->itemAt(1));
|
|
|
|
QVERIFY(subMenuItem2);
|
|
|
|
|
|
|
|
// Open the sub-menu.
|
|
|
|
QTest::keyClick(window, mirrored ? Qt::Key_Left : Qt::Key_Right);
|
|
|
|
// The first sub-menu item is disabled, so it should highlight the second one.
|
|
|
|
QVERIFY(!subMenuItem1->isHighlighted());
|
|
|
|
QVERIFY(subMenuItem2->isHighlighted());
|
|
|
|
|
|
|
|
// Close the menus with escape.
|
|
|
|
QTest::keyClick(window, Qt::Key_Escape);
|
|
|
|
QCOMPARE(mainMenu->isVisible(), cascade);
|
|
|
|
QVERIFY(!subMenu->isVisible());
|
|
|
|
QTest::keyClick(window, Qt::Key_Escape);
|
|
|
|
QVERIFY(!mainMenu->isVisible());
|
|
|
|
QVERIFY(!subMenu->isVisible());
|
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::subMenuPosition_data()
|
2017-06-01 21:36:57 +00:00
|
|
|
{
|
|
|
|
QTest::addColumn<bool>("cascade");
|
2017-06-16 03:28:59 +00:00
|
|
|
QTest::addColumn<bool>("flip");
|
2017-06-01 21:36:57 +00:00
|
|
|
QTest::addColumn<bool>("mirrored");
|
|
|
|
QTest::addColumn<qreal>("overlap");
|
|
|
|
|
2017-06-16 03:28:59 +00:00
|
|
|
QTest::newRow("cascading") << true << false << false << 0.0;
|
|
|
|
QTest::newRow("cascading,flip") << true << true << false << 0.0;
|
|
|
|
QTest::newRow("cascading,overlap") << true << false << false << 10.0;
|
|
|
|
QTest::newRow("cascading,flip,overlap") << true << true << false << 10.0;
|
|
|
|
QTest::newRow("cascading,mirrored") << true << false << true << 0.0;
|
|
|
|
QTest::newRow("cascading,mirrored,flip") << true << true << true << 0.0;
|
|
|
|
QTest::newRow("cascading,mirrored,overlap") << true << false << true << 10.0;
|
|
|
|
QTest::newRow("cascading,mirrored,flip,overlap") << true << true << true << 10.0;
|
|
|
|
QTest::newRow("non-cascading") << false << false << false << 0.0;
|
2017-06-01 21:36:57 +00:00
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::subMenuPosition()
|
2017-06-01 21:36:57 +00:00
|
|
|
{
|
|
|
|
QFETCH(bool, cascade);
|
2017-06-16 03:28:59 +00:00
|
|
|
QFETCH(bool, flip);
|
2017-06-01 21:36:57 +00:00
|
|
|
QFETCH(bool, mirrored);
|
|
|
|
QFETCH(qreal, overlap);
|
|
|
|
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml"));
|
|
|
|
QQuickApplicationWindow *window = helper.appWindow;
|
2017-06-16 03:28:59 +00:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2017-06-01 21:36:57 +00:00
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
2017-08-09 10:51:40 +00:00
|
|
|
centerOnScreen(window);
|
2017-06-01 21:36:57 +00:00
|
|
|
moveMouseAway(window);
|
|
|
|
|
|
|
|
if (mirrored)
|
|
|
|
window->setLocale(QLocale("ar_EG"));
|
|
|
|
|
|
|
|
QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(mainMenu);
|
|
|
|
mainMenu->setCascade(cascade);
|
|
|
|
QCOMPARE(mainMenu->cascade(), cascade);
|
|
|
|
mainMenu->setOverlap(overlap);
|
|
|
|
QCOMPARE(mainMenu->overlap(), overlap);
|
|
|
|
|
|
|
|
QQuickMenu *subMenu1 = window->property("subMenu1").value<QQuickMenu *>();
|
|
|
|
QVERIFY(subMenu1);
|
|
|
|
subMenu1->setCascade(cascade);
|
|
|
|
QCOMPARE(subMenu1->cascade(), cascade);
|
|
|
|
subMenu1->setOverlap(overlap);
|
|
|
|
QCOMPARE(subMenu1->overlap(), overlap);
|
|
|
|
|
|
|
|
QQuickMenu *subMenu2 = window->property("subMenu2").value<QQuickMenu *>();
|
|
|
|
QVERIFY(subMenu2);
|
|
|
|
subMenu2->setCascade(cascade);
|
|
|
|
QCOMPARE(subMenu2->cascade(), cascade);
|
|
|
|
subMenu2->setOverlap(overlap);
|
|
|
|
QCOMPARE(subMenu2->overlap(), overlap);
|
|
|
|
|
|
|
|
QQuickMenu *subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>();
|
|
|
|
QVERIFY(subSubMenu1);
|
|
|
|
subSubMenu1->setCascade(cascade);
|
|
|
|
QCOMPARE(subSubMenu1->cascade(), cascade);
|
|
|
|
subSubMenu1->setOverlap(overlap);
|
|
|
|
QCOMPARE(subSubMenu1->overlap(), overlap);
|
|
|
|
|
2017-06-16 03:28:59 +00:00
|
|
|
// choose the main menu position so that there's room for the
|
|
|
|
// sub-menus to cascade to the left when mirrored
|
2017-06-01 21:36:57 +00:00
|
|
|
if (mirrored)
|
2017-06-16 03:28:59 +00:00
|
|
|
mainMenu->setX(window->width() - 200);
|
2017-06-01 21:36:57 +00:00
|
|
|
|
|
|
|
mainMenu->open();
|
|
|
|
QVERIFY(mainMenu->isVisible());
|
|
|
|
QVERIFY(!subMenu1->isVisible());
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(!subSubMenu1->isVisible());
|
|
|
|
|
2017-06-16 03:28:59 +00:00
|
|
|
// open the sub-menu (never flips)
|
2017-06-01 21:36:57 +00:00
|
|
|
QQuickMenuItem *subMenu1Item = qobject_cast<QQuickMenuItem *>(mainMenu->itemAt(1));
|
|
|
|
QVERIFY(subMenu1Item);
|
|
|
|
QCOMPARE(subMenu1Item->subMenu(), subMenu1);
|
|
|
|
emit subMenu1Item->triggered();
|
|
|
|
QCOMPARE(mainMenu->isVisible(), cascade);
|
|
|
|
QVERIFY(subMenu1->isVisible());
|
|
|
|
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
|
|
|
|
} else {
|
|
|
|
QCOMPARE(subMenu1->parentItem(), mainMenu->parentItem());
|
|
|
|
// centered over the parent menu
|
|
|
|
QCOMPARE(subMenu1->popupItem()->x(), mainMenu->popupItem()->x() + (mainMenu->width() - subMenu1->width()) / 2);
|
|
|
|
QCOMPARE(subMenu1->popupItem()->y(), mainMenu->popupItem()->y() + (mainMenu->height() - subMenu1->height()) / 2);
|
|
|
|
}
|
|
|
|
|
2017-06-16 03:28:59 +00:00
|
|
|
// open the sub-sub-menu (can flip)
|
2017-06-01 21:36:57 +00:00
|
|
|
QQuickMenuItem *subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2));
|
|
|
|
QVERIFY(subSubMenu1Item);
|
|
|
|
QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1);
|
|
|
|
emit subSubMenu1Item->triggered();
|
|
|
|
QCOMPARE(mainMenu->isVisible(), cascade);
|
|
|
|
QCOMPARE(subMenu1->isVisible(), cascade);
|
|
|
|
QVERIFY(!subMenu2->isVisible());
|
|
|
|
QVERIFY(subSubMenu1->isVisible());
|
|
|
|
|
|
|
|
if (cascade) {
|
|
|
|
QCOMPARE(subSubMenu1->parentItem(), subSubMenu1Item);
|
|
|
|
// vertically aligned to the parent menu item
|
|
|
|
QCOMPARE(subSubMenu1->popupItem()->y(), subMenu1->popupItem()->y() + subSubMenu1Item->y() - subSubMenu1->topPadding());
|
2017-06-16 03:28:59 +00:00
|
|
|
if (mirrored != flip)
|
2017-06-01 21:36:57 +00:00
|
|
|
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
|
|
|
|
} else {
|
|
|
|
QCOMPARE(subSubMenu1->parentItem(), subMenu1->parentItem());
|
|
|
|
// centered over the parent menu
|
|
|
|
QCOMPARE(subSubMenu1->popupItem()->x(), subMenu1->popupItem()->x() + (subMenu1->width() - subSubMenu1->width()) / 2);
|
|
|
|
QCOMPARE(subSubMenu1->popupItem()->y(), subMenu1->popupItem()->y() + (subMenu1->height() - subSubMenu1->height()) / 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-27 18:07:23 +00:00
|
|
|
void tst_QQuickMenu::addRemoveSubMenus()
|
2017-06-07 17:43:58 +00:00
|
|
|
{
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("subMenus.qml"));
|
|
|
|
QQuickWindow *window = helper.window;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
|
|
|
|
QQuickMenu *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
|
|
|
|
QVERIFY(mainMenu);
|
|
|
|
|
2017-07-10 09:59:47 +00:00
|
|
|
QVERIFY(!mainMenu->menuAt(0));
|
|
|
|
|
2017-06-07 17:43:58 +00:00
|
|
|
QPointer<QQuickMenu> subMenu1 = window->property("subMenu1").value<QQuickMenu *>();
|
|
|
|
QVERIFY(!subMenu1.isNull());
|
2017-07-10 09:59:47 +00:00
|
|
|
QCOMPARE(mainMenu->menuAt(1), subMenu1.data());
|
|
|
|
|
|
|
|
QVERIFY(!mainMenu->menuAt(2));
|
2017-06-07 17:43:58 +00:00
|
|
|
|
|
|
|
QPointer<QQuickMenu> subMenu2 = window->property("subMenu2").value<QQuickMenu *>();
|
|
|
|
QVERIFY(!subMenu2.isNull());
|
2017-07-10 09:59:47 +00:00
|
|
|
QCOMPARE(mainMenu->menuAt(3), subMenu2.data());
|
|
|
|
|
|
|
|
QVERIFY(!mainMenu->menuAt(4));
|
2017-06-07 17:43:58 +00:00
|
|
|
|
|
|
|
QPointer<QQuickMenu> subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>();
|
|
|
|
QVERIFY(!subSubMenu1.isNull());
|
|
|
|
|
|
|
|
// takeMenu(int) does not destroy the menu, but does destroy the respective item in the parent menu
|
|
|
|
QPointer<QQuickMenuItem> subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2));
|
|
|
|
QVERIFY(subSubMenu1Item);
|
|
|
|
QCOMPARE(subSubMenu1Item->subMenu(), subSubMenu1.data());
|
|
|
|
QCOMPARE(subMenu1->takeMenu(2), subSubMenu1.data());
|
|
|
|
QVERIFY(!subMenu1->itemAt(2));
|
|
|
|
QCoreApplication::sendPostedEvents(subSubMenu1, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(!subSubMenu1.isNull());
|
|
|
|
QCoreApplication::sendPostedEvents(subSubMenu1Item, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(subSubMenu1Item.isNull());
|
|
|
|
|
|
|
|
// takeMenu(int) does not destroy an item that doesn't present a menu
|
|
|
|
QPointer<QQuickMenuItem> subMenuItem1 = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0));
|
|
|
|
QVERIFY(subMenuItem1);
|
|
|
|
QVERIFY(!subMenuItem1->subMenu());
|
|
|
|
QVERIFY(!subMenu1->takeMenu(0));
|
|
|
|
QCoreApplication::sendPostedEvents(subMenuItem1, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(!subMenuItem1.isNull());
|
|
|
|
|
|
|
|
// addMenu(Menu) re-creates the respective item in the parent menu
|
|
|
|
subMenu1->addMenu(subSubMenu1);
|
|
|
|
subSubMenu1Item = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(2));
|
|
|
|
QVERIFY(!subSubMenu1Item.isNull());
|
|
|
|
|
|
|
|
// removeMenu(Menu) destroys both the menu and the respective item in the parent menu
|
|
|
|
subMenu1->removeMenu(subSubMenu1);
|
|
|
|
QVERIFY(!subMenu1->itemAt(2));
|
|
|
|
QCoreApplication::sendPostedEvents(subSubMenu1, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(subSubMenu1.isNull());
|
|
|
|
QCoreApplication::sendPostedEvents(subSubMenu1Item, QEvent::DeferredDelete);
|
|
|
|
QVERIFY(subSubMenu1Item.isNull());
|
|
|
|
}
|
|
|
|
|
2018-06-18 09:38:40 +00:00
|
|
|
void tst_QQuickMenu::scrollable_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<QString>("qmlFilePath");
|
|
|
|
|
|
|
|
QTest::addRow("Window") << QString::fromLatin1("windowScrollable.qml");
|
|
|
|
QTest::addRow("ApplicationWindow") << QString::fromLatin1("applicationWindowScrollable.qml");
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QQuickMenu::scrollable()
|
|
|
|
{
|
|
|
|
QFETCH(QString, qmlFilePath);
|
|
|
|
|
|
|
|
QQuickApplicationHelper helper(this, qmlFilePath);
|
|
|
|
QQuickWindow *window = helper.window;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
|
|
|
|
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
|
|
|
|
menu->open();
|
|
|
|
QVERIFY(menu->isVisible());
|
|
|
|
|
|
|
|
QQuickItem *contentItem = menu->contentItem();
|
|
|
|
QCOMPARE(contentItem->property("interactive").toBool(), true);
|
|
|
|
}
|
|
|
|
|
Fix Menu not being dismissed when the triggered item disables itself
Problem
Consider the following code:
Menu {
title: "Menu"
Action {
text: "Item"
onTriggered: enabled = false
}
}
A MenuItem (AbstractButton) is created for the Action, and when it is
clicked, this function is called:
void QQuickAbstractButtonPrivate::trigger()
{
Q_Q(QQuickAbstractButton);
if (action && action->isEnabled())
QQuickActionPrivate::get(action)->trigger(q, false);
else if (effectiveEnable)
emit q->clicked();
}
QQuickActionPrivate::get(action)->trigger(q, false) results in this
function being called:
void QQuickAbstractButtonPrivate::click()
{
Q_Q(QQuickAbstractButton);
if (effectiveEnable)
emit q->clicked();
}
Since the action (and hence the menu item) was disabled in the signal
handler, the effectiveEnable check fails and clicked() is not emitted.
This causes the menu to not be dismissed.
Solution
Before calling QQuickActionPrivate::get(action)->trigger(), store
the button's enabled state. If triggering the action causes the action
to be disabled (due to the signal handler), we can then choose whether
or not we emit QQuickAbstractButton::clicked(). Specifically, we emit
clicked() if:
- we were enabled before triggering the action, and
- we have no associated action, or it's no longer enabled
Task-number: QTBUG-69682
Change-Id: Ib4e3c313b776decc74089a6beffe415605c430be
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
2018-07-30 12:28:44 +00:00
|
|
|
void tst_QQuickMenu::disableWhenTriggered_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<int>("menuItemIndex");
|
|
|
|
QTest::addColumn<int>("subMenuItemIndex");
|
|
|
|
|
|
|
|
QTest::addRow("Action") << 0 << -1;
|
|
|
|
QTest::addRow("MenuItem with Action") << 1 << -1;
|
|
|
|
QTest::addRow("MenuItem with Action declared outside menu") << 2 << -1;
|
|
|
|
QTest::addRow("MenuItem with no Action") << 3 << -1;
|
|
|
|
|
|
|
|
QTest::addRow("Sub-Action") << 4 << 0;
|
|
|
|
QTest::addRow("Sub-MenuItem with Action declared inside") << 4 << 1;
|
|
|
|
QTest::addRow("Sub-MenuItem with Action declared outside menu") << 4 << 2;
|
|
|
|
QTest::addRow("Sub-MenuItem with no Action") << 4 << 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that the menu is dismissed when a menu item sets "enabled = false" in onTriggered().
|
|
|
|
void tst_QQuickMenu::disableWhenTriggered()
|
|
|
|
{
|
|
|
|
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|
|
|
|
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
|
|
|
|
QSKIP("Mouse hovering not functional on offscreen/minimal platforms");
|
|
|
|
|
|
|
|
QFETCH(int, menuItemIndex);
|
|
|
|
QFETCH(int, subMenuItemIndex);
|
|
|
|
|
|
|
|
QQuickApplicationHelper helper(this, QLatin1String("disableWhenTriggered.qml"));
|
|
|
|
QQuickWindow *window = helper.window;
|
|
|
|
window->show();
|
|
|
|
QVERIFY(QTest::qWaitForWindowActive(window));
|
|
|
|
|
|
|
|
QQuickMenu *menu = window->findChild<QQuickMenu*>("Menu");
|
|
|
|
QVERIFY(menu);
|
|
|
|
|
|
|
|
menu->open();
|
|
|
|
QVERIFY(menu->isVisible());
|
|
|
|
|
|
|
|
QPointer<QQuickMenuItem> menuItem = qobject_cast<QQuickMenuItem*>(menu->itemAt(menuItemIndex));
|
|
|
|
QVERIFY(menuItem);
|
|
|
|
|
|
|
|
if (subMenuItemIndex == -1) {
|
|
|
|
// Click a top-level menu item.
|
|
|
|
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier,
|
|
|
|
menuItem->mapToScene(QPointF(menuItem->width() / 2, menuItem->height() / 2)).toPoint());
|
|
|
|
QCOMPARE(menuItem->isEnabled(), false);
|
|
|
|
QVERIFY(!menu->isVisible());
|
|
|
|
} else {
|
|
|
|
// Click a sub-menu item.
|
|
|
|
QPointer<QQuickMenu> subMenu = menuItem->subMenu();
|
|
|
|
QVERIFY(subMenu);
|
|
|
|
|
|
|
|
QPointer<QQuickMenuItem> subMenuItem = qobject_cast<QQuickMenuItem*>(subMenu->itemAt(subMenuItemIndex));
|
|
|
|
QVERIFY(subMenuItem);
|
|
|
|
|
|
|
|
// First, open the sub-menu.
|
|
|
|
QTest::mouseMove(window, menuItem->mapToScene(QPoint(1, 1)).toPoint());
|
|
|
|
QTRY_VERIFY(subMenu->isVisible());
|
|
|
|
QVERIFY(menuItem->isHovered());
|
|
|
|
QTRY_VERIFY(subMenu->contentItem()->property("contentHeight").toReal() > 0.0);
|
|
|
|
|
|
|
|
// Click the item.
|
|
|
|
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier,
|
|
|
|
subMenuItem->mapToScene(QPointF(subMenuItem->width() / 2, subMenuItem->height() / 2)).toPoint());
|
|
|
|
QCOMPARE(subMenuItem->isEnabled(), false);
|
|
|
|
QVERIFY(!menu->isVisible());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
QTEST_MAIN(tst_QQuickMenu)
|
2015-11-16 15:06:07 +00:00
|
|
|
|
2017-09-27 13:14:32 +00:00
|
|
|
#include "tst_qquickmenu.moc"
|